Skip to content
Snippets Groups Projects
Commit 0b283ce2 authored by Armin Luntzer's avatar Armin Luntzer
Browse files

import GRESB bridge prototype

parents
No related branches found
No related tags found
No related merge requests found
CC = gcc
SOURCEDIR = ./
INCLUDEDIR = ./
BUILDDIR = ./
PATH +=
CFLAGS := -O2 -W -Wall -Wextra #-Wno-unused #-Werror -pedantic
CPPFLAGS := -I$(INCLUDEDIR)
LDFLAGS := -lpthread
SOURCES := $(wildcard *.c)
OBJECTS := $(patsubst %.c, $(BUILDDIR)/%.o, $(subst $(SOURCEDIR)/,, $(SOURCES)))
TARGET := gresb_bridge
DEBUG?=1
ifeq "$(shell expr $(DEBUG) \> 1)" "1"
CFLAGS += -DDEBUGLEVEL=$(DEBUG)
else
CFLAGS += -DDEBUGLEVEL=1
endif
all: $(SOURCES)
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ -o $(TARGET)
clean:
rm -f $(TARGET)
/**
* @file gresb.c
* @author Armin Luntzer (armin.luntzer@univie.ac.at),
* @date 2020
*
* @copyright GPLv2
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* @brief GRESP protocol interface
*
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <gresb.h>
/**
* @brief set the protocol field in the header
*
* @pkt a host-to-gresb packet
* @protocol the protocol to set
*
* @returns -1 on error
*/
static int gresb_host_pkt_set_protocol(struct host_to_gresb_pkt *pkt,
uint8_t protocol)
{
if (!pkt)
return -1;
switch (protocol) {
case GRESP_FROM_HOST_DATA:
case GRESP_FROM_HOST_SET_CFG:
case GRESP_FROM_HOST_GET_CFG:
case GRESP_FROM_HOST_SEND_TIME:
pkt->protocol = protocol;
break;
default:
return -1;
}
return 0;
}
/**
* @brief set the data size field in the header
*
* @pkt a host-to-gresb packet
* @size the data size to set
*
* @note size is truncated to 24 bits
*
* @returns -1 on error
*/
static int gresb_host_pkt_set_data_size(struct host_to_gresb_pkt *pkt,
uint32_t size)
{
if (!pkt)
return -1;
if (pkt->protocol != GRESP_FROM_HOST_DATA)
return -1;
/* byte order is big endian */
pkt->size[0] = (size >> 16) & 0xff;
pkt->size[1] = (size >> 8) & 0xff;
pkt->size[2] = (size >> 0) & 0xff;
return 0;
}
/**
* @brief get the data size of a packet
*
* @pkt a host-to-gresb packet
*
* @returns the data size
*/
static size_t gresb_host_pkt_get_data_size(struct host_to_gresb_pkt *pkt)
{
size_t n = 0;
if (pkt->protocol == GRESP_FROM_HOST_DATA) {
n = (pkt->size[0] << 16) & 0xff0000;
n |= (pkt->size[1] << 8) & 0x00ff00;
n |= (pkt->size[2] << 0) & 0x0000ff;
}
return n;
}
/**
* @brief get the data size of a packet
*
* @pkt a gresb-to-host packet
*
* @returns the data size
*/
static size_t gresb_pkt_get_data_size(struct gresb_to_host_pkt *pkt)
{
size_t n;
n = (pkt->size[0] << 16) & 0xff0000;
n |= (pkt->size[1] << 8) & 0x00ff00;
n |= (pkt->size[2] << 0) & 0x0000ff;
return n;
}
/**
* @brief create a new host-to-gresb data packet
*
* @param data the data to append
* @param len the length of the data
*
* @returns the packet or NULL on error
*/
uint8_t *gresb_create_host_data_pkt(const uint8_t *data, uint32_t len)
{
struct host_to_gresb_pkt *pkt;
pkt = malloc(sizeof(struct host_to_gresb_pkt));
if (!pkt)
return NULL;
gresb_host_pkt_set_protocol(pkt, GRESP_FROM_HOST_DATA);
gresb_host_pkt_set_data_size(pkt, len);
if (data)
memcpy(pkt->data, data, len);
return (uint8_t *) pkt;
}
/**
* @brief destroy a new host-to-gresb data packet
*/
void gresb_destroy_host_data_pkt(struct host_to_gresb_pkt *pkt)
{
free(pkt);
}
/**
* @brief get the total size of a host-to-gresb data packet
*/
size_t gresb_get_host_data_pkt_size(uint8_t *buf)
{
size_t n;
if (!buf)
return 0;
n = sizeof(struct host_to_gresb_pkt);
n += gresb_host_pkt_get_data_size((struct host_to_gresb_pkt *) buf);
return n;
}
/**
* @brief get the SpW data of a gresb-to-host packet
*
* @param buf the buffer holding the packet
*
* @returns a reference to the data buffer in the packet
*/
const uint8_t *gresb_get_spw_data(const uint8_t *buf)
{
struct gresb_to_host_pkt *pkt;
pkt = (struct gresb_to_host_pkt *) buf;
if (!pkt)
return NULL;
return pkt->data;
}
/**
* @brief get the SpW data size of a gresb-to-host packet
*
* @param buf the buffer holding the packet
*
* @returns the packet data size, always 0 if argument is NULL
*/
size_t gresb_get_spw_data_size(uint8_t *buf)
{
if (!buf)
return 0;
return gresb_pkt_get_data_size((struct gresb_to_host_pkt *) buf);
}
/**
* @brief check if SpW packet contained in gresb-to-host packet was truncated
*
* @param buf the buffer holding the packet
*
* @returns 0 if not truncated or NULL, value set otherwise
*/
uint8_t gresb_get_spw_pkt_truncated(uint8_t *buf)
{
struct gresb_to_host_pkt *pkt;
pkt = (struct gresb_to_host_pkt *) buf;
if (!pkt)
return 0;
return pkt->truncated;
}
/**
* @brief check if SpW packet contained in gresb-to-host packet ended
* ended with error end of packet (EEOP) character
*
* @param buf the buffer holding the packet
*
* @returns 0 if no error or NULL, value set otherwise
*/
uint8_t gresb_get_spw_pkt_eeop(uint8_t *buf)
{
struct gresb_to_host_pkt *pkt;
pkt = (struct gresb_to_host_pkt *) buf;
if (!pkt)
return 0;
return pkt->eeop;
}
/**
* @brief get a GRESB virtual link transmit network port
*
* @param link the desired virtual link (0-5)
*
* @returns the transmit network port or -1 on error
*/
int gresb_get_virtual_link_tx_port(unsigned int link)
{
if (link > GRESB_VLINK_MAX)
return -1;
return GRESB_VLINK_TX(link);
}
/**
* @brief get a GRESB virtual link receive network port
*
* @param link the desired virtual link (0-5)
*
* @returns the receive network port or -1 on error
*/
int gresb_get_virtual_link_rx_port(unsigned int link)
{
if (link > GRESB_VLINK_MAX)
return -1;
return GRESB_VLINK_TX(link);
}
int test(void)
{
size_t i;
uint8_t *pkt;
char *b;
uint8_t buf[] = {0xa, 2, 3, 4, 5, 6, 7};
pkt = gresb_create_host_data_pkt(buf, sizeof(buf));
b = (char *) gresb_get_spw_data(pkt);
for (i = 0; i < gresb_get_spw_data_size(pkt); i++)
printf("%x:", b[i]);
return 0;
}
/**
* @file gresb.h
* @author Armin Luntzer (armin.luntzer@univie.ac.at),
* @date 2020
*
* @copyright GPLv2
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* @brief GRESP protocol interface
*/
#ifndef GRESB_H
#define GRESB_H
#include <stdint.h>
/**
* highest number of virtual link ports on the GRESB
* total 6, index starts at 0
* base port address is 3000, two ports per link: even is TX, odd is RX
*
* @see GRESB-UM v1.5.14, p. 5
*/
#define GRESB_VLINK_MAX 5
#define GRESB_VLINK_PORT_BASE 3000
#define GRESB_VLINK_TX(link) (GRESB_VLINK_PORT_BASE + (2 * (link)))
#define GRESB_VLINK_RX(link) (GRESB_VLINK_PORT_BASE + (2 * (link) + 1))
/**
* the maximum packet size exchangeable with the GRESB
*
* @see GRESB-UM v1.5.14, pp. 5
*/
#define GRESB_SNIFF_HDR_SIZE 13
#define GRESB_SPW_DATA_MAX_SIZE 0x8000000
#define GRESB_PKT_SIZE_MAX (GRESB_SPW_DATA_MAX_SIZE + GRESB_SNIFF_HDR_SIZE)
/**
* host to GRESP protocol ids
*
* @see GRESB-UM v1.5.14, pp. 8
*/
#define GRESP_FROM_HOST_DATA 0
#define GRESP_FROM_HOST_SET_CFG 1
#define GRESP_FROM_HOST_GET_CFG 2
#define GRESP_FROM_HOST_SEND_TIME 3
__extension__
struct host_to_gresb_pkt {
union {
struct {
uint8_t protocol;
uint8_t size[3];
};
uint32_t hdr;
};
uint8_t data[];
}__attribute__((packed));
__extension__
struct gresb_to_host_pkt {
union {
struct {
uint8_t reserved:6;
uint8_t truncated:1;
uint8_t eeop:1;
uint8_t size[3];
};
uint32_t hdr;
};
uint8_t data[];
}__attribute__((packed));
uint8_t *gresb_create_host_data_pkt(const uint8_t *data, uint32_t len);
void gresb_destroy_host_data_pkt(struct host_to_gresb_pkt *pkt);
size_t gresb_get_host_data_pkt_size(uint8_t *buf);
const uint8_t *gresb_get_spw_data(const uint8_t *buf);
size_t gresb_get_spw_data_size(uint8_t *buf);
uint8_t gresb_get_spw_pkt_truncated(uint8_t *buf);
uint8_t gresb_get_spw_pkt_eeop(uint8_t *buf);
int gresb_get_virtual_link_tx_port(unsigned int link);
int gresb_get_virtual_link_rx_port(unsigned int link);
#endif /* GRESB_H */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/types.h>
#include <netdb.h>
#include <pthread.h>
#include <gresb.h>
#define DEFAULT_LINK 0
#define DEFAULT_PORT 1234
#define DEFAULT_ADDR "0.0.0.0"
struct bridge_cfg {
int socket;
int n_fd;
fd_set set;
pthread_t thread_accept;
pthread_t thread_poll;
struct bridge_cfg *bridge;
struct bridge_cfg *gresb_tx;
struct bridge_cfg *gresb_rx;
};
/**
* @brief a sigint handler, should we ever need it
*/
static void sigint_handler(__attribute__((unused)) int s)
{
printf("\nCaught signal %d\n", s);
}
/**
* @brief transmits the contents of a buffer from a socket to its peer
*/
static int send_all(int sock_fd, const unsigned char *buf, int len)
{
int n;
while (len) {
printf("len: %d\n", len);
n = send(sock_fd, buf, len, 0);
if (n == -1) {
perror("send_all");
return len;
}
len -= n;
buf += n;
}
return len;
}
/**
* @brief create socket address from url
*
* @note url expected to be <ip>:<port>
*/
static struct sockaddr_in sockaddr_from_url(const char *url)
{
char *str;
struct sockaddr_in sockaddr;
str = (char *) malloc(strlen(url));
if (!str) {
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(str, url);
sockaddr.sin_addr.s_addr = inet_addr(strtok(str, ":"));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(atoi(strtok(NULL, ":")));
free(str);
return sockaddr;
}
/**
* @brief establish a client socket connection
*/
static int connect_client_socket(const char *url, struct bridge_cfg *cfg)
{
int fd;
int ret;
struct sockaddr_in server;
server = sockaddr_from_url(url);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
return fd;
ret = connect(fd, (struct sockaddr *) &server, sizeof(server));
if (ret < 0)
return ret;
FD_ZERO(&cfg->set);
FD_SET(fd, &cfg->set);
/* update maximum file descriptor number */
if (fd > cfg->n_fd)
cfg->n_fd = fd;
return fd;
}
/**
* @brief bind a socket for a listening server
*
* @note url expected to be <ip>:<port>
*/
static int bind_server_socket(const char* url, struct bridge_cfg *cfg)
{
int fd;
int endpoint;
int optval = 1;
struct sockaddr_in server;
server = sockaddr_from_url(url);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
printf("Socket creation failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
FD_ZERO(&cfg->set);
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
endpoint = bind(fd, (struct sockaddr *) &server, sizeof(server));
if (endpoint < 0) {
close(fd);
printf("could not bind endpoint %s: %s\n", url, strerror(errno));
exit(EXIT_FAILURE);
}
if (listen(fd, 0) < 0) {
close(fd);
perror("listen");
exit(EXIT_FAILURE);
}
printf("Listening on %s\n", url);
return fd;
}
/**
* @brief thread function accepting incoming connections on a server socket
*/
static void *accept_connections(void *data)
{
int fd = 0;
struct bridge_cfg *cfg;
struct sockaddr_storage client_addr;
socklen_t client_addr_len;
cfg = (struct bridge_cfg *) data;
client_addr_len = sizeof(client_addr);
while(1) {
fd = accept(cfg->socket, (struct sockaddr *) &client_addr,
&client_addr_len);
if (fd < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
printf("New incoming connection\n");
FD_SET(fd, &cfg->set);
/* update maximum file descriptor number */
if (fd > cfg->n_fd)
cfg->n_fd = fd;
}
}
/**
* @brief send user packets to the GRESB
*/
static int usr_pkt_to_gresb(int fd, struct bridge_cfg *cfg)
{
int ret;
ssize_t recv_bytes;
unsigned char *recv_buffer;
recv_buffer = malloc(GRESB_PKT_SIZE_MAX);
recv_bytes = recv(fd, recv_buffer, GRESB_PKT_SIZE_MAX, 0);
for (int i = 0; i < recv_bytes; i++)
printf("%c", recv_buffer[i]);
/* we SEND to the TX port */
ret = send_all(cfg->gresb_tx->socket,
recv_buffer, recv_bytes);
if (ret == -1)
perror("send");
free(recv_buffer);
return recv_bytes;
}
/**
* @brief thread function polling a network socket
*/
static void *poll_socket(void *data)
{
int fd;
fd_set r_set;
struct timeval to;
struct bridge_cfg *cfg;
if (!data)
return NULL;
cfg = (struct bridge_cfg *) data;
/* wait 10 ms in select() */
to.tv_sec = 0;
to.tv_usec = 10000;
while (1) {
r_set = cfg->set;
/* select ready sockets */
if (select((cfg->n_fd + 1), &r_set, NULL, NULL, &to) <= 0) {
usleep(1000);
continue;
}
for (fd = 0; fd <= cfg->n_fd; fd++) {
if (!FD_ISSET(fd, &r_set))
continue;
/* clean up disconnected socket */
if (usr_pkt_to_gresb(fd, cfg) <= 0) {
FD_CLR(fd, &cfg->set);
close(fd);
}
}
}
return NULL;
}
static int gresb_pkt_to_usr(int fd, struct bridge_cfg *cfg)
{
int ret;
ssize_t recv_bytes;
uint8_t *recv_buffer;
recv_buffer = malloc(GRESB_PKT_SIZE_MAX);
recv_bytes = recv(fd, recv_buffer, GRESB_PKT_SIZE_MAX, 0);
for (int i = 0; i < recv_bytes; i++)
printf("%c", recv_buffer[i]);
for(int fdc = 0; fdc <= cfg->bridge->n_fd; fdc++) {
if (!FD_ISSET(fdc, &cfg->bridge->set))
continue;
ret = send_all(fdc,
gresb_get_spw_data(recv_buffer),
gresb_get_spw_data_size(recv_buffer));
printf("size: %ld\n", gresb_get_spw_data_size(recv_buffer));
if (ret == -1) {
perror("send");
close(fdc);
FD_CLR(fdc, &cfg->bridge->set);
}
}
free(recv_buffer);
return recv_bytes;
}
/**
* @brief thread function polling a GRESB network socket
*/
static void *poll_socket_gresb(void *data)
{
int fd;
fd_set r_set;
struct timeval to;
struct bridge_cfg *cfg;
if (!data)
return NULL;
cfg = (struct bridge_cfg *) data;
/* wait 10 ms in select() */
to.tv_sec = 0;
to.tv_usec = 10000;
while (1) {
r_set = cfg->set;
/* select ready sockets */
if (select((cfg->n_fd + 1), &r_set, NULL, NULL, &to) <= 0) {
usleep(1000);
continue;
}
for (fd = 0; fd <= cfg->n_fd; fd++) {
if (!FD_ISSET(fd, &r_set))
continue;
/* clean up disconnected socket */
if (gresb_pkt_to_usr(fd, cfg) <= 0) {
FD_CLR(fd, &cfg->set);
close(fd);
}
}
}
return NULL;
}
int main(int argc, char **argv)
{
char url[256];
char host[128];
char gresb[128];
int opt;
unsigned int ret;
unsigned int port;
unsigned int link;
struct addrinfo *res;
struct sigaction SIGINT_handler;
enum {SERVER, CLIENT} mode;
struct bridge_cfg bridge;
struct bridge_cfg gresb_tx;
struct bridge_cfg gresb_rx;
bzero(&bridge, sizeof(struct bridge_cfg));
bzero(&gresb_tx, sizeof(struct bridge_cfg));
bzero(&gresb_rx, sizeof(struct bridge_cfg));
/**
* defaults
*/
gresb[0] = '\0';
link = DEFAULT_LINK;
mode = SERVER;
port = DEFAULT_PORT;
sprintf(host, "%s", DEFAULT_ADDR);
bridge.gresb_tx = &gresb_tx;
bridge.gresb_rx = &gresb_rx;
gresb_tx.bridge = &bridge;
gresb_rx.bridge = &bridge;
while ((opt = getopt(argc, argv, "G:L:p:s:r:h")) != -1) {
switch (opt) {
case 'G':
ret = getaddrinfo(optarg, NULL, NULL, &res);
if (ret) {
printf("error in getaddrinfo: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
sprintf(gresb, "%s", optarg);
while (res) {
if (res->ai_family == AF_INET) {
inet_ntop(res->ai_family,
&((struct sockaddr_in *) res->ai_addr)->sin_addr,
gresb, sizeof(host));
break; /* just take the first one and hope for the best */
}
res = res->ai_next;
}
freeaddrinfo(res);
break;
case 'L':
link = strtol(optarg, NULL, 0);
break;
case 'p':
port = strtol(optarg, NULL, 0);
break;
case 's':
ret = getaddrinfo(optarg, NULL, NULL, &res);
if (ret) {
printf("error in getaddrinfo: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
sprintf(host, "%s", strtok(optarg, ":"));
while (res) {
if (res->ai_family == AF_INET) {
inet_ntop(res->ai_family,
&((struct sockaddr_in *) res->ai_addr)->sin_addr,
host, sizeof(host));
break; /* just take the first one and hope for the best */
}
res = res->ai_next;
}
freeaddrinfo(res);
break;
case 'r':
mode = CLIENT;
/* yes, it's totally redundant... */
sprintf(host, "%s", strtok(optarg, ":"));
port = strtol(strtok(NULL, ":"), NULL, 0);
ret = getaddrinfo(optarg, NULL, NULL, &res);
if (ret) {
printf("error in getaddrinfo: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
while (res) {
if (res->ai_family == AF_INET) {
inet_ntop(res->ai_family,
&((struct sockaddr_in *) res->ai_addr)->sin_addr,
host, sizeof(host));
break;
}
res = res->ai_next;
}
freeaddrinfo(res);
break;
case 'h':
default:
printf("\nUsage: %s [OPTIONS]\n", argv[0]);
printf(" -G ADDRESS address of the GRESP\n");
printf(" -L LINK_ID link id to use on GRESP\n");
printf(" -p PORT local port number (default %d)\n", port);
printf(" -s ADDRESS local source address (default: %s\n", url);
printf(" -r ADDRESS:PORT client mode: address and port of remote target\n");
printf(" -h, --help print this help and exit\n");
printf("\n");
exit(0);
}
}
/**
* set up GRESB connection
*/
if (!strlen(gresb)) {
printf("Please specify GRESB host address\n");
exit(EXIT_FAILURE);
}
if (link > GRESB_VLINK_MAX) {
printf("GRESB link must be in range 0-%d\n", GRESB_VLINK_MAX);
exit(EXIT_FAILURE);
}
/* TX port on the GRESB (i.e. sent by us to NET routed to SPW) */
sprintf(url, "%s:%d", gresb, GRESB_VLINK_TX(link));
gresb_tx.socket = connect_client_socket(url, &gresb_tx);
if (gresb_tx.socket < 0) {
printf("Failed to connect to %s\n", url),
exit(EXIT_FAILURE);
}
/* the GRESB answers to configuration requests on the TX port */
ret = pthread_create(&gresb_tx.thread_poll, NULL,
poll_socket_gresb, &gresb_tx);
if (ret) {
printf("Epic fail in pthread_create: %s\n", strerror(ret));
exit(EXIT_FAILURE);
}
printf("Connected to GRESB TX\n");
/* RX port on the GRESB (i.e. route from SPW to NET, received by us */
sprintf(url, "%s:%d", gresb, GRESB_VLINK_RX(link));
gresb_rx.socket = connect_client_socket(url, &gresb_rx);
if (gresb_rx.socket < 0) {
printf("Failed to connect to %s\n", url),
exit(EXIT_FAILURE);
}
ret = pthread_create(&gresb_rx.thread_poll, NULL,
poll_socket_gresb, &gresb_rx);
if (ret) {
printf("Epic fail in pthread_create: %s\n", strerror(ret));
exit(EXIT_FAILURE);
}
printf("Connected to GRESB RX\n");
/**
* set up our network
*/
sprintf(url, "%s:%d", host, port);
if (mode == SERVER) {
bridge.n_fd = 0;
bridge.socket = bind_server_socket(url, &bridge);
ret = pthread_create(&bridge.thread_accept, NULL,
accept_connections,
&bridge);
if (ret) {
printf("Epic fail in pthread_create: %s\n", strerror(ret));
exit(EXIT_FAILURE);
}
ret = pthread_create(&bridge.thread_poll, NULL, poll_socket, &bridge);
if (ret) {
printf("Epic fail in pthread_create: %s\n", strerror(ret));
exit(EXIT_FAILURE);
}
printf("Started in SERVER mode\n");
} else {
bridge.socket = connect_client_socket(url, &bridge);
if (bridge.socket < 0) {
printf("Failed to connect to %s\n", url),
exit(EXIT_FAILURE);
}
ret = pthread_create(&bridge.thread_poll, NULL, poll_socket, &bridge);
if (ret) {
printf("Epic fail in pthread_create: %s\n", strerror(ret));
exit(EXIT_FAILURE);
}
printf("Started in CLIENT mode\n");
}
/**
* catch ctrl+c
*/
SIGINT_handler.sa_handler = sigint_handler;
sigemptyset(&SIGINT_handler.sa_mask);
SIGINT_handler.sa_flags = 0;
sigaction(SIGINT, &SIGINT_handler, NULL);
/**
* wait for signal, then clean up
*/
printf("Ready...\n");
pause();
if (bridge.thread_accept)
pthread_cancel(bridge.thread_accept);
if (bridge.thread_accept)
pthread_cancel(bridge.thread_accept);
if (gresb_tx.thread_poll)
pthread_cancel(gresb_tx.thread_poll);
if (gresb_rx.thread_poll)
pthread_cancel(gresb_rx.thread_poll);
if (bridge.socket)
close(bridge.socket);
if (gresb_rx.socket)
close(gresb_rx.socket);
if (gresb_tx.socket)
close(gresb_tx.socket);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment