Supporting TCP/IP socket communication.
authorSung-jae Park <nicesj.park@samsung.com>
Mon, 29 Jul 2013 09:53:01 +0000 (18:53 +0900)
committerSung-jae Park <nicesj.park@samsung.com>
Thu, 1 Aug 2013 10:06:50 +0000 (19:06 +0900)
[model] Redwood
[binary_type] AP
[customer] Docomo/Orange/Open
[issue#] N/A
[problem]
[cause]
[solution]
[team] HomeTF
[request]
[horizontal_expansion]

Change-Id: I67f778a2006342b055290bc67c38a88d4ac7d6d2

include/secure_socket.h
packaging/libcom-core.spec
src/com-core_packet-router.c
src/secure_socket.c

index 64a7832..c5c7c35 100644 (file)
 extern "C" {
 #endif
 
+/*!
+ * local:///tmp/.socket.file => /tmp/.socket.file
+ */
+#define COM_CORE_LOCAL_SCHEME          "local://"
+#define COM_CORE_LOCAL_SCHEME_LEN      (8)
+
+/*!
+ * remote://IPADDR:PORT
+ * remote://:PORT      => Using INADDR_ANY in this case
+ */
+#define COM_CORE_REMOTE_SCHEME         "remote://"
+#define COM_CORE_REMOTE_SCHEME_LEN     (9)
 
 /*
  * Create client connection
index b4abc22..facc9d8 100644 (file)
@@ -1,6 +1,6 @@
 Name: libcom-core
 Summary: Library for the light-weight IPC 
-Version: 0.4.5
+Version: 0.5.0
 Release: 1
 Group: HomeTF/Framework
 License: Apache License
@@ -24,6 +24,12 @@ Light-weight IPC supporting library (dev)
 %setup -q
 
 %build
+%if 0%{?tizen_build_binary_release_type_eng}
+export CFLAGS="${CFLAGS} -DTIZEN_ENGINEER_MODE"
+export CXXFLAGS="${CXXFLAGS} -DTIZEN_ENGINEER_MODE"
+export FFLAGS="${FFLAGS} -DTIZEN_ENGINEER_MODE"
+%endif
+
 cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix}
 make %{?jobs:-j%jobs}
 
index 57f45d0..f716751 100644 (file)
@@ -888,7 +888,7 @@ static inline int route_packet(struct router *router, int handle, struct packet
  * \NOTE
  * Running Threads: Main / Client / Server
  */
-static inline int put_send_packet(struct router *router, int handle, struct packet *packet)
+static int put_send_packet(struct router *router, int handle, struct packet *packet)
 {
        if (packet) {
                struct packet_item *item;
index 98185c7..d3ae477 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <netdb.h>
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <errno.h>
+#include <stdlib.h>
 
 #include <dlog.h>
 
 #include "debug.h"
 #include "util.h"
 
-#define BACKLOG 50     /*!< Accept only 50 connections as default */
-#define SNDBUF_SZ      262144
-#define RCVBUF_SZ      524288
+#define BACKLOG        50      /*!< Accept only 50 connections as default */
+#define SNDBUF_SZ      262144  /*!< 256 KB, this will be doubled by kernel */
+#define RCVBUF_SZ      524288  /*!< 512 KB, this will be doubled by kernel */
+
+enum scheme {
+       SCHEME_LOCAL = 0x00,
+       SCHEME_REMOTE = 0x01,
+       SCHEME_UNKNOWN = 0x02,
+};
+
+struct function_table {
+       int type;
+       int (*create_socket)(const char *peer, int port, struct sockaddr *addr);
+       int (*setup_handle)(int handle);
+};
 
 int errno;
 
-static inline int create_socket(const char *peer, struct sockaddr_un *addr)
+static inline int create_unix_socket(const char *peer, int port, struct sockaddr *addr)
 {
        int len;
        int handle;
+       struct sockaddr_un *un_addr = (struct sockaddr_un *)addr;
 
-       len = sizeof(*addr);
-       bzero(addr, len);
+       len = sizeof(*un_addr);
+       bzero(un_addr, len);
 
-       if (strlen(peer) >= sizeof(addr->sun_path)) {
+       if (strlen(peer) >= sizeof(un_addr->sun_path)) {
                ErrPrint("peer %s is too long to remember it\\n", peer);
                return -1;
        }
@@ -56,8 +71,8 @@ static inline int create_socket(const char *peer, struct sockaddr_un *addr)
        /* We can believe this has no prob, because
         * we already check the size of add.rsun_path
         */
-       strcpy(addr->sun_path, peer);
-       addr->sun_family = AF_UNIX;
+       strcpy(un_addr->sun_path, peer);
+       un_addr->sun_family = AF_UNIX;
 
        handle = socket(PF_UNIX, SOCK_STREAM, 0);
        if (handle < 0) {
@@ -68,52 +83,183 @@ static inline int create_socket(const char *peer, struct sockaddr_un *addr)
        return handle;
 }
 
-EAPI int secure_socket_create_client(const char *peer)
+static inline int create_inet_socket(const char *peer, int port, struct sockaddr *addr)
 {
-       struct sockaddr_un addr;
        int handle;
-       int state;
+       struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
+
+       bzero(in_addr, sizeof(*in_addr));
+
+       in_addr->sin_port = htons(port);
+       in_addr->sin_family = AF_INET;
+       if (*peer == '\0')
+               in_addr->sin_addr.s_addr = htonl(INADDR_ANY);
+       else
+               in_addr->sin_addr.s_addr = inet_addr(peer);
+
+       handle = socket(AF_INET, SOCK_STREAM, 0);
+       if (handle < 0) {
+               handle = -errno;
+               ErrPrint("socket: %s\n", strerror(errno));
+       }
+
+       return handle;
+}
+
+static inline int setup_unix_handle(int handle)
+{
        int on = 1;
        int sndbuf = SNDBUF_SZ;
        int rcvbuf = RCVBUF_SZ;
 
-       handle = create_socket(peer, &addr);
+       if (setsockopt(handle, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+               int ret;
+               ret = -errno;
+               ErrPrint("Failed to change sock opt : %s\n", strerror(errno));
+               return ret;
+       }
+
+       (void)setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
+       (void)setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
+       (void)setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on));
+
+       return 0;
+}
+
+static inline int setup_inet_handle(int handle)
+{
+       int on = 1;
+
+       (void)setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on));
+
+       return 0;
+}
+
+static inline char *parse_scheme(const char *peer, int *port, struct function_table *vtable)
+{
+       int _port;
+       char *addr = NULL;
+
+       if (!port)
+               port = &_port;
+
+       *port = 0;
+
+       if (!strncasecmp(peer, COM_CORE_LOCAL_SCHEME, COM_CORE_LOCAL_SCHEME_LEN)) {
+               vtable->type = (int)SCHEME_LOCAL;
+               peer += COM_CORE_LOCAL_SCHEME_LEN;
+
+               addr = strdup(peer);
+               if (!addr)
+                       ErrPrint("Heap: %s\n", strerror(errno));
+
+               vtable->create_socket = create_unix_socket;
+               vtable->setup_handle = setup_unix_handle;
+       } else if (!strncasecmp(peer, COM_CORE_REMOTE_SCHEME, COM_CORE_REMOTE_SCHEME_LEN)) {
+               register int len;
+               char *endptr;
+
+               vtable->type = (int)SCHEME_REMOTE;
+               peer += COM_CORE_REMOTE_SCHEME_LEN;
+
+               for (len = 0; peer[len] && peer[len] != ':'; len++);
+               if (peer[len] != ':') {
+                       ErrPrint("Invalid syntax: %s\n", peer);
+                       goto out;
+               }
+
+               addr = malloc(len + 1);
+               if (!addr) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       goto out;
+               }
+
+               if (len > 0)
+                       strncpy(addr, peer, len);
+               addr[len] = '\0';
+
+               peer += len + 1;
+               *port = strtoul(peer, &endptr, 10);
+               if (*endptr != '\0' || peer == endptr) {
+                       ErrPrint("Invalid: %s[%d]\n", peer - len - 1, len + 1);
+                       free(addr);
+                       addr = NULL;
+                       goto out;
+               }
+
+               vtable->create_socket = create_inet_socket;
+               vtable->setup_handle = setup_inet_handle;
+       } else {
+               /* Fallback to local scheme */
+               vtable->type = (int)SCHEME_LOCAL;
+               addr = strdup(peer);
+               if (!addr) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       goto out;
+               }
+
+               vtable->create_socket = create_unix_socket;
+               vtable->setup_handle = setup_unix_handle;
+       }
+
+out:
+       return addr;
+}
+
+EAPI int secure_socket_create_client(const char *peer)
+{
+       int port;
+       char *addr;
+       int ret;
+       struct function_table vtable;
+       struct sockaddr *sockaddr;
+       struct sockaddr_in in_addr;
+       struct sockaddr_un un_addr;
+       int handle;
+       int addrlen;
+
+       addr = parse_scheme(peer, &port, &vtable);
+       if (!addr) {
+               ErrPrint("peer: [%s] is not valid\n", peer);
+               return -EINVAL;
+       }
+
+       switch (vtable.type) {
+       case SCHEME_LOCAL:
+               sockaddr = (struct sockaddr *)&un_addr;
+               addrlen = sizeof(un_addr);
+               break;
+       case SCHEME_REMOTE:
+               sockaddr = (struct sockaddr *)&in_addr;
+               addrlen = sizeof(in_addr);
+               break;
+       default:
+               free(addr);
+               return -EINVAL;
+       }
+
+       handle = vtable.create_socket(addr, port, sockaddr);
+       free(addr);
        if (handle < 0)
                return handle;
 
-       state = connect(handle, (struct sockaddr *)&addr, sizeof(addr));
-       if (state < 0) {
+       ret = connect(handle, sockaddr, addrlen);
+       if (ret < 0) {
+               ret = -errno;
                ErrPrint("Failed to connect to server [%s] %s\n",
                                                        peer, strerror(errno));
                if (close(handle) < 0)
                        ErrPrint("close: %s\n", strerror(errno));
 
-               return -ENOTCONN;
+               return ret;
        }
 
-       if (setsockopt(handle, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
-               ErrPrint("Failed to change sock opt : %s\n", strerror(errno));
+       ret = vtable.setup_handle(handle);
+       if (ret < 0) {
                if (close(handle) < 0)
                        ErrPrint("close: %s\n", strerror(errno));
-               return -EFAULT;
-       }
-
-       if (setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0) {
-               ErrPrint("Failed to change rcvbuf size: %s\n", strerror(errno));
-       } else {
-               DbgPrint("rcvbuf: %d\n", rcvbuf);
-       }
-
-       if (setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) {
-               ErrPrint("Failed to change rcvbuf size: %s\n", strerror(errno));
-       } else {
-               DbgPrint("sndbuf: %d\n", sndbuf);
-       }
 
-       if (setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on)) < 0) {
-               ErrPrint("Failed to change rcvbuf size: %s\n", strerror(errno));
-       } else {
-               DbgPrint("TCP_NODELAY: %d\n", on);
+               return ret;
        }
 
        return handle;
@@ -121,84 +267,110 @@ EAPI int secure_socket_create_client(const char *peer)
 
 EAPI int secure_socket_create_server(const char *peer)
 {
+       int port;
+       char *addr;
        int handle;
-       int state;
-       struct sockaddr_un addr;
+       int ret;
+       struct sockaddr *sockaddr;
+       struct sockaddr_in in_addr;
+       struct sockaddr_un un_addr;
+       struct function_table vtable;
+       int addrlen;
+
+       addr = parse_scheme(peer, &port, &vtable);
+       if (!addr) {
+               ErrPrint("Failed to parse scheme\n");
+               return -EFAULT;
+       }
 
-       handle = create_socket(peer, &addr);
+       switch (vtable.type) {
+       case SCHEME_LOCAL:
+               sockaddr = (struct sockaddr *)&un_addr;
+               addrlen = sizeof(un_addr);
+               break;
+       case SCHEME_REMOTE:
+               sockaddr = (struct sockaddr *)&in_addr;
+               addrlen = sizeof(in_addr);
+               break;
+       default:
+               free(addr);
+               return -EINVAL;
+       }
+
+       handle = vtable.create_socket(addr, port, sockaddr);
+       free(addr);
        if (handle < 0)
                return handle;
 
-       state = bind(handle, &addr, sizeof(addr));
-       if (state < 0) {
-               state = -errno;
-
-               ErrPrint("Failed to bind a socket %s\n", strerror(errno));
+       ret = bind(handle, sockaddr, addrlen);
+       if (ret < 0) {
+               ret = -errno;
+               ErrPrint("bind: %s\n", strerror(errno));
                if (close(handle) < 0)
                        ErrPrint("close: %s\n", strerror(errno));
-
-               return state;
+               return ret;
        }
 
-       state = listen(handle, BACKLOG);
-       if (state < 0) {
-               state = -errno;
-               ErrPrint("Failed to listen a socket %s\n", strerror(errno));
-
+       ret = listen(handle, BACKLOG);
+       if (ret < 0) {
+               ret = -errno;
+               ErrPrint("listen: %s\n", strerror(errno));
                if (close(handle) < 0)
                        ErrPrint("close: %s\n", strerror(errno));
-
-               return state;
+               return ret;
        }
 
-       if (chmod(peer, 0666) < 0)
-               ErrPrint("Failed to change the permission of a socket (%s)\n",
-                                                       strerror(errno));
+       if (vtable.type == SCHEME_LOCAL) {
+               if (chmod(peer, 0666) < 0)
+                       ErrPrint("Failed to change the permission of a socket (%s)\n", strerror(errno));
+       }
 
        return handle;
 }
 
 EAPI int secure_socket_get_connection_handle(int server_handle)
 {
-       struct sockaddr_un addr;
+       struct sockaddr_in in_addr;
+       struct sockaddr_un un_addr;
+       struct sockaddr *addr;
        int handle;
-       int on = 1;
-       socklen_t size = sizeof(addr);
-       int sndbuf = SNDBUF_SZ;
-       int rcvbuf = RCVBUF_SZ;
+       int ret;
+       socklen_t size = sizeof(un_addr);
 
-       handle = accept(server_handle, (struct sockaddr *)&addr, &size);
-       if (handle < 0) {
-               handle = -errno;
-               ErrPrint("Failed to accept a new client %s\n", strerror(errno));
-               return handle;
+       /* Finding the largest buffer */
+       if (sizeof(in_addr) > sizeof(un_addr)) {
+               addr = (struct sockaddr *)&in_addr;
+               size = sizeof(in_addr);
+       } else {
+               addr = (struct sockaddr *)&un_addr;
+               size = sizeof(un_addr);
        }
 
-       if (setsockopt(handle, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
-               int ret;
+       handle = accept(server_handle, addr, &size);
+       if (handle < 0) {
                ret = -errno;
-               ErrPrint("Failed to change sock opt : %s\n", strerror(errno));
-               if (close(handle) < 0)
-                       ErrPrint("close: %s\n", strerror(errno));
+               ErrPrint("Failed to accept a new client %s\n", strerror(errno));
                return ret;
        }
 
-       if (setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0) {
-               ErrPrint("Failed to change rcvbuf size: %s\n", strerror(errno));
-       } else {
-               DbgPrint("rcvbuf: %d\n", rcvbuf);
-       }
+       if (addr->sa_family == AF_UNIX) {
+               ret = setup_unix_handle(handle);
+               if (ret < 0) {
+                       if (close(handle) < 0)
+                               ErrPrint("close: %s\n", strerror(errno));
 
-       if (setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) {
-               ErrPrint("Failed to change rcvbuf size: %s\n", strerror(errno));
-       } else {
-               DbgPrint("sndbuf: %d\n", sndbuf);
-       }
+                       handle = ret;
+               }
+       } else if (addr->sa_family == AF_INET) {
+               ret = setup_inet_handle(handle);
+               if (ret < 0) {
+                       if (close(handle) < 0)
+                               ErrPrint("close: %s\n", strerror(errno));
 
-       if (setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on)) < 0) {
-               ErrPrint("Failed to change rcvbuf size: %s\n", strerror(errno));
+                       handle = ret;
+               }
        } else {
-               DbgPrint("TCP_NODELAY: %d\n", on);
+               ErrPrint("Unknown address family: %d\n", addr->sa_family);
        }
 
        return handle;
@@ -241,11 +413,15 @@ EAPI int secure_socket_recv(int handle, char *buffer, int size, int *sender_pid)
        struct cmsghdr *cmsg;
        struct iovec iov;
        char control[1024];
+       int _pid;
        int ret;
 
-       if (!sender_pid || size <= 0 || !buffer)
+       if (size <= 0 || !buffer)
                return -EINVAL;
 
+       if (!sender_pid)
+               sender_pid = &_pid;
+
        memset(&msg, 0, sizeof(msg));
        iov.iov_base = buffer;
        iov.iov_len = size;
@@ -272,11 +448,12 @@ EAPI int secure_socket_recv(int handle, char *buffer, int size, int *sender_pid)
                return ret;
        }
 
+       *sender_pid = -1;       /* In case of remote socket, cannot delivery this */ 
        cmsg = CMSG_FIRSTHDR(&msg);
        while (cmsg) {
-               if (cmsg->cmsg_level == SOL_SOCKET
-                       && cmsg->cmsg_type == SCM_CREDENTIALS)  {
+               if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
                        struct ucred *cred;
+
                        cred = (struct ucred *)CMSG_DATA(cmsg);
                        *sender_pid = cred->pid;
                }
@@ -289,7 +466,6 @@ EAPI int secure_socket_recv(int handle, char *buffer, int size, int *sender_pid)
 
 EAPI int secure_socket_destroy_handle(int handle)
 {
-       DbgPrint("Close socket handle %d\n", handle);
        if (close(handle) < 0) {
                ErrPrint("close: %s\n", strerror(errno));
                return -1;