receiver: Introduce waltham-receiver
[src/weston-ivi-plugins.git] / waltham-receiver / src / wth-receiver-main.c
1 /*
2  * Copyright © 2019 Advanced Driver Information Technology GmbH
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 /*******************************************************************************
27 **                                                                            **
28 **  TARGET    : linux                                                         **
29 **                                                                            **
30 **  PROJECT   : waltham-receiver                                              **
31 **                                                                            **
32 **  PURPOSE   : This file handles connection with remote-client               **
33 **                                                                            **
34 *******************************************************************************/
35
36 #include <signal.h>
37 #include "wth-receiver-comm.h"
38
39 #define MAX_EPOLL_WATCHES 2
40
41 uint16_t tcp_port;
42
43 /** Print out the application help
44  */
45 static void usage(void)
46 {
47     printf("Usage: waltham receiver [options]\n");
48     printf("Options:\n");
49     printf("  -p --port number          TCP port number\n");
50     printf("  -h --help                 Usage\n");
51     printf("  -v --verbose              Set verbose flag (Default:%d)\n", get_verbosity());
52 }
53
54 static struct option long_options[] = {
55     {"port",     required_argument,  0,  'p'},
56     {"verbose",  no_argument,    0,  'v'},
57     {"help",     no_argument,    0,  'h'},
58     {0,          0,              0,   0}
59 };
60
61 /**
62  * parse_args
63  *
64  * Parses the application arguments
65  * The arguments are parsed and saved in static structure for future use.
66  *
67  * @param argc The amount of arguments
68  * @param argv The table of arguments
69  *
70  * @return 0 on success, -1 otherwise
71  */
72 static int parse_args(int argc, char *argv[])
73 {
74     int c = -1;
75     int long_index = 0;
76
77     while ((c = getopt_long(argc,
78                             argv,
79                             "p:vh",
80                             long_options,
81                             &long_index)) != -1)
82     {
83         switch (c)
84         {
85         case 'p':
86             tcp_port = atoi(optarg);
87             break;
88         case 'v':
89 #if DEBUG
90             set_verbosity(1);
91 #else
92             printf("No verbose logs for release mode");
93 #endif
94             break;
95         case 'h':
96             usage();
97             return -1;
98         default:
99             wth_error("Try %s -h for more information.\n", argv[0]);
100             return -1;
101         }
102     }
103
104     if (tcp_port == 0)
105     {
106         wth_error("TCP port not set \n");
107         wth_error("Try %s -h for more information.\n", argv[0]);
108         return -1;
109     }
110
111     return 0;
112 }
113
114 static int
115 watch_ctl(struct watch *w, int op, uint32_t events)
116 {
117     wth_verbose("%s >>> \n",__func__);
118     struct epoll_event ee;
119
120     ee.events = events;
121     ee.data.ptr = w;
122     wth_verbose(" <<< %s \n",__func__);
123     return epoll_ctl(w->receiver->epoll_fd, op, w->fd, &ee);
124 }
125
126 /**
127 * listen_socket_handle_data
128 *
129 * Handles all incoming events on socket
130 *
131 * @param names        struct watch *w ,uint32_t events
132 * @param value        pointer to watch connection it holds receiver information, Incoming events information
133 * @return             none
134 */
135 static void
136 listen_socket_handle_data(struct watch *w, uint32_t events)
137 {
138     wth_verbose("%s >>> \n",__func__);
139     struct receiver *srv = container_of(w, struct receiver, listen_watch);
140
141     if (events & EPOLLERR) {
142         wth_error("Listening socket errored out.\n");
143         srv->running = false;
144
145         return;
146     }
147
148     if (events & EPOLLHUP) {
149         wth_error("Listening socket hung up.\n");
150         srv->running = false;
151
152         return;
153     }
154
155     if (events & EPOLLIN)
156     {
157         wth_verbose("EPOLLIN evnet received. \n");
158         receiver_accept_client(srv);
159     }
160     wth_verbose(" <<< %s \n",__func__);
161 }
162
163 /**
164 * receiver_mainloop
165 *
166 * This is the main loop, which will flush all pending clients requests and
167 * listen to input events from socket
168 *
169 * @param names        void *data
170 * @param value        pointer to receiver struct -
171 *                     struct holds the client connection information
172 * @return             none
173 */
174 static void
175 receiver_mainloop(struct receiver *srv)
176 {
177     wth_verbose("%s >>> \n",__func__);
178
179     struct epoll_event ee[MAX_EPOLL_WATCHES];
180     struct watch *w;
181     int count;
182     int i;
183
184     srv->running = true;
185
186     while (srv->running) {
187         /* Run any idle tasks at this point. */
188
189         receiver_flush_clients(srv);
190
191         /* Wait for events or signals */
192         count = epoll_wait(srv->epoll_fd,
193                    ee, ARRAY_LENGTH(ee), -1);
194         if (count < 0 && errno != EINTR) {
195             perror("Error with epoll_wait");
196             break;
197         }
198
199         /* Handle all fds, both the listening socket
200          * (see listen_socket_handle_data()) and clients
201          * (see connection_handle_data()).
202          */
203         for (i = 0; i < count; i++) {
204             w = ee[i].data.ptr;
205             w->cb(w, ee[i].events);
206         }
207     }
208     wth_verbose(" <<< %s \n",__func__);
209 }
210
211 static int
212 receiver_listen(uint16_t tcp_port)
213 {
214     wth_verbose("%s >>> \n",__func__);
215     int fd;
216     int reuse = 1;
217     struct sockaddr_in addr;
218
219     fd = socket(AF_INET, SOCK_STREAM, 0);
220
221     memset(&addr, 0, sizeof(addr));
222     addr.sin_family = AF_INET;
223     addr.sin_port = htons(tcp_port);
224     addr.sin_addr.s_addr = htonl(INADDR_ANY);
225
226     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse);
227
228     if (bind(fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
229         wth_error("Failed to bind to port %d", tcp_port);
230         close(fd);
231         return -1;
232     }
233
234     if (listen(fd, 1024) < 0) {
235         wth_error("Failed to listen to port %d", tcp_port);
236         close (fd);
237         return -1;
238     }
239
240     wth_verbose(" <<< %s \n",__func__);
241     return fd;
242 }
243
244 static bool *signal_int_handler_run_flag;
245
246 static void
247 signal_int_handler(int signum)
248 {
249     wth_verbose("%s >>> \n",__func__);
250     if (!*signal_int_handler_run_flag)
251         abort();
252
253     *signal_int_handler_run_flag = false;
254     wth_verbose(" <<< %s \n",__func__);
255 }
256
257 static void
258 set_sigint_handler(bool *running)
259 {
260     wth_verbose("%s >>> \n",__func__);
261     struct sigaction sigint;
262
263     signal_int_handler_run_flag = running;
264     sigint.sa_handler = signal_int_handler;
265     sigemptyset(&sigint.sa_mask);
266     sigint.sa_flags = SA_RESETHAND;
267     sigaction(SIGINT, &sigint, NULL);
268     wth_verbose(" <<< %s \n",__func__);
269 }
270
271 /**
272 * main
273 *
274 * waltham receiver main function, it accepts tcp port number as argument.
275 * Establishes connection on the port and listen to port for incoming connection
276 * request from waltham clients
277 *
278 * @param names        argv - argument list and argc -argument count
279 * @param value        tcp port number as argument
280 * @return             0 on success, -1 on error
281 */
282 int
283 main(int argc, char *argv[])
284 {
285     struct receiver srv = { 0 };
286     struct client *c;
287
288     wth_verbose("%s >>> \n",__func__);
289
290     /* Get command line arguments */
291     if (parse_args(argc, argv) != 0)
292     {
293         return -1;
294     }
295
296     set_sigint_handler(&srv.running);
297
298     wl_list_init(&srv.client_list);
299
300     srv.epoll_fd = epoll_create1(EPOLL_CLOEXEC);
301     if (srv.epoll_fd == -1) {
302         perror("Error on epoll_create1");
303         exit(1);
304     }
305
306     srv.listen_fd = receiver_listen(tcp_port);
307     if (srv.listen_fd < 0) {
308         perror("Error setting up listening socket");
309         exit(1);
310     }
311
312     srv.listen_watch.receiver = &srv;
313     srv.listen_watch.cb = listen_socket_handle_data;
314     srv.listen_watch.fd = srv.listen_fd;
315     if (watch_ctl(&srv.listen_watch, EPOLL_CTL_ADD, EPOLLIN) < 0) {
316         perror("Error setting up listen polling");
317         exit(1);
318     }
319
320     wth_verbose("Waltham receiver listening on TCP port %u...\n",tcp_port);
321
322
323     receiver_mainloop(&srv);
324
325     /* destroy all things */
326     wl_list_last_until_empty(c, &srv.client_list, link)
327             client_destroy(c);
328
329     close(srv.listen_fd);
330     close(srv.epoll_fd);
331
332     wth_verbose(" <<< %s \n",__func__);
333     return 0;
334 }