summaryrefslogtreecommitdiff
path: root/src/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/socket.c')
-rw-r--r--src/socket.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/src/socket.c b/src/socket.c
new file mode 100644
index 0000000..e6256c3
--- /dev/null
+++ b/src/socket.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Per Persson per.xb.persson@stericsson.com for
+ * ST-Ericsson.
+ * License terms: <FOSS license>.
+ */
+
+#include <unistd.h> /* Symbolic Constants */
+#include <sys/types.h> /* Primitive System Data Types */
+#include <errno.h> /* Errors */
+#include <stdarg.h>
+#include <stdio.h> /* Input/Output */
+#include <stdlib.h> /* General Utilities */
+#include <pthread.h> /* POSIX Threads */
+#include <string.h> /* String handling */
+#include <fcntl.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <utils/Log.h>
+#include "../include/hdmi_service_api.h"
+#include "../include/hdmi_service_local.h"
+
+pthread_t thread_sockclient;
+#ifdef HDMI_SERVICE_USE_CALLBACK_FN
+pthread_t thread_sockserver;
+#endif /*HDMI_SERVICE_USE_CALLBACK_FN*/
+int clientsocket = -1;
+int listensocket = -1;
+int serversocket = -1;
+int no_return_msg = -1;
+
+int listensocket_set(int sock)
+{
+ listensocket = sock;
+ return 0;
+}
+
+int listensocket_get(void)
+{
+ return listensocket;
+}
+
+static int clientsocket_set(int sock)
+{
+ clientsocket = sock;
+ return 0;
+}
+
+int clientsocket_get(void)
+{
+ return clientsocket;
+}
+
+/* Client socket thread. Handles incoming socket messages */
+static void thread_sockclient_fn(void *arg)
+{
+ int res;
+ char buffer[SOCKET_DATA_MAX];
+ struct cmd_data cmd_data;
+ int cont = 1;
+ int sock;
+
+ LOGHDMILIB("%s begin", __func__);
+
+ sock = (int)arg;
+ clientsocket_set(sock);
+ LOGHDMILIB("clisock:%d", sock);
+
+ while (cont) {
+ memset(buffer, 0, SOCKET_DATA_MAX);
+ res = read(sock, buffer, SOCKET_DATA_MAX);
+ if (res <= 0) {
+ LOGHDMILIB("clisocket closed:%d", res);
+ goto thread_sockclient_fn_end;
+ }
+
+ LOGHDMILIB("clisockread res:%d", res);
+
+ cmd_data.cmd = (__u32)buffer[0];
+ cmd_data.cmd_id = (__u32)buffer[4];
+ cmd_data.data_len = (__u32)buffer[8];
+ memcpy(cmd_data.data, &buffer[12], cmd_data.data_len);
+ cmd_data.next = NULL;
+
+ /* Add to list */
+ cmd_add(&cmd_data);
+
+ /* Signal */
+ hdmi_event(HDMIEVENT_CMD);
+
+ if (cmd_data.cmd == HDMI_EXIT)
+ cont = 0;
+ }
+
+thread_sockclient_fn_end:
+ close(sock);
+ clientsocket_set(-1);
+
+ LOGHDMILIB("%s end res:%d", __func__, res);
+ pthread_exit(NULL);
+}
+
+int clientsocket_send(__u8 *buf, int len)
+{
+ int sock;
+ int sent = -1;
+ int res = -1;
+
+ if (no_return_msg == 1)
+ return 0;
+
+ sock = clientsocket_get();
+ if (sock >= 0) {
+ sent = write(sock, buf, len);
+ LOGHDMILIB("%s written %d bytes on sock", __func__, sent);
+ }
+
+ if (sent == len)
+ res = 0;
+ return res;
+}
+
+/* Socket listen thread.
+ * Creates a listen socket.
+ * Listens for incoming connection.
+ * At connection attempt, creates a client socket in client thread.
+ */
+void thread_socklisten_fn(void *arg)
+{
+ int socknew;
+ socklen_t clilen;
+ struct sockaddr_un serv_addr;
+ struct sockaddr_un cli_addr;
+ int res;
+ fd_set descr;
+ struct timeval timeout;
+ int sockl;
+
+ LOGHDMILIB("%s begin", __func__);
+
+ /* Create listen socket */
+ sockl = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sockl < 0) {
+ LOGHDMILIB("%s", "socket create fail");
+ goto thread_socklisten_fn_end;
+ }
+ listensocket_set(sockl);
+ LOGHDMILIB2("Listen socket create:%d", sockl);
+
+ /* Remove any old path */
+ unlink(SOCKET_LISTEN_PATH);
+
+ /* Bind to path */
+ memset((char *) &serv_addr, 0, sizeof(struct sockaddr_un));
+ serv_addr.sun_family = AF_UNIX;
+ strcpy(serv_addr.sun_path, SOCKET_LISTEN_PATH);
+ res = bind(sockl, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
+ if (res < 0) {
+ LOGHDMILIB("socket bind fail:%d", res);
+ goto thread_socklisten_fn_end;
+ }
+
+ LOGHDMILIB2("Listen socket bind: %d", res);
+
+ /* while loop is breaked by shutdown on listen socket */
+ while (1) {
+ /* Listen for incoming connection */
+ listen(sockl, SOCKET_MAX_CONN);
+
+ /* Establish a client connection */
+ clilen = sizeof(cli_addr);
+ socknew = accept(sockl, (struct sockaddr *) &cli_addr, &clilen);
+ if (socknew < 0) {
+ LOGHDMILIB("socket accept fail:%d", socknew);
+ goto thread_socklisten_fn_end;
+ }
+ LOGHDMILIB2("socket accept:%d", socknew);
+
+ if (socknew >= 0)
+ /* Create a client thread */
+ pthread_create(&thread_sockclient, NULL,
+ (void *)thread_sockclient_fn, (void *)socknew);
+ }
+
+thread_socklisten_fn_end:
+ /* Remove any old path */
+ unlink(SOCKET_LISTEN_PATH);
+
+ LOGHDMILIB("%s end", __func__);
+ pthread_exit(NULL);
+}
+
+static int serversocket_set(int sock)
+{
+ serversocket = sock;
+ return 0;
+}
+
+#ifdef HDMI_SERVICE_USE_CALLBACK_FN
+/* Server socket thread. Handles outgoing socket messages */
+static void thread_sockserver_fn(void *arg)
+{
+ int res;
+ char buffer[SOCKET_DATA_MAX];
+ struct cmd_data cmd_data;
+ int cont = 1;
+ int sock;
+ cb_fn callback;
+
+ LOGHDMILIB("%s begin", __func__);
+
+ sock = (int)arg;
+
+ while (cont) {
+ memset(buffer, 0, SOCKET_DATA_MAX);
+ res = read(sock, buffer, SOCKET_DATA_MAX);
+ if (res <= 0) {
+ LOGHDMILIB("servsocket closed:%d", res);
+ goto thread_sockserver_fn_end;
+ }
+
+ LOGHDMILIB("servsockread res:%d", res);
+
+ if (cmd_data.cmd == HDMI_EXIT) {
+ cont = 0;
+ } else {
+ cmd_data.cmd = (__u32)buffer[0];
+ cmd_data.cmd_id = (__u32)buffer[4];
+ cmd_data.data_len = (__u32)buffer[8];
+ memcpy(cmd_data.data, &buffer[12], cmd_data.data_len);
+ cmd_data.next = NULL;
+
+ /* Send through callback fn */
+ callback = hdmi_service_callback_get();
+ LOGHDMILIB("callback:%p", callback);
+ if (callback)
+ callback(cmd_data.cmd, cmd_data.data_len,
+ cmd_data.data);
+ }
+ }
+
+thread_sockserver_fn_end:
+ close(sock);
+
+ LOGHDMILIB("%s end res:%d", __func__, res);
+ pthread_exit(NULL);
+}
+#endif /*HDMI_SERVICE_USE_CALLBACK_FN*/
+
+int serversocket_create(int avoid_return_msg)
+{
+ int sock;
+ int len;
+ struct sockaddr_un addr;
+ int result;
+ int n;
+
+ LOGHDMILIB("%s begin", __func__);
+
+ no_return_msg = avoid_return_msg;
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ LOGHDMILIB("sock:%d", sock);
+
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, SOCKET_LISTEN_PATH);
+ len = sizeof(addr);
+
+ n = connect(sock, (struct sockaddr *)&addr, len);
+ LOGHDMILIB("connect:%d", n);
+
+ if (n < 0) {
+ LOGHDMILIB("socket connect err:%d", n);
+ goto socket_test_end;
+ }
+
+socket_test_end:
+ LOGHDMILIB("%s end", __func__);
+ if (sock >= 0)
+ serversocket_set(sock);
+ LOGHDMILIB("servsock:%d", sock);
+
+#ifdef HDMI_SERVICE_USE_CALLBACK_FN
+ /* Create a server thread */
+ pthread_create(&thread_sockserver, NULL,
+ (void *)thread_sockserver_fn, (void *)sock);
+#endif /*HDMI_SERVICE_USE_CALLBACK_FN*/
+ return sock;
+}
+
+static int serversocket_get(void)
+{
+ return serversocket;
+}
+
+int serversocket_write(int len, __u8 *data)
+{
+ int n;
+ int sock;
+
+ sock = serversocket_get();
+ n = write(sock, data, len);
+ LOGHDMILIB("write socket len res:%d %d %d", sock, len, n);
+
+ return n;
+}
+
+int serversocket_close(void)
+{
+ int sock;
+
+ sock = serversocket_get();
+ return close(sock);
+}