Parse commandline of sdbd and make use of values provided 19/15719/5
authorAleksander Zdyb <a.zdyb@partner.samsung.com>
Fri, 31 Jan 2014 11:00:45 +0000 (12:00 +0100)
committerAleksander Zdyb <a.zdyb@partner.samsung.com>
Fri, 31 Jan 2014 13:19:10 +0000 (14:19 +0100)
Settings such as emulator name or ports are no longer parsed
from /proc/cmdline. Individual ports can be now explicitly
specified and not determined by some hardcoded arithmetical logic.
An additional advantage is possibility to launch sdbd in tcp mode
on specified IP and port. Moreover running on emulator or not
is not determined at runtime, but rather passed as an option.

Available options are:
* -e, --emulator=HOST:PORT   emulator's name and forward port
* -c, --connect-to=HOST:PORT hostname or IP and port of sdb
                             listening on host (for notification)
* -s, --sensors=HOST:PORT    hostname or IP and port of sensors
                             daemon
* -l, --listen-port=PORT     port on which sdbd shall be
                             listening on

Some functions are rewritten to make use of commandline args:
* is_emulator(),
* get_emulator_forward_port(),
* get_emulator_name().

send_msg_to_localhost_from_guest() is more generic now -- accepts
hostname.

Change-Id: I498ce3688019418548dc94c55c4ea8144be8687a
Signed-off-by: Aleksander Zdyb <a.zdyb@partner.samsung.com>
Makefile
packaging/sdbd_emulator.service
src/commandline_sdbd.c [new file with mode: 0644]
src/commandline_sdbd.h [new file with mode: 0644]
src/sdb.c
src/sdb.h
src/transport_local.c
test/test_commandline_sdbd.c [new file with mode: 0644]

index dc0eb36..6fef698 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,8 @@ SDBD_SRC_FILES := \
        src/strutils.c \
        src/libsmack.c \
        src/init.c \
-       src/fileutils.c
+       src/fileutils.c \
+       src/commandline_sdbd.c
 
 SDBD_CFLAGS := -O2 -g -DSDB_HOST=0 -Wall -Wno-unused-parameter
 SDBD_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
index 274c3e9..3bcbcf1 100644 (file)
@@ -7,9 +7,7 @@ Type=forking
 Environment=DISPLAY=:0
 PIDFile=/tmp/.sdbd.pid
 RemainAfterExit=yes
-ExecStartPre=/bin/bash -c "/bin/echo `/bin/sed 's/^.*sdb_port=\([^, ]*\).*$/\1/g' /proc/cmdline` > /opt/home/sdb_port.txt"
-ExecStart=/usr/sbin/sdbd
+ExecStart=/bin/sh -c "/usr/sbin/sdbd `/usr/bin/awk '{match($0, /sdb_port=([0-9]+)/,port_match); match($0, /vm_name=([^, ]*)/,vm_match); print \"--emulator=\" vm_match[1] \":\" port_match[1] \" --connect-to=10.0.2.2:26099\" \" --sensors=10.0.2.2:\"port_match[1]+3 \" --listen-port=\"port_match[1]+1 }' /proc/cmdline`"
 
 [Install]
 WantedBy=emulator.target
