#define _POSIX_SOURCE #define _BSD_SOURCE #include #include #include #include #include #include #include /* * server.c: Implementation of a very simple tcp server. */ int main(int argc, char *argv[]) { struct addrinfo hints; /* specify our needs */ struct addrinfo *res; /* resulting address structure */ struct addrinfo *r; /* iterator */ int err; /* status of get{addr,name}info() */ int ss; /* the server's socket */ int cs; /* the client's socket */ ssize_t read; /* received bytes */ char c; /* used to store received byte */ struct sockaddr sa; /*********************/ socklen_t len; /* $ man getnameinfo */ char hbuf[NI_MAXHOST]; /*********************/ /* Enforce correct usage */ if (argc != 2) { printf("Usage: %s [port]\n", argv[0]); exit(EXIT_FAILURE); } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; /* IPv4 */ hints.ai_socktype = SOCK_STREAM; /* Stream socket */ hints.ai_flags = AI_PASSIVE; /* INADDR_ANY */ hints.ai_protocol = 0; /* Any (TCP) */ /* $ man getaddrinfo [...] Given node and service, which identify an Internet host and a service, getaddrinfo() returns one or more addrinfo structures, each of which contains an Internet address that can be specified in a call to bind(2) or connect(2). [...] */ err = getaddrinfo(NULL, argv[1], &hints, &res); if (err != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err)); exit(EXIT_FAILURE); } /* Loop through the address structures */ for (r = res; r != NULL; r = r->ai_next) { /* Create the socket */ ss = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (ss < 0) { perror("socket"); continue; } /* Bind the address to the socket */ if (bind(ss, res->ai_addr, res->ai_addrlen) < 0) { close(ss); perror("bind"); continue; } break; /* Success*/ } /* Give up */ if (r == NULL) { fprintf(stderr, "Binding failed!\n"); exit(EXIT_FAILURE); } /* No longer needed */ freeaddrinfo(res); /* Listen for incoming connections */ if (listen(ss, 0) < 0) { perror("listen"); exit(EXIT_FAILURE); } printf("Waiting...\n"); /* $ man accept [...] The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; on return it will contain the actual size of the peer address. [...] */ len = sizeof(sa); /* Wait for and accept new connection */ cs = accept(ss, &sa, &len); if (cs < 0) { perror("accept"); exit(EXIT_FAILURE); } /* Lookup client's hostname */ err = getnameinfo(&sa, len, hbuf, sizeof(hbuf), NULL, 0, 0); if (err != 0) { fprintf(stderr, "getnameinfo: %s\n", gai_strerror(err)); /* Print the error, but do not exit */ } printf("Connection established...\n"); printf("-------------------------\n"); printf("%s:\n\n", hbuf); /* Infiniteley reading characters */ for (;;) { /* Finally: Receive user's message */ read = recv(cs, &c, 1, 0); if (read > 0) { printf("%c", c); fflush(stdout); } else { /* $ man recv [...] These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an orderly shutdown. [...] */ if (read < 0) { perror("recv"); } else /* read == 0 */ { printf("\n-------------------\n"); printf("Orderly shutdown...\n"); } close(cs); break; } } /* Clean up */ close(ss); return EXIT_SUCCESS; }