/* * server.c * Main code for the server side of things. * * Copyright (c) 2002 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "netstrain.h" /* error reporting settings */ const char *progname = "netstraind"; /* internal functions */ static void usage(void); static void setup_socket(const char *portspec); static int wait_for_connection(); /* internal data */ static int family = PF_UNSPEC; static int listen_sock; static int sock; int main(int argc, char **argv) { int ch; const char *portspec; int handshake; printf(PRODUCT_NAME " " PRODUCT_VERSION " " PRODUCT_COPYRIGHT "\n"); while ((ch = getopt(argc, argv, "46hv")) != -1) switch (ch) { case '4': family = PF_INET; break; case '6': family = PF_INET6; break; case 'v': /* we have already printed version info */ exit(0); case 'h': case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 1) usage(); portspec = argv[0]; transfer_init(); setup_socket(portspec); handshake = wait_for_connection(); transfer_run(sock, handshake); return 0; } static void usage(void) { fprintf(stderr, "Usage: %s [-46] \n", progname); exit(1); } static void setup_socket(const char *portspec) { struct addrinfo hints, *ai, *aitop; int gai_error, tries; char hostaddr[NI_MAXHOST], portaddr[NI_MAXSERV]; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; gai_error = getaddrinfo(NULL, portspec, &hints, &aitop); if (gai_error) bailout_n("getaddrinfo: %s", gai_strerror(gai_error)); for (tries = 0, ai = aitop; ai != NULL; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; tries++; if (getnameinfo(ai->ai_addr, ai->ai_addrlen, hostaddr, sizeof(hostaddr), portaddr, sizeof(portaddr), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { error("getnameinfo"); continue; } printf("Listening on %s port %s using %s...\n", hostaddr, portaddr, (ai->ai_family == AF_INET) ? "IPv4" : ((ai->ai_family == AF_INET6) ? "IPv6" : "unknown proto") ); listen_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (listen_sock < 0) { error("socket"); continue; } if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { error("bind"); close(sock); continue; } if (listen(listen_sock, 1) < 0) { error("listen"); close(sock); continue; } freeaddrinfo(aitop); printf("One-shot server waiting for connection\n"); return; } freeaddrinfo(aitop); if (tries == 0) { bailout_n("Didn't get any usable addresses"); } else if (tries > 1) { bailout_n("All addresses failed"); } exit(1); } static int wait_for_connection() { struct sockaddr_storage hisaddr; int al; char hostaddr[NI_MAXHOST], portaddr[NI_MAXSERV]; int got; unsigned char c; al = sizeof(hisaddr); sock = accept(listen_sock, (struct sockaddr *)&hisaddr, &al); if (sock < 0) bailout("accept"); close(listen_sock); if (getnameinfo((struct sockaddr *)&hisaddr, al, hostaddr, sizeof(hostaddr), portaddr, sizeof(portaddr), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { bailout("getnameinfo"); } printf("Incoming connection from %s port %s\n", hostaddr, portaddr); for(;;) { got = read(sock, &c, 1); if (got == 0) { printf("Got EOF from socket while waiting for handshake\n"); close(sock); exit(0); } else if (got < 0) { if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { bailout("read"); } } else { return (int)c; } } }