-
diff --git a/src/commandline_sdbd.c b/src/commandline_sdbd.c
new file mode 100644 (file)
index 0000000..ccf75f2
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "commandline_sdbd.h"
+#include "sdb.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+
+
+/*!
+ * @fn int split_host_port(const char *optarg, char **host, int *port)
+ * @brief Splits string of form \c "localhost:22" into \c host (string)
+ *        and \c port (int) parts.
+ *
+ * @param optarg optarg from getopt
+ * @param host Where to put host part string
+ * @param port Where to put port part int
+ *
+ * @returns \ref SDBD_COMMANDLINE_SUCCESS on success
+ *          or \ref SDBD_COMMANDLINE_FAILURE otherwise
+ */
+int split_host_port(const char *optarg, char **host, int *port);
+
+int parse_sdbd_commandline(SdbdCommandlineArgs *sdbd_args, int argc, char *argv[]) {
+       int split_retval;
+
+       int opt;
+       int long_index = 0;
+
+       static struct option long_options[] = {
+               { ARG_EMULATOR_VM_NAME, required_argument, NULL, ARG_S_EMULATOR_VM_NAME },
+               { ARG_SENSORS, required_argument, NULL, ARG_S_SENSORS },
+               { ARG_SDB, required_argument, NULL, ARG_S_SDB },
+               { ARG_SDBD_LISTEN_PORT, required_argument, NULL, ARG_S_SDBD_LISTEN_PORT },
+               { NULL, 0, NULL, 0 }
+       };
+
+       optind = 1;     /* the index of the next element to be processed in argv */
+
+       while ((opt = getopt_long(argc, argv, "", long_options, &long_index)) != -1) {
+               switch (opt) {
+               case ARG_S_EMULATOR_VM_NAME:
+                       split_retval = split_host_port(optarg,
+                                       &sdbd_args->emulator.host,
+                                       &sdbd_args->emulator.port);
+                       if (split_retval != SDBD_COMMANDLINE_SUCCESS) {
+                               return split_retval;
+                       }
+                       break;
+               case ARG_S_SENSORS:
+                       split_retval = split_host_port(optarg,
+                                       &sdbd_args->sensors.host,
+                                       &sdbd_args->sensors.port);
+                       if (split_retval != SDBD_COMMANDLINE_SUCCESS) {
+                               return split_retval;
+                       }
+                       break;
+               case ARG_S_SDB:
+                       split_retval = split_host_port(optarg,
+                                       &sdbd_args->sdb.host,
+                                       &sdbd_args->sdb.port);
+                       if (split_retval != SDBD_COMMANDLINE_SUCCESS) {
+                               return split_retval;
+                       }
+                       break;
+               case ARG_S_SDBD_LISTEN_PORT:
+                       if (sscanf(optarg, "%d", &sdbd_args->sdbd_port) < 1) {
+                               return SDBD_COMMANDLINE_FAILURE;
+                       }
+                       break;
+               case 1:
+                       return SDBD_COMMANDLINE_FAILURE_UNKNOWN_OPT;
+               case '?':
+                       return SDBD_COMMANDLINE_FAILURE_UNKNOWN_OPT;
+               default:
+                       return SDBD_COMMANDLINE_FAILURE;
+               }
+       }
+
+       return SDBD_COMMANDLINE_SUCCESS;
+}
+
+
+void apply_sdbd_commandline_defaults(SdbdCommandlineArgs *sdbd_args) {
+       sdbd_args->sensors.host = strdup(QEMU_FORWARD_IP);
+       sdbd_args->sensors.port = DEFAULT_SENSORS_LOCAL_TRANSPORT_PORT;
+
+       sdbd_args->sdb.host = strdup(QEMU_FORWARD_IP);
+       sdbd_args->sdb.port = DEFAULT_SDB_PORT;
+
+       sdbd_args->sdbd_port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
+}
+
+
+int split_host_port(const char *optarg, char **host, int *port) {
+       const char *colon = strchr(optarg, ':');
+       char *old_val = NULL;
+
+       if (colon) {
+               old_val = *host;
+               *host = strndup(optarg, colon - optarg);
+               if (sscanf(colon + 1, "%d", port) < 1) {
+                       return SDBD_COMMANDLINE_FAILURE;
+               }
+       } else {
+               return SDBD_COMMANDLINE_FAILURE;
+       }
+
+       if (old_val) {
+               free(old_val);
+       }
+       return SDBD_COMMANDLINE_SUCCESS;
+}
+
+
+void clear_sdbd_commandline_args(SdbdCommandlineArgs *sdbd_args) {
+    free(sdbd_args->emulator.host);
+    sdbd_args->emulator.host = NULL;
+
+    free(sdbd_args->sdb.host);
+    sdbd_args->sdb.host = NULL;
+
+    free(sdbd_args->sensors.host);
+    sdbd_args->sensors.host = NULL;
+
+       memset(sdbd_args, 0, sizeof(SdbdCommandlineArgs));
+}
diff --git a/src/commandline_sdbd.h b/src/commandline_sdbd.h
new file mode 100644 (file)
index 0000000..9b070ad
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMMANDLINE_SDBD_H
+#define COMMANDLINE_SDBD_H
+
+#define ARG_EMULATOR_VM_NAME "emulator"
+#define ARG_S_EMULATOR_VM_NAME 'e'
+
+#define ARG_SDBD_LISTEN_PORT "listen-port"
+#define ARG_S_SDBD_LISTEN_PORT 'l'
+
+#define ARG_SDB "connect-to"
+#define ARG_S_SDB 'c'
+
+#define ARG_SENSORS "sensors"
+#define ARG_S_SENSORS 's'
+
+#define SDBD_COMMANDLINE_SUCCESS 0 ///< Success
+#define SDBD_COMMANDLINE_FAILURE -1 ///< Generic failure
+#define SDBD_COMMANDLINE_FAILURE_UNKNOWN_OPT -2 ///< Unknown option
+
+/*!
+ * @struct HostPort
+ * @brief A simple host:port tuple
+ */
+typedef struct {
+       char *host;
+       int port;
+} HostPort;
+
+/*!
+ * @struct SdbdCommandlineArgs
+ * @brief Contains all values, which are read from commandline.
+ */
+typedef struct {
+       HostPort emulator; ///< emulator name and forward port
+       HostPort sdb; ///< sdb address
+       HostPort sensors; ///< sensors address
+       int sdbd_port; ///< Port to listen on in tcp mode
+} SdbdCommandlineArgs;
+
+
+/*!
+ * @fn int parse_sdbd_commandline(SdbdCommandlineArgs *sdbd_args, int argc, char *argv[])
+ * @brief Parses commandline and stores result in sdbd_args.
+ *
+ * @note \c argc and \c argv must be the ones passed to main() function,
+ * e.g. have program name as the first value.
+ *
+ * @param sdbd_args SdbdCommandlineArgs where arguments shall be put
+ * @param argc Count of arguments passed to the program (from main())
+ * @param argv Array of pointers to the strings, which are program arguments (from main())
+ *
+ * @returns \ref SDBD_COMMANDLINE_SUCCESS on success. On failure one of:
+ *  - \ref SDBD_COMMANDLINE_FAILURE
+ *  - \ref SDBD_COMMANDLINE_FAILURE_UNKNOWN_OPT
+ */
+int parse_sdbd_commandline(SdbdCommandlineArgs *sdbd_args, int argc, char **argv);
+
+
+/*!
+ * @fn void apply_sdbd_commandline_defaults(SdbdCommandlineArgs *sdbd_args)
+ * @brief Applies default values to \c sdbd_args.
+ *
+ * @param sdbd_args SdbdCommandlineArgs where values shall be put
+ *
+ * @note It won't free old values.
+ * @see \ref clear_sdbd_commandline_args
+ */
+void apply_sdbd_commandline_defaults(SdbdCommandlineArgs *sdbd_args);
+
+
+/*!
+ * @fn void clear_sdbd_commandline_args(SdbdCommandlineArgs *sdbd_args)
+ * @brief Frees and clears \c sdbd_args 's members.
+ *
+ * @param sdbd_args SdbdCommandlineArgs to be cleared
+ *
+ * @note This function will generate segmentation fault,
+ * if string pointers are not allocated and not NULL-ed.
+ */
+void clear_sdbd_commandline_args(SdbdCommandlineArgs *sdbd_args);
+
+#endif /* COMMANDLINE_SDBD_H */
index b726574..42383d0 100644 (file)
--- a/src/sdb.c
+++ b/src/sdb.c
 #include <sys/time.h>
 #include <signal.h>
 #include <grp.h>
