2 measure latency of tcp sockets
3 tridge@samba.org July 2006
12 #include <sys/ioctl.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
23 #include <arpa/inet.h>
31 static struct timeval tp1,tp2;
33 static void start_timer()
35 gettimeofday(&tp1,NULL);
38 static double end_timer()
40 gettimeofday(&tp2,NULL);
41 return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) -
42 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
45 static void fatal(const char *why)
47 fprintf(stderr, "fatal: %s - %s\n", why, strerror(errno));
51 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
60 } socket_options[] = {
61 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
62 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
63 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
65 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
68 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
70 #ifdef IPTOS_THROUGHPUT
71 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
74 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
77 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
80 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
83 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
86 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
89 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
94 /****************************************************************************
95 Get the next token from a string, return False if none found
96 handles double-quotes.
97 Based on a routine by GJC@VILLAGE.COM.
98 Extensively modified by Andrew.Tridgell@anu.edu.au
99 ****************************************************************************/
100 BOOL next_token(char **ptr,char *buff,char *sep)
104 static char *last_ptr=NULL;
106 if (!ptr) ptr = &last_ptr;
107 if (!ptr) return(False);
111 /* default to simple separators */
112 if (!sep) sep = " \t\n\r";
114 /* find the first non sep char */
115 while(*s && strchr(sep,*s)) s++;
118 if (! *s) return(False);
120 /* copy over the token */
121 for (quoted = False; *s && (quoted || !strchr(sep,*s)); s++)
129 *ptr = (*s) ? s+1 : s;
137 /****************************************************************************
138 set user socket options
139 ****************************************************************************/
140 void set_socket_options(int fd, char *options)
144 while (next_token(&options,tok," \t,"))
149 BOOL got_value = False;
151 if ((p = strchr(tok,'=')))
158 for (i=0;socket_options[i].name;i++)
159 if (strcasecmp(socket_options[i].name,tok)==0)
162 if (!socket_options[i].name)
164 printf("Unknown socket option %s\n",tok);
168 switch (socket_options[i].opttype)
172 ret = setsockopt(fd,socket_options[i].level,
173 socket_options[i].option,(char *)&value,sizeof(int));
178 printf("syntax error - %s does not take a value\n",tok);
181 int on = socket_options[i].value;
182 ret = setsockopt(fd,socket_options[i].level,
183 socket_options[i].option,(char *)&on,sizeof(int));
189 printf("Failed to set socket option %s\n",tok);
194 connect to a tcp socket
196 int tcp_socket_connect(int port)
198 int type = SOCK_STREAM;
199 struct sockaddr_in sock_out;
202 const char *host = "localhost";
204 res = socket(PF_INET, type, 0);
209 hp = gethostbyname(host);
211 fprintf(stderr,"unknown host: %s\n", host);
216 memcpy(&sock_out.sin_addr, hp->h_addr, hp->h_length);
217 sock_out.sin_port = htons(port);
218 sock_out.sin_family = PF_INET;
220 if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
221 fprintf(stderr,"failed to connect to %s - %s\n", host, strerror(errno));
231 create a tcp socket and bind it
232 return a file descriptor open on the socket
234 static int tcp_socket_bind(int port)
237 struct sockaddr_in sock;
238 char host_name[1000];
242 /* get my host name */
243 if (gethostname(host_name, sizeof(host_name)) == -1) {
244 fprintf(stderr,"gethostname failed\n");
249 if ((hp = gethostbyname(host_name)) == 0) {
250 fprintf(stderr,"gethostbyname: Unknown host %s\n",host_name);
254 memset((char *)&sock,0,sizeof(sock));
255 memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
256 sock.sin_port = htons(port);
257 sock.sin_family = hp->h_addrtype;
258 sock.sin_addr.s_addr = INADDR_ANY;
259 res = socket(hp->h_addrtype, SOCK_STREAM, 0);
261 fprintf(stderr,"socket failed\n");
265 setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
267 /* now we've got a socket - we need to bind it */
268 if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) == -1) {
269 fprintf(stderr,"bind failed on port %d\n", port);
280 accept on a tcp socket
282 static int tcp_socket_accept(int fd)
286 return accept(fd, &a, &len);
289 static void worker(int port1, int port2, int w)
291 int l = tcp_socket_bind(port1);
295 set_socket_options(l, "SO_REUSEADDR");
299 s2 = tcp_socket_connect(port2);
300 s1 = tcp_socket_accept(l);
302 set_socket_options(s1, "TCP_NODELAY");
303 set_socket_options(s2, "TCP_NODELAY");
309 if (write(s2, &c, 1) != 1) {
312 if (read(s1, &c, 1) != 1) {
315 if (w == 1 && (end_timer() > 1.0)) {
316 printf("%8u ops/sec\r",
317 (unsigned)(2*count/end_timer()));
326 int main(int argc, char *argv[])
329 worker(1313, 1314, 0);
331 worker(1314, 1313, 1);