/* * client program to read data from server * * based on proxy.c * $Id: client.c,v 1.5 2003/11/28 20:48:23 ca Exp $ */ /* * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. * 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. * 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. Neither the name of Silicon Graphics, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``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 COPYRIGHT * HOLDERS AND CONTRIBUTORS 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 "sm/generic.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "st.h" #if !HAVE_SNPRINTF # define snprintf sm_snprintf # include "sm/string.h" #endif /* !HAVE_SNPRINTF */ #define IOBUFSIZE (16*1024) #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif #define MAXTC 512L /* max. number of total connections */ #define REQUEST_TIMEOUT 3 #define SEC2USEC(s) ((s)*1000000LL) static char *prog; /* Program name */ static struct sockaddr_in rmt_addr; /* Remote address */ static int conns; static int debug = 0; static int busy = 0; static long int total = 0; static void read_address(const char *str, struct sockaddr_in *sin); static void *handle_request(void *arg); static void print_sys_error(const char *msg); /* * This program acts as client for the server program. * It connects to the specified remote address ('-r' option) and * asks for data. */ int main(int argc, char *argv[]) { extern char *optarg; int opt, n, threads; int raddr; long int tc; prog = argv[0]; raddr = 0; conns = threads = 1; /* Parse arguments */ while((opt = getopt(argc, argv, "c:d:hr:t:S")) != -1) { switch (opt) { case 'c': conns = atoi(optarg); if (conns < 1 || conns > 100) { fprintf(stderr, "%s: invalid number of connections: %s\n", prog, optarg); exit(1); } break; case 'd': debug = atoi(optarg); if (debug < 0) { fprintf(stderr, "%s: invalid number for debug: %s\n", prog, optarg); exit(1); } break; case 'r': read_address(optarg, &rmt_addr); if (rmt_addr.sin_addr.s_addr == INADDR_ANY) { fprintf(stderr, "%s: invalid remote address: %s\n", prog, optarg); exit(1); } raddr = 1; break; case 't': threads = atoi(optarg); if (threads < 1 || threads > 100) { fprintf(stderr, "%s: invalid number of threads: %s\n", prog, optarg); exit(1); } break; case 'h': case '?': fprintf(stderr, "Usage: %s -l <[host]:port> -r " "[-p ] [-S]\n", prog); exit(1); } } if (!raddr) { fprintf(stderr, "%s: remote address required\n", prog); exit(1); } tc = (long) threads * (long) conns; if (tc > MAXTC) { fprintf(stderr, "%s: too many total connections (%ld > %ld)\n", prog, tc, MAXTC); exit(1); } if (debug) fprintf(stderr, "%s: starting client [%d]\n", prog, threads); /* Initialize the ST library */ if (st_init() < 0) { print_sys_error("st_init"); exit(1); } for (n = 0; n < threads; n++) { if (debug) fprintf(stderr, "%s: starting client %d/%d\n", prog, n, threads); if (st_thread_create(handle_request, (void *) n, 0, 0) == NULL) { print_sys_error("st_thread_create"); exit(1); } } /* wait for them... */ st_sleep(1); while (busy > 0) st_sleep(1); /* XXX how? */ fprintf(stderr, "%s: total=%ld (should be %ld)\n", prog, total, (long) threads * (long) conns); return 0; } static void read_address(const char *str, struct sockaddr_in *sin) { char host[128], *p; struct hostent *hp; short port; strlcpy(host, str, sizeof(host)); if ((p = strchr(host, ':')) == NULL) { fprintf(stderr, "%s: invalid address: %s\n", prog, host); exit(1); } *p++ = '\0'; port = (short) atoi(p); if (port < 1) { fprintf(stderr, "%s: invalid port: %s\n", prog, p); exit(1); } memset(sin, 0, sizeof(struct sockaddr_in)); sin->sin_family = AF_INET; sin->sin_port = htons(port); if (host[0] == '\0') { sin->sin_addr.s_addr = INADDR_ANY; return; } sin->sin_addr.s_addr = inet_addr(host); if (sin->sin_addr.s_addr == INADDR_NONE) { /* not dotted-decimal */ if ((hp = gethostbyname(host)) == NULL) { fprintf(stderr, "%s: can't resolve address: %s\n", prog, host); exit(1); } memcpy(&sin->sin_addr, hp->h_addr, hp->h_length); } } static void *handle_request(void *arg) { struct pollfd pds[1]; st_netfd_t rmt_nfd; int sock, n, i, tid, r; char buf[IOBUFSIZE]; ++busy; tid = (int) arg; if (debug) fprintf(stderr, "client[%d]: conns=%d\n", tid, conns); /* * currently the server only answers one request... * * hence this breaks for too many connections since too many sckets * are opened */ for (i = 0; i < conns; i++) { /* Connect to remote host */ if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { snprintf(buf, sizeof(buf), "[%d] socket i=%d", tid, i); print_sys_error(buf); goto done; } if ((rmt_nfd = st_netfd_open_socket(sock)) == NULL) { snprintf(buf, sizeof(buf), "[%d] st_netfd_open_socket i=%d", tid, i); print_sys_error(buf); close(sock); goto done; } if (st_connect(rmt_nfd, (struct sockaddr *)&rmt_addr, sizeof(rmt_addr), SEC2USEC(REQUEST_TIMEOUT)) < 0) { snprintf(buf, sizeof(buf), "[%d] connect i=%d", tid, i); print_sys_error(buf); st_netfd_close(rmt_nfd); goto done; } pds[0].fd = sock; pds[0].events = POLLIN; if (debug > 2) fprintf(stderr, "client[%d]: connected (%d/%d)\n", tid, i, conns); n = strlcpy(buf, "gimme\n\r", sizeof(buf)); if ((r = st_write(rmt_nfd, buf, n, SEC2USEC(REQUEST_TIMEOUT))) != n) { fprintf(stderr, "[%d] server went away? i=%d, n=%d, r=%d, errno=%d\n", tid, i, n, r, errno); break; } for ( ; ; ) { if (st_poll(pds, 1, -1) <= 0) { print_sys_error("st_poll"); break; } if (pds[0].revents & POLLIN) { if ((n = (int) st_read(rmt_nfd, buf, IOBUFSIZE, -1)) <= 0) break; } } ++total; st_netfd_close(rmt_nfd); } done: --busy; return NULL; } static void print_sys_error(const char *msg) { fprintf(stderr, "%s: %s: %s\n", prog, msg, strerror(errno)); }