PageRenderTime 59ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/UNIX/unp/sock/main.c

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