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