summaryrefslogtreecommitdiffstats
path: root/src/wth-receiver-main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wth-receiver-main.c')
-rw-r--r--src/wth-receiver-main.c306
1 files changed, 306 insertions, 0 deletions
diff --git a/src/wth-receiver-main.c b/src/wth-receiver-main.c
new file mode 100644
index 0000000..8af8eda
--- /dev/null
+++ b/src/wth-receiver-main.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*******************************************************************************
+** **
+** TARGET : linux **
+** **
+** PROJECT : waltham-receiver **
+** **
+** PURPOSE : This file handles connection with remote-client **
+** **
+*******************************************************************************/
+
+#include <signal.h>
+#include "wth-receiver-comm.h"
+
+#define MAX_EPOLL_WATCHES 2
+#define DEFAULT_TCP_PORT 34400
+
+uint16_t tcp_port = 0;
+const char *my_app_id = NULL;
+static bool *signal_int_handler_run_flag;
+
+/** Print out the application help
+ */
+static void
+usage(void)
+{
+ printf("Usage: waltham receiver [options]\n");
+ printf("Options:\n");
+ printf(" -p --port number TCP port number\n");
+ printf(" -i --app_id Specify an app_id\n");
+ printf(" -h --help Usage\n");
+}
+
+static struct option long_options[] = {
+ {"port", required_argument, 0, 'p'},
+ {"app_id", required_argument, NULL, 'i'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+};
+
+/**
+ * parse_args
+ *
+ * Parses the application arguments
+ * The arguments are parsed and saved in static structure for future use.
+ *
+ * @param argc The amount of arguments
+ * @param argv The table of arguments
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int
+parse_args(int argc, char *argv[])
+{
+ int c = -1;
+ int long_index = 0;
+
+ while ((c = getopt_long(argc, argv, "i:p:vh",
+ long_options,
+ &long_index)) != -1) {
+ switch (c) {
+ case 'i':
+ my_app_id = optarg;
+ break;
+ case 'p':
+ tcp_port = (uint16_t) atoi(optarg);
+ break;
+ case 'v':
+ printf("No verbose logs for release mode");
+ break;
+ case 'h':
+ usage();
+ return -1;
+ default:
+ wth_error("Try %s -h for more information.\n", argv[0]);
+ return -1;
+ }
+ }
+
+ if (tcp_port == 0) {
+ tcp_port = DEFAULT_TCP_PORT;
+ }
+
+
+ return 0;
+}
+
+static int
+watch_ctl(struct watch *w, int op, uint32_t events)
+{
+ struct epoll_event ee;
+
+ ee.events = events;
+ ee.data.ptr = w;
+ return epoll_ctl(w->receiver->epoll_fd, op, w->fd, &ee);
+}
+
+/**
+* listen_socket_handle_data
+*
+* Handles all incoming events on socket
+*
+* @param names struct watch *w ,uint32_t events
+* @param value pointer to watch connection it holds receiver information, Incoming events information
+* @return none
+*/
+static void
+listen_socket_handle_data(struct watch *w, uint32_t events)
+{
+ struct receiver *srv = container_of(w, struct receiver, listen_watch);
+
+ if (events & EPOLLERR) {
+ wth_error("Listening socket errored out.\n");
+ srv->running = false;
+ return;
+ }
+
+ if (events & EPOLLHUP) {
+ wth_error("Listening socket hung up.\n");
+ srv->running = false;
+ return;
+ }
+
+ if (events & EPOLLIN) {
+ receiver_accept_client(srv);
+ }
+}
+
+/**
+* receiver_mainloop
+*
+* This is the main loop, which will flush all pending clients requests and
+* listen to input events from socket
+*
+* @param names void *data
+* @param value pointer to receiver struct -
+* struct holds the client connection information
+* @return none
+*/
+static void
+receiver_mainloop(struct receiver *srv)
+{
+ struct epoll_event ee[MAX_EPOLL_WATCHES];
+ struct watch *w;
+ int count;
+ int i;
+
+ srv->running = true;
+
+ while (srv->running) {
+ /* Run any idle tasks at this point. */
+
+ receiver_flush_clients(srv);
+
+ /* Wait for events or signals */
+ count = epoll_wait(srv->epoll_fd,
+ ee, ARRAY_LENGTH(ee), -1);
+ if (count < 0 && errno != EINTR) {
+ perror("Error with epoll_wait");
+ break;
+ }
+
+ /* Handle all fds, both the listening socket
+ * (see listen_socket_handle_data()) and clients
+ * (see connection_handle_data()).
+ */
+ for (i = 0; i < count; i++) {
+ w = ee[i].data.ptr;
+ w->cb(w, ee[i].events);
+ }
+ }
+}
+
+static int
+receiver_listen(uint16_t tcp_port)
+{
+ int fd;
+ int reuse = 1;
+ struct sockaddr_in addr;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(tcp_port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse);
+
+ if (bind(fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
+ wth_error("Failed to bind to port %d", tcp_port);
+ close(fd);
+ return -1;
+ }
+
+ if (listen(fd, 1024) < 0) {
+ wth_error("Failed to listen to port %d", tcp_port);
+ close (fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+
+static void
+signal_int_handler(int signum)
+{
+ if (!*signal_int_handler_run_flag)
+ abort();
+
+ *signal_int_handler_run_flag = false;
+}
+
+static void
+set_sigint_handler(bool *running)
+{
+ struct sigaction sigint;
+
+ signal_int_handler_run_flag = running;
+ sigint.sa_handler = signal_int_handler;
+ sigemptyset(&sigint.sa_mask);
+ sigint.sa_flags = SA_RESETHAND;
+ sigaction(SIGINT, &sigint, NULL);
+}
+
+/**
+ * main
+ *
+ * waltham receiver main function, it accepts tcp port number as argument.
+ * Establishes connection on the port and listen to port for incoming connection
+ * request from waltham clients
+ *
+ * @param names argv - argument list and argc -argument count
+ * @param value tcp port number as argument
+ * @return 0 on success, -1 on error
+ */
+int main(int argc, char *argv[])
+{
+ struct receiver srv = { 0 };
+ struct client *c;
+
+ /* Get command line arguments */
+ if (parse_args(argc, argv) != 0) {
+ return -1;
+ }
+
+ set_sigint_handler(&srv.running);
+
+ wl_list_init(&srv.client_list);
+
+ srv.epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (srv.epoll_fd == -1) {
+ perror("Error on epoll_create1");
+ exit(1);
+ }
+
+ srv.listen_fd = receiver_listen(tcp_port);
+ if (srv.listen_fd < 0) {
+ perror("Error setting up listening socket");
+ exit(1);
+ }
+
+ srv.listen_watch.receiver = &srv;
+ srv.listen_watch.cb = listen_socket_handle_data;
+ srv.listen_watch.fd = srv.listen_fd;
+ if (watch_ctl(&srv.listen_watch, EPOLL_CTL_ADD, EPOLLIN) < 0) {
+ perror("Error setting up listen polling");
+ exit(1);
+ }
+
+ receiver_mainloop(&srv);
+
+ /* destroy all things */
+ wl_list_last_until_empty(c, &srv.client_list, link)
+ client_destroy(c);
+
+ close(srv.listen_fd);
+ close(srv.epoll_fd);
+
+ return 0;
+}