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/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
+}