tizen 2.3 release
[framework/appfw/com-core.git] / src / secure_socket.c
index 58cc898..a299b50 100644 (file)
 #define RCVBUF_SZ      524288  /*!< 512 KB, this will be doubled by kernel */
 
 enum scheme {
-       SCHEME_LOCAL = 0x00,
-       SCHEME_REMOTE = 0x01,
-       SCHEME_UNKNOWN = 0x02,
+    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 type;
+    int (*create_socket)(const char *peer, int port, struct sockaddr *addr);
+    int (*setup_handle)(int handle);
 };
 
 int errno;
 
 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(*un_addr);
-       bzero(un_addr, len);
-
-       if (strlen(peer) >= sizeof(un_addr->sun_path)) {
-               ErrPrint("peer %s is too long to remember it\\n", peer);
-               return -1;
-       }
-
-       /* We can believe this has no prob, because
-        * we already check the size of add.rsun_path
-        */
-       strcpy(un_addr->sun_path, peer);
-       un_addr->sun_family = AF_UNIX;
-
-       handle = socket(PF_UNIX, SOCK_STREAM, 0);
-       if (handle < 0) {
-               ErrPrint("Failed to create a socket %s\n", strerror(errno));
-               return -1;
-       }
-
-       return handle;
+    int len;
+    int handle;
+    struct sockaddr_un *un_addr = (struct sockaddr_un *)addr;
+
+    len = sizeof(*un_addr);
+    bzero(un_addr, len);
+
+    if (strlen(peer) >= sizeof(un_addr->sun_path)) {
+       ErrPrint("peer %s is too long to remember it\\n", peer);
+       return -1;
+    }
+
+    /* We can believe this has no prob, because
+     * we already check the size of add.rsun_path
+     */
+    strcpy(un_addr->sun_path, peer);
+    un_addr->sun_family = AF_UNIX;
+
+    handle = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (handle < 0) {
+       handle = -errno;
+       ErrPrint("Failed to create a socket %s\n", strerror(errno));
+    }
+
+    return handle;
 }
 
 static inline int create_inet_socket(const char *peer, int port, struct sockaddr *addr)
 {
-       int handle;
-       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;
+    int handle;
+    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 create_systemd_socket(const char *peer, int port, struct sockaddr *addr)
 {
-       int handle = -1;
-       int cnt;
-
-       cnt = sd_listen_fds(0);
-       if (cnt > 1) {
-               ErrPrint("To many file descriptors are received on socket activation: %d\n", cnt);
-       } else if (cnt == 1) {
-               handle = SD_LISTEN_FDS_START + 0;
-       } else {
-               handle = create_inet_socket(peer, port, addr);
-       }
-
-       return handle;
+    int handle = -1;
+    int cnt;
+
+    cnt = sd_listen_fds(0);
+    if (cnt > 1) {
+       ErrPrint("To many file descriptors are received on socket activation: %d\n", cnt);
+    } else if (cnt == 1) {
+       handle = SD_LISTEN_FDS_START + 0;
+    } else {
+       handle = create_inet_socket(peer, port, addr);
+    }
+
+    return handle;
 }
 
 static inline int setup_unix_handle(int handle)
 {
-       int on = 1;
-       int sndbuf = SNDBUF_SZ;
-       int rcvbuf = RCVBUF_SZ;
-
-       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;
-       }
+    int on = 1;
+    int sndbuf = SNDBUF_SZ;
+    int rcvbuf = RCVBUF_SZ;
 
-       (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));
+    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;
+    }
 
-       return 0;
+    (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;
+    int on = 1;
 
-       (void)setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on));
+    (void)setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on));
 
