Advertisement
dmkozyrev

sockets

Dec 20th, 2016
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.27 KB | None | 0 0
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <sys/un.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6.  
  7. #include <err.h>
  8. #include <errno.h>
  9. #include <netdb.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <unistd.h>
  14.  
  15.  
  16. /* number of lines to generate on client side */
  17. static const unsigned int nlines = 10;
  18.  
  19. static void proceed_client(FILE *f, const char *name);
  20. static void server_loop(int servsock);
  21. static void client_loop(int csock, unsigned int lines);
  22. static void usage(const char *msg);
  23.  
  24.  
  25. /*
  26. * Processes data sent by client until end-of-stream or error.
  27. */
  28. void
  29. proceed_client(FILE *f, const char *name) {
  30.     char    *line = NULL;
  31.     size_t   linesize = 0;
  32.     ssize_t  linelen;
  33.  
  34.     while ((linelen = getline(&line, &linesize, f)) != -1) {
  35.         printf("from %s: ", name);
  36.         fwrite(line, linelen, 1, stdout);
  37.     }
  38.     free(line);
  39.     /* don't care if there was any error, or just EOF */
  40. }
  41.  
  42. /*
  43. * Accepts clients and proceeds them in protocol-agnostic way.
  44. */
  45. void
  46. server_loop(int servsock) {
  47.     struct sockaddr_storage  sas;
  48.     FILE            *f;
  49.     socklen_t        len;
  50.     int          csock, cnum = 0;
  51.     char             numbuf[20];
  52.  
  53.     for (;;) {
  54.         len = sizeof(struct sockaddr_storage);
  55.         if ((csock = accept(servsock, (struct sockaddr*)&sas, &len)) == -1) {
  56.             if (errno == EINTR)
  57.                 continue;
  58.             err(1, "accept");
  59.             break;
  60.         }
  61.         if ((f = fdopen(csock, "r+")) == NULL)
  62.             err(1, "fdopen");
  63.         cnum++;
  64.         snprintf(numbuf, sizeof(numbuf), "client %d", cnum);
  65.         printf("===> %s connected\n", numbuf);
  66.         proceed_client(f, numbuf);
  67.         printf("===> %s disconnected\n", numbuf);
  68.         fclose(f);
  69.         close(csock);
  70.     }
  71. }
  72.  
  73. #define countof(x)  (sizeof(x) / sizeof(x[0]))
  74.  
  75. void
  76. client_loop(int csock, unsigned int lines) {
  77.     static const char   *nouns[] = {
  78.         "danger",
  79.         "security",
  80.         "table",
  81.         "picture",
  82.         "rainbow"
  83.     };
  84.     static const char   *verbs[] = {
  85.         "eats",
  86.         "sleeps",
  87.         "invites",
  88.         "sends",
  89.         "sees"
  90.     };
  91.     static const char   *adjectives[] = {
  92.         "beautifully",
  93.         "exclusively",
  94.         "blue",
  95.         "funny",
  96.         "last"
  97.     };
  98.  
  99.     FILE        *f;
  100.     int      i, j;
  101.     const char  *noun, *verb, *adjective;
  102.  
  103.     if ((f = fdopen(csock, "r+")) == NULL)
  104.         err(1, "fdopen");
  105.     setvbuf(f, NULL, _IOLBF, 0);
  106.     for (i = 0; i < lines; i++) {
  107.         /*
  108.          * CAUTION in non-fun code you should care about uniform
  109.          * distribution; see, e.g., arc4random(3).
  110.          */
  111.         noun = nouns[rand() % countof(nouns)];
  112.         verb = verbs[rand() % countof(verbs)];
  113.         adjective = adjectives[rand() % countof(adjectives)];
  114.         if (fprintf(f, "%s %s %s\n", noun, verb, adjective) < 0)
  115.             break;
  116.         sleep(1);
  117.     }
  118.     fclose(f);
  119. }
  120.  
  121. #undef countof
  122.  
  123. void
  124. usage(const char *msg) {
  125.     const char  *name;
  126.     if (msg != NULL)
  127.         fprintf(stderr, "%s\n", msg);
  128.     name = getprogname();
  129.     fprintf(stderr, "usage: %s {server|client} unix path\n", name);
  130.     fprintf(stderr, "       %s {server|client} {inet|inet6} port [address]\n", name);
  131.     exit(2);
  132. }
  133.  
  134. int
  135. main(int argc, char **argv) {
  136.     struct sockaddr_storage ss;
  137.     socklen_t       slen;
  138.     int         s, servermode;
  139.  
  140.     if (argc < 4 || argc > 5)
  141.         usage(NULL);
  142.  
  143.     if (strcmp(argv[1], "server") == 0)
  144.         servermode = 1;
  145.     else if (strcmp(argv[1], "client") == 0)
  146.         servermode = 0;
  147.     else
  148.         usage("invalid mode, should be either server or client");
  149.  
  150.     memset(&ss, 0, sizeof(struct sockaddr_storage));
  151.     if (strcmp(argv[2], "unix") == 0) {
  152.         struct sockaddr_un  *sun = (struct sockaddr_un*)&ss;
  153.  
  154.         if (argc > 4)
  155.             usage(NULL);
  156.         sun->sun_family = AF_UNIX;
  157.         if (strlcpy(sun->sun_path, argv[3], sizeof(sun->sun_path)) >= sizeof(sun->sun_path))
  158.             usage("UNIX socket path is too long");
  159.         slen = sizeof(struct sockaddr_un);
  160.         if (servermode)
  161.             unlink(argv[3]);
  162.     } else if (strcmp(argv[2], "inet") == 0 || strcmp(argv[2], "inet6") == 0) {
  163.         int          port, rv;
  164.  
  165.         ss.ss_family = ((argv[2][4] == '\0') ? AF_INET : AF_INET6);
  166.         port = atoi(argv[3]);
  167.         if (port <= 0 || port > 65535)
  168.             errx(1, "invalid port: %s", argv[3]);
  169.         if (argc > 4) {
  170.             if (ss.ss_family == AF_INET) {
  171.                 struct sockaddr_in  *sin = (struct sockaddr_in*)&ss;
  172.  
  173.                 sin->sin_port = htons((uint16_t)port);
  174.                 rv = inet_pton(AF_INET, argv[4], &sin->sin_addr);
  175.                 slen = sizeof(struct sockaddr_in);
  176.             } else {
  177.                 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&ss;
  178.  
  179.                 sin6->sin6_port = htons((uint16_t)port);
  180.                 rv = inet_pton(AF_INET6, argv[4], &sin6->sin6_addr);
  181.                 slen = sizeof(struct sockaddr_in6);
  182.             }
  183.             if (!rv)
  184.                 errx(1, "invalid network address: %s", argv[4]);
  185.         } else if (servermode) {
  186.             /*
  187.              * Binding to "any" address is done by zeroing address,
  188.              * which was already done by memset(3).
  189.              */
  190.         } else {
  191.             /* connect to local address by default */
  192.             if (ss.ss_family == AF_INET) {
  193.                 inet_pton(ss.ss_family, "127.0.0.1",
  194.                     &((struct sockaddr_in*)&ss)->sin_addr);
  195.             } else {
  196.                 inet_pton(ss.ss_family, "::1",
  197.                     &((struct sockaddr_in6*)&ss)->sin6_addr);
  198.             }
  199.         }
  200.     } else {
  201.         usage("invalid protocol family");
  202.     }
  203.  
  204.     if ((s = socket(ss.ss_family, SOCK_STREAM, 0)) == -1)
  205.         err(1, "socket");
  206.     if (servermode) {
  207.         if (bind(s, (const struct sockaddr*)&ss, slen) == -1)
  208.             err(1, "bind");
  209.         if (listen(s, 10) == -1)
  210.             err(1, "listen");
  211.         server_loop(s);
  212.     } else {
  213.         if (connect(s, (const struct sockaddr*)&ss, slen) == -1)
  214.             err(1, "connect");
  215.         client_loop(s, nlines);
  216.     }
  217.     close(s);
  218.  
  219.     return 0;
  220. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement