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