lib_tcp.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * tcp_lib.c - routines for managing TCP connections.
  3. *
  4. * Positive port/program numbers are RPC ports, negative ones are TCP ports.
  5. *
  6. * Copyright (c) 1994-1996 Larry McVoy.
  7. */
  8. #define _LIB /* bench.h needs this */
  9. #include "bench.h"
  10. /*
  11. * Get a TCP socket, bind it, figure out the port,
  12. * and advertise the port as program "prog".
  13. *
  14. * XXX - it would be nice if you could advertise ascii strings.
  15. */
  16. int
  17. tcp_server(int prog, int rdwr)
  18. {
  19. int sock;
  20. struct sockaddr_in s;
  21. #ifdef LIBTCP_VERBOSE
  22. fprintf(stderr, "tcp_server(%u, %u)\n", prog, rdwr);
  23. #endif
  24. if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  25. perror("socket");
  26. exit(1);
  27. }
  28. sock_optimize(sock, rdwr);
  29. bzero((void*)&s, sizeof(s));
  30. s.sin_family = AF_INET;
  31. if (prog < 0) {
  32. s.sin_port = htons(-prog);
  33. }
  34. if (bind(sock, (struct sockaddr*)&s, sizeof(s)) < 0) {
  35. perror("bind");
  36. exit(2);
  37. }
  38. if (listen(sock, 100) < 0) {
  39. perror("listen");
  40. exit(4);
  41. }
  42. if (prog > 0) {
  43. #ifdef LIBTCP_VERBOSE
  44. fprintf(stderr, "Server port %d\n", sockport(sock));
  45. #endif
  46. (void)pmap_unset((u_long)prog, (u_long)1);
  47. if (!pmap_set((u_long)prog, (u_long)1, (u_long)IPPROTO_TCP,
  48. (unsigned short)sockport(sock))) {
  49. perror("pmap_set");
  50. exit(5);
  51. }
  52. }
  53. return (sock);
  54. }
  55. /*
  56. * Unadvertise the socket
  57. */
  58. int
  59. tcp_done(int prog)
  60. {
  61. if (prog > 0) {
  62. pmap_unset((u_long)prog, (u_long)1);
  63. }
  64. return (0);
  65. }
  66. /*
  67. * Accept a connection and return it
  68. */
  69. int
  70. tcp_accept(int sock, int rdwr)
  71. {
  72. struct sockaddr_in s;
  73. int newsock, namelen;
  74. namelen = sizeof(s);
  75. bzero((void*)&s, namelen);
  76. retry:
  77. if ((newsock = accept(sock, (struct sockaddr*)&s, &namelen)) < 0) {
  78. if (errno == EINTR)
  79. goto retry;
  80. perror("accept");
  81. exit(6);
  82. }
  83. #ifdef LIBTCP_VERBOSE
  84. fprintf(stderr, "Server newsock port %d\n", sockport(newsock));
  85. #endif
  86. sock_optimize(newsock, rdwr);
  87. return (newsock);
  88. }
  89. /*
  90. * Connect to the TCP socket advertised as "prog" on "host" and
  91. * return the connected socket.
  92. *
  93. * Hacked Thu Oct 27 1994 to cache pmap_getport calls. This saves
  94. * about 4000 usecs in loopback lat_connect calls. I suppose we
  95. * should time gethostbyname() & pmap_getprot(), huh?
  96. */
  97. int
  98. tcp_connect(char *host, int prog, int rdwr)
  99. {
  100. static struct hostent *h;
  101. static struct sockaddr_in s;
  102. static u_short save_port;
  103. static u_long save_prog;
  104. static char *save_host;
  105. int sock;
  106. static int tries = 0;
  107. if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  108. perror("socket");
  109. exit(1);
  110. }
  111. if (rdwr & SOCKOPT_PID) {
  112. static unsigned short port;
  113. struct sockaddr_in sin;
  114. if (!port) {
  115. port = (unsigned short)(getpid() << 4);
  116. if (port < 1024) {
  117. port += 1024;
  118. }
  119. }
  120. do {
  121. port++;
  122. bzero((void*)&sin, sizeof(sin));
  123. sin.sin_family = AF_INET;
  124. sin.sin_port = htons(port);
  125. } while (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) == -1);
  126. }
  127. #ifdef LIBTCP_VERBOSE
  128. else {
  129. struct sockaddr_in sin;
  130. bzero((void*)&sin, sizeof(sin));
  131. sin.sin_family = AF_INET;
  132. if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
  133. perror("bind");
  134. exit(2);
  135. }
  136. }
  137. fprintf(stderr, "Client port %d\n", sockport(sock));
  138. #endif
  139. sock_optimize(sock, rdwr);
  140. if (!h || host != save_host || prog != save_prog) {
  141. save_host = host; /* XXX - counting on them not
  142. * changing it - benchmark only.
  143. */
  144. save_prog = prog;
  145. if (!(h = gethostbyname(host))) {
  146. perror(host);
  147. exit(2);
  148. }
  149. bzero((void *) &s, sizeof(s));
  150. s.sin_family = AF_INET;
  151. bcopy((void*)h->h_addr, (void *)&s.sin_addr, h->h_length);
  152. if (prog > 0) {
  153. save_port = pmap_getport(&s, prog,
  154. (u_long)1, IPPROTO_TCP);
  155. if (!save_port) {
  156. perror("lib TCP: No port found");
  157. exit(3);
  158. }
  159. #ifdef LIBTCP_VERBOSE
  160. fprintf(stderr, "Server port %d\n", save_port);
  161. #endif
  162. s.sin_port = htons(save_port);
  163. } else {
  164. s.sin_port = htons(-prog);
  165. }
  166. }
  167. if (connect(sock, (struct sockaddr*)&s, sizeof(s)) < 0) {
  168. if (errno == ECONNRESET || errno == ECONNREFUSED) {
  169. close(sock);
  170. if (++tries > 10) return(-1);
  171. return (tcp_connect(host, prog, rdwr));
  172. }
  173. perror("connect");
  174. exit(4);
  175. }
  176. tries = 0;
  177. return (sock);
  178. }
  179. void
  180. sock_optimize(int sock, int flags)
  181. {
  182. if (flags & SOCKOPT_READ) {
  183. int sockbuf = SOCKBUF;
  184. while (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &sockbuf,
  185. sizeof(int))) {
  186. sockbuf >>= 1;
  187. }
  188. #ifdef LIBTCP_VERBOSE
  189. fprintf(stderr, "sockopt %d: RCV: %dK\n", sock, sockbuf>>10);
  190. #endif
  191. }
  192. if (flags & SOCKOPT_WRITE) {
  193. int sockbuf = SOCKBUF;
  194. while (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sockbuf,
  195. sizeof(int))) {
  196. sockbuf >>= 1;
  197. }
  198. #ifdef LIBTCP_VERBOSE
  199. fprintf(stderr, "sockopt %d: SND: %dK\n", sock, sockbuf>>10);
  200. #endif
  201. }
  202. if (flags & SOCKOPT_REUSE) {
  203. int val = 1;
  204. if (setsockopt(sock, SOL_SOCKET,
  205. SO_REUSEADDR, &val, sizeof(val)) == -1) {
  206. perror("SO_REUSEADDR");
  207. }
  208. }
  209. }
  210. int
  211. sockport(int s)
  212. {
  213. int namelen;
  214. struct sockaddr_in sin;
  215. namelen = sizeof(sin);
  216. if (getsockname(s, (struct sockaddr *)&sin, &namelen) < 0) {
  217. perror("getsockname");
  218. return(-1);
  219. }
  220. return ((int)ntohs(sin.sin_port));
  221. }