main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. * Copyright (c) 1993 W. Richard Stevens. All rights reserved.
  3. * Permission to use or modify this software and its documentation only for
  4. * educational purposes and without fee is hereby granted, provided that
  5. * the above copyright notice appear in all copies. The author makes no
  6. * representations about the suitability of this software for any purpose.
  7. * It is provided "as is" without express or implied warranty.
  8. */
  9. #include "sock.h"
  10. char *host; /* hostname or dotted-decimal string */
  11. char *port;
  12. /* DefinE global variables */
  13. int bindport; /* 0 or TCP or UDP port number to bind */
  14. /* set by -b or -l options */
  15. int broadcast; /* SO_BROADCAST */
  16. int cbreak; /* set terminal to cbreak mode */
  17. int chunkwrite; /* write in small chunks; not all-at-once */
  18. int client = 1; /* acting as client is the default */
  19. int connectudp = 1; /* connect UDP client */
  20. int crlf; /* convert newline to CR/LF & vice versa */
  21. int debug; /* SO_DEBUG */
  22. int dofork; /* concurrent server, do a fork() */
  23. int dontroute; /* SO_DONTROUTE */
  24. char foreignip[32]; /* foreign IP address, dotted-decimal string */
  25. int foreignport; /* foreign port number */
  26. int halfclose; /* TCP half close option */
  27. int ignorewerr; /* true if write() errors should be ignored */
  28. int iptos = -1; /* IP_TOS opton */
  29. int ipttl = -1; /* IP_TTL opton */
  30. char joinip[32]; /* multicast IP address, dotted-decimal string */
  31. int keepalive; /* SO_KEEPALIVE */
  32. long linger = -1; /* 0 or positive turns on option */
  33. int listenq = 5; /* listen queue for TCP Server */
  34. char localip[32]; /* local IP address, dotted-decimal string */
  35. int maxseg; /* TCP_MAXSEG */
  36. int mcastttl; /* multicast TTL */
  37. int msgpeek; /* MSG_PEEK */
  38. int nodelay; /* TCP_NODELAY (Nagle algorithm) */
  39. int nbuf = 1024; /* number of buffers to write (sink mode) */
  40. int onesbcast; /* set IP_ONESBCAST for 255.255.255.255 bcasts */
  41. int pauseclose; /* #ms to sleep after recv FIN, before close */
  42. int pauseinit; /* #ms to sleep before first read */
  43. int pauselisten; /* #ms to sleep after listen() */
  44. int pauserw; /* #ms to sleep before each read or write */
  45. int reuseaddr; /* SO_REUSEADDR */
  46. int reuseport; /* SO_REUSEPORT */
  47. int readlen = 1024; /* default read length for socket */
  48. int writelen = 1024; /* default write length for socket */
  49. int recvdstaddr; /* IP_RECVDSTADDR option */
  50. int rcvbuflen; /* size for SO_RCVBUF */
  51. int sndbuflen; /* size for SO_SNDBUF */
  52. long rcvtimeo; /* SO_RCVTIMEO */
  53. long sndtimeo; /* SO_SNDTIMEO */
  54. int sroute_cnt; /* count of #IP addresses in route */
  55. char *rbuf; /* pointer that is malloc'ed */
  56. char *wbuf; /* pointer that is malloc'ed */
  57. int server; /* to act as server requires -s option */
  58. int sigio; /* send SIGIO */
  59. int sourcesink; /* source/sink mode */
  60. int udp; /* use UDP instead of TCP */
  61. int urgwrite; /* write urgent byte after this write */
  62. int verbose; /* each -v increments this by 1 */
  63. int usewritev; /* use writev() instead of write() */
  64. struct sockaddr_in cliaddr, servaddr;
  65. static void usage(const char *);
  66. int
  67. main(int argc, char *argv[])
  68. {
  69. int c, fd;
  70. char *ptr;
  71. if (argc < 2)
  72. usage("");
  73. opterr = 0; /* don't want getopt() writing to stderr */
  74. while ( (c = getopt(argc, argv, "2b:cf:g:hij:kl:n:op:q:r:st:uvw:x:y:ABCDEFG:H:IJ:KL:NO:P:Q:R:S:TU:VWX:YZ")) != -1) {
  75. switch (c) {
  76. #ifdef IP_ONESBCAST
  77. case '2': /* use 255.255.255.255 as broadcast address */
  78. onesbcast = 1;
  79. break;
  80. #endif
  81. case 'b':
  82. bindport = atoi(optarg);
  83. break;
  84. case 'c': /* convert newline to CR/LF & vice versa */
  85. crlf = 1;
  86. break;
  87. case 'f': /* foreign IP address and port#: a.b.c.d.p */
  88. if ( (ptr = strrchr(optarg, '.')) == NULL)
  89. usage("invalid -f option");
  90. *ptr++ = 0; /* null replaces final period */
  91. foreignport = atoi(ptr); /* port number */
  92. strcpy(foreignip, optarg); /* save dotted-decimal IP */
  93. break;
  94. case 'g': /* loose source route */
  95. sroute_doopt(0, optarg);
  96. break;
  97. case 'h': /* TCP half-close option */
  98. halfclose = 1;
  99. break;
  100. case 'i': /* source/sink option */
  101. sourcesink = 1;
  102. break;
  103. #ifdef IP_ADD_MEMBERSHIP
  104. case 'j': /* join multicast group a.b.c.d */
  105. strcpy(joinip, optarg); /* save dotted-decimal IP */
  106. break;
  107. #endif
  108. case 'k': /* chunk-write option */
  109. chunkwrite = 1;
  110. break;
  111. case 'l': /* local IP address and port#: a.b.c.d.p */
  112. if ( (ptr = strrchr(optarg, '.')) == NULL)
  113. usage("invalid -l option");
  114. *ptr++ = 0; /* null replaces final period */
  115. bindport = atoi(ptr); /* port number */
  116. strcpy(localip, optarg); /* save dotted-decimal IP */
  117. break;
  118. case 'n': /* number of buffers to write */
  119. nbuf = atol(optarg);
  120. break;
  121. case 'o': /* do not connect UDP client */
  122. connectudp = 0;
  123. break;
  124. case 'p': /* pause before each read or write */
  125. pauserw = atoi(optarg);
  126. break;
  127. case 'q': /* listen queue for TCP server */
  128. listenq = atoi(optarg);
  129. break;
  130. case 'r': /* read() length */
  131. readlen = atoi(optarg);
  132. break;
  133. case 's': /* server */
  134. server = 1;
  135. client = 0;
  136. break;
  137. #ifdef IP_MULTICAST_TTL
  138. case 't': /* IP_MULTICAST_TTL */
  139. mcastttl = atoi(optarg);
  140. break;
  141. #endif
  142. case 'u': /* use UDP instead of TCP */
  143. udp = 1;
  144. break;
  145. case 'v': /* output what's going on */
  146. verbose++;
  147. break;
  148. case 'w': /* write() length */
  149. writelen = atoi(optarg);
  150. break;
  151. case 'x': /* SO_RCVTIMEO socket option */
  152. rcvtimeo = atol(optarg);
  153. break;
  154. case 'y': /* SO_SNDTIMEO socket option */
  155. sndtimeo = atol(optarg);
  156. break;
  157. case 'A': /* SO_REUSEADDR socket option */
  158. reuseaddr = 1;
  159. break;
  160. case 'B': /* SO_BROADCAST socket option */
  161. broadcast = 1;
  162. break;
  163. case 'C': /* set standard input to cbreak mode */
  164. cbreak = 1;
  165. break;
  166. case 'D': /* SO_DEBUG socket option */
  167. debug = 1;
  168. break;
  169. case 'E': /* IP_RECVDSTADDR socket option */
  170. recvdstaddr = 1;
  171. break;
  172. case 'F': /* concurrent server, do a fork() */
  173. dofork = 1;
  174. break;
  175. case 'G': /* strict source route */
  176. sroute_doopt(1, optarg);
  177. break;
  178. #ifdef IP_TOS
  179. case 'H': /* IP_TOS socket option */
  180. iptos = atoi(optarg);
  181. break;
  182. #endif
  183. case 'I': /* SIGIO signal */
  184. sigio = 1;
  185. break;
  186. #ifdef IP_TTL
  187. case 'J': /* IP_TTL socket option */
  188. ipttl = atoi(optarg);
  189. break;
  190. #endif
  191. case 'K': /* SO_KEEPALIVE socket option */
  192. keepalive = 1;
  193. break;
  194. case 'L': /* SO_LINGER socket option */
  195. linger = atol(optarg);
  196. break;
  197. case 'N': /* SO_NODELAY socket option */
  198. nodelay = 1;
  199. break;
  200. case 'O': /* pause before listen(), before first accept() */
  201. pauselisten = atoi(optarg);
  202. break;
  203. case 'P': /* pause before first read() */
  204. pauseinit = atoi(optarg);
  205. break;
  206. case 'Q': /* pause after receiving FIN, but before close() */
  207. pauseclose = atoi(optarg);
  208. break;
  209. case 'R': /* SO_RCVBUF socket option */
  210. rcvbuflen = atoi(optarg);
  211. break;
  212. case 'S': /* SO_SNDBUF socket option */
  213. sndbuflen = atoi(optarg);
  214. break;
  215. #ifdef SO_REUSEPORT
  216. case 'T': /* SO_REUSEPORT socket option */
  217. reuseport = 1;
  218. break;
  219. #endif
  220. case 'U': /* when to write urgent byte */
  221. urgwrite = atoi(optarg);
  222. break;
  223. case 'V': /* use writev() instead of write() */
  224. usewritev = 1;
  225. chunkwrite = 1; /* implies this option too */
  226. break;
  227. case 'W': /* ignore write errors */
  228. ignorewerr = 1;
  229. break;
  230. case 'X': /* TCP maximum segment size option */
  231. maxseg = atoi(optarg);
  232. break;
  233. case 'Y': /* SO_DONTROUTE socket option */
  234. dontroute = 1;
  235. break;
  236. case 'Z': /* MSG_PEEK option */
  237. msgpeek = MSG_PEEK;
  238. break;
  239. case '?':
  240. usage("unrecognized option");
  241. }
  242. }
  243. /* check for options that don't make sense */
  244. if (udp && halfclose)
  245. usage("can't specify -h and -u");
  246. if (udp && debug)
  247. usage("can't specify -D and -u");
  248. if (udp && linger >= 0)
  249. usage("can't specify -L and -u");
  250. if (udp && nodelay)
  251. usage("can't specify -N and -u");
  252. #ifdef notdef
  253. if (udp == 0 && broadcast)
  254. usage("can't specify -B with TCP");
  255. #endif
  256. if (udp == 0 && foreignip[0] != 0)
  257. usage("can't specify -f with TCP");
  258. if (client) {
  259. if (optind != argc-2)
  260. usage("missing <hostname> and/or <port>");
  261. host = argv[optind];
  262. port = argv[optind+1];
  263. } else {
  264. /* If server specifies host and port, then local address is
  265. bound to the "host" argument, instead of being wildcarded. */
  266. if (optind == argc-2) {
  267. host = argv[optind];
  268. port = argv[optind+1];
  269. } else if (optind == argc-1) {
  270. host = NULL;
  271. port = argv[optind];
  272. } else
  273. usage("missing <port>");
  274. }
  275. if (client)
  276. fd = cliopen(host, port);
  277. else
  278. fd = servopen(host, port);
  279. if (sourcesink) { /* ignore stdin/stdout */
  280. if (client) {
  281. if (udp)
  282. source_udp(fd);
  283. else
  284. source_tcp(fd);
  285. } else {
  286. if (udp)
  287. sink_udp(fd);
  288. else
  289. sink_tcp(fd);
  290. }
  291. } else { /* copy stdin/stdout to/from socket */
  292. if (udp)
  293. loop_udp(fd);
  294. else
  295. loop_tcp(fd);
  296. }
  297. exit(0);
  298. }
  299. static void
  300. usage(const char *msg)
  301. {
  302. err_msg(
  303. "usage: sock [ options ] <host> <port> (for client; default)\n"
  304. " sock [ options ] -s [ <IPaddr> ] <port> (for server)\n"
  305. " sock [ options ] -i <host> <port> (for \"source\" client)\n"
  306. " sock [ options ] -i -s [ <IPaddr> ] <port> (for \"sink\" server)\n"
  307. "options: -b n bind n as client's local port number\n"
  308. " -c convert newline to CR/LF & vice versa\n"
  309. " -f a.b.c.d.p foreign IP address = a.b.c.d, foreign port # = p\n"
  310. " -g a.b.c.d loose source route\n"
  311. " -h issue TCP half close on standard input EOF\n"
  312. " -i \"source\" data to socket, \"sink\" data from socket (w/-s)\n"
  313. #ifdef IP_ADD_MEMBERSHIP
  314. " -j a.b.c.d join multicast group\n"
  315. #endif
  316. " -k write or writev in chunks\n"
  317. " -l a.b.c.d.p client's local IP address = a.b.c.d, local port # = p\n"
  318. " -n n # buffers to write for \"source\" client (default 1024)\n"
  319. " -o do NOT connect UDP client\n"
  320. " -p n # ms to pause before each read or write (source/sink)\n"
  321. " -q n size of listen queue for TCP server (default 5)\n"
  322. " -r n # bytes per read() for \"sink\" server (default 1024)\n"
  323. " -s operate as server instead of client\n"
  324. #ifdef IP_MULTICAST_TTL
  325. " -t n set multicast ttl\n"
  326. #endif
  327. " -u use UDP instead of TCP\n"
  328. " -v verbose\n"
  329. " -w n # bytes per write() for \"source\" client (default 1024)\n"
  330. " -x n # ms for SO_RCVTIMEO (receive timeout)\n"
  331. " -y n # ms for SO_SNDTIMEO (send timeout)\n"
  332. " -A SO_REUSEADDR option\n"
  333. " -B SO_BROADCAST option\n"
  334. " -C set terminal to cbreak mode\n"
  335. " -D SO_DEBUG option\n"
  336. " -E IP_RECVDSTADDR option\n"
  337. " -F fork after connection accepted (TCP concurrent server)\n"
  338. " -G a.b.c.d strict source route\n"
  339. #ifdef IP_TOS
  340. " -H n IP_TOS option (16=min del, 8=max thru, 4=max rel, 2=min$)\n"
  341. #endif
  342. " -I SIGIO signal\n"
  343. #ifdef IP_TTL
  344. " -J n IP_TTL option\n"
  345. #endif
  346. " -K SO_KEEPALIVE option\n"
  347. " -L n SO_LINGER option, n = linger time\n"
  348. " -N TCP_NODELAY option\n"
  349. " -O n # ms to pause after listen, but before first accept\n"
  350. " -P n # ms to pause before first read or write (source/sink)\n"
  351. " -Q n # ms to pause after receiving FIN, but before close\n"
  352. " -R n SO_RCVBUF option\n"
  353. " -S n SO_SNDBUF option\n"
  354. #ifdef SO_REUSEPORT
  355. " -T SO_REUSEPORT option\n"
  356. #endif
  357. " -U n enter urgent mode before write number n (source only)\n"
  358. " -V use writev() instead of write(); enables -k too\n"
  359. " -W ignore write errors for sink client\n"
  360. " -X n TCP_MAXSEG option (set MSS)\n"
  361. " -Y SO_DONTROUTE option\n"
  362. " -Z MSG_PEEK\n"
  363. #ifdef IP_ONESBCAST
  364. " -2 IP_ONESBCAST option (255.255.255.255 for broadcast\n"
  365. #endif
  366. );
  367. if (msg[0] != 0)
  368. err_quit("%s", msg);
  369. exit(1);
  370. }