ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/lte-telephony/apps/diag/command_api.c b/marvell/lte-telephony/apps/diag/command_api.c
new file mode 100644
index 0000000..3a541fe
--- /dev/null
+++ b/marvell/lte-telephony/apps/diag/command_api.c
@@ -0,0 +1,380 @@
+/******************************************************************************
+*(C) Copyright 2011 Marvell International Ltd.
+* All Rights Reserved
+******************************************************************************/
+/*--------------------------------------------------------------------------------------------------------------------
+ *  -------------------------------------------------------------------------------------------------------------------
+ *
+ *  Filename: command_api.c
+ *
+ *  Description: The APIs to remotely control DIAG internal behaviors.
+ *
+ *  History:
+ *    Aug, 13 2012 - Haili Wang(hlw@marvell.com) Creation of file
+ *
+ *  Notes:
+ *
+ ******************************************************************************/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#ifdef ANDROID
+#include <cutils/sockets.h>
+#endif
+
+#include "utlEventHandler.h"
+#include "media_manager.h"
+#include "diag_state_machine.h"
+#include "sd_api.h"
+#include "pxa_dbg.h"
+#include "diag_al.h"
+#include "diag_api.h"
+
+static const char response_error[] = "ERROR";
+static const char response_invalid[] = "INVALID";
+static const char response_success[] = "SUCCESS";
+
+static int cmdfd = -1;
+static utlEventHandlerId_T cmdHandler;
+
+
+struct command_client{
+	int fd;
+	utlEventHandlerId_T handle_id;
+};
+
+#define MAX_CLIENT_NUMBER 10
+static struct command_client clients[MAX_CLIENT_NUMBER];
+
+#ifdef ANDROID
+#define DIAG_CMD_SOCKET "diagcmd"
+#else
+#define DIAG_CMD_SOCKET "/tmp/diagcmd"
+#endif
+
+static void init_clients(void)
+{
+	int i;
+	for(i = 0; i < MAX_CLIENT_NUMBER; i ++)
+	{
+		clients[i].fd = -1;
+		clients[i].handle_id = 0;
+	}
+}
+
+static int client_id_is_valid(int id)
+{
+	if((id >= 0) && (id < MAX_CLIENT_NUMBER))
+		return 1;
+	else
+		return 0;
+}
+
+static void close_client(int i)
+{
+	if(client_id_is_valid(i))
+	{
+		if(clients[i].handle_id > 0)
+			utlDeleteEventHandler(clients[i].handle_id);
+		if(clients[i].fd > 0)
+			close(clients[i].fd);
+		clients[i].handle_id = 0;
+		clients[i].fd = -1;
+	}
+}
+
+static void close_clients(void)
+{
+	int i;
+	for(i = 0; i < MAX_CLIENT_NUMBER; i ++)
+	{
+		close_client(i);
+	}
+}
+
+static int get_free_client_id(void)
+{
+	int i;
+	for(i = 0; i < MAX_CLIENT_NUMBER; i ++)
+	{
+		if(clients[i].fd == -1)
+			return i;
+	}
+	return -1;
+}
+
+static int get_client_id_by_fd(int fd)
+{
+	int i;
+	if(fd < 0)
+		return -1;
+	for(i = 0; i < MAX_CLIENT_NUMBER; i ++)
+	{
+		if(clients[i].fd == fd)
+		{
+			return i;
+		}
+	}
+	return -1;
+}
+
+static int sendReply(int fd, const char* cmd, const char* arg)
+{
+	char buf[128];
+	int len;
+
+	strncpy(buf, cmd, sizeof(buf) - 1);
+	if(arg)
+	{
+		len = strlen(cmd) + 1;
+		buf[len - 1] = ' ';
+		strncpy(buf + len, arg , sizeof(buf) - len - 1);
+	}
+
+	return send(fd, buf, strlen(buf) + 1, MSG_NOSIGNAL);
+}
+
+static void parseCommand(char* cmd, int client_id)
+{
+	char* command, *arg;
+	const char *reply = response_invalid, *reply_arg = NULL;
+	char media_list[32];
+	int ret;
+
+	arg = strchr(cmd, ' ');
+	if(arg != NULL)
+		*arg++ = '\0';
+	else
+		arg = "";
+	command = cmd;
+	DBGMSG("command:%s, arg:%s\n", command, arg);
+	if(strcasecmp(command,"start") == 0)
+	{
+		ret = getMediaByName(arg);
+		if(ret >= 0)
+		{
+			if(startMediaMachine(ret) == 0)
+				reply = response_success;
+			else
+				reply = response_error;
+		}
+	}
+	else if(strcasecmp(command,"folder") == 0)
+	{
+#if CONFIG_DIAG_ALL
+		if(switchSDFolder(arg) == 0)
+			reply = response_success;
+		else
+			reply = response_error;
+#endif
+	}
+	else if(strcasecmp(command,"switch") == 0)
+	{
+		ret = getMediaByName(arg);
+		if(ret >= 0)
+		{
+			if(switchMediaMachine(ret) == 0)
+				reply = response_success;
+			else
+				reply = response_error;
+		}
+	}
+	else if (strcasecmp(command,"stop") == 0)
+	{
+		ret = getMediaByName(arg);
+		if(ret >= 0)
+		{
+			if(stopMediaMachine(ret) == 0)
+				reply = response_success;
+			else
+				reply = response_error;
+		}
+	}
+	else if(strcasecmp(command,"dump") == 0)
+	{
+		if(dumpCPBuffer(arg) == 0)
+			reply = response_success;
+		else
+			reply = response_error;
+	}
+	else if(strcasecmp(command, "print") == 0)
+	{
+		if(strcasecmp(arg, "active") == 0)
+		{
+			if(getActiveMedia(media_list))
+				reply_arg = media_list;
+			reply = response_success;
+		}
+		else if(strcasecmp(arg, "status") == 0)
+		{
+			dumpMediaMachine();
+			reply = response_success;
+		}
+	}
+	else if(strcasecmp(command,"exit") == 0)
+	{
+		stopAllMediaMachine();
+		(void)sendReply(clients[client_id].fd, response_success, NULL);
+		sleep(3); // wait for CP to disconnect
+		exit(0);
+	}
+
+	(void)sendReply(clients[client_id].fd, reply, reply_arg);
+}
+
+static utlReturnCode_T ReceiveDataFromUtility(const utlEventHandlerType_T handler_type UNUSED,
+			      const utlEventHandlerType_T event_type UNUSED,
+			      const int fd,
+			      const utlRelativeTime_P2c period_p UNUSED,
+			      void                  *arg_p UNUSED)
+{
+	int received, offset, client_id;
+	char* current;
+	char cmdBuffer[512];
+
+	client_id = get_client_id_by_fd(fd);
+	if(client_id < 0)
+		return utlFAILED;
+
+	received = recv (fd, &cmdBuffer, sizeof(cmdBuffer), 0);
+
+	if(received == 0)
+	{
+		DBGMSG("***** DIAG Command Client %d Connection closed by peer *****\r\n", client_id);
+		close_client(client_id);
+		return utlSUCCESS;
+	}
+
+	else if(received < 0)
+	{
+		DBGMSG("***** DIAG Command Client %d Read failed:%s. *****\r\n", client_id, strerror(errno));
+		close_client(client_id);
+		return utlSUCCESS;
+	}
+
+	DBGMSG("Receive Diag Command from Client(%d) %d bytes!",client_id,received);
+	current = cmdBuffer;
+	for(offset = 0; received != 0; --received)
+	{
+		/* Each cmd message is terminated by '\0' */
+		if( current[offset] == '\0')
+		{//coverity[path_manipulation_sink:SUPPRESS]
+			parseCommand(current, client_id);
+			current += offset + 1;
+			offset = 0;
+		}
+		else ++offset;
+	}
+	if(offset != 0)  //number of bytes left
+	{
+		ERRMSG("Fragmented packet received from DIAG command socket");
+	}
+	return utlSUCCESS;
+}
+
+
+static int acceptCmdPort(const utlEventHandlerType_T handler_type UNUSED,
+	      const utlEventHandlerType_T event_type UNUSED,
+	      const int fd UNUSED,
+	      const utlRelativeTime_P2c period_p UNUSED,
+	      void                  *arg_p UNUSED)
+{
+	int ret;
+	int flags;
+	int client_id;
+
+	ret = accept(cmdfd, NULL, NULL);
+	if( ret < 0)
+	{
+		ERRMSG("***** DIAG Command Port: accept control socket Error: %s *****\r\n",strerror(errno));
+		return utlFAILED;
+	}
+	else
+	{
+		flags = fcntl(ret,F_GETFL, 0);
+		(void)fcntl(ret,F_SETFL, flags | O_NONBLOCK);
+		client_id = get_free_client_id();
+		DBGMSG("Accept Diag Command Client:%d!",client_id);
+		if(client_id_is_valid(client_id))
+		{
+			clients[client_id].fd = ret;
+			clients[client_id].handle_id = utlSetFdEventHandler(utlEVENT_HANDLER_TYPE_READ, utlEVENT_HANDLER_PRIORITY_LOW, ret, ReceiveDataFromUtility, NULL);
+		}
+		else
+		{
+			DBGMSG("Diag Command Clients reach max number! Connection will be closed");
+			close(ret);
+		}
+	}
+	return utlSUCCESS;
+}
+
+int openCmdPort(void)
+{
+	int len;
+	struct sockaddr_un socket_name;
+	init_clients();
+	socket_name.sun_family = AF_UNIX;
+#ifdef ANDROID
+	cmdfd = android_get_control_socket(DIAG_CMD_SOCKET);
+	if (cmdfd < 0 )
+	{
+		ERRMSG("***** DIAG Command Port: control socket Error: %s *****\r\n",strerror(errno));
+		return -1;
+	}
+#else
+	if (strlen(DIAG_CMD_SOCKET) < sizeof(socket_name.sun_path))
+		strcpy (socket_name.sun_path, DIAG_CMD_SOCKET);
+	else
+	{
+		/* socket path is TOO big for the socket name */
+		ERRMSG("socket path is TOO big for the socket name\n");
+		return -1;
+	}
+
+	cmdfd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if ( cmdfd < 0 )
+	{
+		ERRMSG("***** DIAG Command Port: control socket Error: %s *****\r\n",strerror(errno));
+		return -1;
+	}
+
+	/* unlink to make sure the bind operation won't fail */
+	unlink(DIAG_CMD_SOCKET);
+
+	/* calculate length */
+	len = sizeof(socket_name.sun_family) + strlen(socket_name.sun_path);
+	if ( bind(cmdfd, (const struct sockaddr*) &socket_name, len) < 0 )
+	{
+		ERRMSG("***** DIAG Command Port: bind control socket Error: %s *****\r\n",strerror(errno));
+		close(cmdfd);
+		return -1;
+	}
+	(void)chmod(socket_name.sun_path, 0660);
+#endif
+
+	if( listen(cmdfd, MAX_CLIENT_NUMBER) < 0)
+	{
+		ERRMSG("***** DIAG Command Port: listen control socket Error: %s *****\r\n",strerror(errno));
+		close(cmdfd);
+		return -1;
+	}
+
+	cmdHandler = utlSetFdEventHandler(utlEVENT_HANDLER_TYPE_READ, utlEVENT_HANDLER_PRIORITY_LOW, cmdfd, acceptCmdPort, NULL);
+	return 0;
+}
+
+
+void closeCmdPort(void)
+{
+	utlDeleteEventHandler(cmdHandler);
+	close(cmdfd);
+	close_clients();
+	cmdfd = -1;
+}
+