-       return 0;
+    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_SD_LOCAL_SCHEME, COM_CORE_SD_LOCAL_SCHEME_LEN)) {
-               vtable->type = (int)SCHEME_LOCAL;
-               peer += COM_CORE_SD_LOCAL_SCHEME_LEN;
-
-               addr = strdup(peer);
-               if (!addr) {
-                       ErrPrint("Heap: %s\n", strerror(errno));
-               }
-
-               vtable->create_socket = create_systemd_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;
-       }
+    int _port;
+    char *addr = NULL;
 
-out:
-       return addr;
-}
+    if (!port)
+       port = &_port;
 
-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);
+    *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("peer: [%s] is not valid\n", peer);
-               return -EINVAL;
+           ErrPrint("Heap: %s\n", strerror(errno));
        }
 
-       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;
-       }
+       vtable->create_socket = create_unix_socket;
+       vtable->setup_handle = setup_unix_handle;
+    } else if (!strncasecmp(peer, COM_CORE_SD_LOCAL_SCHEME, COM_CORE_SD_LOCAL_SCHEME_LEN)) {
+       vtable->type = (int)SCHEME_LOCAL;
+       peer += COM_CORE_SD_LOCAL_SCHEME_LEN;
 
-       handle = vtable.create_socket(addr, port, sockaddr);
-       free(addr);
-       if (handle < 0) {
-               return handle;
+       addr = strdup(peer);
+       if (!addr) {
+           ErrPrint("Heap: %s\n", strerror(errno));
        }
 
-       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 ret;
+       vtable->create_socket = create_systemd_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;
        }
 
-       ret = vtable.setup_handle(handle);
-       if (ret < 0) {
-               if (close(handle) < 0) {
-                       ErrPrint("close: %s\n", strerror(errno));
-               }
+       addr = malloc(len + 1);
+       if (!addr) {
+           ErrPrint("Heap: %s\n", strerror(errno));
+           goto out;
+       }
 
-               return ret;
+       if (len > 0) {
+           strncpy(addr, peer, len);
        }
 
-       return handle;
-}
+       addr[len] = '\0';
 
-EAPI int secure_socket_create_server(const char *peer)
-{
-       int port;
-       char *addr;
-       int handle;
-       int ret;
-       struct sockaddr *sockaddr;
-       struct sockaddr_in in_addr;
-       struct sockaddr_un un_addr;
-       struct function_table vtable;
-       int addrlen;
+       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;
+       }
 
-       addr = parse_scheme(peer, &port, &vtable);
+       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("Failed to parse scheme\n");
-               return -EFAULT;
+           ErrPrint("Heap: %s\n", strerror(errno));
+           goto out;
        }
 
-       switch (vtable.type) {
+       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;
+           sockaddr = (struct sockaddr *)&un_addr;
+           addrlen = sizeof(un_addr);
+           break;
        case SCHEME_REMOTE:
-               sockaddr = (struct sockaddr *)&in_addr;
-               addrlen = sizeof(in_addr);
-               break;
+           sockaddr = (struct sockaddr *)&in_addr;
+           addrlen = sizeof(in_addr);
+           break;
        default:
-               free(addr);
-               return -EINVAL;
-       }
+           free(addr);
+           return -EINVAL;
+    }
 
-       handle = vtable.create_socket(addr, port, sockaddr);
-       free(addr);
-       if (handle < 0) {
-               return handle;
-       }
+    handle = vtable.create_socket(addr, port, sockaddr);
+    free(addr);
+    if (handle < 0) {
+       return handle;
+    }
 
-       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 ret;
+    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));
        }
 
-       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 ret;
-       }
+       return ret;
+    }
 
-       if (vtable.type == SCHEME_LOCAL) {
-               if (chmod(peer, 0666) < 0) {
-                       ErrPrint("Failed to change the permission of a socket (%s)\n", strerror(errno));
-               }
+    ret = vtable.setup_handle(handle);
+    if (ret < 0) {
+       if (close(handle) < 0) {
+           ErrPrint("close: %s\n", strerror(errno));
        }
 
-       return handle;
+       return ret;
+    }
+
+    return handle;
 }
 
