wigig: Adding debug tools
Adding the debug tools package for 11ad
Change-Id: I171d7534614ec8941e0b48bb01d757ccd3be8960
Signed-off-by: Vadim Iosevich <vadimi@codeaurora.org>
diff --git a/debug-tools/remoteserver/Android.mk b/debug-tools/remoteserver/Android.mk
new file mode 100644
index 0000000..9a215a8
--- /dev/null
+++ b/debug-tools/remoteserver/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := wigig_remoteserver
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CPPFLAGS := -Wall -lpthread -fexceptions
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../lib/WlctPciAcss \
+ $(LOCAL_PATH)/../lib/inc \
+ $(LOCAL_PATH)/../lib/utils
+
+LOCAL_SHARED_LIBRARIES := \
+ libwigig_utils \
+ libwigig_pciaccess
+
+LOCAL_SRC_FILES := $(shell find $(LOCAL_PATH) -name '*.cpp' | sed s:^$(LOCAL_PATH)::g )
+LOCAL_SRC_FILES += parser.l
+
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/debug-tools/remoteserver/Makefile b/debug-tools/remoteserver/Makefile
new file mode 100644
index 0000000..e9bef43
--- /dev/null
+++ b/debug-tools/remoteserver/Makefile
@@ -0,0 +1,62 @@
+-include $(TOPDIR)/rules.mk
+
+CFLAGS := -fPIE -Wall -g -MMD -Wno-unused-function
+LDFLAGS := -pie -fPIE -pthread -lwigig_pciaccess -lwigig_utils
+
+ifneq ($(CONFIG_TARGET_ipq)$(CONFIG_TARGET_ipq806x),)
+is_ipq806x = 1
+endif
+
+ifeq ($(is_ipq806x), 1)
+ifneq ($(strip $(TOOLPREFIX)),)
+CROSS:=$(TOOLPREFIX)
+endif
+endif
+
+CC := $(CROSS)gcc
+CXX := $(CROSS)g++
+
+.DEFAULT_GOAL = all
+PROG = wigig_remoteserver
+
+INCLUDES = -I ../lib/WlctPciAcss \
+ -I ../lib/inc \
+ -I ../lib/utils \
+
+LIBS = -L../lib/WlctPciAcss \
+ -L../lib/utils \
+
+all: $(PROG)
+
+CPP_FILES = $(shell find . -type f -name '*.cpp')
+C_FILES = $(shell find . -type f -name '*.c')
+LEX_FILES = $(shell find . -type f -name '*.l')
+
+
+GENERATED_C_FILES=$(LEX_FILES:.l=.c)
+OBJ_FILES= $(CPP_FILES:.cpp=.o)
+OBJ_FILES += $(C_FILES:.c=.o)
+OBJ_FILES += $(GENERATED_C_FILES:.c=.o)
+
+.PRECIOUS: $(GENERATED_C_FILES)
+
+$(PROG): $(OBJ_FILES)
+ $(CXX) -o $@ $^ $(LIBS) $(LDFLAGS)
+
+%.o : %.c
+ $(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $<
+
+%.o : %.cpp
+ $(CXX) $(CFLAGS) $(INCLUDES) -o $@ -c $<
+
+%.c : %.l
+ flex -o $@ $<
+
+
+
+clean:
+ rm -rf $(PROG) $(GENERATED_C_FILES)
+ find . -type f \( -name "*.d" -o -name "*.o" \) -delete
+
+
+-include $(OBJ_FILES:%.o=%.d)
diff --git a/debug-tools/remoteserver/cmdiface.cpp b/debug-tools/remoteserver/cmdiface.cpp
new file mode 100644
index 0000000..9c03471
--- /dev/null
+++ b/debug-tools/remoteserver/cmdiface.cpp
@@ -0,0 +1,645 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sstream>
+#include <iostream>
+#include <fstream>
+
+#include "cmdiface.h"
+#include "parser.h"
+#include "debug.h"
+#include "WlctPciAcss.h"
+#include "pmc_file.h"
+#include "udp_server.h"
+
+
+struct open_interface_s *CmdIface::open_interfaces = NULL;
+pthread_mutex_t CmdIface::open_interfaces_mutex = PTHREAD_MUTEX_INITIALIZER;
+int CmdIface::interface_id = 0;
+
+/*
+*/
+void *CmdIface::get_interface(const char *name)
+{
+ struct open_interface_s *s = open_interfaces;
+ LOG_DEBUG << "Looking for interface: " << name << std::endl;
+
+ while(s != NULL)
+ {
+ LOG_VERBOSE << "Checking interface for match: " << s->interface << std::endl;
+ if(0 == strncasecmp(name, s->interface, MAX_INTERFACE_NAME))
+ {
+ LOG_VERBOSE << "Match found" << std::endl;
+ return s->handler;
+ }
+ s = s->next;
+ }
+
+ return NULL;
+}
+
+/*
+*/
+void *CmdIface::add_interface(const char *name, void *handler)
+{
+ LOG_DEBUG << "Adding interface: " << name << std::endl;
+
+ void *h = get_interface(name);
+ if(h != NULL)
+ {
+ LOG_DEBUG << "The interface is already open" << std::endl;
+ return h; // Interface already opened
+ }
+
+ // Add interface to the list
+ struct open_interface_s *s = new struct open_interface_s;
+ if(s == NULL)
+ {
+ return NULL;
+ }
+
+ snprintf(s->interface, MAX_INTERFACE_NAME, "%s", name);
+ s->handler = handler;
+ pthread_mutex_lock(&open_interfaces_mutex);
+ s->next = open_interfaces;
+ open_interfaces = s;
+ pthread_mutex_unlock(&open_interfaces_mutex);
+
+ return handler;
+}
+
+/*
+*/
+void CmdIface::del_interface(void *handler)
+{
+ LOG_DEBUG << "Deleting interfaces by handler" << std::endl;
+
+ struct open_interface_s *s = open_interfaces;
+ struct open_interface_s *prev = NULL;
+
+ while(s != NULL) {
+ if(handler == s->handler) {
+ // Remove the interface from the list
+ pthread_mutex_lock(&open_interfaces_mutex);
+ if(prev != NULL)
+ prev->next = s->next;
+ else
+ open_interfaces = s->next;
+ pthread_mutex_unlock(&open_interfaces_mutex);
+ delete s;
+ }
+ prev = s;
+ s = s->next;
+ }
+}
+
+/*
+*/
+int CmdIface::cmd_get_interfaces()
+{
+ INTERFACE_LIST interfaces;
+ int num_interfaces;
+ int rc;
+
+ LOG_DEBUG << "Getting active WIGIG card interfaces" << std::endl;
+
+ rc = GetInterfaces(&interfaces, &num_interfaces);
+ LOG_DEBUG << "Found " << num_interfaces << " interfaces" << std::endl;
+
+ std::ostringstream replyBuilder;
+
+ if(rc == 0)
+ {
+ for(int i=0; i < num_interfaces; i++)
+ {
+ replyBuilder << interfaces.list[i].ifName << ' ';
+ }
+ }
+
+ replyBuilder << "\r\n";
+ m_Reply = replyBuilder.str();
+
+ return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_open_interface(char *interface)
+{
+ void *handler = NULL;
+ int rc=0;
+
+ LOG_DEBUG << "Opening an interface: " << interface << std::endl;
+
+ if( strstr(interface, "SPARROW")|| strstr(interface, "sparrow")){
+ rc = CreateDeviceAccessHandler(interface, MST_SPARROW, &handler);
+ }
+ else if(strstr(interface, "MARLON") || strstr(interface, "marlon")){
+ rc = CreateDeviceAccessHandler(interface, MST_MARLON, &handler);
+ }
+ else{
+ m_Reply = "0xDEAD\r\n";
+ }
+ if(rc != 0)
+ m_Reply = "0xDEADDEAD\r\n";
+ else {
+
+ std::ostringstream replyBuilder;
+
+ replyBuilder << interface << '_' << interface_id;
+ add_interface(replyBuilder.str().c_str(), handler);
+ replyBuilder << "\r\n";
+ m_Reply = replyBuilder.str();
+ interface_id++; // TODO: Should be protected by a mutex? I didn't see it's being used in the application
+ }
+ return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_close_interface(char *interface)
+{
+ LOG_DEBUG << "Closing interface: " << interface << std::endl;
+
+ void *handler = get_interface(interface);
+
+ if(handler != NULL)
+ {
+ del_interface(handler);
+ interface_id--;
+ }
+ else
+ {
+ LOG_WARNING << "Interface " << interface << " wasn't opened" << std::endl;
+ }
+
+ m_Reply = "0\r\n";
+ return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_r(char *interface, unsigned int address)
+{
+ unsigned int val = 0xDEADDEAD;
+ void *handler = get_interface(interface);
+
+ std::ostringstream replyBuilder;
+ if(handler == NULL)
+ {
+ m_Reply = "0xDEADDEAD";
+ }
+ else
+ {
+ int rc = WlctAccssRead(handler, address, val);
+ (void)rc;
+ replyBuilder << val;
+ }
+
+ replyBuilder << "\r\n";
+ m_Reply = replyBuilder.str();
+
+ return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_w(char *interface, unsigned int address, unsigned int data)
+{
+ int rc;
+ void *handler = get_interface(interface);
+
+ std::ostringstream replyBuilder;
+
+ if(handler == NULL)
+ {
+ replyBuilder << "0xDEADDEAD";
+ }
+ else
+ {
+ rc = WlctAccssWrite(handler, address, data);
+ if(rc == 0)
+ replyBuilder << "0";
+ else
+ replyBuilder << "ERROR";
+ }
+
+ replyBuilder << "\r\n";
+ m_Reply = replyBuilder.str();
+
+ return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_alloc_pmc(char *interface, unsigned int desc_size, unsigned int desc_num)
+{
+ int rc;
+ LOG_DEBUG << "Allocating PMC descriptors:"
+ << " interface = " << interface
+ << " size = " << desc_size
+ << " number = " << desc_num
+ << std::endl;
+
+ std::ostringstream replyBuilder;
+
+ void *handler = get_interface(interface);
+ if(handler == NULL)
+ {
+ LOG_DEBUG << "Cannot get handler for interface " << interface << std::endl;
+ replyBuilder << "0xDEADDEAD";
+ }
+ else
+ {
+ rc = WlctAccssAllocPmc(handler, desc_size, desc_num);
+
+ if(rc == 0)
+ {
+ LOG_DEBUG << "Successfully allocated PMC descriptors" << std::endl;
+ replyBuilder << "0";
+ }
+ else
+ {
+ LOG_ERROR << "Error allocating PMC descriptors" << std::endl;
+ replyBuilder << "ERROR";
+ }
+ }
+
+ replyBuilder << "\r\n";
+ m_Reply = replyBuilder.str();
+
+ return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_read_pmc(char *interface, unsigned int ref_number)
+{
+ LOG_DEBUG << "Reading PMC data:"
+ << " interface = " << interface
+ << " reference number = " << ref_number
+ << std::endl;
+
+ void *handler = get_interface(interface);
+
+ if(handler == NULL)
+ {
+ LOG_ERROR << "No interface found: " << interface << std::endl;
+ m_Reply = "0xDEADDEAD\r\n";
+ return 0;
+ }
+
+ PmcFile pmcFile(ref_number);
+ PmcFileWriter pmcFileWriter(pmcFile);
+ bool status = pmcFileWriter.WriteFile();
+ if (false == status)
+ {
+ LOG_ERROR << "Error creating PMC data file" << std::endl;
+ m_Reply = "0xDEADDEAD\r\n";
+ return 0;
+ }
+
+ // Reply with file size
+ size_t pmcFileSize = pmcFileWriter.GetFileSize();
+
+ std::ostringstream replyBuilder;
+ replyBuilder << pmcFileSize << "\r\n";
+ m_Reply = replyBuilder.str();
+
+ return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_read_pmc_file(unsigned int ref_number)
+{
+ LOG_DEBUG << "Reading PMC File #" << ref_number << std::endl;
+
+ PmcFile pmcFile(ref_number);
+
+ if (NULL == pmcFile.GetFileName())
+ {
+ LOG_ERROR << "Error getting PMC data file #" << ref_number << std::endl;
+ m_Reply = "0xDEADDEAD\r\n";
+ return 0;
+ }
+
+ // Note: No \r\n is needed here, the file name won't be sent to a clientls
+ m_Reply = pmcFile.GetFileName();
+ replyType = REPLY_TYPE_FILE;
+ return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_rb(char *interface, unsigned int address, unsigned int num_regs)
+{
+ void *handler = get_interface(interface);
+
+ if((handler == NULL) || (num_regs > MAX_REGS_LEN))
+ {
+ m_Reply = "0xDEADDEAD\r\n";
+ return 0;
+ }
+
+ unsigned int *val = new unsigned int[num_regs];
+ int rc = readBlock(handler, address, num_regs*sizeof(unsigned int), (char*)val);
+
+ if (rc == 0)
+ {
+ std::ostringstream replyBuilder;
+ replyBuilder << std::hex;
+
+ for(unsigned int i=0; i < num_regs; i++)
+ {
+ replyBuilder << "0x" << val[i];
+ if(i < num_regs -1 )
+ {
+ replyBuilder << ' ';
+ }
+ }
+
+ replyBuilder << "\r\n";
+ m_Reply = replyBuilder.str();
+ }
+ else
+ {
+ m_Reply = "0xDEADDEAD\r\n";
+ }
+
+ delete[] val;
+ return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_wb(char *interface, unsigned int address, unsigned int len, const char *block)
+{
+ void *handler = get_interface(interface);
+
+ if((handler == NULL) || (len > MAX_REGS_LEN))
+ {
+ m_Reply = "0xDEADDEAD\r\n";
+ return 0;
+ }
+
+ LOG_VERBOSE << "current WB is " << block << " length is " << len << std::endl;
+ int rc = writeBlock(handler, address, len, block);
+ if(rc == 0)
+ {
+ m_Reply = "0\r\n";
+ }
+ else
+ {
+ m_Reply = "ERROR\r\n";
+ }
+
+ return 0;
+}
+
+
+int CmdIface::cmd_interface_reset(char *interface)
+{
+ void *handler = get_interface(interface);
+ if(handler == NULL)
+ {
+ m_Reply = "0xDEADDEAD\r\n";
+ }
+ else
+ {
+ int rc = InterfaceReset(handler);
+ if(rc == 0)
+ {
+ m_Reply = "OK\r\n";
+ }
+ else
+ {
+ m_Reply = "0xDEADDEAD\r\n";
+ }
+ }
+
+ return 0;
+}
+
+
+int CmdIface::cmd_sw_reset(char *interface)
+{
+ void *handler = get_interface(interface);
+ if (handler == NULL)
+ {
+ m_Reply = "0xDEADDEAD\r\n";
+ }
+ else
+ {
+ int rc = SwReset(handler);
+ if (rc == 0)
+ {
+ m_Reply = "OK\r\n";
+ }
+ else
+ {
+ m_Reply = "0xDEADDEAD\r\n";
+ }
+ }
+
+ return 0;
+}
+
+int CmdIface::cmd_set_host_alias(char* alias)
+{
+ std::ofstream fd(UdpServer::host_details_file_name.c_str());
+ if (!fd.is_open())
+ {
+ m_Reply = "FAIL : Coudn't set the new alias: failed to open the configuration file";
+ LOG_VERBOSE << m_Reply << std::endl;
+ return -1;
+ }
+ fd << alias;
+ if (fd.bad())
+ {
+ m_Reply = "FAIL : Coudn't set the new alias: failed to write the new alias to the configuration file";
+ LOG_VERBOSE << m_Reply << std::endl;
+ fd.close();
+ return -2;
+ }
+ fd.close();
+
+ UdpServer::SetHostAlias(alias);
+ UdpServer::SendAll(UdpServer::GetHostDetails());
+ return 0;
+}
+
+
+/*
+ Execute command received from a remote client
+ The command of length 'len' is in 'buf'. 'outlen' has
+ the max output buffer size.
+ On return, 'outbuf' may have a reply to be sent to the client,
+ 'outlen' should have the reply length or 0 if no reply required.
+ Returns KEEPALIVE_OK if ok, KEEPALIVE_CLOSE to close the connection, KEEPALIVE_SHUTDOWN to shutdown the server (debug mode)
+*/
+int CmdIface::do_command(const char *buf, int len)
+{
+ servercmd_t s;
+ int result = KEEPALIVE_OK;
+ replyType = REPLY_TYPE_BUFFER;
+
+ ((char*)buf)[len] = '\0'; // Make a zero-terminated string
+
+ // Parse the command
+ parse_line(buf, &s);
+ dump_parser(&s);
+
+ // Check for the parser error. Note, not all the commands in the original protocol report about errors. so we check the error
+ // for selected commands only TODO: verify the commands list reporting the error
+ if(s.cmd == CMD_OPEN_INTERFACE || s.cmd == CMD_R || s.cmd == CMD_RB || s.cmd == CMD_W || s.cmd == CMD_WB)
+ {
+ if(s.error != 0)
+ {
+ LOG_ERROR << "Command line parsing error" << std::endl;
+ m_Reply = "0xDEADDEAD\r\n"; // TODO: or should it be "dmtools_error"??
+ return result;
+ }
+ }
+
+ switch(s.cmd)
+ {
+ case CMD_GET_INTERFACES:
+ cmd_get_interfaces();
+ break;
+ case CMD_OPEN_INTERFACE:
+ cmd_open_interface(s.interface);
+ break;
+ case CMD_CLOSE_INTERFACE:
+ cmd_close_interface(s.interface);
+ break;
+ case CMD_R:
+ cmd_r(s.interface, s.address);
+ break;
+ case CMD_RB:
+ cmd_rb(s.interface, s.address, s.value);
+ break;
+ case CMD_W:
+ cmd_w(s.interface, s.address, s.value);
+ break;
+ case CMD_WB:
+ // hexdata_len is in dwords, cmd_wb works in bytes. (hence * 4)
+ cmd_wb(s.interface, s.address, s.hexdata_len * 4, (const char*)s.hexdata);
+ break;
+ case CMD_INTERFACE_RESET:
+ cmd_interface_reset(s.interface);
+ break;
+ case CMD_SW_RESET:
+ cmd_sw_reset(s.interface);
+ break;
+ case CMD_EXIT:
+ result = KEEPALIVE_CLOSE; // Terminate the connection
+ break;
+ case CMD_ALLOC_PMC:
+ cmd_alloc_pmc(s.interface, s.address, s.value);
+ break;
+ case CMD_READ_PMC:
+ cmd_read_pmc(s.interface, s.address);
+ break;
+ case CMD_READ_PMC_FILE:
+ cmd_read_pmc_file(s.address);
+ break;
+ case CMD_SET_HOST_ALIAS:
+ cmd_set_host_alias(s.interface);
+ break;
+ case CMD_COMMAND_UNKNOWN:
+ default:
+ m_Reply = "dmtools_error\r\n";
+
+ }
+ return result;
+}
+
+/*
+ Dump the parser structure, for debugging only
+*/
+void CmdIface::dump_parser(servercmd_t *s)
+{
+ if(s->error)
+ {
+ LOG_ERROR << "Parser error in comand parsing."
+ << " Error: " << s->error
+ << " Message: " << parser_error_to_string(s->error)
+ << std::endl;
+
+ return;
+ }
+
+ LOG_VERBOSE << "Parsed Command: " << command_to_string(s->cmd)
+ << " Interface: " << s->interface << std::endl;
+
+ if(s->address != (unsigned int)-1)
+ {
+ LOG_VERBOSE << "Address: " << s->address << std::endl;
+ }
+ if(s->value != (unsigned int)-1)
+ {
+ LOG_VERBOSE << "Value: " << s->value << std::endl;
+ }
+ if(s->hexdata_len)
+ {
+ for(int i=0; i < s->hexdata_len && i < MAX_REGS_LEN; i++)
+ LOG_VERBOSE << std::hex << "0x" << s->hexdata[i] << std::dec << std::endl;
+ }
+}
+
+/*
+*/
+int CmdIface::get_reply_len()
+{
+ return m_Reply.size();
+}
+
+/*
+*/
+void CmdIface::to_lower(char* string)
+{
+ for (int i = 0; string[i]; i++)
+ {
+ string[i] = tolower(string[i]);
+ }
+
+ return;
+}
+
+/*
+*/
+CmdIface::CmdIface()
+ : replyType(REPLY_TYPE_BUFFER)
+{
+}
diff --git a/debug-tools/remoteserver/cmdiface.h b/debug-tools/remoteserver/cmdiface.h
new file mode 100644
index 0000000..a58864e
--- /dev/null
+++ b/debug-tools/remoteserver/cmdiface.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __interface_h
+#define __interface_h
+
+#include <pthread.h>
+#include <string>
+
+extern "C"
+{
+#include "parser.h"
+}
+
+struct open_interface_s {
+ char interface[MAX_INTERFACE_NAME];
+ void *handler;
+ struct open_interface_s *next;
+};
+
+#define KEEPALIVE_OK 0 // keep the connection
+#define KEEPALIVE_CLOSE 1 // close the connection
+#define KEEPALIVE_SHUTDOWN 2 // close the connection and shutdown the server. For debugging only, remove from the production
+
+
+// Max buffer size for a command and a reply. We should consider the longest command/data sequence to fit in a buffer.
+// rb reading 1024 (MAX_REGS_LEN) registers: rb HHHHHHHH HHHH 1024*(0xHHHHHHHH) = 17 + 1024*10 = 10257 bytes
+// wb writing 1024 (MAX_REGS_LEN) hex values: wb HHHHHHHH "1024*HH" = 14+1024*2 = 2062 bytes
+#define MAX_INPUT_BUF (11*MAX_REGS_LEN)
+
+// The reply data may be generated in several ways, the data is expected to be obtained according to this type
+enum REPLY_TYPE
+{
+ REPLY_TYPE_NONE,
+ REPLY_TYPE_BUFFER,
+ REPLY_TYPE_FILE
+};
+
+
+class CmdIface
+{
+public:
+ CmdIface();
+
+ int do_command(const char *buf, int len);
+ const char *get_reply() const { return m_Reply.c_str(); };
+ int get_reply_len();
+ REPLY_TYPE get_reply_type() const { return replyType; }
+
+private:
+
+ static struct open_interface_s *open_interfaces;
+ static pthread_mutex_t open_interfaces_mutex;
+ static int interface_id; // Interface id counter returned in open_interface
+
+ void *get_interface(const char *name);
+ void *add_interface(const char *name, void *handler);
+ void del_interface(void *handler);
+
+ int cmd_get_interfaces();
+ int cmd_open_interface(char *interface);
+ int cmd_close_interface(char *interface);
+ int cmd_r(char *interface, unsigned int address);
+ int cmd_rb(char *interface, unsigned int address, unsigned int num_regs);
+ int cmd_w(char *interface, unsigned int address, unsigned int data);
+ int cmd_wb(char *interface, unsigned int address, unsigned int len, const char *block);
+ int cmd_interface_reset(char *interface);
+ int cmd_sw_reset(char *interface);
+ int cmd_alloc_pmc(char *interface, unsigned int desc_size, unsigned int desc_num);
+ int cmd_read_pmc(char *interface, unsigned int ref_number);
+ int cmd_read_pmc_file(unsigned int ref_number);
+ void dump_parser(servercmd_t *s);
+ int cmd_set_host_alias(char *alias);
+
+ void to_lower(char* string);
+
+ REPLY_TYPE replyType;
+ std::string m_Reply;
+
+};
+
+#endif // interface_h
+
diff --git a/debug-tools/remoteserver/debug.cpp b/debug-tools/remoteserver/debug.cpp
new file mode 100644
index 0000000..7a3502d
--- /dev/null
+++ b/debug-tools/remoteserver/debug.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "debug.h"
+#include <stdio.h>
+
+// *************************************************************************************************
+
+LogConfig g_LogConfig(LOG_SEV_INFO, false);
+
+// *************************************************************************************************
+
+LogConfig::LogConfig(LogSeverity maxSeverity, bool bPrintLocation)
+ : m_MaxSeverity(maxSeverity), m_PrintLocation(bPrintLocation)
+{
+}
+
+void LogConfig::SetMaxSeverity(int traceLevel)
+{
+ if (traceLevel > LOG_SEV_VERBOSE)
+ {
+ fprintf(stderr, "Invalid trace level, setting %d\n", LOG_SEV_VERBOSE);
+ m_MaxSeverity = LOG_SEV_VERBOSE;
+ }
+ else
+ {
+ m_MaxSeverity = static_cast<LogSeverity>(traceLevel);
+ fprintf(stdout, "Setting trace level to %d\n", m_MaxSeverity);
+ }
+}
+
+// *************************************************************************************************
+
+const char* LogMsgPrefix::SeverityToString(LogSeverity sev)
+{
+ static const char* const pSeverityToString[] = { "ERR", "WRN", "INF", "DBG", "VRB" };
+
+ size_t index = static_cast<size_t>(sev);
+ if (index >= sizeof(pSeverityToString)/sizeof(pSeverityToString[0]))
+ {
+ return "---";
+ }
+
+ return pSeverityToString[index];
+}
+
+std::ostream& operator<<(std::ostream& os, const LogMsgPrefix& prefix)
+{
+ os << '[' << LogMsgPrefix::SeverityToString(prefix.Severity) << "] ";
+ if (!g_LogConfig.ShouldPrintLocation()) return os;
+ return os << "(" << prefix.File << ':' << prefix.Line << ") ";
+}
diff --git a/debug-tools/remoteserver/debug.h b/debug-tools/remoteserver/debug.h
new file mode 100644
index 0000000..d3c99bf
--- /dev/null
+++ b/debug-tools/remoteserver/debug.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __debug_h
+#define __debug_h
+
+#include <iostream>
+
+// Severity values are expected to raise from zero
+enum LogSeverity
+{
+ LOG_SEV_ERROR = 0, // Unexpected input/events that may cause server misbehavior
+ LOG_SEV_WARNING = 1, // Suspicious events
+ LOG_SEV_INFO = 2, // Events like command/response
+ LOG_SEV_DEBUG = 3, // Detailed functionality
+ LOG_SEV_VERBOSE = 4 // Excessive debug
+};
+
+#define TRACE_WITH_PREFIX(SEV) \
+ g_LogConfig.ShouldPrint(SEV) && std::cout << LogMsgPrefix(SEV, __FILE__, __LINE__)
+
+#define LOG_ERROR TRACE_WITH_PREFIX(LOG_SEV_ERROR)
+#define LOG_WARNING TRACE_WITH_PREFIX(LOG_SEV_WARNING)
+#define LOG_INFO TRACE_WITH_PREFIX(LOG_SEV_INFO)
+#define LOG_DEBUG TRACE_WITH_PREFIX(LOG_SEV_DEBUG)
+#define LOG_VERBOSE TRACE_WITH_PREFIX(LOG_SEV_VERBOSE)
+
+// *************************************************************************************************
+
+struct LogConfig
+{
+public:
+ LogConfig(LogSeverity maxSeverity, bool bPrintLocation);
+ void SetMaxSeverity(int traceLevel);
+
+ bool ShouldPrint(LogSeverity sev) const { return sev <= m_MaxSeverity; }
+ bool ShouldPrintLocation() const { return m_PrintLocation; }
+
+private:
+
+ LogSeverity m_MaxSeverity;
+ const bool m_PrintLocation;
+
+};
+
+// *************************************************************************************************
+
+extern LogConfig g_LogConfig;
+
+// *************************************************************************************************
+
+class LogMsgPrefix
+{
+ friend std::ostream& operator<<(std::ostream& os, const LogMsgPrefix& prefix);
+
+public:
+
+ LogMsgPrefix(LogSeverity severity, const char* pFile, int line)
+ : Severity(severity), File(pFile), Line(line) {}
+
+private:
+
+ static const char* SeverityToString(LogSeverity sev);
+
+ const LogSeverity Severity;
+ const char* const File;
+ const int Line;
+};
+
+
+// *************************************************************************************************
+// Stream Formatters
+// *************************************************************************************************
+
+// Print a boolean value as a string
+struct BoolStr
+{
+ explicit BoolStr(bool value): Value(value) {}
+ const bool Value;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const BoolStr& boolStr)
+{
+ return os << std::boolalpha << boolStr.Value << std::noboolalpha;
+}
+
+// *************************************************************************************************
+
+// Print a string while displaying newline characters
+struct PlainStr
+{
+ explicit PlainStr(const std::string& value): Value(value) {}
+ const std::string& Value;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const PlainStr& plainStr)
+{
+ for (std::string::const_iterator it = plainStr.Value.begin(); it != plainStr.Value.end(); ++it)
+ {
+ switch (*it)
+ {
+ case '\r': os << "\\r"; break;
+ case '\n': os << "\\n"; break;
+ case '\t': os << "\\t"; break;
+ default: os << *it; break;
+ }
+ }
+
+ return os;
+}
+
+
+#endif
diff --git a/debug-tools/remoteserver/file_reader.cpp b/debug-tools/remoteserver/file_reader.cpp
new file mode 100644
index 0000000..3e08e73
--- /dev/null
+++ b/debug-tools/remoteserver/file_reader.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "file_reader.h"
+#include "debug.h"
+
+#include <cstring>
+#include <cerrno>
+#include <stdio.h>
+
+// *************************************************************************************************
+
+FileReader::FileReader(const char* pFileName)
+ : m_FileName(pFileName)
+ , m_pFile(NULL)
+ , m_FileSize(0)
+ , m_ReadTillNow(0)
+ , m_IsCompleted(false)
+ , m_IsError(false)
+{
+ if (NULL == pFileName)
+ {
+ LOG_ERROR << "No file name provided" << std::endl;
+ return;
+ }
+
+ LOG_DEBUG << "Opening file reader for: " << m_FileName << std::endl;
+ m_pFile = fopen(pFileName, "rb");
+
+ if (NULL == m_pFile)
+ {
+ int lastErrno = errno;
+ LOG_ERROR << "Error opening file."
+ << " Name: " << pFileName
+ << " Error: " << lastErrno
+ << " Message: " << strerror(lastErrno)
+ << std::endl;
+ return;
+ }
+
+ fseek (m_pFile, 0, SEEK_END);
+ m_FileSize = ftell(m_pFile);
+ rewind(m_pFile);
+
+ LOG_DEBUG <<"Get file size for " << pFileName << ": " << m_FileSize << "B" << std::endl;
+}
+
+// *************************************************************************************************
+
+FileReader::~FileReader()
+{
+ if (m_pFile)
+ {
+ LOG_DEBUG << "Closing the file: " << m_FileName << std::endl;
+ fclose (m_pFile);
+ m_pFile = NULL;
+ }
+}
+
+// *************************************************************************************************
+
+bool FileReader::CanReadFromFile(char* pBuf, size_t availableSpace)
+{
+ if (!pBuf)
+ {
+ LOG_ERROR << "Cannot read from file " << m_FileName << ": "
+ << "No buffer is provided" << std::endl;
+ return false;
+ }
+
+ if (0 == availableSpace)
+ {
+ LOG_ERROR << "Cannot read from file " << m_FileName << ": "
+ << "No buffer space is provided" << std::endl;
+ return false;
+ }
+
+ if (NULL == m_pFile)
+ {
+ LOG_ERROR << "Cannot read from file " << m_FileName << ": "
+ << "No file handle is available" << std::endl;
+ return false;
+ }
+
+ if (m_IsCompleted)
+ {
+ LOG_ERROR << "Unexpected read from file " << m_FileName << ": "
+ << "EoF is reached" << std::endl;
+ return false;
+ }
+
+ if (m_IsError)
+ {
+ LOG_ERROR << "Unexpected read from file " << m_FileName << ": "
+ << "Error occured" << std::endl;
+ return false;
+ }
+
+ return true;
+
+}
+
+// *************************************************************************************************
+
+size_t FileReader::ReadChunk(char* pBuf, size_t availableSpace)
+{
+ LOG_DEBUG << "Reading a chunk."
+ << " File Name: " << m_FileName
+ << " File Size: " << m_FileSize << "B"
+ << " Read till now: " << m_ReadTillNow << "B"
+ << " Buffer: " << availableSpace << "B"
+ << " Completed: " << BoolStr(m_IsCompleted)
+ << " Error: " << BoolStr(m_IsError)
+ << std::endl;
+
+ if (false == CanReadFromFile(pBuf, availableSpace))
+ {
+ LOG_ERROR << "Cannot read from file: " << m_FileName
+ << " Check previous errors/status" << std::endl;
+ m_IsError = true;
+ return 0;
+ }
+
+ // Read up to availableSpace. Reading less means either EoF is reached or read error occured
+ size_t readBytes = fread(pBuf, 1, availableSpace, m_pFile);
+ m_ReadTillNow += readBytes;
+
+ if (feof(m_pFile))
+ {
+ LOG_DEBUG << "EOF reached" << std::endl;
+ m_IsCompleted = true;
+ }
+
+ if (ferror(m_pFile))
+ {
+ int lastErrno = errno;
+ m_IsError = true;
+ LOG_ERROR << "Cannot read file"
+ << " Name: " << m_FileName
+ << " Error: " << lastErrno
+ << " Message:" << strerror(lastErrno)
+ << std::endl;
+ }
+
+ LOG_VERBOSE << "Got a chunk."
+ << " File Name: " << m_FileName
+ << " File Size: " << m_FileSize << "B"
+ << " Read till now: " << m_ReadTillNow << "B"
+ << " Buffer: " << availableSpace << "B"
+ << " Completed: " << BoolStr(m_IsCompleted)
+ << " Error: " << BoolStr(m_IsError)
+ << std::endl;
+
+ return readBytes;
+
+}
diff --git a/debug-tools/remoteserver/file_reader.h b/debug-tools/remoteserver/file_reader.h
new file mode 100644
index 0000000..2b7b12f
--- /dev/null
+++ b/debug-tools/remoteserver/file_reader.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FILE_READER_H_
+#define _FILE_READER_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+// *************************************************************************************************
+
+// Reads a file from the file system and exports its content to a buffer provided by the caller.
+// If the file is larger than a provide bugffer, it is delivered by chunks of the buffer size.
+// The last chunk may occupy less than the whole buffer. It's a caller's responsibility to allocate
+// the buffer and call the FileReader API untill the file is fully exported.
+
+class FileReader
+{
+public:
+
+ explicit FileReader(const char* pFileName);
+ ~FileReader();
+
+ size_t ReadChunk(char* pBuf, size_t availableSpace);
+
+ bool IsCompleted() const { return m_ReadTillNow == m_FileSize; }
+ bool IsError() const { return m_IsError; }
+
+ size_t ReadTillNow() const { return m_ReadTillNow; }
+ size_t GetFileSize() const { return m_FileSize; }
+
+private:
+
+ bool CanReadFromFile(char* pBuf, size_t availableSpace);
+
+ const std::string m_FileName; // File name - cached for tracing
+ FILE* m_pFile; // File Handler - open for read
+ size_t m_FileSize; // File Size
+ size_t m_ReadTillNow; // Bytes read till now
+ bool m_IsCompleted; // Set to true when OEF is reached
+ bool m_IsError; // Error flag
+
+};
+
+
+#endif // _FILE_READER_H_
diff --git a/debug-tools/remoteserver/main.cpp b/debug-tools/remoteserver/main.cpp
new file mode 100644
index 0000000..dae1030
--- /dev/null
+++ b/debug-tools/remoteserver/main.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h> // getopt
+#include <stdlib.h> // atoi
+#include <signal.h> // SIGQUIT handling
+#include "parser.h"
+#include "server.h"
+#include "udp_server.h"
+#include "debug.h"
+
+#define WILSERVER_VERSION 0x0100
+#define DEFAULT_SERVER_PORT 12348
+#define DEFAULT_UDP_LOCAL_SERVER_PORT_IN 12349
+#define DEFAULT_UDP_REMOTE_SERVER_PORT_IN 12350
+
+UdpServer us;
+Server s;
+
+void sig_quit_handler(int signum)
+{
+ if (signum == SIGQUIT)
+ {
+ printf("Exiting Wilserver as per user request\n");
+ us.stop();
+ s.stop();
+ exit(signum);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ // Register for SIGQUIT signal
+ signal(SIGQUIT, sig_quit_handler);
+
+ int opt;
+ int port=DEFAULT_SERVER_PORT;
+ int localUdpPortIn = DEFAULT_UDP_LOCAL_SERVER_PORT_IN;
+ int remoteUdpPortIn = DEFAULT_UDP_REMOTE_SERVER_PORT_IN;
+ int traceLevel = LOG_SEV_WARNING;
+
+ while ((opt = getopt(argc, argv, "d:vp:")) != -1) {
+ switch (opt) {
+ case 'd':
+ traceLevel = atoi(optarg);
+ g_LogConfig.SetMaxSeverity(traceLevel);
+ break;
+ case 'p':
+ port = atoi(optarg);
+ if(port == 0) {
+ LOG_ERROR << "Invalid port specified" << optarg << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-d debug_level] | [-p port]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ LOG_INFO << "Starting WIGIG Remote Server" << std::endl;
+ us.start(localUdpPortIn, remoteUdpPortIn);
+ s.start(port);
+ return 0;
+}
+
+
diff --git a/debug-tools/remoteserver/parser.h b/debug-tools/remoteserver/parser.h
new file mode 100644
index 0000000..112f90f
--- /dev/null
+++ b/debug-tools/remoteserver/parser.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __parser_h
+#define __parser_h
+
+#include "servercmd.h"
+
+
+int parse_line(const char *line, servercmd_t *s);
+
+#endif /* __parser_h */
diff --git a/debug-tools/remoteserver/parser.l b/debug-tools/remoteserver/parser.l
new file mode 100644
index 0000000..e4d0507
--- /dev/null
+++ b/debug-tools/remoteserver/parser.l
@@ -0,0 +1,211 @@
+%{
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "servercmd.h"
+
+static int acc_byte = 0;
+static int acc_len = 0;
+
+%}
+%option noyywrap
+%option nounput
+/* We need reentratnt scanner for multiple connections */
+%option reentrant
+/* %option c++ */
+%x str
+DIGIT [0-9]
+HEXDIGIT [0-9A-Fa-f]
+
+ID [A-Za-z_!][A-Za-z_!0-9]*
+
+%%
+"get_interfaces" {
+ if(cb_cmd(yyextra, CMD_GET_INTERFACES))
+ yyterminate();
+ }
+"open_interface" {
+ if(cb_cmd(yyextra, CMD_OPEN_INTERFACE))
+ yyterminate();
+ }
+"close_interface" {
+ if(cb_cmd(yyextra, CMD_CLOSE_INTERFACE))
+ yyterminate();
+ }
+"r" {
+ if(cb_cmd(yyextra, CMD_R))
+ yyterminate();
+ }
+"rb" {
+ if(cb_cmd(yyextra, CMD_RB))
+ yyterminate();
+ }
+"w" {
+ if(cb_cmd(yyextra, CMD_W))
+ yyterminate();
+ }
+"wb" {
+ if(cb_cmd(yyextra, CMD_WB))
+ yyterminate();
+ }
+"alloc_pmc" {
+ if(cb_cmd(yyextra, CMD_ALLOC_PMC))
+ yyterminate();
+ }
+"read_pmc" {
+ if(cb_cmd(yyextra, CMD_READ_PMC))
+ yyterminate();
+ }
+"read_pmc_file" {
+ if(cb_cmd(yyextra, CMD_READ_PMC_FILE))
+ yyterminate();
+ }
+"interface_reset" {
+ if(cb_cmd(yyextra, CMD_INTERFACE_RESET))
+ yyterminate();
+ }
+
+"sw_reset" {
+ if(cb_cmd(yyextra, CMD_SW_RESET))
+ yyterminate();
+ }
+"exit" {
+ if(cb_cmd(yyextra, CMD_EXIT))
+ yyterminate();
+ }
+"set_host_alias" {
+ if(cb_cmd(yyextra, CMD_SET_HOST_ALIAS))
+ yyterminate();
+ }
+{DIGIT}+ {
+ /* A decimal number represents the address/value */
+ if(cb_number(yyextra, yytext))
+ yyterminate();
+ }
+
+{ID} {
+ /* The protocol doesn't separate between interface id and command */
+ if(cb_id(yyextra, yytext))
+ yyterminate();
+ }
+\" {
+ /* Start of string */
+ BEGIN(str);
+ acc_byte = 0;
+ acc_len = 0;
+ }
+<str>\" {
+ /* End of string */
+ if(acc_len > 0) {
+ if(cb_hexbyte(yyextra, acc_byte))
+ yyterminate();
+ }
+ /* Callback for end of hex string */
+ if(cb_endhex(yyextra))
+ yyterminate();
+ BEGIN(INITIAL);
+ }
+<str>{HEXDIGIT} {
+ /* We get hex bytes in the string */
+ if(acc_len == 10) {
+ cb_error(yyextra, ERR_BAD_HEX_VALUE, "");
+ yyterminate();
+ }else if(acc_len <= 1){
+ acc_len++;
+ // do nothing on the 0x
+ }
+ else {
+ acc_len++;
+ acc_byte = acc_byte * 16 + hexdigit(yytext[0]);
+ }
+ }
+<str>[ \t] {
+ /* Hex bytes separated by spaces */
+ if(acc_len > 0) {
+ if(cb_hexbyte(yyextra, acc_byte))
+ yyterminate();
+ acc_len = 0;
+ acc_byte = 0;
+ }
+ }
+<str><<EOF>> {
+ /* Check the end of string with unterminated quote */
+ cb_error(yyextra, ERR_UNTERMINATED_STRING, "");
+ yyterminate();
+ }
+<str>x {
+ /* if we ancounter 0x, remove the x and continue */
+ if(acc_len != 1){
+ cb_error(yyextra, ERR_BAD_HEX_VALUE, "");
+ }
+ acc_len++;
+ }
+<str>. {
+ /* Anything except the hex bytes is not allowed in the string parameter */
+ cb_error(yyextra, ERR_BAD_HEX_VALUE, "");
+ yyterminate();
+ }
+
+[ \t\r\n]+ {
+ /* Whitespace */
+ if(cb_separator(yyextra))
+ yyterminate();
+ }
+. {
+ cb_error(yyextra, ERR_BAD_TOKEN, yytext);
+ yyterminate();
+ }
+%%
+
+/*
+ Parses the input line
+*/
+int parse_line(const char *line, servercmd_t *s)
+{
+ yyscan_t scanner;
+ YY_BUFFER_STATE bs;
+ cb_parser_start(s);
+ yylex_init(&scanner);
+
+ if (!scanner)
+ {
+ return 1;
+ }
+
+ yyset_extra(s, scanner);
+ bs = yy_scan_string(line, scanner);
+ yylex(scanner);
+ yy_delete_buffer(bs, scanner);
+ yylex_destroy(scanner);
+ cb_parser_end(s);
+ return s->error;
+}
+
+
+
diff --git a/debug-tools/remoteserver/pmc_file.cpp b/debug-tools/remoteserver/pmc_file.cpp
new file mode 100644
index 0000000..e449739
--- /dev/null
+++ b/debug-tools/remoteserver/pmc_file.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pmc_file.h"
+#include "debug.h"
+
+#include <cstring>
+#include <cerrno>
+#include <sstream>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// *************************************************************************************************
+#ifdef __ANDROID__
+#define PMC_DATA_DIRECTORY "/data/pmc"
+#else
+#define PMC_DATA_DIRECTORY "/var/pmc"
+#endif
+
+// PMC directory and file name pattern should be managed separately as directory is required as a
+// separate variable.
+
+const char* const PmcFile::s_pDirectory = PMC_DATA_DIRECTORY;
+const char* const PmcFile::s_pFileNamePrefix = "pmc_data_";
+
+// *************************************************************************************************
+
+PmcFile::PmcFile(int fileId)
+ : m_FileId(fileId)
+{
+ std::stringstream ss;
+ ss << s_pDirectory << '/' << s_pFileNamePrefix << fileId;
+ m_FileName = ss.str();
+
+ LOG_DEBUG << "PMC file name #" << fileId << " generated: " << m_FileName << std::endl;
+}
+
+std::ostream& operator<<(std::ostream& os, const PmcFile& pmcFile)
+{
+ return os << "PMC file #" << pmcFile.GetFileId() << " (" << pmcFile.GetFileName() << ')';
+}
+
+// *************************************************************************************************
+
+PmcFileWriter::PmcFileWriter(const PmcFile& pmcFile)
+ : m_PmcFile(pmcFile)
+{
+}
+
+// *************************************************************************************************
+
+bool PmcFileWriter::CreateDirectoryIfNeeded() const
+{
+ // Create a PMC directory if does not exist
+ struct stat st = {};
+ if (stat(m_PmcFile.GetDirectory(), &st) != -1)
+ {
+ LOG_DEBUG << "PMC directory " << m_PmcFile.GetDirectory()
+ << " exists for " << m_PmcFile.GetFileName() << std::endl;
+ return true;
+ }
+
+ LOG_DEBUG << "Creating a PMC directory: " << m_PmcFile.GetDirectory() << std::endl;
+
+ int status = mkdir(m_PmcFile.GetDirectory(), 0700);
+ if (0 != status)
+ {
+ int lastErrno = errno;
+ LOG_ERROR << "Cannot create PMC directory."
+ << " Path: " << m_PmcFile.GetDirectory()
+ << " Error:" << lastErrno
+ << " Message: " << strerror(lastErrno)
+ << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+// *************************************************************************************************
+
+bool PmcFileWriter::WriteFile() const
+{
+ if (false == CreateDirectoryIfNeeded())
+ {
+ LOG_ERROR << "Cannot create a PMC directory for " << m_PmcFile << std::endl;
+ return false;
+ }
+
+ // Create a PMC file
+ const char* pCmdPrefix =
+ "D=$(find /sys/kernel/debug/ieee80211/ -name wil6210); cat $D/pmcdata >> ";
+ std::stringstream ss;
+ ss << pCmdPrefix << m_PmcFile.GetFileName();
+
+ system(ss.str().c_str());
+ return true;
+
+}
+
+// *************************************************************************************************
+
+size_t PmcFileWriter::GetFileSize() const
+{
+ FILE *pFile = fopen(m_PmcFile.GetFileName(), "r");
+
+ if (NULL == pFile)
+ {
+ int lastErrno = errno;
+ LOG_ERROR << "Cannot open " << m_PmcFile << " for writing."
+ << " Error: " << lastErrno
+ << " Message: " << strerror(lastErrno)
+ << std::endl;
+ return 0;
+ }
+
+ fseek (pFile, 0, SEEK_END);
+ size_t fileSize = ftell(pFile);
+ fclose(pFile);
+
+ LOG_DEBUG << "Get PMC file size for " << m_PmcFile
+ << ": " << fileSize << "B" << std::endl;
+
+ return fileSize;
+}
diff --git a/debug-tools/remoteserver/pmc_file.h b/debug-tools/remoteserver/pmc_file.h
new file mode 100644
index 0000000..b7af0b7
--- /dev/null
+++ b/debug-tools/remoteserver/pmc_file.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PMC_FILE_H_
+#define _PMC_FILE_H_
+
+#include <stdio.h>
+#include <string>
+
+// *************************************************************************************************
+
+// Generates a PMC file name from its ID.
+class PmcFile
+{
+public:
+
+ explicit PmcFile(int fileId);
+
+ int GetFileId() const { return m_FileId; }
+ const char* GetFileName() const { return m_FileName.c_str(); }
+
+ static const char* GetDirectory() { return s_pDirectory; }
+
+private:
+
+ static const char* const s_pDirectory;
+ static const char* const s_pFileNamePrefix;
+
+ const int m_FileId; // File ID (expected to be unique)
+ std::string m_FileName; // File Name Buffer
+
+};
+
+std::ostream& operator<<(std::ostream& os, const PmcFile& pmcFile);
+
+// *************************************************************************************************
+
+// Creates a PMC data file according to a provided ID.
+class PmcFileWriter
+{
+public:
+
+ explicit PmcFileWriter(const PmcFile& pmcFile);
+
+ bool WriteFile() const;
+ size_t GetFileSize() const;
+
+private:
+
+ bool CreateDirectoryIfNeeded() const;
+
+ const PmcFile& m_PmcFile;
+
+};
+
+
+#endif // PMC_FILE_H_
diff --git a/debug-tools/remoteserver/server.cpp b/debug-tools/remoteserver/server.cpp
new file mode 100644
index 0000000..5ee1b48
--- /dev/null
+++ b/debug-tools/remoteserver/server.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cerrno>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <fstream>
+#include "server.h"
+#include "cmdiface.h"
+#include "debug.h"
+#include "pmc_file.h"
+#include "file_reader.h"
+
+// Thread parameters structure
+typedef struct {
+ int sock;
+ struct sockaddr address;
+ int addr_len;
+} connection_par_t;
+
+volatile int Server::shutdown_flag = 0;
+volatile int Server::running_threads = 0;
+pthread_mutex_t Server::threads_counter_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void *Server::server_process(void *ptr)
+{
+ char *buf;
+ CmdIface *iface;
+ int rw;
+
+ if(ptr == NULL)
+ {
+ pthread_exit(0);
+ }
+
+ connection_par_t *par = (connection_par_t*)ptr;
+ iface = new CmdIface();
+ buf = new char[MAX_INPUT_BUF+1];
+ memset(buf, 0, MAX_INPUT_BUF+1);
+ rw = read(par->sock, buf, MAX_INPUT_BUF);
+
+ while(rw > 0)
+ {
+ // Got some data
+ if(rw)
+ {
+ buf[rw] = '\0';
+ LOG_INFO << "Client Command: " << PlainStr(buf) << std::endl;
+ int cmdKeepalive = iface->do_command((const char*)buf, rw);
+ LOG_DEBUG << "Command handling keepalive: " << cmdKeepalive << std::endl;
+
+ // Check for keepalive return value
+ int replyKeepalive = reply(par->sock, iface);
+
+ if(cmdKeepalive == KEEPALIVE_CLOSE || replyKeepalive == KEEPALIVE_CLOSE)
+ {
+ // Handler asked to close the connection
+ rw = 0;
+ break;
+ }
+ }
+ rw = read(par->sock, buf, MAX_INPUT_BUF);
+ }
+
+ // if 0 - connection is closed, <0 - error
+ LOG_DEBUG << "Closing connection. Read result: " << rw << std::endl;
+ close(par->sock);
+ delete[] buf;
+ delete iface;
+ delete par;
+ pthread_mutex_lock(&threads_counter_mutex);
+ running_threads--;
+ pthread_mutex_unlock(&threads_counter_mutex);
+ pthread_exit(0);
+}
+
+int Server::reply(int sock, CmdIface* iface)
+{
+ LOG_INFO << "Reply: " << PlainStr(iface->get_reply()) << std::endl;
+
+ switch (iface->get_reply_type())
+ {
+ case REPLY_TYPE_BUFFER:
+ return reply_buffer(sock, iface->get_reply(), iface->get_reply_len());
+
+ case REPLY_TYPE_FILE:
+ return reply_file(sock, iface->get_reply());
+
+ default:
+ LOG_ERROR << "Unexpected reply type: " << iface->get_reply_type() << std::endl;
+ return KEEPALIVE_CLOSE;
+ }
+}
+
+int Server::reply_buffer(int sock, const char* pBuf, size_t len)
+{
+ LOG_DEBUG << "Replying from a buffer (" << len << "B) Content: " << PlainStr(pBuf) << std::endl;
+
+ if (0 == len)
+ {
+ LOG_ERROR << "No reply generated by a command handler - connection will be closed" << std::endl;
+ return KEEPALIVE_CLOSE;
+ }
+
+ if (false == send_buffer(sock, pBuf, len))
+ {
+ return KEEPALIVE_CLOSE;
+ }
+
+ return KEEPALIVE_OK;
+}
+
+int Server::reply_file(int sock, const char* pFileName)
+{
+ LOG_DEBUG << "Replying from a file: " << pFileName << std::endl;
+
+ FileReader fileReader(pFileName);
+ size_t fileSize = fileReader.GetFileSize();
+
+ if (0 == fileSize)
+ {
+ LOG_ERROR << "No file content is available for reply" << std::endl;
+ return KEEPALIVE_CLOSE;
+ }
+
+ static const size_t BUF_LEN = 64 * 1024;
+
+ char* pBuf = new char[BUF_LEN];
+ size_t chunkSize = 0;
+ bool isError = false;
+
+ do
+ {
+ LOG_VERBOSE << "Requesting for a file chunk" << std::endl;
+
+ chunkSize = fileReader.ReadChunk(pBuf, BUF_LEN);
+ if (chunkSize > 0)
+ {
+ if (false == send_buffer(sock, pBuf, chunkSize))
+ {
+ LOG_ERROR << "Send error detected" << std::endl;
+ isError = true;
+ break;
+ }
+ }
+
+ // Error/Completion may occur with non-zero chunk as well
+ if (fileReader.IsError())
+ {
+ LOG_ERROR << "File read error detected" << std::endl;
+ isError = true;
+ break;
+ }
+
+ if (fileReader.IsCompleted())
+ {
+ LOG_DEBUG << "File completion detected" << std::endl;
+ break;
+ }
+
+ LOG_DEBUG << "File Chunk Delivered: " << chunkSize << "B" << std::endl;
+ }
+ while (chunkSize > 0);
+
+ delete[] pBuf;
+
+ if (isError)
+ {
+ LOG_ERROR << "Error occured while replying file content" << std::endl;
+ return KEEPALIVE_CLOSE;
+ }
+ else
+ {
+ LOG_DEBUG << "File Content successfully delivered" << std::endl;
+ return KEEPALIVE_OK;
+ }
+}
+
+bool Server::send_buffer(int sock, const char* pBuf, size_t len)
+{
+ if (!pBuf)
+ {
+ LOG_ERROR << "Cannot reply to a command - No buffer is provided" << std::endl;
+ return false;
+ }
+
+ size_t sentTillNow = 0;
+
+ while(sentTillNow < len)
+ {
+ ssize_t sentBytes = write(sock, pBuf, len);
+ if (sentBytes < 0)
+ {
+ int lastErrno = errno;
+ LOG_ERROR << "Cannot send response buffer."
+ << " Error:" << lastErrno
+ << " Message: " << strerror(lastErrno)
+ << std::endl;
+ return false;
+ }
+
+ sentTillNow += sentBytes;
+ LOG_DEBUG << "Sent response chunk."
+ << " Chunk Size: " << sentBytes
+ << " Sent till now: " << sentTillNow
+ << " Response Length: " << len
+ << std::endl;
+ }
+
+ LOG_DEBUG << "Response buffer fully sent" << std::endl;
+ return true;
+}
+
+/*
+ Close the server to allow un-bind te socket - allowing future connections without delay
+*/
+int Server::stop()
+{
+ LOG_INFO << "Stopping the server" << std::endl;
+ shutdown(sock, SHUT_RDWR);
+ return 0;
+}
+
+/*
+ Initialize server on the given port. The function returns in case of error,
+ otherwise it doesn't return
+*/
+int Server::start(int port)
+{
+ LOG_INFO << "Starting the server on port " << port << std::endl;
+
+ struct sockaddr_in address;
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if(sock < 0)
+ {
+ LOG_ERROR << "Cannot create a socket on port " << port << std::endl;
+ return -1;
+ }
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(port);
+
+ // Set the "Re-Use" socket option - allows reconnections after wilserver exit
+ int reuse = 1;
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
+
+ if(bind(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) < 0)
+ {
+ LOG_ERROR << "Cannot bind socket to port " << port << std::endl;
+ return -2;
+ }
+
+ if (listen(sock, 5) < 0)
+ {
+ LOG_ERROR << "Cannot listen on port " << port << std::endl;
+ return -3;
+ }
+
+ shutdown_flag = 0;
+ while (shutdown_flag == 0) {
+ pthread_t thread;
+ connection_par_t *par = new connection_par_t;
+ par->sock = accept(sock, &par->address, (socklen_t*)&par->addr_len);
+ if(par->sock < 0)
+ delete par;
+ else {
+ pthread_mutex_lock(&threads_counter_mutex);
+ running_threads++;
+ pthread_mutex_unlock(&threads_counter_mutex);
+ pthread_create(&thread, 0, &Server::server_process, (void *)par);
+ pthread_detach(thread);
+ }
+
+ }
+ // Wait till all the threads are done in case we ever exit the loop above
+ while(running_threads > 0)
+ sleep(1);
+
+ LOG_INFO << "Server shutdown" << std::endl;
+
+ return 0; // Wont get here, just to avoid the warning
+}
diff --git a/debug-tools/remoteserver/server.h b/debug-tools/remoteserver/server.h
new file mode 100644
index 0000000..01cd080
--- /dev/null
+++ b/debug-tools/remoteserver/server.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __server_h
+#define __server_h
+#include <pthread.h>
+#include <string>
+
+class CmdIface;
+
+class Server
+{
+public:
+
+ int start(int port);
+ int stop();
+
+ static int get_shutdown_flag() { return shutdown_flag; }
+
+
+private:
+
+ static volatile int shutdown_flag;
+ static volatile int running_threads;
+ static pthread_mutex_t threads_counter_mutex;
+ int sock;
+
+ static void *server_process(void *ptr);
+ static bool send_buffer(int sock, const char* pBuf, size_t len);
+ static int reply(int sock, CmdIface* iface);
+ static int reply_buffer(int sock, const char* pBuf, size_t len);
+ static int reply_file(int sock, const char* pFileName);
+};
+
+#endif // server_h
+
diff --git a/debug-tools/remoteserver/servercmd.cpp b/debug-tools/remoteserver/servercmd.cpp
new file mode 100644
index 0000000..bfc180b
--- /dev/null
+++ b/debug-tools/remoteserver/servercmd.cpp
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sstream>
+
+#include "servercmd.h"
+#include "debug.h"
+
+#define EXP_NON 0
+#define EXP_CMD (-1)
+#define EXP_IFC 1
+#define EXP_NUM 2
+#define EXP_HEX 3
+#define EXP_SEP 4
+#define EXP_END 5
+
+const char* parser_state_to_string(int parserState)
+{
+ switch (parserState)
+ {
+ case EXP_NON: return "EXP_NON";
+ case EXP_CMD: return "EXP_CMD";
+ case EXP_IFC: return "EXP_IFC";
+ case EXP_NUM: return "EXP_NUM";
+ case EXP_HEX: return "EXP_HEX";
+ case EXP_SEP: return "EXP_SEP";
+ case EXP_END: return "EXP_END";
+ default: return "<unknown>";
+ }
+}
+
+
+static int states_table[][5] =
+{
+ { EXP_END, 0, 0, 0, 0 }, // 0 - get_interfaces
+ { EXP_IFC, EXP_END, 0, 0, 0 }, // 1 - open_interface name
+ { EXP_IFC, EXP_END, 0, 0, 0 }, // 2 - close_interface name
+ { EXP_IFC, EXP_NUM, EXP_END, 0, 0 }, // 3 - r name address
+ { EXP_IFC, EXP_NUM, EXP_NUM, EXP_END, 0 }, // 4 - rb name address count
+ { EXP_IFC, EXP_NUM, EXP_NUM, EXP_END, 0 }, // 5 - w name address value
+ { EXP_IFC, EXP_NUM, EXP_HEX, EXP_END, 0 }, // 6 - wb name address hexstring
+ { EXP_IFC, EXP_END, 0, 0, 0 }, // 7 - interface_reset name
+ { EXP_IFC, EXP_END, 0, 0, 0 }, // 8 - sw_reset name
+ { EXP_END, 0, 0, 0, 0 }, // 9 - exit
+ { EXP_IFC, EXP_NUM, EXP_NUM, EXP_END, 0 }, // 10 - Alloc_PMC name number_of_descriptors size_of_descriptors
+ { EXP_IFC, EXP_NUM, EXP_END, 0, 0 }, // 11 - read_pmc interface requestReferenceNumber
+ { EXP_NUM, EXP_END, 0, 0, 0 }, // 12 - read_pmc_file requestReferenceNumber
+ { EXP_IFC, EXP_END, 0, 0, 0 }, // 13 - set_host_alias
+};
+
+
+// The return value is copied because std::stringstream::str() returns a temporary object
+std::string parser_state_machine_to_string(int* pStateMachine)
+{
+ if (!pStateMachine)
+ {
+ return std::string("{}");
+ }
+
+ std::stringstream ss;
+
+ ss << "{ ";
+
+ size_t numStates = sizeof(states_table[0])/sizeof(int);
+ for (size_t i = 0; i < numStates; ++i)
+ {
+ ss << parser_state_to_string(pStateMachine[i]) << " ";
+ }
+ ss << "}";
+
+ return ss.str();
+}
+
+
+const char* command_to_string(int cmdCode)
+{
+ switch (cmdCode)
+ {
+ case CMD_COMMAND_UNKNOWN: return "CMD_COMMAND_UNKNOWN";
+ case CMD_GET_INTERFACES: return "CMD_GET_INTERFACES";
+ case CMD_OPEN_INTERFACE: return "CMD_OPEN_INTERFACE";
+ case CMD_CLOSE_INTERFACE: return "CMD_CLOSE_INTERFACE";
+ case CMD_R: return "CMD_R";
+ case CMD_RB: return "CMD_RB";
+ case CMD_W: return "CMD_W";
+ case CMD_WB: return "CMD_WB";
+ case CMD_INTERFACE_RESET: return "CMD_INTERFACE_RESET";
+ case CMD_SW_RESET: return "CMD_SW_RESET";
+ case CMD_EXIT: return "CMD_EXIT";
+ case CMD_ALLOC_PMC: return "CMD_ALLOC_PMC";
+ case CMD_READ_PMC: return "CMD_READ_PMC";
+ case CMD_READ_PMC_FILE: return "CMD_READ_PMC_FILE";
+ case CMD_SET_HOST_ALIAS: return "CMD_SET_HOST_ALIAS";
+ default: return "<unknown>";
+ }
+}
+
+
+const char* parser_error_to_string(int parserError)
+{
+ switch (parserError)
+ {
+ case ERR_BAD_TOKEN: return "ERR_BAD_TOKEN";
+ case ERR_BAD_VALUE: return "VALUE";
+ case ERR_UNTERMINATED_STRING: return "ERR_UNTERMINATED_STRING";
+ case ERR_BAD_HEX_VALUE: return "ERR_BAD_HEX_VALUE";
+ case ERR_CMD_NOT_EXPECTED: return "ERR_CMD_NOT_EXPECTED";
+ case ERR_IFACE_NOT_EXPECTED: return "ERR_IFACE_NOT_EXPECTED";
+ case ERR_VALUE_NOT_EXPECTED: return "ERR_VALUE_NOT_EXPECTED";
+ case ERR_HEX_NOT_EXPECTED: return "ERR_HEX_NOT_EXPECTED";
+ case ERR_END_NOT_EXPECTED: return "ERR_END_NOT_EXPECTED";
+ default: return "<unknown>";
+ }
+}
+
+
+
+/*
+ Callback on parser start.
+ Returns the handler to be used in all subsequent callbacks
+ or NULL in case of error, the parsing will be aborted then
+*/
+void cb_parser_start(servercmd_t *s)
+{
+ s->states = NULL;
+ s->state = EXP_CMD; // We start with expecting a command
+ s->cmd = CMD_COMMAND_UNKNOWN;
+ s->error = 0;
+ s->address = (unsigned int)-1;
+ s->value = (unsigned int)-1;
+ s->hexdata_len = 0;
+ s->hexdata = (unsigned int*)malloc (sizeof(int)*MAX_REGS_LEN);
+}
+
+/*
+ Callback on a command. Gets the command code.
+ Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int cb_cmd(servercmd_t *s, int cmd)
+{
+ LOG_VERBOSE <<"cb_cmd(" << cmd << ") state index = " << s->state << std::endl;
+ LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+ if(s->state != EXP_CMD) {
+ s->error = ERR_CMD_NOT_EXPECTED;
+ LOG_ERROR << "Command not expected, expecting " << s->state << std::endl;
+ return -1;
+ }
+ LOG_VERBOSE << "Parsed Command: " << cmd << "(" << command_to_string(cmd) << ")" << std::endl;
+ s->cmd = cmd;
+ s->states = states_table[cmd];
+ s->state++;
+
+ return 0;
+}
+
+
+/*
+ Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int cb_id(servercmd_t *s, const char *id)
+{
+ LOG_VERBOSE << "cb_id(" << id << ") state index = " << s->state << std::endl;
+ LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+ if((s->states == NULL) || (s->states[s->state] != EXP_IFC)) {
+ s->error = ERR_IFACE_NOT_EXPECTED;
+ LOG_ERROR << "Interface not expected, expecting: "
+ << (s->states?s->states[s->state]:-1) << std::endl;
+ return -1;
+ }
+
+ LOG_VERBOSE << "Interface id: " << id << std::endl;
+ snprintf(s->interface, MAX_INTERFACE_NAME, "%s", id);
+ s->state++;
+ return 0;
+}
+
+/*
+ Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int cb_number(servercmd_t *s, const char *id)
+{
+ LOG_VERBOSE << "cb_number(" << id << ") state index = " << s->state << std::endl;
+ LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+ if((s->states == NULL) || (s->states[s->state] != EXP_NUM)) {
+ s->error = ERR_VALUE_NOT_EXPECTED;
+ LOG_ERROR << "Number not expected, expecting " << (s->states?s->states[s->state]:-1) << std::endl;
+ return -1;
+ }
+
+ // A hack now. if address already set, the number is for data
+ LOG_VERBOSE << "string number " << id << std::endl;
+
+ if(s->address != (unsigned int)-1){
+ sscanf(id, "%u", &(s->value));
+ //s->value = strtoul(id, tmp, 10); //10 is the base for conversion
+ // dprint("str to uint Parsed val %u\n", strtoul(id, tmp, 10));
+ // dprint("str to int Parsed val %u\n", atol(id));//s->value = atol(id);
+ LOG_VERBOSE << "scanf Parsed value: " << s->value << std::endl;
+ }
+ else{
+ // s->address = atol(id);
+ sscanf(id, "%u", &(s->address));
+ LOG_VERBOSE << "Parsed addr " << s->address << std::endl;
+ }
+ s->state++;
+ return 0;
+}
+
+/*
+ Callback on hex data
+ Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int cb_hexbyte(servercmd_t *s, int b)
+{
+ LOG_VERBOSE << "cb_hexbyte(0x" << std::hex << b << std::dec << ") state index = " << s->state << std::endl;
+ LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+ if((s->states == NULL) || (s->states[s->state] != EXP_HEX)) {
+ s->error = ERR_HEX_NOT_EXPECTED;
+ LOG_ERROR << "Hex not expected, expecting " << (s->states?s->states[s->state]:-1) << std::endl;
+ return -1;
+ }
+ if(s->hexdata_len == MAX_REGS_LEN) {
+ s->error = ERR_BAD_HEX_VALUE;
+ LOG_ERROR << "Too long hex data" << std::endl;
+ return -1;
+ }
+ LOG_VERBOSE << "Hex byte 0x" << std::hex << b << std::dec << std::endl;
+ s->hexdata[s->hexdata_len] = b;
+ s->hexdata_len++;
+ // Do not change the s->state here, we are still expecting hex data. cb_endhex will change the state
+ return 0;
+}
+
+/*
+ Callback on end of hex data string
+ Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+
+int cb_endhex(servercmd_t *s)
+{
+ LOG_VERBOSE << "cb_endhex() state index = " << s->state << std::endl;
+ LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+ if((s->states == NULL) || (s->states[s->state] != EXP_HEX)) {
+ s->error = ERR_HEX_NOT_EXPECTED;
+ LOG_ERROR << "Hex not expected, expecting " << (s->states?s->states[s->state]:-1) << std::endl;
+ return -1;
+ }
+ s->state++;
+ return 0;
+}
+
+/*
+ Callback on a separator, not used.
+ Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int cb_separator(servercmd_t *s)
+{
+ (void)s;
+ return 0;
+}
+
+/*
+ Callback on the parser end
+ Returns the parser result: 0 if ok, error otherwise
+*/
+void cb_parser_end(servercmd_t *s)
+{
+ LOG_VERBOSE << "cb_parser_end() state index = " << s->state << std::endl;
+ LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+ if((s->error == 0) && ((s->states == NULL) || (s->states[s->state] != EXP_END))) {
+ LOG_ERROR << "End of parser while still expecting " << (s->states?s->states[s->state]:-1) << std::endl;
+ s->error = ERR_END_NOT_EXPECTED;
+ }
+
+ free(s->hexdata);
+}
+
+/*
+ Callback on parser error
+*/
+void cb_error(servercmd_t *s, int error, const char *str)
+{
+ (void)str;
+ s->error = error;
+ LOG_ERROR << "Parser error: " << error << std::endl;
+}
+
+/*
+ Service function. Converting a hex digit from a character.
+*/
+int hexdigit(char d)
+{
+ if((d >= '0') && (d <= '9'))
+ return d-'0';
+ else if((d >= 'A') && (d <= 'F'))
+ return d-'A'+10;
+ else if((d >- 'a') && (d <= 'f'))
+ return d-'a'+10;
+ else // This shouldn't happen, it's the parser's responsibility to parse valid hex digits
+ return 0;
+}
diff --git a/debug-tools/remoteserver/servercmd.h b/debug-tools/remoteserver/servercmd.h
new file mode 100644
index 0000000..c63e3c7
--- /dev/null
+++ b/debug-tools/remoteserver/servercmd.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __servercmd_h
+#define __servercmd_h
+
+// This header is included by the parser, which is flex-generated C code
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Commands list
+#define CMD_COMMAND_UNKNOWN (-1)
+#define CMD_GET_INTERFACES 0
+#define CMD_OPEN_INTERFACE 1
+#define CMD_CLOSE_INTERFACE 2
+#define CMD_R 3
+#define CMD_RB 4
+#define CMD_W 5
+#define CMD_WB 6
+#define CMD_INTERFACE_RESET 7
+#define CMD_SW_RESET 8
+#define CMD_EXIT 9 // debug command
+#define CMD_ALLOC_PMC 10
+#define CMD_READ_PMC 11
+#define CMD_READ_PMC_FILE 12
+#define CMD_SET_HOST_ALIAS 13
+
+
+const char* command_to_string(int cmdCode);
+
+#define MAX_INTERFACE_NAME 32 // TODO: better to include WlctPciAcss.h that defines MAX_IF_NAME_LENGTH==32
+#define MAX_REGS_LEN (256* 1024) // Max registers to read/write at once
+
+// Parser errors
+#define ERR_BAD_TOKEN (-1)
+#define ERR_BAD_VALUE (-2)
+#define ERR_UNTERMINATED_STRING (-3)
+#define ERR_BAD_HEX_VALUE (-4)
+#define ERR_CMD_NOT_EXPECTED (-5)
+#define ERR_IFACE_NOT_EXPECTED (-6)
+#define ERR_VALUE_NOT_EXPECTED (-7)
+#define ERR_HEX_NOT_EXPECTED (-8)
+#define ERR_END_NOT_EXPECTED (-9)
+
+const char* parser_error_to_string(int parserError);
+
+
+/*
+ Parser result/state structure
+*/
+typedef struct {
+ int state;
+ int cmd;
+ int *states;
+ char interface[MAX_INTERFACE_NAME+1];
+ unsigned int address;
+ unsigned int value;
+ unsigned int* hexdata;
+ int hexdata_len;
+ int error;
+} servercmd_t;
+
+
+
+/*
+ Parser callbacks
+*/
+void cb_parser_start(servercmd_t *s);
+int cb_cmd(servercmd_t *s, int cmd);
+int cb_id(servercmd_t *s, const char *id);
+int cb_number(servercmd_t *s, const char *id);
+int cb_hexbyte(servercmd_t *s, int b);
+int cb_endhex(servercmd_t *s);
+int cb_separator(servercmd_t *s);
+void cb_parser_end(servercmd_t *s);
+void cb_error(servercmd_t *s, int error, const char *str);
+
+/* helper functions */
+int hexdigit(char d);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // servercmd_h
diff --git a/debug-tools/remoteserver/udp_server.cpp b/debug-tools/remoteserver/udp_server.cpp
new file mode 100644
index 0000000..64c161d
--- /dev/null
+++ b/debug-tools/remoteserver/udp_server.cpp
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cerrno>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <fstream>
+#include "server.h"
+#include "cmdiface.h"
+#include "debug.h"
+#include "pmc_file.h"
+#include "file_reader.h"
+#include "udp_server.h"
+
+const std::string UdpServer::local_host = "127.0.0.1";
+const std::string UdpServer::host_details_file_name = "/etc/wigig_remoteserver_details";
+const std::string UdpServer::cmd_get_host_identity = "GetHostIdentity";
+const std::string UdpServer::cmd_delimiter = ";";
+
+std::string UdpServer::host_broadcast_ip = "";
+std::string UdpServer::host_ip = "";
+std::string UdpServer::host_alias = "";
+int UdpServer::sock_in = 0;
+int UdpServer::sock_out = 0;
+int UdpServer::port_in = 0;
+int UdpServer::port_out = 0;
+
+int UdpServer::SendAll(std::string message)
+{
+ int result = -1;
+
+ struct sockaddr_in dstAddress;
+ dstAddress.sin_family = AF_INET;
+ inet_pton(AF_INET , host_broadcast_ip.c_str(), &dstAddress.sin_addr.s_addr);
+ dstAddress.sin_port = htons(UdpServer::port_out);
+ int messageSize = message.length() * sizeof(char);
+ result = sendto(UdpServer::sock_out, message.c_str(), messageSize, 0, (sockaddr*)&dstAddress, sizeof(dstAddress));
+ LOG_DEBUG << "INFO : sendto with sock_out=" << UdpServer::sock_out << ", message=" << message << " messageSize=" << messageSize << " returned with " << result << std::endl;
+ if (result < 0)
+ {
+ LOG_DEBUG << "ERROR : Cannot send udp broadcast message, error " << errno << ": " << strerror(errno) << std::endl;
+ return -4;
+ }
+
+ return 0;
+}
+
+int UdpServer::HandleRequest(char* buf)
+{
+ if(NULL == buf)
+ {
+ return 0;
+ }
+
+ LOG_DEBUG << "INFO : Client Command: " << PlainStr(buf) << std::endl;
+
+ std::string cmd(buf);
+ std::string answer;
+
+ if (UdpServer::local_host == host_ip)
+ {
+ LOG_DEBUG << "WARNING : There is no support in UDP srevices when using local host" << std::endl;
+ return 0;
+ }
+
+ if (UdpServer::cmd_get_host_identity == cmd)
+ {
+ answer = GetHostDetails();
+ }
+ else
+ {
+ LOG_DEBUG << "ERROR : Unkonwn UDP command" << std::endl;
+ }
+
+ // send back response in broadcast
+ // For the time being, all requests will have broadcast response
+ // All responses will use the same outgoing communication port
+ LOG_DEBUG << "INFO : Answer is: " << PlainStr(answer.c_str()) << std::endl;
+ SendAll(answer);
+
+ return 0;
+}
+
+
+/*
+ Close the server to allow un-bind te socket - allowing future connections without delay
+*/
+int UdpServer::stop()
+{
+ LOG_DEBUG << "INFO : Stopping the UDP server" << std::endl;
+ shutdown(UdpServer::sock_in, SHUT_RDWR);
+ return 0;
+}
+
+/*
+ Initialize UPD server on the given port. The function returns in case of error,
+ otherwise it doesn't return
+*/
+int UdpServer::start(int localUdpPortIn, int remoteUdpPortIn)
+{
+ LOG_DEBUG << "INFO : Starting UDP server on port " << localUdpPortIn << std::endl;
+ LOG_DEBUG << "INFO : Sending broadcast answers to port " << remoteUdpPortIn << std::endl;
+
+ // open the UDP server on a new thread
+ UdpServer::port_in = localUdpPortIn;
+ UdpServer::port_out = remoteUdpPortIn;
+ pthread_t thread;
+ pthread_create(&thread, 0, start_udp_server, NULL);
+ pthread_detach(thread);
+
+ return 0;
+}
+
+void* UdpServer::start_udp_server(void* unused)
+{
+ (void)unused;
+ if (LoadHostDetails() < 0)
+ {
+ return NULL;
+ }
+
+ // Create outgoing response socket
+ UdpServer::sock_out = socket(AF_INET, SOCK_DGRAM, 0);
+ if (UdpServer::sock_out < 0)
+ {
+ LOG_DEBUG << "ERROR : Cannot open udp broadcast outgoing socket" << std::endl;
+ return NULL;
+ }
+
+ int enabled = 1;
+ int result;
+ result = setsockopt(UdpServer::sock_out, SOL_SOCKET, SO_BROADCAST, (char*)&enabled, sizeof(enabled));
+ if (result < 0)
+ {
+ LOG_DEBUG << "ERROR : Cannot set broadcast option for udp socket, error " << errno << ": " << strerror(errno) << std::endl;
+ shutdown(UdpServer::sock_out, SHUT_RDWR);
+ return NULL;
+ }
+
+ // Create incoming request socket
+ struct sockaddr_in address;
+ UdpServer::sock_in = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if(UdpServer::sock_in < 0)
+ {
+ LOG_DEBUG << "ERROR : Cannot create a socket on port " << UdpServer::port_in << std::endl;
+ return NULL;
+ }
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(UdpServer::port_in);
+ // Set the "Re-Use" socket option - allows reconnections after wilserver exit
+ int reuse = 1;
+ setsockopt(UdpServer::sock_in, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
+ if(bind(UdpServer::sock_in, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) < 0)
+ {
+ LOG_DEBUG << "ERROR : Cannot bind socket to port " << UdpServer::port_in << ", error " << errno << ": " << strerror(errno) << std::endl;
+ return NULL;
+ }
+
+ char* buf = new char[MAX_INPUT_BUF];
+
+ do
+ {
+ if (recvfrom(UdpServer::sock_in, buf, MAX_INPUT_BUF, 0, NULL, 0) < 0)
+ {
+ LOG_DEBUG << "ERROR : Cannot listen on port " << UdpServer::port_in << std::endl;
+ return NULL;
+ }
+
+ HandleRequest(buf);
+
+ } while (true);
+
+ LOG_DEBUG << "INFO : UDP server shutdown" << std::endl;
+ return NULL; // Wont get here, just to avoid the warning
+}
+
+bool FindEthernetInterface(struct ifreq& ifr, int& fd)
+{
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if(fd < 0)
+ {
+ LOG_DEBUG << "ERROR : Cannot get host and broadcast IPs" << std::endl;
+ return -1;
+ }
+
+ for (int i = 0; i < 100; i++)
+ {
+ snprintf(ifr.ifr_name, IFNAMSIZ-1, "eth%d", i);
+
+ if (ioctl(fd, SIOCGIFADDR, &ifr) >= 0)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int UdpServer::LoadHostAndBroadcastIps()
+{
+ int fd;
+ struct ifreq ifr;
+
+ ifr.ifr_addr.sa_family = AF_INET; // IP4V
+
+ // Get IP address according to OS
+ if (FindEthernetInterface(ifr, fd))
+ {
+ LOG_INFO << "Linux OS" << std::endl;
+ }
+ else
+ {
+ snprintf(ifr.ifr_name, IFNAMSIZ, "br-lan");
+ if (ioctl(fd, SIOCGIFADDR, &ifr) >= 0)
+ {
+ LOG_INFO << "OpenWRT OS" << std::endl;
+ }
+ else
+ {
+ // Probably Android OS
+ LOG_INFO << "Android OS (no external IP Adress)" << std::endl;
+ host_ip = UdpServer::local_host;
+ host_broadcast_ip = UdpServer::local_host;
+ return 0;
+ }
+ }
+ host_ip = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
+
+ if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
+ {
+ LOG_DEBUG << "ERROR : Cannot get broadcast IP" << std::endl;
+ return -3;
+ }
+ host_broadcast_ip = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
+ LOG_DEBUG << "INFO : " << "host_ip=" << host_ip << std::endl;
+ LOG_DEBUG << "INFO : " << "host_broadcast_ip=" << host_broadcast_ip << std::endl;
+
+ close(fd);
+ return 0;
+}
+
+void UdpServer::LoadHostAlias()
+{
+ std::ifstream infile;
+ infile.open(host_details_file_name.c_str());
+ std::getline(infile, host_alias);
+ infile.close();
+}
+
+int UdpServer::LoadHostDetails()
+{
+ if (LoadHostAndBroadcastIps() < 0)
+ {
+ return -1;
+ }
+ LoadHostAlias();
+ return 0;
+}
diff --git a/debug-tools/remoteserver/udp_server.h b/debug-tools/remoteserver/udp_server.h
new file mode 100644
index 0000000..01855d7
--- /dev/null
+++ b/debug-tools/remoteserver/udp_server.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __udp_server_h
+#define __udp_server_h
+
+class UdpServer
+{
+public:
+ int start(int localUdpPortIn, int remoteUdpPortIn);
+ int stop();
+
+ static int SendAll(std::string message);
+ static std::string GetHostDetails() { return UdpServer::cmd_get_host_identity + UdpServer::cmd_delimiter + host_ip + UdpServer::cmd_delimiter + host_alias; }
+ static void SetHostAlias(std::string alias) { host_alias = alias; }
+
+ static const std::string host_details_file_name;
+
+private:
+ // members
+ static const std::string local_host;
+ static const std::string cmd_get_host_identity;
+ static const std::string cmd_delimiter;
+ static std::string host_broadcast_ip;
+ static std::string host_ip;
+ static std::string host_alias;
+ static int sock_in;
+ static int sock_out;
+ static int port_in;
+ static int port_out;
+
+ // methods
+ static void* start_udp_server(void* unused);
+ static int LoadHostDetails();
+ static int LoadHostIp(); // assumption: each host has only one IP address for ethernet interfaces
+ static void LoadHostAlias();
+ static int HandleRequest(char* buf);
+ static int LoadHostAndBroadcastIps();
+};
+
+#endif // udp_server_h