/* $Id: client.c,v 1.6 2007/10/03 02:16:20 tacha Exp $ */ /* * Copyright (c) 2007 * Tatoku Ogaito. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Tatoku Ogaito. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include int setup_client(char *, char *, int, int); int do_client_job(int); struct addrinfo dst; #define MAXSOCKETSIZE (512) #define BUF_LEN (512) int verbose = 0; char buf1[BUF_LEN]; char buf2[BUF_LEN]; int main(int argc, char *argv[]) { char *hostname = "localhost"; char *service = "echo"; int s; int ch; int family = PF_UNSPEC; int socktype = SOCK_STREAM; while ((ch = getopt(argc, argv, "46uth:s:v")) != -1) { switch (ch) { case '4': family = PF_INET; break; case '6': family = PF_INET6; break; case 'h': hostname = strdup(optarg); break; case 's': service = strdup(optarg); break; case 't': socktype = SOCK_STREAM; break; case 'u': socktype = SOCK_DGRAM; break; case 'v': verbose = 1; break; default: exit(1); } } argc -= optind; argv += optind; /* prepare socket */ if ((s = setup_client(hostname, service, family, socktype)) < 0) { exit(1); } do_client_job(s); return 0; } int do_client_job(int s) { char send_buffer[BUF_LEN]; char recv_buffer[BUF_LEN]; struct sockaddr *ss; socklen_t socksize = MAXSOCKETSIZE; fd_set read_set, read_ready; int ret; int sendto_flags = 0; FD_ZERO(&read_set); FD_SET(STDIN_FILENO, &read_set); FD_SET(s, &read_set); /* check socket status */ ss = malloc(MAXSOCKETSIZE); if (getsockname(s, ss, &socksize) == 0) { getnameinfo(ss, socksize, buf1, sizeof(buf1), buf2, sizeof(buf2), NI_NUMERICHOST | NI_NUMERICSERV); printf("%s %s ==> ", buf1, buf2); fflush(stdout); getnameinfo(dst.ai_addr, dst.ai_addrlen, buf1, sizeof(buf1), buf2, sizeof(buf2), NI_NUMERICHOST | NI_NUMERICSERV); printf("%s %s\n", buf1, buf2); } else { perror("getsockanme"); } /* main loop */ while (1) { read_ready = read_set; /* wait until some of FD become ready */ ret = select(s+1, &read_ready, NULL, NULL, NULL); switch(ret) { case -1: fprintf(stderr, "select:err\n"); exit(1); case 0: /* timeout */ break; default: if (FD_ISSET(s, &read_ready)) { /* data from remote node */ socksize = MAXSOCKETSIZE; memset(ss, 0, socksize); memset(recv_buffer, 0, sizeof(recv_buffer)); if (recvfrom(s, recv_buffer, sizeof(recv_buffer)-1, 0, ss, &socksize)) { getnameinfo(ss, socksize, buf1, sizeof(buf1), buf2, sizeof(buf2), NI_NUMERICHOST | NI_NUMERICSERV); if (verbose) printf("received from <%s %s> data = [", buf1, buf2); printf("%s", recv_buffer); if (verbose) printf("]\n"); } } if (FD_ISSET(STDIN_FILENO, &read_ready)) { /* data from keyboard */ if (NULL == fgets(send_buffer, sizeof(send_buffer), stdin) || strncmp(send_buffer, "quitquit", 8) == 0) return 0; if (sendto(s, send_buffer, strlen(send_buffer), sendto_flags, (struct sockaddr *)dst.ai_addr, dst.ai_addrlen) < 0) { perror("sendto"); exit(1); } } } } } /* setup socket */ int setup_client(char *hostname, char *service, int family, int socktype) { char *cause = NULL; int s; int error; struct addrinfo hints, *res, *res0; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = socktype; error = getaddrinfo(hostname, service, &hints, &res0); if (error) { fprintf(stderr, "%s", gai_strerror(error)); exit(1); /*NOTREACHED*/ } #ifdef TEST /* display all results */ for (res = res0; res; res = res->ai_next) { printf("ai_family = %d, ai_socktype = %d, ai_protocol = %d\n", res->ai_family, res->ai_socktype, res->ai_protocol); getnameinfo(res->ai_addr, res->ai_addrlen, buf1, sizeof(buf1), buf2, sizeof(buf2), NI_NUMERICHOST|NI_NUMERICSERV); printf("%s %s\n", buf1, buf2); } #endif s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { cause = "socket"; continue; } if (socktype == SOCK_STREAM) { if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s); s = -1; continue; } } else if (socktype == SOCK_DGRAM) { struct sockaddr *ss; /* XXX: 512 * if your defines "struct sockaddr_storage", you should use it. */ ss = (struct sockaddr *)malloc(MAXSOCKETSIZE); memset(ss, 0, MAXSOCKETSIZE); ss->sa_family = res->ai_family; #if defined (__NetBSD__) || defined (__FreeBSD__) ss->sa_len = res->ai_addrlen; #endif if (bind(s, ss, res->ai_addrlen) < 0) { cause = "bind"; close(s); s = -1; continue; } } break; /* okay we got one */ } if (s < 0) { perror(cause); exit(1); /*NOTREACHED*/ } memcpy(&dst, res, sizeof(dst)); dst.ai_addr = malloc(res->ai_addrlen); memcpy(dst.ai_addr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res0); return s; }