-EAPI int secure_socket_get_connection_handle(int server_handle)
+EAPI int secure_socket_create_server(const char *peer)
 {
-       struct sockaddr_in in_addr;
-       struct sockaddr_un un_addr;
-       struct sockaddr *addr;
-       int handle;
-       int ret;
-       socklen_t size = sizeof(un_addr);
-
-       /* 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);
+    int port;
+    char *addr;
+    int handle;
+    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 -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;
+    }
+
+    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 ret;
+    }
 
-       handle = accept(server_handle, addr, &size);
-       if (handle < 0) {
-               ret = -errno;
-               ErrPrint("Failed to accept a new client %s\n", strerror(errno));
-               return ret;
+    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 ret;
+    }
 
-       if (addr->sa_family == AF_UNIX) {
-               ret = setup_unix_handle(handle);
-               if (ret < 0) {
-                       if (close(handle) < 0) {
-                               ErrPrint("close: %s\n", strerror(errno));
-                       }
-
-                       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));
-                       }
-
-                       handle = ret;
-               }
-       } else {
-               ErrPrint("Unknown address family: %d\n", addr->sa_family);
+    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;
+    return handle;
 }
 
-EAPI int secure_socket_send(int handle, const char *buffer, int size)
+EAPI int secure_socket_get_connection_handle(int server_handle)
 {
-       struct msghdr msg;
-       struct iovec iov;
-       int ret;
+    struct sockaddr_in in_addr;
+    struct sockaddr_un un_addr;
+    struct sockaddr *addr;
+    int handle;
+    int ret;
+    socklen_t size = sizeof(un_addr);
+
+    /* 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);
+    }
+
+    handle = accept(server_handle, addr, &size);
+    if (handle < 0) {
+       ret = -errno;
+       ErrPrint("Failed to accept a new client %s\n", strerror(errno));
+       return ret;
+    }
+
+    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 (!buffer || size <= 0) {
-               ErrPrint("Reject: 0 byte data sending\n");
-               return -EINVAL;
+           handle = ret;
        }
-
-       memset(&msg, 0, sizeof(msg));
-       iov.iov_base = (char *)buffer;
-       iov.iov_len = size;
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-
-       ret = sendmsg(handle, &msg, 0);
+    } else if (addr->sa_family == AF_INET) {
+       ret = setup_inet_handle(handle);
        if (ret < 0) {
-               ret = -errno;
-               if (errno == EAGAIN || errno == EWOULDBLOCK) {
-                       ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno));
-                       return -EAGAIN;
-               }
-               ErrPrint("Failed to send message [%s]\n", strerror(errno));
-               return ret;
+           if (close(handle) < 0) {
+               ErrPrint("close: %s\n", strerror(errno));
+           }
+
+           handle = ret;
        }
+    } else {
+       ErrPrint("Unknown address family: %d\n", addr->sa_family);
+    }
 
-       return iov.iov_len;
+    return handle;
 }
 
-EAPI int secure_socket_recv(int handle, char *buffer, int size, int *sender_pid)
+EAPI int secure_socket_send_with_fd(int handle, const char *buffer, int size, int fd)
 {
-       struct msghdr msg;
+    struct msghdr msg;
+    struct iovec iov;
+    union {
+       struct cmsghdr hdr;
+       char control[CMSG_SPACE(sizeof(int))];
+    } cmsgu;
+    int ret;
+
+    if (!buffer || size <= 0) {
+       ErrPrint("Reject: 0 byte data sending\n");
+       return -EINVAL;
+    }
+
+    memset(&msg, 0, sizeof(msg));
+    iov.iov_base = (char *)buffer;
+    iov.iov_len = size;
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+
+    if (fd >= 0) {
        struct cmsghdr *cmsg;
-       struct iovec iov;
-       char control[1024];
-       int _pid;
-       int ret;
+       int *cdata;
 
-       if (size <= 0 || !buffer) {
-               return -EINVAL;
-       }
+       msg.msg_control = cmsgu.control;
+       msg.msg_controllen = sizeof(cmsgu.control);
 
-       if (!sender_pid) {
-               sender_pid = &_pid;
+       cmsg = CMSG_FIRSTHDR(&msg);
+       cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_RIGHTS;
+       cdata = (int *)CMSG_DATA(cmsg);
+       *cdata = fd;
+    }
+
+    ret = sendmsg(handle, &msg, 0);
+    if (ret < 0) {
+       ret = -errno;
+       if (errno == EAGAIN || errno == EWOULDBLOCK) {
+           ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno));
+           return -EAGAIN;
        }
+       ErrPrint("Failed to send message [%s]\n", strerror(errno));
+       return ret;
+    }
 
-       memset(&msg, 0, sizeof(msg));
-       iov.iov_base = buffer;
-       iov.iov_len = size;
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-       msg.msg_control = control;
-       msg.msg_controllen = sizeof(control);
-
-       ret = recvmsg(handle, &msg, 0);
-       if (ret == 0) {
-               /*!< Disconnected */
-               DbgPrint("Disconnected\n");
-               return 0;
-       }
+    return iov.iov_len;
+}
 