+#include <netdb.h>
+
 
 #include "sysdeps.h"
 #include "sdb.h"
 #include "strutils.h"
+#if !SDB_HOST
+#include "commandline_sdbd.h"
+#endif
 
 #if !SDB_HOST
 #include <linux/prctl.h>
@@ -45,12 +50,16 @@ SDB_MUTEX_DEFINE( D_lock );
 
 int HOST = 0;
 
+#if !SDB_HOST
+SdbdCommandlineArgs sdbd_commandline_args;
+#endif
+
 int is_emulator(void) {
-    if (access(USB_NODE_FILE, F_OK) == 0) {
-        return 0;
-    } else {
-        return 1;
-    }
+#if SDB_HOST
+       return 0;
+#else
+       return sdbd_commandline_args.emulator.host != NULL;
+#endif
 }
 
 void handle_sig_term(int sig) {
@@ -374,48 +383,23 @@ static int get_str_cmdline(char *src, char *dest, char str[], int str_size) {
 }
 
 int get_emulator_forward_port() {
-    char cmdline[512];
-    int fd = unix_open(PROC_CMDLINE_PATH, O_RDONLY);
-    char *port_str = "sdb_port=";
-    char port_buf[7]={0,};
-    int port = -1;
+    SdbdCommandlineArgs *sdbd_args = &sdbd_commandline_args; /* alias */
 
-    if (fd < 0) {
+    if (sdbd_args->emulator.host == NULL) {
         return -1;
     }
-    if(read_line(fd, cmdline, sizeof(cmdline))) {
-        D("qemu cmd: %s\n", cmdline);
-        if (get_str_cmdline(cmdline, port_str, port_buf, sizeof(port_buf)) < 1) {
-            D("could not get port from cmdline\n");
-            sdb_close(fd);
-            return -1;
-        }
-        // FIXME: remove comma!
-        port_buf[strlen(port_buf)-1]='\0';
-        port = strtol(port_buf, NULL, 10);
-    }
-    sdb_close(fd);
-    return port;
+
+    return sdbd_args->emulator.port;
 }
 
 int get_emulator_name(char str[], int str_size) {
-    char cmdline[512];
-    int fd = unix_open(PROC_CMDLINE_PATH, O_RDONLY);
-    char *name_str = "vm_name=";
+    SdbdCommandlineArgs *sdbd_args = &sdbd_commandline_args; /* alias */
 
-    if (fd < 0) {
-        D("fail to read /proc/cmdline\n");
+    if (sdbd_args->emulator.host == NULL) {
         return -1;
     }
-    if(read_line(fd, cmdline, sizeof(cmdline))) {
-        D("qemu cmd: %s\n", cmdline);
-        if (get_str_cmdline(cmdline, name_str, str, str_size) < 1) {
-            D("could not get emulator name from cmdline\n");
-            sdb_close(fd);
-            return -1;
-        }
-    }
-    sdb_close(fd);
+
+    s_strncpy(str, sdbd_args->emulator.host, str_size);
     return 0;
 }
 
@@ -812,6 +796,7 @@ static BOOL WINAPI ctrlc_handler(DWORD type)
 
 static void sdb_cleanup(void)
 {
+    clear_sdbd_commandline_args(&sdbd_commandline_args);
     usb_cleanup();
 //    if(required_pid > 0) {
 //        kill(required_pid, SIGKILL);
@@ -1628,6 +1613,8 @@ int main(int argc, char **argv)
 
     //sdbd will never die on emulator!
     signal(SIGTERM, handle_sig_term); /* tizen specific */
+    apply_sdbd_commandline_defaults(&sdbd_commandline_args);
+    parse_sdbd_commandline(&sdbd_commandline_args, argc, argv);
     return sdb_main(0, DEFAULT_SDB_PORT);
 #endif
 }
index 01c8b40..e8bb48c 100644 (file)
--- a/src/sdb.h
+++ b/src/sdb.h
 #define __SDB_H
 
 #include <limits.h>
+#include <stdlib.h>
 
 #include "transport.h"  /* readx(), writex() */
+#include "fdevent.h"
+#if !SDB_HOST
+#include "commandline_sdbd.h"
+#endif
 
 #define MAX_PAYLOAD 4096
 
@@ -444,6 +449,7 @@ void sdb_qemu_trace(const char* fmt, ...);
 #  define QEMU_FORWARD_IP "10.0.2.2"
 
 #define DEFAULT_SDB_LOCAL_TRANSPORT_PORT 26101 /* tizen specific */
+#define DEFAULT_SENSORS_LOCAL_TRANSPORT_PORT 26103 /* tizen specific */
 
 #define SDB_CLASS              0xff
 #define SDB_SUBCLASS           0x20 //0x42 /* tizen specific */
@@ -483,6 +489,9 @@ int connection_state(atransport *t);
 
 extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
+#if !SDB_HOST
+extern SdbdCommandlineArgs sdbd_commandline_args;
+#endif
 
 #define CHUNK_SIZE (64*1024)
 
index ee59551..743ef2d 100644 (file)
@@ -19,6 +19,7 @@
 #include <string.h>
 #include <errno.h>
 #include <arpa/inet.h>
+#include <netdb.h>
 
 #include "sysdeps.h"
 #include <sys/types.h>
@@ -32,6 +33,9 @@
 #define  TRACE_TAG  TRACE_TRANSPORT
 #include "sdb.h"
 #include "strutils.h"
+#if !SDB_HOST
+#include "commandline_sdbd.h"
+#endif
 
 #ifdef HAVE_BIG_ENDIAN
 #define H4(x)  (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
@@ -403,38 +407,79 @@ static const char _ok_resp[]    = "ok";
 #endif  // !SDB_HOST
 #endif
 
-static int send_msg_to_localhost_from_guest(int local_port, char *request, int sock_type) {
-    int                  ret, s;
-    struct sockaddr_in   server;
+/*!
+ * static int send_msg_to_host_from_guest(const char *hostname, int host_port, char *request, int sock_type)
+ * @brief Sends \c request to host using specified protocol
+ *
+ * @param hostname Hostname -- could be domain name or IP
+ * @param host_port Host port
+ * @param request Message to be sent to host
+ * @param protocol IP protocol to be used: IPPROTO_TCP or IPPROTO_UDP
+ *
+ * @returns 0 on success, -1 otherwise
+ *
+ * @note SOCK_STREAM will be used for IPPROTO_TCP as socket type
+ *       and SOCK_DGRAM for IPPROTO_UDP
+ */
+static int send_msg_to_host_from_guest(const char *hostname, int host_port, char *request, int protocol) {
+    int sock = -1;
+    char port[32]; /* string decimal representation for getaddrinfo */
+    struct addrinfo hints = {0};
+    struct addrinfo *addresses, *curr_addr;
+    int getaddr_ret;
+    const char *protocol_name = "unknown"; /* for debug message */
+
+    switch(protocol) {
+    case IPPROTO_TCP:
+        protocol_name = "tcp";
+        hints.ai_socktype = SOCK_STREAM;
+        break;
+    case IPPROTO_UDP:
+        protocol_name = "udp";
+        hints.ai_socktype = SOCK_DGRAM;
+        break;
+    default:
+        D("unsupported protocol: %d", protocol);
+        return -1;
+    }
 
-    memset( &server, 0, sizeof(server) );
-    server.sin_family      = AF_INET;
-    server.sin_port        = htons(local_port);
-    server.sin_addr.s_addr = inet_addr(QEMU_FORWARD_IP);
+    D("try to send notification to host(%s:%d) using %s:[%s]\n", hostname, host_port, protocol_name, request);
 
-    D("try to send notification to host(%s:%d) using %s:[%s]\n", QEMU_FORWARD_IP, local_port, (sock_type == 0) ? "tcp" : "udp", request);
+    hints.ai_family = AF_INET;
 
-    if (sock_type == 0) {
-        s = socket(AF_INET, SOCK_STREAM, 0);
-    } else {
-        s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-    }
-    if (s < 0) {
-        D("could not create socket\n");
+    sprintf(port, "%d", host_port);
+    getaddr_ret = getaddrinfo(hostname, port, &hints, &addresses);
+
+    if (getaddr_ret != 0) {
+        D("could not resolve %s\n", hostname);
         return -1;
     }
-    ret = connect(s, (struct sockaddr*) &server, sizeof(server));
-    if (ret < 0) {
+
+    for(curr_addr = addresses; curr_addr != NULL; curr_addr = curr_addr->ai_next) {
+        sock = socket(curr_addr->ai_family, curr_addr->ai_socktype, curr_addr->ai_protocol);
+        if (sock == -1)
+            continue;
+
+        if (connect(sock, curr_addr->ai_addr, curr_addr->ai_addrlen) != -1)
+            break; /* Success */
+
+        sdb_close(sock);
+    }
+
+    if(curr_addr == NULL) { /* No address succeeded */
+        freeaddrinfo(addresses);
         D("could not connect to server\n");
-        sdb_close(s);
         return -1;
     }
-    if (sdb_write(s, request, strlen(request)) < 0) {
+
+    freeaddrinfo(addresses);
+
+    if (sdb_write(sock, request, strlen(request)) < 0) {
         D("could not send notification request to host\n");
-        sdb_close(s);
+        sdb_close(sock);
         return -1;
     }
-    sdb_close(s);
+    sdb_close(sock);
     D("sent notification request to host\n");
 
     return 0;
@@ -444,27 +489,30 @@ static void notify_sdbd_startup() {
     char                 buffer[512];
     char                 request[512];
 
+    SdbdCommandlineArgs *sdbd_args = &sdbd_commandline_args; /* alias */
+
     // send the request to sdbserver
-    char vm_name[256]={0,};
-    int base_port = get_emulator_forward_port();
-    int r = get_emulator_name(vm_name, sizeof vm_name);
+    const char *vm_name = sdbd_args->emulator.host;
+    int sdbd_port = sdbd_args->sdbd_port;
+    int sensors_port = sdbd_args->sensors.port;
+
 
-    if (base_port < 0 || r < 0) {
+    if (sdbd_port <= 0 || vm_name == NULL) {
         return;
     }
 
     // tell qemu sdbd is just started with udp
     char sensord_buf[16];
     snprintf(sensord_buf, sizeof sensord_buf, "2\n");
-    if (send_msg_to_localhost_from_guest(base_port + 3, sensord_buf, 1) < 0) {
+    if (send_msg_to_host_from_guest(sdbd_args->sensors.host, sensors_port, sensord_buf, IPPROTO_UDP) < 0) {
         D("could not send sensord noti request\n");
     }
 
-    // tell sdb server emulator's vms name
-    snprintf(request, sizeof request, "host:emulator:%d:%s",base_port + 1, vm_name);
-    snprintf(buffer, sizeof buffer, "%04x%s", strlen(request), request );
+    // tell sdb server emulator's vms name and forward port
+    snprintf(request, sizeof request, "host:emulator:%d:%s", sdbd_port, vm_name);
+    snprintf(buffer, sizeof buffer, "%04x%s", strlen(request), request);
 
-    if (send_msg_to_localhost_from_guest(DEFAULT_SDB_PORT, buffer, 0) <0) {
+    if (send_msg_to_host_from_guest(sdbd_args->sdb.host, sdbd_args->sdb.port, buffer, IPPROTO_TCP) < 0) {
         D("could not send sdbd noti request. it might sdb server has not been started yet.\n");
     }
 }
diff --git a/test/test_commandline_sdbd.c b/test/test_commandline_sdbd.c
new file mode 100644 (file)
index 0000000..8d332f5
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "commandline_sdbd.h"
+#include "sdb.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <check.h>
+
+/*!
+ * @define print_nullable(s)
+ * Takes string (<tt>const char *</tt>) and returns it or "(null)" literal
+ * in case \c s is NULL.
+ */
+#define print_nullable(s) \
+       (((s) == NULL) ? "(null)" : (s))
+
+
+/*!
+ * @define ck_hostport(hp, h, p)
+ * Check if HostPort contains given host and port
+ *
+ * Host strings are equal if both point to the same address (including NULL)
+ * or, provided none of them is NULL, if strcmp() == 0.
+ *
+ * @param hp \ref HostPort to be checked (<tt>const HostPort *</tt>)
+ * @param h hostname (<tt>const char *</tt>) to be checked against
+ * @param p port (\c int) to be checked against
+ */
+#define _ck_hostport(hp, h, p) \
+       ( (((hp)->host == (h)) \
+                       || (((hp)->host) && (h) && (strcmp((hp)->host, (h)) == 0))) \
+               && (hp)->port == (p) )
+
+
+/*!
+ * @define ck_assert_hostport_eq(hp,h,p)
+ * Makes assertion against HostPort containing given host and port
+ *
+ * @param hp \ref HostPort to be checked (<tt>const HostPort *</tt>)
+ * @param h hostname (<tt>const char *</tt>) to be checked against
+ * @param p port (\c int) to be checked against
+ *
+ * @see ck_hostport
+ */
+#define ck_assert_hostport_eq(hp,h,p) \
+       (fail_unless(_ck_hostport(hp,h,p), "Assertion failed (%s,%d) != (%s, %d)", \
+                       print_nullable((hp)->host), (hp)->port, print_nullable(h), (p)))
+
+
+void setup(void) {
+
+}
+
+void teardown(void) {
+
+}
+
+
+START_TEST(test_ok) {
+       char *argv[] = {
+                       "./test",
+                       "--emulator=tizen:101",
+                       "--listen-port=101",
+                       "--sensors=localhost:103",
+                       "--connect-to=localhost:99"
+       };
+
+       SdbdCommandlineArgs sdbd_args = {0};
+
+       apply_sdbd_commandline_defaults(&sdbd_args);
+       int parse_res = parse_sdbd_commandline(&sdbd_args, 5, argv);
+
+       if (parse_res != SDBD_COMMANDLINE_SUCCESS) {
+               ck_abort_msg("parsing commandline failed");
+               return;
+       }
+
+       ck_assert_hostport_eq(&sdbd_args.emulator, "tizen", 101);
+       ck_assert_hostport_eq(&sdbd_args.sensors, "localhost", 103);
+       ck_assert_hostport_eq(&sdbd_args.sdb, "localhost", 99);
+       ck_assert_int_eq(sdbd_args.sdbd_port, 101);
+
+} END_TEST
+
+
+START_TEST(test_empty) {
+       char *argv[] = {
+                       "./test"
+       };
+
+       SdbdCommandlineArgs sdbd_args = {0};
+
+       int parse_res = parse_sdbd_commandline(&sdbd_args, 1, argv);
+
+       if (parse_res != SDBD_COMMANDLINE_SUCCESS) {
+               ck_abort_msg("parsing commandline failed");
+               return;
+       }
+
+       /* Now check if sdbd_commandline_args was not tainted */
+       SdbdCommandlineArgs zero_args;
+       memset(&zero_args, 0, sizeof(SdbdCommandlineArgs));
+       if (memcmp(&sdbd_args, &zero_args, sizeof(SdbdCommandlineArgs)) != 0) {
+               ck_abort_msg("SdbdCommandlineArgs is tainted");
+       }
+
+} END_TEST
+
+
+START_TEST(test_unknown) {
+       char *argv[] = {
+                       "./test",
+                       "--emulator=tizen:26101",
+                       "--unknown=true"
+       };
+
+       SdbdCommandlineArgs sdbd_args = {0};
+
+       int parse_res = parse_sdbd_commandline(&sdbd_args, 3, argv);
+
+       if (parse_res != SDBD_COMMANDLINE_FAILURE_UNKNOWN_OPT) {
+               ck_abort_msg("parsing commandline failed");
+               return;
+       }
+
+} END_TEST
+
+
+START_TEST(test_clear_args) {
+       SdbdCommandlineArgs sdbd_args = {0};
+
+       sdbd_args.emulator.host = strdup("emul_host");
+       sdbd_args.emulator.port = 123456;
+       sdbd_args.sdb.host = strdup("sdb_host");
+       sdbd_args.sdb.port = 623451;
+       sdbd_args.sensors.host = strdup("sdb_host");
+       sdbd_args.sensors.port = 634512;
+       sdbd_args.sdbd_port = 543216;
+
+       clear_sdbd_commandline_args(&sdbd_args);
+
+       ck_assert_hostport_eq(&sdbd_args.emulator, NULL, 0);
+       ck_assert_hostport_eq(&sdbd_args.sensors, NULL, 0);
+       ck_assert_hostport_eq(&sdbd_args.sdb, NULL, 0);
+       ck_assert_int_eq(sdbd_args.sdbd_port, 0);
+} END_TEST
+
+
+START_TEST(test_double_clear) {
+    SdbdCommandlineArgs sdbd_args = {0};
+    clear_sdbd_commandline_args(&sdbd_args);
+} END_TEST
+
+
+START_TEST(test_default_args) {
+       SdbdCommandlineArgs sdbd_args = {0};
+
+       apply_sdbd_commandline_defaults(&sdbd_args);
+
+       ck_assert_hostport_eq(&sdbd_args.emulator, NULL, 0);
+       ck_assert_hostport_eq(&sdbd_args.sensors, QEMU_FORWARD_IP, DEFAULT_SENSORS_LOCAL_TRANSPORT_PORT);
+       ck_assert_hostport_eq(&sdbd_args.sdb, QEMU_FORWARD_IP, DEFAULT_SDB_PORT);
+       ck_assert_int_eq(sdbd_args.sdbd_port, DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
+} END_TEST
+
+
+Suite *sdbd_commandline_suite (void) {
+       Suite *s = suite_create ("sdbd commandline");
+
+       TCase *tc_core = tcase_create ("Core");
+       tcase_add_checked_fixture(tc_core, setup, teardown);
+       tcase_add_test (tc_core, test_ok);
+       tcase_add_test (tc_core, test_empty);
+       tcase_add_test (tc_core, test_unknown);
+       tcase_add_test (tc_core, test_clear_args);
+       tcase_add_test (tc_core, test_double_clear);
+       tcase_add_test (tc_core, test_default_args);
+       suite_add_tcase (s, tc_core);
+
+       return s;
+}
+
+
+int run_tests(int print_output) {
+       int number_failed;
+       Suite *s = sdbd_commandline_suite();
+       SRunner *sr = srunner_create (s);
+       srunner_run_all (sr, print_output);
+       number_failed = srunner_ntests_failed (sr);
+       srunner_free (sr);
+       return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+
+#ifndef COMMANDLINE_SDBD_TESTS_NO_MAIN
+int main(int argc, char *argv[]) {
+       return run_tests(CK_NORMAL);
+}
+#endif /* COMMANDLINE_SDBD_TESTS_NO_MAIN */