[dbench @ cvs-1:tridge-20010812182557-rkvm3a5cqeobpai7]
[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, uint32 socket_addr)
26 {
27         struct hostent *hp;
28         struct sockaddr_in sock;
29         char host_name[1000];
30         int res;
31         int one=1;
32         extern char *tcp_options;
33
34         /* get my host name */
35         if (gethostname(host_name, sizeof(host_name)) == -1) { 
36                 fprintf(stderr,"gethostname failed\n"); return -1; 
37         } 
38
39         /* get host info */
40         if ((hp = gethostbyname(host_name)) == 0) {
41                 fprintf(stderr,"Get_Hostbyname: Unknown host %s\n",host_name);
42                 return -1;
43         }
44   
45         bzero((char *)&sock,sizeof(sock));
46         memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
47
48 #ifdef HAVE_SOCK_SIN_LEN
49         sock.sin_len = sizeof(sock);
50 #endif
51         sock.sin_port = htons( port );
52         sock.sin_family = hp->h_addrtype;
53         sock.sin_addr.s_addr = socket_addr;
54         res = socket(hp->h_addrtype, type, 0);
55         if (res == -1) { 
56                 fprintf(stderr, "socket failed\n"); return -1; 
57         }
58
59         setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
60
61         /* now we've got a socket - we need to bind it */
62         if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) { 
63                 return(-1); 
64         }
65
66         set_socket_options(res, tcp_options);
67
68         return res;
69 }
70
71
72 /* open a socket to a tcp remote host with the specified port 
73    based on code from Warren */
74 int open_socket_out(char *host, int port)
75 {
76         int type = SOCK_STREAM;
77         struct sockaddr_in sock_out;
78         int res;
79         struct hostent *hp;  
80         extern char *tcp_options;
81
82         res = socket(PF_INET, type, 0);
83         if (res == -1) {
84                 return -1;
85         }
86
87         hp = gethostbyname(host);
88         if (!hp) {
89                 fprintf(stderr,"unknown host: %s\n", host);
90                 return -1;
91         }
92
93         memcpy(&sock_out.sin_addr, hp->h_addr, hp->h_length);
94         sock_out.sin_port = htons(port);
95         sock_out.sin_family = PF_INET;
96
97         set_socket_options(res, tcp_options);
98
99         if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
100                 close(res);
101                 fprintf(stderr,"failed to connect to %s - %s\n", 
102                         host, strerror(errno));
103                 return -1;
104         }
105
106         return res;
107 }
108
109
110
111 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
112
113 struct
114 {
115   char *name;
116   int level;
117   int option;
118   int value;
119   int opttype;
120 } socket_options[] = {
121   {"SO_KEEPALIVE",      SOL_SOCKET,    SO_KEEPALIVE,    0,                 OPT_BOOL},
122   {"SO_REUSEADDR",      SOL_SOCKET,    SO_REUSEADDR,    0,                 OPT_BOOL},
123   {"SO_BROADCAST",      SOL_SOCKET,    SO_BROADCAST,    0,                 OPT_BOOL},
124 #ifdef TCP_NODELAY
125   {"TCP_NODELAY",       IPPROTO_TCP,   TCP_NODELAY,     0,                 OPT_BOOL},
126 #endif
127 #ifdef IPTOS_LOWDELAY
128   {"IPTOS_LOWDELAY",    IPPROTO_IP,    IP_TOS,          IPTOS_LOWDELAY,    OPT_ON},
129 #endif
130 #ifdef IPTOS_THROUGHPUT
131   {"IPTOS_THROUGHPUT",  IPPROTO_IP,    IP_TOS,          IPTOS_THROUGHPUT,  OPT_ON},
132 #endif
133 #ifdef SO_SNDBUF
134   {"SO_SNDBUF",         SOL_SOCKET,    SO_SNDBUF,       0,                 OPT_INT},
135 #endif
136 #ifdef SO_RCVBUF
137   {"SO_RCVBUF",         SOL_SOCKET,    SO_RCVBUF,       0,                 OPT_INT},
138 #endif
139 #ifdef SO_SNDLOWAT
140   {"SO_SNDLOWAT",       SOL_SOCKET,    SO_SNDLOWAT,     0,                 OPT_INT},
141 #endif
142 #ifdef SO_RCVLOWAT
143   {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},
144 #endif
145 #ifdef SO_SNDTIMEO
146   {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},
147 #endif
148 #ifdef SO_RCVTIMEO
149   {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},
150 #endif
151   {NULL,0,0,0,0}};
152
153         
154
155 /****************************************************************************
156 set user socket options
157 ****************************************************************************/
158 void set_socket_options(int fd, char *options)
159 {
160         char tok[200];
161
162         while (next_token(&options,tok," \t,"))
163     {
164       int ret=0,i;
165       int value = 1;
166       char *p;
167       BOOL got_value = False;
168
169       if ((p = strchr(tok,'=')))
170         {
171           *p = 0;
172           value = atoi(p+1);
173           got_value = True;
174         }
175
176       for (i=0;socket_options[i].name;i++)
177         if (strcasecmp(socket_options[i].name,tok)==0)
178           break;
179
180       if (!socket_options[i].name)
181         {
182           fprintf(stderr, "Unknown socket option %s\n",tok);
183           continue;
184         }
185
186       switch (socket_options[i].opttype)
187         {
188         case OPT_BOOL:
189         case OPT_INT:
190           ret = setsockopt(fd,socket_options[i].level,
191                            socket_options[i].option,(char *)&value,sizeof(int));
192           break;
193
194         case OPT_ON:
195           if (got_value)
196             fprintf(stderr,"syntax error - %s does not take a value\n",tok);
197
198           {
199             int on = socket_options[i].value;
200             ret = setsockopt(fd,socket_options[i].level,
201                              socket_options[i].option,(char *)&on,sizeof(int));
202           }
203           break;          
204         }
205       
206       if (ret != 0)
207         fprintf(stderr, "Failed to set socket option %s\n",tok);
208     }
209 }
210
211 int read_sock(int s, char *buf, int size)
212 {
213         int total=0;
214
215         while (size) {
216                 int r = recv(s, buf, size, MSG_WAITALL);
217                 if (r <= 0) break;
218                 buf += r;
219                 size -= r;
220                 total += r;
221         }
222         return total;
223 }
224
225 int write_sock(int s, char *buf, int size)
226 {
227         int total=0;
228
229         while (size) {
230                 int r = send(s, buf, size, 0);
231                 if (r <= 0) break;
232                 buf += r;
233                 size -= r;
234                 total += r;
235         }
236         return total;
237 }