-       if (ret < 0) {
-               ret = -errno;
-               if (errno == EAGAIN || errno == EWOULDBLOCK) {
-                       ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno));
-                       return -EAGAIN;
-               }
-
-               ErrPrint("Failed to recvmsg [%s]\n", strerror(errno));
-               return ret;
-       }
+EAPI int secure_socket_send(int handle, const char *buffer, int size)
+{
+    return secure_socket_send_with_fd(handle, buffer, size, -1);
+}
 
-       *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) {
-                       struct ucred *cred;
+EAPI int secure_socket_recv_with_fd(int handle, char *buffer, int size, int *sender_pid, int *fd)
+{
+    struct msghdr msg;
+    struct cmsghdr *cmsg;
+    struct iovec iov;
+    char control[1024];
+    int _pid;
+    int ret;
+
+    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;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = control;
+    msg.msg_controllen = sizeof(control);
+
+    ret = recvmsg(handle, &msg, 0);
+    if (ret == 0) {
+       /*!< Disconnected */
+       DbgPrint("Disconnected\n");
+       return 0;
+    }
 
-                       cred = (struct ucred *)CMSG_DATA(cmsg);
-                       *sender_pid = cred->pid;
-               }
+    if (ret < 0) {
+       ret = -errno;
+       if (errno == EAGAIN || errno == EWOULDBLOCK) {
+           ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno));
+           return -EAGAIN;
+       }
 
-               cmsg = CMSG_NXTHDR(&msg, cmsg);
+       ErrPrint("Failed to recvmsg [%s]\n", strerror(errno));
+       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) {
+           struct ucred *cred;
+
+           cred = (struct ucred *)CMSG_DATA(cmsg);
+           *sender_pid = cred->pid;
+       } else if (fd && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+           int *cdata;
+           cdata = (int *)CMSG_DATA(cmsg);
+           *fd = *cdata;
        }
 
-       return iov.iov_len;
+       cmsg = CMSG_NXTHDR(&msg, cmsg);
+    }
+
+    return iov.iov_len;
+}
+
+EAPI int secure_socket_recv(int handle, char *buffer, int size, int *sender_pid)
+{
+    return secure_socket_recv_with_fd(handle, buffer, size, sender_pid, NULL);
 }
 
 EAPI int secure_socket_destroy_handle(int handle)
 {
-       if (close(handle) < 0) {
-               ErrPrint("close: %s\n", strerror(errno));
-               return -1;
-       }
-       return 0;
+    if (close(handle) < 0) {
+       int ret;
+       ret = -errno;
+       ErrPrint("close: %s\n", strerror(errno));
+       return ret;
+    }
+
+    return 0;
 }
 
 #undef _GNU_SOURCE