Skip to content

Instantly share code, notes, and snippets.

@lorsi96
Last active August 11, 2021 23:31
Show Gist options
  • Save lorsi96/aaaa185ccbc849a53e3ac04697805e89 to your computer and use it in GitHub Desktop.
Save lorsi96/aaaa185ccbc849a53e3ac04697805e89 to your computer and use it in GitHub Desktop.
[Sistemas Operativos de Propósito General] TP II
/**
* @file main.c
* @author Lucas Orsi (lorsi@itba.edu.ar)
* @version 0.1
* @date 2021-08-07
*
* @copyright Copyright (c) 2021
*
*/
/* ****************************************************************************************************************** */
/* Includes */
/* ****************************************************************************************************************** */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netdb.h>
#include "SerialManager.h"
/* ****************************************************************************************************************** */
/* Macros */
/* ****************************************************************************************************************** */
#define SOPG_ASSERT(exp, msg) \
{ \
if ((exp) <= -1) { \
perror("[ERROR]" msg "\r\n"); \
if (s) close(s); \
if (u) serial_close(); \
exit(1); \
} \
\
}
#define S_LOOP_ASSERT(exp, msg) \
{ \
if ((exp) <= -1) { \
if(!show_must_go_on) break; \
perror("[ERROR]" msg "\r\n"); \
if (s) close(s); \
if (u) serial_close(); \
exit(1); \
} \
\
}
#define LOGD(format, ...) \
DEBUG&& fprintf(stdout, "[DEBUG]: " format "\r\n", ##__VA_ARGS__);
/* ****************************************************************************************************************** */
/* Constants */
/* ****************************************************************************************************************** */
#define ISERVICE_PORT 10000
#define BUFFER_SIZE 128
#define BACKLOG 10
#define LOALHOST "127.0.0.1"
#define SW_MSG_SIZE 9
#define EMPTY_CHAR 32
#define UART_BPS 115200
#define UART_USB1 1
#define UART_SLEEP_US 3000
#define UART_SOM '>'
#define DEBUG true
/* ****************************************************************************************************************** */
/* Private Variables */
/* ****************************************************************************************************************** */
static bool show_must_go_on = true;
static int newfd;
static int s;
static int u;
pthread_mutex_t socket_writeable_lock = PTHREAD_MUTEX_INITIALIZER;
/* ****************************************************************************************************************** */
/* Private Functions */
/* ****************************************************************************************************************** */
static inline void forward_msg_to_socket(char* buffer, size_t len) {
LOGD("UART is about to write to the Socket");
pthread_mutex_lock(&socket_writeable_lock);
SOPG_ASSERT(write(newfd, buffer, len), "Error writing to Socket");
pthread_mutex_unlock(&socket_writeable_lock);
LOGD("UART wrote to the Socket and unlocked it");
}
static void* uart_thread(void* _) {
static const char MSG_LEN = 7;
static char uartbuff[BUFFER_SIZE] = {EMPTY_CHAR};
static uint8_t sz;
for (;;) {
if (sz = serial_receive(uartbuff, BUFFER_SIZE)) {
LOGD("(UART)\tRead(%dby): %s", sz, uartbuff);
if (sz != SW_MSG_SIZE) {
perror("Ignorning invalid msg");
continue;
}
forward_msg_to_socket(uartbuff, MSG_LEN);
}
usleep(UART_SLEEP_US);
}
}
static void signals_handler(int signal) {
show_must_go_on = false;
}
static void block_signals(bool block) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGTERM);
SOPG_ASSERT(pthread_sigmask(block ? SIG_BLOCK : SIG_UNBLOCK, &set, NULL),
"Unable to block/unblock Signals");
}
/* ****************************************************************************************************************** */
/* Main */
/* ****************************************************************************************************************** */
int main() {
socklen_t addr_len;
struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
pthread_t t1;
char buffer[BUFFER_SIZE];
struct sigaction sa;
sa.sa_handler = signals_handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
SOPG_ASSERT(sigaction(SIGINT, &sa, NULL), "Failed at Configuring SIGINT handler");
SOPG_ASSERT(sigaction(SIGTERM, &sa, NULL), "Failed at Configuring SIGTERM handler" );
LOGD("Initializing UART /dev/ttyUSB%d", UART_USB1);
SOPG_ASSERT(u = serial_open(UART_USB1, UART_BPS), "Failed to init UART");
LOGD("UART initialized");
// Creamos socket
SOPG_ASSERT(s = socket(AF_INET, SOCK_STREAM, 0), "Failed to create Socket");
bzero((char*)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(ISERVICE_PORT);
SOPG_ASSERT(inet_pton(AF_INET, LOALHOST, &(serveraddr.sin_addr)),
"Invalid server IP");
// Abrimos puerto con bind()
if (bind(s, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) == -1) {
close(s);
perror("listener: bind");
return 1;
}
LOGD("Socket bound");
SOPG_ASSERT(listen(s, BACKLOG), "Sockets listening error");
LOGD("Socket Listening");
// We lock the Socket Mutex until it's ready to be written -- a client is connected.
pthread_mutex_lock(&socket_writeable_lock);
LOGD("Socket Locked -- No one can write to it! (internally)");
block_signals(/*block=*/true);
SOPG_ASSERT(pthread_create(&t1, NULL, uart_thread, NULL),
"Failed to create UART Thread");
block_signals(/*block=*/false);
LOGD("UART listening to incoming serial packets");
while (show_must_go_on) {
int n;
char ipClient[32];
addr_len = sizeof(struct sockaddr_in);
S_LOOP_ASSERT(newfd = accept(s, (struct sockaddr*)&clientaddr, &addr_len),
"Accept Error");
inet_ntop(AF_INET, &(clientaddr.sin_addr), ipClient, sizeof(ipClient));
LOGD("Socket accepted a new client");
// Now we allow other processes to write to our socket.
pthread_mutex_unlock(&socket_writeable_lock);
LOGD("Socket Unlocked -- UART Thread can write to the Socket now");
while ((n = read(newfd, buffer, BUFFER_SIZE)) > 0) {
if(!show_must_go_on) break;
buffer[n] = '\0';
LOGD("(Socket)Read(%dby): %s", n, buffer);
serial_send(buffer, n);
}
LOGD("Socket lost a client");
// We block the socket until a new client is accepted.
pthread_mutex_lock(&socket_writeable_lock);
LOGD("Socket Locked -- There're no clients to send data to");
S_LOOP_ASSERT(n, "Error reading message in Socket");
}
LOGD("Terminating program");
LOGD("Cancelling UART Thread");
pthread_cancel(t1);
pthread_join(t1, NULL);
LOGD("Closing UART");
serial_close();
LOGD("Closing Socket");
close(newfd);
close(s);
LOGD("That's all folks");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment