]> git.meshlink.io Git - meshlink/blob - test/blackbox/common/mesh_event_handler.c
0f331d67e00690d787c3c2c00121ae843124ecd7
[meshlink] / test / blackbox / common / mesh_event_handler.c
1 /*
2     mesh_event_handler.c -- handling of mesh events API
3     Copyright (C) 2018  Guus Sliepen <guus@meshlink.io>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <sys/types.h>
25 #include <net/if.h>
26 #include <sys/ioctl.h>
27 #include <sys/socket.h>
28 #include <stdbool.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <fcntl.h>
32 #include <time.h>
33 #include "mesh_event_handler.h"
34
35 #define SERVER_LISTEN_PORT "9000" /* Port number that is binded with mesh event server socket */
36
37 // TODO: Implement mesh event handling with reentrant functions(if required).
38 static struct sockaddr_in server_addr;
39 static int client_fd = -1;
40 static int server_fd = -1;
41
42 char *mesh_event_sock_create(const char *if_name) {
43         struct sockaddr_in server;
44         char *ip;
45         struct ifreq req_if;
46         struct sockaddr_in *resp_if_addr;
47
48         if(if_name == NULL) {
49                 return NULL;
50         }
51
52         server_fd = socket(AF_INET, SOCK_DGRAM, 0);
53
54         if(server_fd < 0) {
55                 perror("socket");
56         }
57
58         assert(server_fd >= 0);
59
60         int reuse = 1;
61         assert(setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) != -1);
62
63         memset(&req_if, 0, sizeof(req_if));
64         req_if.ifr_addr.sa_family = AF_INET;
65         strncpy(req_if.ifr_name, if_name, IFNAMSIZ - 1);
66         assert(ioctl(server_fd, SIOCGIFADDR, &req_if) != -1);
67         resp_if_addr = (struct sockaddr_in *) & (req_if.ifr_addr);
68
69         memset(&server, 0, sizeof(server));
70         server.sin_family = AF_INET;
71         server.sin_addr   = resp_if_addr->sin_addr;
72         server.sin_port   = htons(atoi(SERVER_LISTEN_PORT));
73         assert(bind(server_fd, (struct sockaddr *) &server, sizeof(struct sockaddr)) != -1);
74
75         assert(ip = malloc(30));
76         strncpy(ip, inet_ntoa(resp_if_addr->sin_addr), 20);
77         strcat(ip, ":");
78         strcat(ip, SERVER_LISTEN_PORT);
79
80         return ip;
81 }
82
83 void mesh_event_sock_connect(const char *import) {
84         char *port = NULL;
85
86         assert(import);
87
88         char *ip = strdup(import);
89         assert((port = strchr(ip, ':')) != NULL);
90         *port = '\0';
91         port++;
92
93         memset(&server_addr, 0, sizeof(server_addr));
94         server_addr.sin_family      = AF_INET;
95         server_addr.sin_addr.s_addr = inet_addr(ip);
96         server_addr.sin_port        = htons(atoi(port));
97         client_fd = socket(AF_INET, SOCK_DGRAM, 0);
98         free(ip);
99         assert(client_fd >= 0);
100 }
101
102 bool mesh_event_sock_send(int client_id, mesh_event_t event, void *payload, size_t payload_length) {
103         mesh_event_payload_t mesh_event_send_packet;
104         ssize_t send_ret;
105
106         // Packing the mesh event
107         assert(client_id >= 0);
108         assert(client_fd >= 0);
109         assert(event >= 0 && event < MAX_EVENT);
110         mesh_event_send_packet.client_id   = client_id;
111         mesh_event_send_packet.mesh_event  = event;
112
113         if((payload == NULL) || (payload_length == 0)) {
114                 mesh_event_send_packet.payload_length = 0;
115         } else {
116                 mesh_event_send_packet.payload_length = payload_length;
117                 memmove(mesh_event_send_packet.payload, payload, payload_length);
118         }
119
120         send_ret = sendto(client_fd, &mesh_event_send_packet, sizeof(mesh_event_send_packet), 0, (const struct sockaddr *) &server_addr, sizeof(server_addr));
121
122         if(send_ret < 0) {
123                 perror("sendto status");
124                 return false;
125         } else {
126                 return true;
127         }
128 }
129
130 bool wait_for_event(mesh_event_callback_t callback, int t) {
131         struct timeval timeout;
132         struct sockaddr client;
133         socklen_t soc_len;
134         fd_set read_fds;
135         int activity;
136         mesh_event_payload_t mesh_event_rec_packet;
137
138         assert(callback);
139         assert(server_fd >= -1);
140         assert(t >= 0);
141
142         timeout.tv_sec  = t;
143         timeout.tv_usec = 0;
144         FD_ZERO(&read_fds);
145         FD_SET(server_fd, &read_fds);
146
147         while(1) {
148                 activity = select(server_fd + 1, &read_fds, NULL, NULL, &timeout);
149                 assert(activity != -1);
150
151                 if(activity == 0) {
152                         // If no activity happened for the timeout given
153                         return false;
154                 } else if(FD_ISSET(server_fd, &read_fds)) {
155                         // Unpacking the mesh event
156                         ssize_t recv_ret = recvfrom(server_fd, &mesh_event_rec_packet, sizeof(mesh_event_rec_packet), 0, &client, &soc_len);
157                         assert(recv_ret == sizeof(mesh_event_rec_packet));
158                         callback(mesh_event_rec_packet);
159                         return true;
160                 }
161         }// while
162 }