/* * client.c * Main code for the client 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 = "netstrain"; /* internal functions */ static void usage(void); static void setup_socket(const char *hostspec, const char *portspec); static void send_handshake(int hs); /* internal data */ static int family = PF_UNSPEC; static int sock; int main(int argc, char **argv) { int ch; const char *hostspec = NULL; const char *portspec = NULL; int my_handshake, his_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 != 3) usage(); hostspec = argv[0]; portspec = argv[1]; if (strcmp(argv[2], "send") == 0) { my_handshake = 1; his_handshake = 0; } else if (strcmp(argv[2], "recv") == 0) { my_handshake = 0; his_handshake = 1; } else if (strcmp(argv[2], "both") == 0) { my_handshake = 1; his_handshake = 1; } else { fprintf(stderr, "Unknown direction (%s)\n", argv[2]); usage(); exit(1); } transfer_init(); setup_socket(hostspec, portspec); send_handshake(his_handshake); stats_init(); transfer_run(sock, my_handshake); return 0; } static void usage(void) { fprintf(stderr, "Usage: %s [-46] send|recv|both\n", progname); exit(1); } static void setup_socket(const char *hostspec, const char *portspec) { struct addrinfo hints, *ai, *aitop; int gai_error, tries; char hostaddr[NI_MAXHOST], portaddr[NI_MAXSERV]; printf("Looking up hostname %s...\n", hostspec); memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; gai_error = getaddrinfo(hostspec, 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("Connecting to %s port %s using %s...\n", hostaddr, portaddr, (ai->ai_family == AF_INET) ? "IPv4" : ((ai->ai_family == AF_INET6) ? "IPv6" : "unknown proto") ); sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock < 0) { error("socket"); continue; } if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { error("connect"); close(sock); continue; } freeaddrinfo(aitop); printf("Connected\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 void send_handshake(int hs) { int got; unsigned char c = (unsigned char)hs; for(;;) { got = write(sock, &c, 1); if (got == 0) { /* nothing */ } else if (got < 0) { if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { bailout("write"); } } else { break; } } }