From f95c37e3cf4d9ed5cb4ad1899e80d19fca888118 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Sun, 31 Jul 2011 21:48:13 +0200 Subject: [PATCH] examples: add getopt argument parsing for client and server Signed-off-by: Olivier Matz --- src/calculator_server/main.c | 123 ++++++++++++++++++++++++++++-- src/client/main.c | 143 +++++++++++++++++++++++++++++++---- src/event_server/main.c | 120 ++++++++++++++++++++++++++--- 3 files changed, 355 insertions(+), 31 deletions(-) diff --git a/src/calculator_server/main.c b/src/calculator_server/main.c index 0406a06..d3c5e05 100644 --- a/src/calculator_server/main.c +++ b/src/calculator_server/main.c @@ -29,15 +29,15 @@ #include #include #include -#include #include #include #include #include -#include #include -#include #include +#include + +#include #include #include @@ -46,15 +46,124 @@ extern cmdline_parse_ctx_t main_ctx[]; -struct cmdline *cl; +static struct sockaddr addr; +static uint16_t port = 1234; + +static void +usage(const char *prgname) +{ + printf("%s [-a ADDRESS] [-p PORT]\n" + "\n" + "Start a command line server on a TCP listen socket. Only\n" + "one connection is accepted, then the program exits.\n" + "The default behaviour is to listen on 0.0.0.0:1234\n" + "\n" + " -a ADDR: IPv4 or IPv6 local address to listen on (default\n" + " is 0.0.0.0).\n" + " -p PORT: port to listen on (default is 1234).\n", + prgname); +} + +/* Parse the argument given in the command line of the application */ +static int +parse_args(int argc, char **argv) +{ + int opt, ret; + char **argvopt; + int option_index; + char *prgname = argv[0]; + char *end = NULL; + static struct option lgopts[] = { + {0, 0, 0, 0} + }; + + argvopt = argv; + + while ((opt = getopt_long(argc, argvopt, "a:p:", + lgopts, &option_index)) != EOF) { + + switch (opt) { + + case 'a': + if (strchr(optarg, '.') != NULL) { + struct sockaddr_in *sin = + (struct sockaddr_in *)&addr; + addr.sa_family = AF_INET; + ret = inet_pton(AF_INET, optarg, + &sin->sin_addr); + } + else { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)&addr; + addr.sa_family = AF_INET6; + ret = inet_pton(AF_INET6, optarg, + &sin6->sin6_addr); + } + + if (ret != 1) { + printf("Bad address\n"); + usage(prgname); + return -1; + } + break; -int main(void) + case 'p': + port = strtoul(optarg, &end, 0); + if ((optarg[0] == '\0') || + (end == NULL) || + (*end != '\0')) { + printf("Invalid port\n"); + usage(prgname); + return -1; + } + + break; + + /* long options */ + case 0: + /* if (!strcmp(lgopts[option_index].name, "option")) */ + break; + + default: + usage(prgname); + return -1; + } + } + + if (argc != optind) { + printf("Invalid argument\n"); + usage(prgname); + return -1; + } + + ret = optind-1; + + return ret; +} + +int main(int argc, char **argv) { + struct sockaddr_in *sin = (struct sockaddr_in *)&addr; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; + struct cmdline *cl; int s; - s = cmdline_tcpv4_listen(INADDR_ANY, 1234); + + if (parse_args(argc, argv) < 0) + exit(1); + + printf("Listening on port %d\n", port); + + /* open a tcp server on specified port */ + if (addr.sa_family == AF_INET) + s = cmdline_tcpv4_listen(sin->sin_addr.s_addr, port); + else + s = cmdline_tcpv6_listen(sin6->sin6_addr, port); + cl = cmdline_accept(main_ctx, "example> ", s); - if (cl == NULL) + if (cl == NULL) { + printf("accept() failed\n"); return 1; + } cmdline_interact(cl); cmdline_free(cl); return 0; diff --git a/src/client/main.c b/src/client/main.c index 5f177d2..c0d6079 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -26,9 +26,10 @@ */ #include +#include #include #include -#include +#include #include #include @@ -38,14 +39,117 @@ #include #include +static struct sockaddr addr; +static uint16_t port = 1234; -int main(void) +static void +usage(const char *prgname) { + printf("%s [-a ADDRESS] [-p PORT]\n" + "\n" + "Start a client to connect to a command line server, using\n" + "a TCP socket.\n" + "The default behaviour is to connect to 127.0.0.1:1234\n" + "\n" + " -a ADDR: IPv4 or IPv6 local address to listen on (default\n" + " is 127.0.0.1).\n" + " -p PORT: port to connect to (default is 1234).\n", + prgname); +} + +/* Parse the argument given in the command line of the application */ +static int +parse_args(int argc, char **argv) +{ + int opt, ret; + char **argvopt; + int option_index; + char *prgname = argv[0]; + char *end = NULL; + static struct option lgopts[] = { + {0, 0, 0, 0} + }; + + argvopt = argv; + + while ((opt = getopt_long(argc, argvopt, "a:p:", + lgopts, &option_index)) != EOF) { + + switch (opt) { + + case 'a': + if (strchr(optarg, '.') != NULL) { + struct sockaddr_in *sin = + (struct sockaddr_in *)&addr; + addr.sa_family = AF_INET; + ret = inet_pton(AF_INET, optarg, + &sin->sin_addr); + } + else { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)&addr; + addr.sa_family = AF_INET6; + ret = inet_pton(AF_INET6, optarg, + &sin6->sin6_addr); + } + + if (ret != 1) { + printf("Bad address\n"); + usage(prgname); + return -1; + } + break; + + case 'p': + port = strtoul(optarg, &end, 0); + if ((optarg[0] == '\0') || + (end == NULL) || + (*end != '\0')) { + printf("Invalid port\n"); + usage(prgname); + return -1; + } + + break; + + /* long options */ + case 0: + /* if (!strcmp(lgopts[option_index].name, "option")) */ + break; + + default: + usage(prgname); + return -1; + } + } + + if (argc != optind) { + printf("Invalid argument\n"); + usage(prgname); + return -1; + } + + ret = optind-1; + + return ret; +} + +int main(int argc, char **argv) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)&addr; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; struct termios oldterm, term; - struct sockaddr_in sin_ci; fd_set fds; int s; char c; + char buf[INET6_ADDRSTRLEN]; + + /* default */ + sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sin->sin_family = AF_INET; + + if (parse_args(argc, argv) < 0) + exit(1); s = socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { @@ -53,18 +157,33 @@ int main(void) return s; } - /* XXX specify address */ - memset(&sin_ci, 0, sizeof(sin_ci)); - sin_ci.sin_family = AF_INET; - inet_pton(AF_INET, "127.0.0.1", &sin_ci.sin_addr.s_addr); - sin_ci.sin_port = htons(1234); + switch (addr.sa_family) { + case AF_INET: + sin->sin_port = htons(port); #ifndef __linux__ - sin_ci.sin_len = sizeof(sin_ci); + sin->sin_len = sizeof(*sin); #endif + printf("Connecting to %s:%d\n", + inet_ntop(AF_INET, &sin->sin_addr, buf, + sizeof(*sin)), port); + break; + case AF_INET6: + sin6->sin6_port = htons(port); +#ifndef __linux__ + sin6->sin6_len = sizeof(*sin6); +#endif + printf("Connecting to %s:%d\n", + inet_ntop(AF_INET6, &sin6->sin6_addr, buf, + sizeof(*sin6)), port); + break; + default: + printf("bad address\n"); + return -1; + } - if (connect(s, (struct sockaddr *)&sin_ci, sizeof(sin_ci)) < 0) { + if (connect(s, &addr, sizeof(addr)) < 0) { printf("connect() failed\n"); - return s; + return -1; } tcgetattr(0, &oldterm); @@ -95,5 +214,3 @@ int main(void) return 0; } - - diff --git a/src/event_server/main.c b/src/event_server/main.c index 289bd71..eb88dbb 100644 --- a/src/event_server/main.c +++ b/src/event_server/main.c @@ -29,15 +29,15 @@ #include #include #include -#include #include #include #include #include -#include #include -#include #include +#include + +#include #include #include @@ -46,9 +46,10 @@ #include -extern cmdline_parse_ctx_t main_ctx[]; +static struct sockaddr addr; +static uint16_t port = 1234; -/*** main */ +extern cmdline_parse_ctx_t main_ctx[]; static void evt_server_input(int s, short event, void *arg) @@ -95,19 +96,118 @@ evt_server_new_connection(int s, short event, void *arg) event_add(evt, NULL); } +static void +usage(const char *prgname) +{ + printf("%s [-a ADDRESS] [-p PORT]\n" + "\n" + "Start a command line server on a TCP listen socket. This example\n" + "uses the libevent to support several simultaneous connections.\n" + "The default behaviour is to listen on 0.0.0.0:1234\n" + "\n" + " -a ADDR: IPv4 or IPv6 local address to listen on (default\n" + " is 0.0.0.0).\n" + " -p PORT: port to listen on (default is 1234).\n", + prgname); +} + +/* Parse the argument given in the command line of the application */ +static int +parse_args(int argc, char **argv) +{ + int opt, ret; + char **argvopt; + int option_index; + char *prgname = argv[0]; + char *end = NULL; + static struct option lgopts[] = { + {0, 0, 0, 0} + }; + + argvopt = argv; + + while ((opt = getopt_long(argc, argvopt, "a:p:", + lgopts, &option_index)) != EOF) { + + switch (opt) { + + case 'a': + if (strchr(optarg, '.') != NULL) { + struct sockaddr_in *sin = + (struct sockaddr_in *)&addr; + addr.sa_family = AF_INET; + ret = inet_pton(AF_INET, optarg, + &sin->sin_addr); + } + else { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)&addr; + addr.sa_family = AF_INET6; + ret = inet_pton(AF_INET6, optarg, + &sin6->sin6_addr); + } + + if (ret != 1) { + printf("Bad address\n"); + usage(prgname); + return -1; + } + break; + + case 'p': + port = strtoul(optarg, &end, 0); + if ((optarg[0] == '\0') || + (end == NULL) || + (*end != '\0')) { + printf("Invalid port\n"); + usage(prgname); + return -1; + } + + break; + + /* long options */ + case 0: + /* if (!strcmp(lgopts[option_index].name, "option")) */ + break; + + default: + usage(prgname); + return -1; + } + } + + if (argc != optind) { + printf("Invalid argument\n"); + usage(prgname); + return -1; + } -int main(void) + ret = optind-1; + + return ret; +} + +int main(int argc, char **argv) { + struct sockaddr_in *sin = (struct sockaddr_in *)&addr; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; struct event listen_evt; int s; - printf("Listening on port 1234\n"); + if (parse_args(argc, argv) < 0) + exit(1); + + printf("Listening on port %d\n", port); /* initializa libevent */ event_init(); - /* open a tcp server on port 1234 */ - s = cmdline_tcpv4_listen(INADDR_ANY, 1234); + /* open a tcp server on specified port */ + if (addr.sa_family == AF_INET) + s = cmdline_tcpv4_listen(sin->sin_addr.s_addr, port); + else + s = cmdline_tcpv6_listen(sin6->sin6_addr, port); event_set(&listen_evt, s, EV_READ | EV_PERSIST, evt_server_new_connection, NULL); event_add(&listen_evt, NULL); @@ -117,5 +217,3 @@ int main(void) return 0; } - - -- 2.20.1