blob: d2f2dfc9908ab101e0bbe6767d738b6f9554e8fc [file] [log] [blame]
/*
* Copyright (c) 2017 FH Dortmund and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Description:
* Socket server for rover-web to rover-app communication
*
* Contributors:
* M.Ozcelikors <mozcelikors@gmail.com>, created 26.10.2017
*
*/
#include <tasks/socket_server_task.h>
#include <string.h>
#include <ctime>
#include <unistd.h>
#include <libraries/timing/timing.h>
#include <interfaces.h>
#include <pthread.h>
#include <signal.h>
/* Socket defs header */
#include <socket_settings.h>
/* json-cpp library */
#include <json/json.h>
#include <roverapp.h>
/* Global definitions */
int roverapp_listen_sockfd;
int newroverapp_listen_sockfd;
/* If returns nonzero -> socket has a non zero error status */
int checkServerSocketStatus (int socket_fd)
{
//TODO: Fix this function!
int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);
return error;
}
void parseJSONData (char *server_buffer)
{
Json::Value root;
Json::Reader reader;
bool parsingSuccessful = reader.parse( server_buffer, root );
if ( !parsingSuccessful )
{
std::cout << "Failed to parse" << reader.getFormattedErrorMessages();
}
if (root["rover_dtype"].asString() == "control")
{
// Update shared variable
pthread_mutex_lock(&keycommand_lock);
//Take only the first char - since interface uses 1 char only
keycommand_shared = root["data"]["command"].asString()[0];
//printf("RECV=%c\n",keycommand_shared);
pthread_mutex_unlock(&keycommand_lock);
}
else if (root["rover_dtype"].asString() == "speed")
{
// Update shared variable
pthread_mutex_lock(&speed_lock);
speed_shared = root["data"]["speed"].asInt();
//printf("RECV=%d\n",speed_shared);
pthread_mutex_unlock(&speed_lock);
}
else
{
std::cout << "Unable to parse in socket_server_task.cpp" << std::endl;
}
}
void Socket_Server_Task_Terminator (int dummy)
{
close(roverapp_listen_sockfd);
close(newroverapp_listen_sockfd);
running_flag = 0;
}
void *Socket_Server_Task(void * arg)
{
timing socket_server_task_tmr;
socket_server_task_tmr.setTaskID("Socket_Server_Task");
socket_server_task_tmr.setDeadline(0.05);
socket_server_task_tmr.setPeriod(0.05);
/* Add termination signal handler to properly close socket */
signal(SIGINT, Socket_Server_Task_Terminator);
signal(SIGTERM, Socket_Server_Task_Terminator);
signal(SIGKILL, Socket_Server_Task_Terminator);
socklen_t clilen;
char server_buffer[JSON_DATA_BUFSIZE];
struct sockaddr_in serv_addr, cli_addr;
int n;
int true_ = 1;
int client_connected_flag = 0;
/* First call to socket() function */
roverapp_listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (roverapp_listen_sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
/* Handle re-binding problems */
setsockopt(roverapp_listen_sockfd, SOL_SOCKET,SO_REUSEADDR,&true_,sizeof(int));
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(BINDING_HOSTNAME);
serv_addr.sin_port = htons(ROVERAPP_LISTEN_PORT);
memset(serv_addr.sin_zero, '\0', sizeof serv_addr.sin_zero);
/* Now bind the host address using bind() call.*/
if (bind(roverapp_listen_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
/* Now start listening for the clients, here process will
* go in sleep mode and will wait for the incoming connection
*/
listen(roverapp_listen_sockfd,5); // Max 5 connections queued
clilen = sizeof(cli_addr);
while(running_flag)
{
socket_server_task_tmr.recordStartTime();
socket_server_task_tmr.calculatePreviousSlackTime();
//Task content starts here -----------------------------------------------
/* Handle client acception or re-acception */
/* Checking if client socket is available */
if (checkServerSocketStatus(newroverapp_listen_sockfd)!=0)
{
client_connected_flag = 0;
}
if (client_connected_flag == 0)
{
/* If no client is connected currently */
/* Accept actual connection from the client */
newroverapp_listen_sockfd = accept(roverapp_listen_sockfd, (struct sockaddr *)&cli_addr, &clilen);
if (newroverapp_listen_sockfd < 0) {
perror("ERROR on accept -> newroverapp_listen_sockfd");
exit(1);
}
else
{
printf ("Client connected to newroverapp_listen_sockfd \n");
client_connected_flag = 1;
}
}
else
{
/* If a client is connected */
/* If connection is established then start communicating */
size_t buf_idx = 0;
/* Read one char at a time until the EOF_STR "\r\n" is reached */
while (buf_idx < JSON_DATA_BUFSIZE)
{
if ( 1 == read(newroverapp_listen_sockfd, &server_buffer[buf_idx], 1))
{
if (buf_idx > 0 && LINE_FEED == server_buffer[buf_idx] && CARRIAGE_RETURN == server_buffer[buf_idx - 1])
{
break;
}
buf_idx++;
}
else
{
/* Very important approach to have re-usable socket server */
/* Client connection status is determined by exit status of read */
printf ("Client disconnected!");
client_connected_flag = 0;
break;
}
}
// Received buffer
//printf ("buffer: %s\n",server_buffer);
/* Remove \r\n from at the end of the string */
server_buffer[buf_idx] = '\0';
server_buffer[buf_idx-1] = '\0';
/* Parse the JSON data, and update global variables */
parseJSONData(server_buffer);
}
//Task content ends here -------------------------------------------------
socket_server_task_tmr.recordEndTime();
socket_server_task_tmr.calculateExecutionTime();
socket_server_task_tmr.calculateDeadlineMissPercentage();
socket_server_task_tmr.incrementTotalCycles();
pthread_mutex_lock(&socket_server_task_ti_l);
socket_server_task_ti.deadline = socket_server_task_tmr.getDeadline();
socket_server_task_ti.deadline_miss_percentage = socket_server_task_tmr.getDeadlineMissPercentage();
socket_server_task_ti.execution_time = socket_server_task_tmr.getExecutionTime();
socket_server_task_ti.period = socket_server_task_tmr.getPeriod();
socket_server_task_ti.prev_slack_time = socket_server_task_tmr.getPrevSlackTime();
socket_server_task_ti.task_id = socket_server_task_tmr.getTaskID();
socket_server_task_ti.start_time = socket_server_task_tmr.getStartTime();
socket_server_task_ti.end_time = socket_server_task_tmr.getEndTime();
pthread_mutex_unlock(&socket_server_task_ti_l);
socket_server_task_tmr.sleepToMatchPeriod();
}
}