1 #define EFL_NET_SOCKET_UDP_PROTECTED 1
2 #define EFL_NET_SOCKET_FD_PROTECTED 1
3 #define EFL_LOOP_FD_PROTECTED 1
4 #define EFL_IO_READER_FD_PROTECTED 1
5 #define EFL_IO_WRITER_FD_PROTECTED 1
6 #define EFL_IO_CLOSER_FD_PROTECTED 1
7 #define EFL_IO_READER_PROTECTED 1
8 #define EFL_IO_WRITER_PROTECTED 1
9 #define EFL_IO_CLOSER_PROTECTED 1
10 #define EFL_NET_SOCKET_PROTECTED 1
11
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15
16 #include "Ecore.h"
17 #include "Ecore_Con.h"
18 #include "ecore_con_private.h"
19
20 #ifdef HAVE_SYS_SOCKET_H
21 # include <sys/socket.h>
22 #endif
23 #ifdef HAVE_NETINET_UDP_H
24 # include <netinet/udp.h>
25 #endif
26 #ifdef HAVE_NETINET_IN_H
27 # include <netinet/in.h>
28 #endif
29 #ifdef HAVE_ARPA_INET_H
30 # include <arpa/inet.h>
31 #endif
32
33 #define MY_CLASS EFL_NET_SOCKET_UDP_CLASS
34
35 typedef struct _Efl_Net_Socket_Udp_Data
36 {
37 struct {
38 Eina_List *groups; /* list of newly allocated strings */
39 Eina_List *pending; /* list of nodes of groups pending join */
40 uint8_t ttl;
41 Eina_Bool loopback;
42 Eina_Bool ttl_set;
43 } multicast;
44 Eina_Stringshare *address_bind;
45 struct sockaddr *addr_remote;
46 socklen_t addr_remote_len;
47 Eina_Bool cork;
48 Eina_Bool dont_route;
49 Eina_Bool reuse_address;
50 Eina_Bool reuse_port;
51 } Efl_Net_Socket_Udp_Data;
52
53 void
_efl_net_socket_udp_init(Eo * o,Efl_Net_Socket_Udp_Data * pd,Efl_Net_Ip_Address * remote_address)54 _efl_net_socket_udp_init(Eo *o, Efl_Net_Socket_Udp_Data *pd, Efl_Net_Ip_Address *remote_address)
55 {
56 const struct sockaddr *addr = efl_net_ip_address_sockaddr_get(remote_address);
57 socklen_t addrlen;
58
59 EINA_SAFETY_ON_NULL_RETURN(addr);
60
61 if (addr->sa_family == AF_INET) addrlen = sizeof(struct sockaddr_in);
62 else addrlen = sizeof(struct sockaddr_in6);
63
64 pd->addr_remote = malloc(addrlen);
65 EINA_SAFETY_ON_NULL_RETURN(pd->addr_remote);
66 memcpy(pd->addr_remote, addr, addrlen);
67 pd->addr_remote_len = addrlen;
68 efl_net_socket_address_remote_set(o, efl_net_ip_address_string_get(remote_address));
69 }
70
71 static Eina_Error
_efl_net_socket_udp_bind(Eo * o,Efl_Net_Socket_Udp_Data * pd)72 _efl_net_socket_udp_bind(Eo *o, Efl_Net_Socket_Udp_Data *pd)
73 {
74 const char *bhost, *bport;
75 struct sockaddr_in bsa4 = {.sin_family = AF_INET};
76 struct sockaddr_in6 bsa6 = {.sin6_family = AF_INET6};
77 char *str = NULL, *endptr;
78 unsigned long ul;
79 Eina_Error err = 0;
80 SOCKET fd = efl_loop_fd_get(o);
81 int family = efl_net_socket_fd_family_get(o);
82 int r;
83
84 if (!pd->address_bind) return 0;
85
86 str = strdup(pd->address_bind);
87 EINA_SAFETY_ON_NULL_GOTO(str, error_bind);
88 if (!efl_net_ip_port_split(str, &bhost, &bport))
89 {
90 bhost = (family == AF_INET) ? "0.0.0.0" : "::";
91 bport = "0";
92 err = EINVAL;
93 ERR("invalid bind address '%s', using host='%s' port=%s", pd->address_bind, bhost, bport);
94 }
95 else if (!bport) bport = "0";
96
97 if (family == AF_INET)
98 r = inet_pton(AF_INET, bhost, &bsa4.sin_addr);
99 else
100 r = inet_pton(AF_INET6, bhost, &bsa6.sin6_addr);
101 if (r != 1)
102 {
103 if (r < 0) err = efl_net_socket_error_get();
104 else err = EINVAL;
105 ERR("invalid host='%s': %s", bhost, eina_error_msg_get(err));
106 goto error_bind;
107 }
108
109 errno = 0;
110 ul = strtoul(bport, &endptr, 10);
111 if ((endptr == bport) || (endptr[0] != '\0'))
112 errno = EINVAL;
113 else if (ul > UINT16_MAX)
114 errno = ERANGE;
115
116 if (errno)
117 {
118 err = errno;
119 ERR("invalid port numer '%s': %s", bport, eina_error_msg_get(errno));
120 goto error_bind;
121 }
122
123 if (family == AF_INET)
124 bsa4.sin_port = eina_htons(ul);
125 else
126 bsa6.sin6_port = eina_htons(ul);
127
128 if (family == AF_INET)
129 r = bind(fd, (struct sockaddr *)&bsa4, sizeof(bsa4));
130 else
131 r = bind(fd, (struct sockaddr *)&bsa6, sizeof(bsa6));
132 if (r != 0)
133 {
134 err = efl_net_socket_error_get();
135 ERR("could not bind to host='%s', port=%s: %s", bhost, bport, eina_error_msg_get(err));
136 goto error_bind;
137 }
138
139 error_bind:
140 free(str);
141 return err;
142 }
143
144 EOLIAN static void
_efl_net_socket_udp_efl_loop_fd_fd_set(Eo * o,Efl_Net_Socket_Udp_Data * pd,int pfd)145 _efl_net_socket_udp_efl_loop_fd_fd_set(Eo *o, Efl_Net_Socket_Udp_Data *pd, int pfd)
146 {
147 SOCKET fd = (SOCKET)pfd;
148 Eina_List *node;
149 struct sockaddr_storage addr;
150 socklen_t addrlen;
151 int family;
152
153 efl_loop_fd_set(efl_super(o, MY_CLASS), pfd);
154
155 if (fd == INVALID_SOCKET) return;
156
157 family = efl_net_socket_fd_family_get(o);
158 if (family == AF_UNSPEC) return;
159
160 /* apply postponed values or fetch & sync */
161 if (pd->cork == 0xff)
162 efl_net_socket_udp_cork_get(o);
163 else
164 efl_net_socket_udp_cork_set(o, pd->cork);
165
166 if (pd->dont_route == 0xff)
167 efl_net_socket_udp_dont_route_get(o);
168 else
169 efl_net_socket_udp_dont_route_set(o, pd->dont_route);
170
171 if (pd->reuse_address == 0xff)
172 efl_net_socket_udp_reuse_address_get(o);
173 else
174 efl_net_socket_udp_reuse_address_set(o, pd->reuse_address);
175
176 if (pd->reuse_port == 0xff)
177 efl_net_socket_udp_reuse_port_get(o);
178 else
179 efl_net_socket_udp_reuse_port_set(o, pd->reuse_port);
180
181 _efl_net_socket_udp_bind(o, pd);
182
183 EINA_LIST_FREE(pd->multicast.pending, node)
184 {
185 const char *mcast_addr = node->data;
186 Eina_Error mr = efl_net_multicast_join(fd, family, mcast_addr);
187 if (mr)
188 ERR("could not join pending multicast group '%s': %s", mcast_addr, eina_error_msg_get(mr));
189 }
190
191 if (!pd->multicast.ttl_set)
192 efl_net_socket_udp_multicast_time_to_live_get(o);
193 else
194 efl_net_socket_udp_multicast_time_to_live_set(o, pd->multicast.ttl);
195
196 if (pd->multicast.loopback == 0xff)
197 efl_net_socket_udp_multicast_loopback_get(o);
198 else
199 efl_net_socket_udp_multicast_loopback_set(o, pd->multicast.loopback);
200
201 addrlen = sizeof(addr);
202 if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) != 0)
203 ERR("getsockname(" SOCKET_FMT "): %s", fd, eina_error_msg_get(efl_net_socket_error_get()));
204 else
205 {
206 char str[INET6_ADDRSTRLEN + sizeof("[]:65536")];
207 if (efl_net_ip_port_fmt(str, sizeof(str), (struct sockaddr *)&addr))
208 efl_net_socket_address_local_set(o, str);
209 }
210 }
211
212 EOLIAN static size_t
_efl_net_socket_udp_next_datagram_size_query(Eo * o,Efl_Net_Socket_Udp_Data * pd EINA_UNUSED)213 _efl_net_socket_udp_next_datagram_size_query(Eo *o, Efl_Net_Socket_Udp_Data *pd EINA_UNUSED)
214 {
215 SOCKET fd = efl_loop_fd_get(o);
216 if (fd == INVALID_SOCKET) return 0;
217 return efl_net_udp_datagram_size_query(fd);
218 }
219
220 static inline int
_cork_option_get(void)221 _cork_option_get(void)
222 {
223 #if defined(HAVE_UDP_CORK)
224 return UDP_CORK;
225 #else
226 return -1;
227 #endif
228 }
229
230 EOLIAN static Eina_Bool
_efl_net_socket_udp_cork_set(Eo * o,Efl_Net_Socket_Udp_Data * pd,Eina_Bool cork)231 _efl_net_socket_udp_cork_set(Eo *o, Efl_Net_Socket_Udp_Data *pd, Eina_Bool cork)
232 {
233 SOCKET fd;
234 int value, option;
235 Eina_Bool old = pd->cork;
236
237 option = _cork_option_get();
238 if (EINA_UNLIKELY(option < 0))
239 {
240 if (cork)
241 ERR("Could not find a UDP_CORK equivalent on your system");
242 return EINA_FALSE;
243 }
244
245 pd->cork = cork;
246
247 fd = efl_loop_fd_get(o);
248 if (fd == INVALID_SOCKET) return EINA_TRUE; /* postpone until fd_set() */
249
250 value = cork;
251 if (setsockopt(fd, IPPROTO_UDP, option, (const char *)&value, sizeof(value)) != 0)
252 {
253 ERR("setsockopt(" SOCKET_FMT ", IPPROTO_UDP, 0x%x, %d): %s",
254 fd, option, value, eina_error_msg_get(efl_net_socket_error_get()));
255 pd->cork = old;
256 return EINA_FALSE;
257 }
258
259 return EINA_TRUE;
260 }
261
262 EOLIAN static Eina_Bool
_efl_net_socket_udp_cork_get(const Eo * o,Efl_Net_Socket_Udp_Data * pd)263 _efl_net_socket_udp_cork_get(const Eo *o, Efl_Net_Socket_Udp_Data *pd)
264 {
265 SOCKET fd;
266 int value = 0;
267 socklen_t valuelen;
268 int option;
269
270 option = _cork_option_get();
271 if (EINA_UNLIKELY(option < 0))
272 {
273 WRN("Could not find a UDP_CORK equivalent on your system");
274 return EINA_FALSE;
275 }
276
277 fd = efl_loop_fd_get(o);
278 if (fd == INVALID_SOCKET) return pd->cork;
279
280 /* if there is a fd, always query it directly as it may be modified
281 * elsewhere by nasty users.
282 */
283 valuelen = sizeof(value);
284 if (getsockopt(fd, IPPROTO_UDP, option, (char *)&value, &valuelen) != 0)
285 {
286 ERR("getsockopt(" SOCKET_FMT ", IPPROTO_UDP, 0x%x): %s",
287 fd, option, eina_error_msg_get(efl_net_socket_error_get()));
288 return EINA_FALSE;
289 }
290
291 pd->cork = !!value; /* sync */
292 return pd->cork;
293 }
294
295 EOLIAN static Eina_Bool
_efl_net_socket_udp_dont_route_set(Eo * o,Efl_Net_Socket_Udp_Data * pd,Eina_Bool dont_route)296 _efl_net_socket_udp_dont_route_set(Eo *o, Efl_Net_Socket_Udp_Data *pd, Eina_Bool dont_route)
297 {
298 Eina_Bool old = pd->dont_route;
299 SOCKET fd = efl_loop_fd_get(o);
300 #ifdef _WIN32
301 DWORD value = dont_route;
302 #else
303 int value = dont_route;
304 #endif
305
306 pd->dont_route = dont_route;
307
308 if (fd == INVALID_SOCKET) return EINA_TRUE;
309
310 if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, (const char *)&value, sizeof(value)) != 0)
311 {
312 Eina_Error err = efl_net_socket_error_get();
313 ERR("setsockopt(" SOCKET_FMT ", SOL_SOCKET, SO_DONTROUTE, %u): %s", fd, dont_route, eina_error_msg_get(err));
314 pd->dont_route = old;
315 return EINA_FALSE;
316 }
317
318 return EINA_TRUE;
319 }
320
321 EOLIAN static Eina_Bool
_efl_net_socket_udp_dont_route_get(const Eo * o,Efl_Net_Socket_Udp_Data * pd)322 _efl_net_socket_udp_dont_route_get(const Eo *o, Efl_Net_Socket_Udp_Data *pd)
323 {
324 SOCKET fd = efl_loop_fd_get(o);
325 #ifdef _WIN32
326 DWORD value;
327 #else
328 int value;
329 #endif
330 socklen_t valuelen;
331
332 if (fd == INVALID_SOCKET) return pd->dont_route;
333
334 /* if there is a fd, always query it directly as it may be modified
335 * elsewhere by nasty users.
336 */
337 valuelen = sizeof(value);
338 if (getsockopt(fd, SOL_SOCKET, SO_DONTROUTE, (char *)&value, &valuelen) != 0)
339 {
340 Eina_Error err = efl_net_socket_error_get();
341 ERR("getsockopt(" SOCKET_FMT ", SOL_SOCKET, SO_DONTROUTE): %s", fd, eina_error_msg_get(err));
342 return EINA_FALSE;
343 }
344
345 pd->dont_route = !!value; /* sync */
346 return pd->dont_route;
347 }
348
349
350 EOLIAN static Eina_Bool
_efl_net_socket_udp_reuse_address_set(Eo * o,Efl_Net_Socket_Udp_Data * pd,Eina_Bool reuse_address)351 _efl_net_socket_udp_reuse_address_set(Eo *o, Efl_Net_Socket_Udp_Data *pd, Eina_Bool reuse_address)
352 {
353 SOCKET fd;
354 int value;
355 Eina_Bool old = pd->reuse_address;
356
357 pd->reuse_address = reuse_address;
358
359 fd = efl_loop_fd_get(o);
360 if (fd == INVALID_SOCKET) return EINA_TRUE; /* postpone until fd_set() */
361
362 value = reuse_address;
363 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&value, sizeof(value)) != 0)
364 {
365 ERR("setsockopt(" SOCKET_FMT ", SOL_SOCKET, SO_REUSEADDR, %d): %s",
366 fd, value, eina_error_msg_get(efl_net_socket_error_get()));
367 pd->reuse_address = old;
368 return EINA_FALSE;
369 }
370
371 return EINA_TRUE;
372 }
373
374 EOLIAN static Eina_Bool
_efl_net_socket_udp_reuse_address_get(const Eo * o,Efl_Net_Socket_Udp_Data * pd)375 _efl_net_socket_udp_reuse_address_get(const Eo *o, Efl_Net_Socket_Udp_Data *pd)
376 {
377 SOCKET fd;
378 int value = 0;
379 socklen_t valuelen;
380
381 fd = efl_loop_fd_get(o);
382 if (fd == INVALID_SOCKET) return pd->reuse_address;
383
384 /* if there is a fd, always query it directly as it may be modified
385 * elsewhere by nasty users.
386 */
387 valuelen = sizeof(value);
388 if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&value, &valuelen) != 0)
389 {
390 ERR("getsockopt(" SOCKET_FMT ", SOL_SOCKET, SO_REUSEADDR): %s",
391 fd, eina_error_msg_get(efl_net_socket_error_get()));
392 return EINA_FALSE;
393 }
394
395 pd->reuse_address = !!value; /* sync */
396 return pd->reuse_address;
397 }
398
399 EOLIAN static Eina_Bool
_efl_net_socket_udp_reuse_port_set(Eo * o,Efl_Net_Socket_Udp_Data * pd,Eina_Bool reuse_port)400 _efl_net_socket_udp_reuse_port_set(Eo *o, Efl_Net_Socket_Udp_Data *pd, Eina_Bool reuse_port)
401 {
402 #ifdef SO_REUSEPORT
403 SOCKET fd;
404 int value;
405 Eina_Bool old = pd->reuse_port;
406 #endif
407
408 pd->reuse_port = reuse_port;
409
410 #ifdef SO_REUSEPORT
411 fd = efl_loop_fd_get(o);
412 if (fd == INVALID_SOCKET) return EINA_TRUE; /* postpone until fd_set() */
413
414 value = reuse_port;
415 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const char *)&value, sizeof(value)) != 0)
416 {
417 ERR("setsockopt(" SOCKET_FMT ", SOL_SOCKET, SO_REUSEPORT, %d): %s",
418 fd, value, eina_error_msg_get(efl_net_socket_error_get()));
419 pd->reuse_port = old;
420 return EINA_FALSE;
421 }
422 #else
423 (void)o;
424 #endif
425
426 return EINA_TRUE;
427 }
428
429 EOLIAN static Eina_Bool
_efl_net_socket_udp_reuse_port_get(const Eo * o,Efl_Net_Socket_Udp_Data * pd)430 _efl_net_socket_udp_reuse_port_get(const Eo *o, Efl_Net_Socket_Udp_Data *pd)
431 {
432 #ifdef SO_REUSEPORT
433 SOCKET fd;
434 int value = 0;
435 socklen_t valuelen;
436
437 fd = efl_loop_fd_get(o);
438 if (fd == INVALID_SOCKET) return pd->reuse_port;
439
440 /* if there is a fd, always query it directly as it may be modified
441 * elsewhere by nasty users.
442 */
443 valuelen = sizeof(value);
444 if (getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&value, &valuelen) != 0)
445 {
446 ERR("getsockopt(" SOCKET_FMT ", SOL_SOCKET, SO_REUSEPORT): %s",
447 fd, eina_error_msg_get(efl_net_socket_error_get()));
448 return EINA_FALSE;
449 }
450
451 pd->reuse_port = !!value; /* sync */
452 #else
453 (void)o;
454 #endif
455
456 return pd->reuse_port;
457 }
458
459 EOLIAN static Eina_Error
_efl_net_socket_udp_bind_set(Eo * o,Efl_Net_Socket_Udp_Data * pd,const char * address)460 _efl_net_socket_udp_bind_set(Eo *o, Efl_Net_Socket_Udp_Data *pd, const char *address)
461 {
462 SOCKET fd = efl_loop_fd_get(o);
463
464 EINA_SAFETY_ON_TRUE_RETURN_VAL(fd != INVALID_SOCKET, EALREADY);
465
466 eina_stringshare_replace(&pd->address_bind, address);
467 return 0;
468 }
469
470 EOLIAN static const char *
_efl_net_socket_udp_bind_get(const Eo * o EINA_UNUSED,Efl_Net_Socket_Udp_Data * pd)471 _efl_net_socket_udp_bind_get(const Eo *o EINA_UNUSED, Efl_Net_Socket_Udp_Data *pd)
472 {
473 return pd->address_bind;
474 }
475
476 EOLIAN Efl_Object *
_efl_net_socket_udp_efl_object_constructor(Eo * o,Efl_Net_Socket_Udp_Data * pd)477 _efl_net_socket_udp_efl_object_constructor(Eo *o, Efl_Net_Socket_Udp_Data *pd)
478 {
479 pd->multicast.ttl = 1;
480 pd->multicast.ttl_set = EINA_FALSE;
481 pd->multicast.loopback = 0xff;
482 pd->cork = 0xff;
483 pd->dont_route = 0xff;
484 pd->reuse_address = 0xff;
485 pd->reuse_port = 0xff;
486 return efl_constructor(efl_super(o, MY_CLASS));
487 }
488
489 EOLIAN void
_efl_net_socket_udp_efl_object_destructor(Eo * o,Efl_Net_Socket_Udp_Data * pd)490 _efl_net_socket_udp_efl_object_destructor(Eo *o, Efl_Net_Socket_Udp_Data *pd)
491 {
492 if (pd->multicast.pending)
493 {
494 eina_list_free(pd->multicast.pending);
495 pd->multicast.pending = NULL;
496 }
497
498 while (pd->multicast.groups)
499 efl_net_socket_udp_multicast_leave(o, pd->multicast.groups->data);
500
501 efl_destructor(efl_super(o, MY_CLASS));
502
503 eina_stringshare_replace(&pd->address_bind, NULL);
504
505 free(pd->addr_remote);
506 pd->addr_remote = NULL;
507 pd->addr_remote_len = 0;
508 }
509
510 EOLIAN static Eina_Error
_efl_net_socket_udp_efl_io_reader_read(Eo * o,Efl_Net_Socket_Udp_Data * pd,Eina_Rw_Slice * rw_slice)511 _efl_net_socket_udp_efl_io_reader_read(Eo *o, Efl_Net_Socket_Udp_Data *pd, Eina_Rw_Slice *rw_slice)
512 {
513 SOCKET fd = efl_io_reader_fd_get(o);
514 ssize_t r;
515
516 EINA_SAFETY_ON_NULL_RETURN_VAL(rw_slice, EINVAL);
517 if (fd == INVALID_SOCKET) goto error;
518 do
519 {
520 struct sockaddr_storage addr = {};
521 socklen_t addrlen = sizeof(addr);
522 r = recvfrom(fd, rw_slice->mem, rw_slice->len, 0, (struct sockaddr *)&addr, &addrlen);
523 if (r == SOCKET_ERROR)
524 {
525 Eina_Error err = efl_net_socket_error_get();
526
527 if (err == EINTR) continue;
528
529 rw_slice->len = 0;
530 rw_slice->mem = NULL;
531
532 efl_io_reader_can_read_set(o, EINA_FALSE);
533 return err;
534 }
535
536 if (addr.ss_family == AF_INET)
537 {
538 const struct sockaddr_in *a = (const struct sockaddr_in *)pd->addr_remote;
539 uint32_t ipv4 = eina_ntohl(a->sin_addr.s_addr);
540 if ((ipv4 != INADDR_BROADCAST) && (ipv4 != INADDR_ANY) && (!IN_MULTICAST(ipv4)))
541 {
542 if ((addrlen != pd->addr_remote_len) ||
543 (memcmp(&addr, pd->addr_remote, addrlen) != 0))
544 {
545 char buf[INET_ADDRSTRLEN + sizeof(":65536")];
546 efl_net_ip_port_fmt(buf, sizeof(buf), (struct sockaddr *)&addr);
547 ERR("dropping spurious datagram from %s (expected %s)", buf, efl_net_socket_address_remote_get(o));
548 rw_slice->len = 0;
549 rw_slice->mem = NULL;
550 efl_io_reader_can_read_set(o, EINA_FALSE); /* wait Efl.Loop.Fd "read" */
551 return EAGAIN;
552 }
553 }
554 }
555 else
556 {
557 const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)pd->addr_remote;
558 if ((!IN6_IS_ADDR_MULTICAST(&a->sin6_addr)) && (memcmp(&a->sin6_addr, &in6addr_any, sizeof(in6addr_any)) != 0))
559 {
560 if ((addrlen != pd->addr_remote_len) ||
561 (memcmp(&addr, pd->addr_remote, addrlen) != 0))
562 {
563 char buf[INET6_ADDRSTRLEN + sizeof("[]:65536")];
564 efl_net_ip_port_fmt(buf, sizeof(buf), (struct sockaddr *)&addr);
565 ERR("dropping spurious datagram from %s (expected %s)", buf, efl_net_socket_address_remote_get(o));
566 rw_slice->len = 0;
567 rw_slice->mem = NULL;
568 efl_io_reader_can_read_set(o, EINA_FALSE); /* wait Efl.Loop.Fd "read" */
569 return EAGAIN;
570 }
571 }
572 }
573 }
574 while (r == SOCKET_ERROR);
575
576 rw_slice->len = r;
577 efl_io_reader_can_read_set(o, EINA_FALSE); /* wait Efl.Loop.Fd "read" */
578 if (r == 0)
579 efl_io_reader_eos_set(o, EINA_TRUE);
580
581 return 0;
582
583 error:
584 rw_slice->len = 0;
585 rw_slice->mem = NULL;
586 efl_io_reader_can_read_set(o, EINA_FALSE);
587 return EINVAL;
588 }
589
590 EOLIAN static Eina_Error
_efl_net_socket_udp_efl_io_writer_write(Eo * o,Efl_Net_Socket_Udp_Data * pd,Eina_Slice * ro_slice,Eina_Slice * remaining)591 _efl_net_socket_udp_efl_io_writer_write(Eo *o, Efl_Net_Socket_Udp_Data *pd, Eina_Slice *ro_slice, Eina_Slice *remaining)
592 {
593 SOCKET fd = efl_io_writer_fd_get(o);
594 ssize_t r;
595
596 EINA_SAFETY_ON_NULL_RETURN_VAL(ro_slice, EINVAL);
597 if (fd == INVALID_SOCKET) goto error;
598
599 do
600 {
601 r = sendto(fd, ro_slice->mem, ro_slice->len, 0, pd->addr_remote, pd->addr_remote_len);
602 if (r == SOCKET_ERROR)
603 {
604 Eina_Error err = efl_net_socket_error_get();
605
606 if (err == EINTR) continue;
607
608 if (remaining) *remaining = *ro_slice;
609 ro_slice->len = 0;
610 ro_slice->mem = NULL;
611 efl_io_writer_can_write_set(o, EINA_FALSE);
612 return err;
613 }
614 }
615 while (r == SOCKET_ERROR);
616
617 if (remaining)
618 {
619 remaining->len = ro_slice->len - r;
620 remaining->bytes = ro_slice->bytes + r;
621 }
622 ro_slice->len = r;
623 efl_io_writer_can_write_set(o, EINA_FALSE); /* wait Efl.Loop.Fd "write" */
624
625 return 0;
626
627 error:
628 if (remaining) *remaining = *ro_slice;
629 ro_slice->len = 0;
630 ro_slice->mem = NULL;
631 efl_io_writer_can_write_set(o, EINA_FALSE);
632 return EINVAL;
633 }
634
635 static Eina_List *
_efl_net_socket_udp_multicast_find(const Eina_List * lst,const char * address)636 _efl_net_socket_udp_multicast_find(const Eina_List *lst, const char *address)
637 {
638 const char *str;
639 const Eina_List *node;
640
641 EINA_LIST_FOREACH(lst, node, str)
642 {
643 if (strcmp(str, address) == 0)
644 return (Eina_List *)node;
645 }
646
647 return NULL;
648 }
649
650 EOLIAN static Eina_Error
_efl_net_socket_udp_multicast_join(Eo * o,Efl_Net_Socket_Udp_Data * pd,const char * address)651 _efl_net_socket_udp_multicast_join(Eo *o, Efl_Net_Socket_Udp_Data *pd, const char *address)
652 {
653 const Eina_List *found;
654 SOCKET fd = efl_loop_fd_get(o);
655
656 EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
657
658 found = _efl_net_socket_udp_multicast_find(pd->multicast.groups, address);
659 if (found) return EEXIST;
660
661 pd->multicast.groups = eina_list_append(pd->multicast.groups, strdup(address));
662
663 if (fd == INVALID_SOCKET)
664 {
665 pd->multicast.pending = eina_list_append(pd->multicast.pending, eina_list_last(pd->multicast.groups));
666 return 0;
667 }
668
669 return efl_net_multicast_join(fd, efl_net_socket_fd_family_get(o), address);
670 }
671
672 EOLIAN static Eina_Error
_efl_net_socket_udp_multicast_leave(Eo * o,Efl_Net_Socket_Udp_Data * pd,const char * address)673 _efl_net_socket_udp_multicast_leave(Eo *o, Efl_Net_Socket_Udp_Data *pd, const char *address)
674 {
675 Eina_List *found;
676 SOCKET fd = efl_loop_fd_get(o);
677 Eina_Error err;
678
679 EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
680
681 found = _efl_net_socket_udp_multicast_find(pd->multicast.groups, address);
682 if (!found) return ENOENT;
683
684 if (fd == INVALID_SOCKET)
685 {
686 free(found->data);
687 pd->multicast.pending = eina_list_remove(pd->multicast.pending, found);
688 pd->multicast.groups = eina_list_remove_list(pd->multicast.groups, found);
689 return 0;
690 }
691
692 err = efl_net_multicast_leave(fd, efl_net_socket_fd_family_get(o), address);
693
694 free(found->data);
695 pd->multicast.groups = eina_list_remove_list(pd->multicast.groups, found);
696 return err;
697 }
698
699 EOLIAN static Eina_Iterator *
_efl_net_socket_udp_multicast_groups_get(Eo * o EINA_UNUSED,Efl_Net_Socket_Udp_Data * pd)700 _efl_net_socket_udp_multicast_groups_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Udp_Data *pd)
701 {
702 return eina_list_iterator_new(pd->multicast.groups);
703 }
704
705 EOLIAN static Eina_Error
_efl_net_socket_udp_multicast_time_to_live_set(Eo * o,Efl_Net_Socket_Udp_Data * pd,uint8_t ttl)706 _efl_net_socket_udp_multicast_time_to_live_set(Eo *o, Efl_Net_Socket_Udp_Data *pd, uint8_t ttl)
707 {
708 SOCKET fd = efl_loop_fd_get(o);
709 Eina_Error err;
710 uint8_t old = pd->multicast.ttl;
711
712 pd->multicast.ttl_set = EINA_TRUE;
713 pd->multicast.ttl = ttl;
714
715 if (fd == INVALID_SOCKET) return 0;
716
717 err = efl_net_multicast_ttl_set(fd, efl_net_socket_fd_family_get(o), ttl);
718 if (err)
719 {
720 ERR("could not set multicast time to live=%hhu: %s", ttl, eina_error_msg_get(err));
721 pd->multicast.ttl = old;
722 }
723
724 return err;
725 }
726
727 EOLIAN static uint8_t
_efl_net_socket_udp_multicast_time_to_live_get(const Eo * o,Efl_Net_Socket_Udp_Data * pd)728 _efl_net_socket_udp_multicast_time_to_live_get(const Eo *o, Efl_Net_Socket_Udp_Data *pd)
729 {
730 SOCKET fd = efl_loop_fd_get(o);
731 Eina_Error err;
732 uint8_t ttl = pd->multicast.ttl;
733
734 if (fd == INVALID_SOCKET) return pd->multicast.ttl;
735
736 err = efl_net_multicast_ttl_get(fd, efl_net_socket_fd_family_get(o), &ttl);
737 if (err)
738 ERR("could not get multicast time to live: %s", eina_error_msg_get(err));
739 else
740 pd->multicast.ttl = ttl;
741
742 return pd->multicast.ttl;
743 }
744
745 EOLIAN static Eina_Error
_efl_net_socket_udp_multicast_loopback_set(Eo * o,Efl_Net_Socket_Udp_Data * pd,Eina_Bool loopback)746 _efl_net_socket_udp_multicast_loopback_set(Eo *o, Efl_Net_Socket_Udp_Data *pd, Eina_Bool loopback)
747 {
748 SOCKET fd = efl_loop_fd_get(o);
749 Eina_Error err;
750 Eina_Bool old = pd->multicast.loopback;
751
752 pd->multicast.loopback = loopback;
753
754 if (fd == INVALID_SOCKET) return 0;
755
756 err = efl_net_multicast_loopback_set(fd, efl_net_socket_fd_family_get(o), loopback);
757 if (err)
758 {
759 ERR("could not set multicast loopback=%hhu: %s", loopback, eina_error_msg_get(err));
760 pd->multicast.loopback = old;
761 }
762
763 return err;
764 }
765
766 EOLIAN static Eina_Bool
_efl_net_socket_udp_multicast_loopback_get(const Eo * o,Efl_Net_Socket_Udp_Data * pd)767 _efl_net_socket_udp_multicast_loopback_get(const Eo *o, Efl_Net_Socket_Udp_Data *pd)
768 {
769 SOCKET fd = efl_loop_fd_get(o);
770 Eina_Error err;
771 Eina_Bool loopback = pd->multicast.loopback;
772
773 if (fd == INVALID_SOCKET) return pd->multicast.loopback;
774
775 err = efl_net_multicast_loopback_get(fd, efl_net_socket_fd_family_get(o), &loopback);
776 if (err)
777 ERR("could not get multicast loopback: %s", eina_error_msg_get(err));
778 else
779 pd->multicast.loopback = loopback;
780
781 return pd->multicast.loopback;
782 }
783
784 #include "efl_net_socket_udp.eo.c"
785