Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <err.h>
- #include <errno.h>
- #include <netdb.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- /* number of lines to generate on client side */
- static const unsigned int nlines = 10;
- static void proceed_client(FILE *f, const char *name);
- static void server_loop(int servsock);
- static void client_loop(int csock, unsigned int lines);
- static void usage(const char *msg);
- /*
- * Processes data sent by client until end-of-stream or error.
- */
- void
- proceed_client(FILE *f, const char *name) {
- char *line = NULL;
- size_t linesize = 0;
- ssize_t linelen;
- while ((linelen = getline(&line, &linesize, f)) != -1) {
- printf("from %s: ", name);
- fwrite(line, linelen, 1, stdout);
- }
- free(line);
- /* don't care if there was any error, or just EOF */
- }
- /*
- * Accepts clients and proceeds them in protocol-agnostic way.
- */
- void
- server_loop(int servsock) {
- struct sockaddr_storage sas;
- FILE *f;
- socklen_t len;
- int csock, cnum = 0;
- char numbuf[20];
- for (;;) {
- len = sizeof(struct sockaddr_storage);
- if ((csock = accept(servsock, (struct sockaddr*)&sas, &len)) == -1) {
- if (errno == EINTR)
- continue;
- err(1, "accept");
- break;
- }
- if ((f = fdopen(csock, "r+")) == NULL)
- err(1, "fdopen");
- cnum++;
- snprintf(numbuf, sizeof(numbuf), "client %d", cnum);
- printf("===> %s connected\n", numbuf);
- proceed_client(f, numbuf);
- printf("===> %s disconnected\n", numbuf);
- fclose(f);
- close(csock);
- }
- }
- #define countof(x) (sizeof(x) / sizeof(x[0]))
- void
- client_loop(int csock, unsigned int lines) {
- static const char *nouns[] = {
- "danger",
- "security",
- "table",
- "picture",
- "rainbow"
- };
- static const char *verbs[] = {
- "eats",
- "sleeps",
- "invites",
- "sends",
- "sees"
- };
- static const char *adjectives[] = {
- "beautifully",
- "exclusively",
- "blue",
- "funny",
- "last"
- };
- FILE *f;
- int i, j;
- const char *noun, *verb, *adjective;
- if ((f = fdopen(csock, "r+")) == NULL)
- err(1, "fdopen");
- setvbuf(f, NULL, _IOLBF, 0);
- for (i = 0; i < lines; i++) {
- /*
- * CAUTION in non-fun code you should care about uniform
- * distribution; see, e.g., arc4random(3).
- */
- noun = nouns[rand() % countof(nouns)];
- verb = verbs[rand() % countof(verbs)];
- adjective = adjectives[rand() % countof(adjectives)];
- if (fprintf(f, "%s %s %s\n", noun, verb, adjective) < 0)
- break;
- sleep(1);
- }
- fclose(f);
- }
- #undef countof
- void
- usage(const char *msg) {
- const char *name;
- if (msg != NULL)
- fprintf(stderr, "%s\n", msg);
- name = getprogname();
- fprintf(stderr, "usage: %s {server|client} unix path\n", name);
- fprintf(stderr, " %s {server|client} {inet|inet6} port [address]\n", name);
- exit(2);
- }
- int
- main(int argc, char **argv) {
- struct sockaddr_storage ss;
- socklen_t slen;
- int s, servermode;
- if (argc < 4 || argc > 5)
- usage(NULL);
- if (strcmp(argv[1], "server") == 0)
- servermode = 1;
- else if (strcmp(argv[1], "client") == 0)
- servermode = 0;
- else
- usage("invalid mode, should be either server or client");
- memset(&ss, 0, sizeof(struct sockaddr_storage));
- if (strcmp(argv[2], "unix") == 0) {
- struct sockaddr_un *sun = (struct sockaddr_un*)&ss;
- if (argc > 4)
- usage(NULL);
- sun->sun_family = AF_UNIX;
- if (strlcpy(sun->sun_path, argv[3], sizeof(sun->sun_path)) >= sizeof(sun->sun_path))
- usage("UNIX socket path is too long");
- slen = sizeof(struct sockaddr_un);
- if (servermode)
- unlink(argv[3]);
- } else if (strcmp(argv[2], "inet") == 0 || strcmp(argv[2], "inet6") == 0) {
- int port, rv;
- ss.ss_family = ((argv[2][4] == '\0') ? AF_INET : AF_INET6);
- port = atoi(argv[3]);
- if (port <= 0 || port > 65535)
- errx(1, "invalid port: %s", argv[3]);
- if (argc > 4) {
- if (ss.ss_family == AF_INET) {
- struct sockaddr_in *sin = (struct sockaddr_in*)&ss;
- sin->sin_port = htons((uint16_t)port);
- rv = inet_pton(AF_INET, argv[4], &sin->sin_addr);
- slen = sizeof(struct sockaddr_in);
- } else {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&ss;
- sin6->sin6_port = htons((uint16_t)port);
- rv = inet_pton(AF_INET6, argv[4], &sin6->sin6_addr);
- slen = sizeof(struct sockaddr_in6);
- }
- if (!rv)
- errx(1, "invalid network address: %s", argv[4]);
- } else if (servermode) {
- /*
- * Binding to "any" address is done by zeroing address,
- * which was already done by memset(3).
- */
- } else {
- /* connect to local address by default */
- if (ss.ss_family == AF_INET) {
- inet_pton(ss.ss_family, "127.0.0.1",
- &((struct sockaddr_in*)&ss)->sin_addr);
- } else {
- inet_pton(ss.ss_family, "::1",
- &((struct sockaddr_in6*)&ss)->sin6_addr);
- }
- }
- } else {
- usage("invalid protocol family");
- }
- if ((s = socket(ss.ss_family, SOCK_STREAM, 0)) == -1)
- err(1, "socket");
- if (servermode) {
- if (bind(s, (const struct sockaddr*)&ss, slen) == -1)
- err(1, "bind");
- if (listen(s, 10) == -1)
- err(1, "listen");
- server_loop(s);
- } else {
- if (connect(s, (const struct sockaddr*)&ss, slen) == -1)
- err(1, "connect");
- client_loop(s, nlines);
- }
- close(s);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement