examples: add getopt argument parsing for client and server
[libcmdline.git] / src / event_server / main.c
index 289bd71..eb88dbb 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <stdint.h>
-#include <math.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <inttypes.h>
 #include <ctype.h>
-#include <ctype.h>
 #include <unistd.h>
-#include <termios.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <getopt.h>
 
 #include <cmdline_rdline.h>
 #include <cmdline_parse.h>
 
 #include <event.h>
 
-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;
 }
-
-