[dbench @ cvs-1:tridge-20020311115727-tlkt4r7bbrguhcr0]
[tridge/dbench.git] / socklib.c
1 /* 
2    dbench version 1
3    Copyright (C) Andrew Tridgell 1999
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "dbench.h"
21
22 /****************************************************************************
23 open a socket of the specified type, port and address for incoming data
24 ****************************************************************************/
25 int open_socket_in(int type, int port)
26 {
27         struct sockaddr_in sock;
28         int res;
29         int one=1;
30         extern char *tcp_options;
31
32         memset((char *)&sock,0, sizeof(sock));
33         sock.sin_port = htons(port);
34         sock.sin_family = AF_INET;
35         sock.sin_addr.s_addr = 0;
36         res = socket(AF_INET, type, 0);
37         if (res == -1) { 
38                 fprintf(stderr, "socket failed\n"); return -1; 
39         }
40
41         setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
42
43         /* now we've got a socket - we need to bind it */
44         if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) { 
45                 return(-1); 
46         }
47
48         set_socket_options(res, tcp_options);
49
50         return res;
51 }
52
53
54 /* open a socket to a tcp remote host with the specified port 
55    based on code from Warren */
56 int open_socket_out(char *host, int port)
57 {
58         int type = SOCK_STREAM;
59         struct sockaddr_in sock_out;
60         int res;
61         struct hostent *hp;  
62         extern char *tcp_options;
63
64         res = socket(PF_INET, type, 0);
65         if (res == -1) {
66                 return -1;
67         }
68
69         hp = gethostbyname(host);
70         if (!hp) {
71                 fprintf(stderr,"unknown host: %s\n", host);
72                 return -1;
73         }
74
75         memcpy(&sock_out.sin_addr, hp->h_addr, hp->h_length);
76         sock_out.sin_port = htons(port);
77         sock_out.sin_family = PF_INET;
78
79         set_socket_options(res, tcp_options);
80
81         if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
82                 close(res);
83                 fprintf(stderr,"failed to connect to %s - %s\n", 
84                         host, strerror(errno));
85                 return -1;
86         }
87
88         return res;
89 }
90
91
92
93 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
94
95 struct
96 {
97   char *name;
98   int level;
99   int option;
100   int value;
101   int opttype;
102 } socket_options[] = {
103   {"SO_KEEPALIVE",      SOL_SOCKET,    SO_KEEPALIVE,    0,                 OPT_BOOL},
104   {"SO_REUSEADDR",      SOL_SOCKET,    SO_REUSEADDR,    0,                 OPT_BOOL},
105   {"SO_BROADCAST",      SOL_SOCKET,    SO_BROADCAST,    0,                 OPT_BOOL},
106 #ifdef TCP_NODELAY
107   {"TCP_NODELAY",       IPPROTO_TCP,   TCP_NODELAY,     0,                 OPT_BOOL},
108 #endif
109 #ifdef IPTOS_LOWDELAY
110   {"IPTOS_LOWDELAY",    IPPROTO_IP,    IP_TOS,          IPTOS_LOWDELAY,    OPT_ON},
111 #endif
112 #ifdef IPTOS_THROUGHPUT
113   {"IPTOS_THROUGHPUT",  IPPROTO_IP,    IP_TOS,          IPTOS_THROUGHPUT,  OPT_ON},
114 #endif
115 #ifdef SO_SNDBUF
116   {"SO_SNDBUF",         SOL_SOCKET,    SO_SNDBUF,       0,                 OPT_INT},
117 #endif
118 #ifdef SO_RCVBUF
119   {"SO_RCVBUF",         SOL_SOCKET,    SO_RCVBUF,       0,                 OPT_INT},
120 #endif
121 #ifdef SO_SNDLOWAT
122   {"SO_SNDLOWAT",       SOL_SOCKET,    SO_SNDLOWAT,     0,                 OPT_INT},
123 #endif
124 #ifdef SO_RCVLOWAT
125   {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},
126 #endif
127 #ifdef SO_SNDTIMEO
128   {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},
129 #endif
130 #ifdef SO_RCVTIMEO
131   {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},
132 #endif
133   {NULL,0,0,0,0}};
134
135         
136
137 /****************************************************************************
138 set user socket options
139 ****************************************************************************/
140 void set_socket_options(int fd, char *options)
141 {
142         char tok[200];
143
144         while (next_token(&options,tok," \t,"))
145     {
146       int ret=0,i;
147       int value = 1;
148       char *p;
149       BOOL got_value = False;
150
151       if ((p = strchr(tok,'=')))
152         {
153           *p = 0;
154           value = atoi(p+1);
155           got_value = True;
156         }
157
158       for (i=0;socket_options[i].name;i++)
159         if (strcasecmp(socket_options[i].name,tok)==0)
160           break;
161
162       if (!socket_options[i].name)
163         {
164           fprintf(stderr, "Unknown socket option %s\n",tok);
165           continue;
166         }
167
168       switch (socket_options[i].opttype)
169         {
170         case OPT_BOOL:
171         case OPT_INT:
172           ret = setsockopt(fd,socket_options[i].level,
173                            socket_options[i].option,(char *)&value,sizeof(int));
174           break;
175
176         case OPT_ON:
177           if (got_value)
178             fprintf(stderr,"syntax error - %s does not take a value\n",tok);
179
180           {
181             int on = socket_options[i].value;
182             ret = setsockopt(fd,socket_options[i].level,
183                              socket_options[i].option,(char *)&on,sizeof(int));
184           }
185           break;          
186         }
187       
188       if (ret != 0)
189         fprintf(stderr, "Failed to set socket option %s\n",tok);
190     }
191 }
192
193 int read_sock(int s, char *buf, int size)
194 {
195         int total=0;
196
197         while (size) {
198                 int r = recv(s, buf, size, MSG_WAITALL);
199                 if (r <= 0) {
200                         if (r == -1) perror("recv");
201                         break;
202                 }
203                 buf += r;
204                 size -= r;
205                 total += r;
206         }
207         return total;
208 }
209
210 int write_sock(int s, char *buf, int size)
211 {
212         int total=0;
213
214         while (size) {
215                 int r = send(s, buf, size, 0);
216                 if (r <= 0) {
217                         if (r == -1) perror("send");
218                         break;
219                 }
220                 buf += r;
221                 size -= r;
222                 total += r;
223         }
224         return total;
225 }