1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
|
#ifndef _ECORE_CON_PRIVATE_H
#define _ECORE_CON_PRIVATE_H
#include "ecore_private.h"
#include "Ecore_Con.h"
#define ECORE_MAGIC_CON_SERVER 0x77665544
#define ECORE_MAGIC_CON_CLIENT 0x77556677
#define ECORE_MAGIC_CON_URL 0x77074255
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#include <inttypes.h>
#define READBUFSIZ 65536
extern int _ecore_con_log_dom;
#ifdef ECORE_CON_DEFAULT_LOG_COLOR
#undef ECORE_LOG_DEFAULT_LOG_COLOR
#endif
#define ECORE_CON_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
#ifdef ERR
# undef ERR
#endif
#define ERR(...) EINA_LOG_DOM_ERR(_ecore_con_log_dom, __VA_ARGS__)
#ifdef DBG
# undef DBG
#endif
#define DBG(...) EINA_LOG_DOM_DBG(_ecore_con_log_dom, __VA_ARGS__)
#ifdef INF
# undef INF
#endif
#define INF(...) EINA_LOG_DOM_INFO(_ecore_con_log_dom, __VA_ARGS__)
#ifdef WRN
# undef WRN
#endif
#define WRN(...) EINA_LOG_DOM_WARN(_ecore_con_log_dom, __VA_ARGS__)
#ifdef CRI
# undef CRI
#endif
#define CRI(...) EINA_LOG_DOM_CRIT(_ecore_con_log_dom, __VA_ARGS__)
typedef struct Ecore_Con_Socks Ecore_Con_Socks_v4;
typedef struct Ecore_Con_Socks_v5 Ecore_Con_Socks_v5;
struct Ecore_Con_Socks /* v4 */
{
unsigned char version;
const char *ip;
int port;
const char *username;
unsigned int ulen;
Eina_Bool lookup : 1;
Eina_Bool bind : 1;
};
struct Ecore_Con_Socks_v5
{
unsigned char version;
const char *ip;
int port;
const char *username;
unsigned int ulen;
Eina_Bool lookup : 1;
Eina_Bool bind : 1;
/* v5 only */
unsigned char method;
const char *password;
unsigned int plen;
};
#ifdef HAVE_SYSTEMD
extern int sd_fd_index;
extern int sd_fd_max;
#endif
/* init must be called from main thread */
Eina_Bool ecore_con_libproxy_init(void);
void ecore_con_libproxy_proxies_free(char **proxies);
/* BLOCKING! should be called from a worker thread */
char **ecore_con_libproxy_proxies_get(const char *url);
Eina_Bool ecore_con_server_check(const Ecore_Con_Server *svr);
extern Ecore_Con_Socks *_ecore_con_proxy_once;
extern Ecore_Con_Socks *_ecore_con_proxy_global;
void ecore_con_socks_init(void);
void ecore_con_socks_shutdown(void);
void ecore_con_mempool_init(void);
void ecore_con_mempool_shutdown(void);
void ecore_con_legacy_init(void);
void ecore_con_legacy_shutdown(void);
void _ecore_con_local_mkpath(const char *path, mode_t mode);
/* allow windows and posix to use the same error comparison */
#ifndef SOCKET_ERROR
#define SOCKET_ERROR -1
#endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#ifndef SOCKET_TO_LOOP_FD
#define SOCKET_TO_LOOP_FD(sock) ((int)sock)
#endif
#ifndef _WIN32
#define closesocket(fd) close(fd)
#define SOCKET int
#define SOCKET_FMT "%d"
#else
#define SOCKET_FMT "%"PRIuPTR
#endif
/*
* This define will force SOCKET to be 'unsigned long', this will
* force compile to emit errors when assuming "int"/"%d", which is the
* case on UNIX but not on Windows.
*/
//#define EFL_NET_CHECK_SOCKET_TYPE 1
#if EFL_NET_CHECK_SOCKET_TYPE
#undef SOCKET
#undef SOCKET_FMT
#undef INVALID_SOCKET
#define SOCKET unsigned long
#define SOCKET_FMT "%lu"
#define INVALID_SOCKET ((SOCKET)-1)
#endif
/* some platforms do not have AI_V4MAPPED, then define to 0 so bitwise OR won't be changed */
#ifndef AI_V4MAPPED
#define AI_V4MAPPED 0
#endif
#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG 0
#endif
#ifndef AI_CANONNAME
#define AI_CANONNAME 0
#endif
/* Windows do not define EAI_SYSTEM, so just define to some number
* that won't be matched, effectively disabling the subsequent
* checks/usage
*/
#ifndef EAI_SYSTEM
#define EAI_SYSTEM 254 /* number that won't match anything in EAI_* */
#endif
void _efl_net_server_udp_client_init(Eo *client, SOCKET fd, const struct sockaddr *addr, socklen_t addrlen, const char *str);
void _efl_net_server_udp_client_feed(Eo *client, Eina_Rw_Slice slice);
void _efl_net_socket_udp_init(Eo *o, const struct sockaddr *addr, socklen_t addrlen, const char *str);
#ifndef _WIN32
Eina_Bool efl_net_unix_fmt(char *buf, size_t buflen, SOCKET fd, const struct sockaddr_un *addr, socklen_t addrlen);
#endif
Eina_Bool efl_net_ip_port_parse(const char *address, struct sockaddr_storage *storage);
Eina_Bool efl_net_ip_port_parse_split(const char *host, const char *port, struct sockaddr_storage *storage);
Eina_Bool efl_net_ip_port_fmt(char *buf, size_t buflen, const struct sockaddr *addr);
#ifdef HAVE_SYSTEMD
/**
* Checks if the next FD in the sd_fd_index:sd_fd_max is of the
* expected family, protocol and if it's listening.
*
* This is similar to sd_is_socket()/sd_is_socket_inet(), but will
* also parse address in our standard format "IP:PORT", including IPv6
* within braces, and then will validate the address with
* getsockaddr() for INET.
*
* @param address the address to validate
* @param family AF_UNIX or AF_UNSPEC for INET, in that case AF_INET
* or AF_INET6 will be inferred from @a address.
* @param type SOCK_STREAM or SOCK_DGRAM
* @param[out] listening where to return listening state, should be
* NULL for @a type SOCK_DGRAM
*
* @return 0 on success, error otherwise.
*
* @internal
*/
Eina_Error efl_net_ip_socket_activate_check(const char *address, int family, int type, Eina_Bool *listening);
#endif
/**
* @brief splits an address in the format "host:port" in two
* null-terminated strings.
*
* The address may be 'server.com:1234', 'server.com:http',
* 'server.com' (@c *p_port will be NULL), IPv4 127.0.0.1:456 or
* IPv6 [::1]:456
*
* @param[inout] buf contains the string to be split and will be modified.
* @param[out] p_host returns a pointer inside @a buf with
* null-terminated host part.
* @param[out] p_port returns a pointer with null-terminated port
* part. The pointer may be inside @a buf if port was
* specified or #NULL if it wasn't specified.
*
* @return #EINA_TRUE on success, #EINA_FALSE on errors.
*
* @internal
*/
Eina_Bool efl_net_ip_port_split(char *buf, const char **p_host, const char **p_port);
SOCKET efl_net_socket4(int domain, int type, int protocol, Eina_Bool close_on_exec);
/**
* @brief callback to notify of resolved address.
*
* The callback is given the ownership of the result, thus must free
* it with freeaddrinfo().
*
* @internal
*/
typedef void (*Efl_Net_Ip_Resolve_Async_Cb)(void *data, const char *host, const char *port, const struct addrinfo *hints, struct addrinfo *result, int gai_error);
/**
* @brief asynchronously resolve a host and port using getaddrinfo().
*
* This will call getaddrinfo() in a thread, taking care to return the
* result to the main loop and calling @a cb with given user @a data.
*
* @internal
*/
Ecore_Thread *efl_net_ip_resolve_async_new(const char *host, const char *port, const struct addrinfo *hints, Efl_Net_Ip_Resolve_Async_Cb cb, const void *data);
/**
* @brief callback to notify of connection.
*
* The callback is given the ownership of the socket (sockfd), thus
* must close().
*
* @internal
*/
typedef void (*Efl_Net_Connect_Async_Cb)(void *data, const struct sockaddr *addr, socklen_t addrlen, SOCKET sockfd, Eina_Error error);
/**
* @brief asynchronously create a socket and connect to the address.
*
* This will call socket() and connect() in a thread, taking care to
* return the result to the main loop and calling @a cb with given
* user @a data.
*
* For name resolution and proxy support use
* efl_net_ip_connect_async_new()
*
* @internal
*/
Ecore_Thread *efl_net_connect_async_new(const struct sockaddr *addr, socklen_t addrlen, int type, int protocol, Eina_Bool close_on_exec, Efl_Net_Connect_Async_Cb cb, const void *data);
/**
* @brief asynchronously create a socket and connect to the IP address.
*
* This wil resolve the address using getaddrinfo(), create a socket
* and connect in a thread.
*
* If a @a proxy is given, then it's always used. Otherwise the
* environment variable @a proxy_env is used unless it matches @a
* no_proxy_env. Some systems may do special queries for proxy from
* the thread.
*
* @param address the host:port to connect. Host may be a name or an
* IP address, IPv6 addresses should be enclosed in braces.
* @param proxy a mandatory proxy to use. If "" (empty string), it's
* disabled. If NULL, then @a proxy_env is used unless it
* matches @a no_proxy_env.
* @param proxy_env if @a proxy is NULL, then this will be used as the
* proxy unless it matches @a no_proxy_env.
* @param no_proxy_env a comma-separated list of matches that will
* avoid using @a proxy_env. "server.com" will inhibit proxy
* for "server.com", "host.server.com" but not "xserver.com".
* @param type the socket type, such as SOCK_STREAM or SOCK_DGRAM.
* @param protocol the socket protocol, such as IPPROTO_TCP.
* @param close_on_exec if EINA_TRUE, will set SOCK_CLOEXEC.
* @param cb the callback to report connection
* @param data data to give to callback
*
* @return an Ecore_Thread that will execute the connection.
*
* @internal
*/
Ecore_Thread *efl_net_ip_connect_async_new(const char *address, const char *proxy, const char *proxy_env, const char *no_proxy_env, int type, int protocol, Eina_Bool close_on_exec, Efl_Net_Connect_Async_Cb cb, const void *data);
static inline Eina_Error
efl_net_socket_error_get(void)
{
#ifndef _WIN32
return errno;
#else
Eina_Error err = WSAGetLastError();
if (0) { }
/* used by send() */
#if defined(WSAEACCES) && (WSAEACCES != EACCES)
else if (err == WSAEACCES) err = EACCES;
#endif
#if defined(WSAEWOULDBLOCK) && (WSAEWOULDBLOCK != EAGAIN)
else if (err == WSAEWOULDBLOCK) err = EAGAIN;
#endif
#if defined(WSAEBADF) && (WSAEBADF != EBADF)
else if (err == WSAEBADF) err = EBADF;
#endif
#if defined(WSAECONNRESET) && (WSAECONNRESET != ECONNRESET)
else if (err == WSAECONNRESET) err = ECONNRESET;
#endif
#if defined(WSAEDESTADDRREQ) && (WSAEDESTADDRREQ != EDESTADDRREQ)
else if (err == WSAEDESTADDRREQ) err = EDESTADDRREQ;
#endif
#if defined(WSAEFAULT) && (WSAEFAULT != EFAULT)
else if (err == WSAEFAULT) err = EFAULT;
#endif
#if defined(WSAEINTR) && (WSAEINTR != EINTR)
else if (err == WSAEINTR) err = EINTR;
#endif
#if defined(WSAEINVAL) && (WSAEINVAL != EINVAL)
else if (err == WSAEINVAL) err = EINVAL;
#endif
#if defined(WSAEISCONN) && (WSAEISCONN != EISCONN)
else if (err == WSAEISCONN) err = EISCONN;
#endif
#if defined(WSAEMSGSIZE) && (WSAEMSGSIZE != EMSGSIZE)
else if (err == WSAEMSGSIZE) err = EMSGSIZE;
#endif
#if defined(WSAENOBUFS) && (WSAENOBUFS != ENOBUFS)
else if (err == WSAENOBUFS) err = ENOBUFS;
#endif
#if defined(WSA_NOT_ENOUGH_MEMORY) && (WSA_NOT_ENOUGH_MEMORY != ENOMEM)
else if (err == WSA_NOT_ENOUGH_MEMORY) err = ENOMEM;
#endif
#if defined(WSAENOTCONN) && (WSAENOTCONN != ENOTCONN)
else if (err == WSAENOTCONN) err = ENOTCONN;
#endif
#if defined(WSAENOTSOCK) && (WSAENOTSOCK != ENOTSOCK)
else if (err == WSAENOTSOCK) err = ENOTSOCK;
#endif
#if defined(WSAEOPNOTSUPP) && (WSAEOPNOTSUPP != EOPNOTSUPP)
else if (err == WSAEOPNOTSUPP) err = EOPNOTSUPP;
#endif
#if defined(WSAESHUTDOWN) && (WSAESHUTDOWN != EPIPE)
else if (err == WSAESHUTDOWN) err = EPIPE;
#endif
/* extras used by recv() */
#if defined(WSAECONNREFUSED) && (WSAECONNREFUSED != ECONNREFUSED)
else if (err == WSAECONNREFUSED) err = ECONNREFUSED;
#endif
/* extras used by getsockopt() */
#if defined(WSAENOPROTOOPT) && (WSAENOPROTOOPT != ENOPROTOOPT)
else if (err == WSAENOPROTOOPT) err = ENOPROTOOPT;
#endif
return err;
#endif
}
/**
* Join a multicast group specified by address.
*
* Address must be an IPv4 or IPv6 depending on @a fd and will be
* parsed using inet_pton() with corresponding @a family. The address
* may contain an '@@' delimiter to specify the local interface IP
* address to use. No interface means '0.0.0.0'.
*
* @param fd socket to operate on.
* @param family the socket family of fd, AF_INET or AF_INET6.
* @param address the address in the format IP[@@IFACE]
*
* @return 0 on success, errno mapping otherwise.
* @internal
*/
Eina_Error efl_net_multicast_join(SOCKET fd, int family, const char *address);
/**
* Leave a multicast group specified by address.
*
* This reverses the effect of efl_net_multicast_join().
*
* @param fd socket to operate on.
* @param family the socket family of fd, AF_INET or AF_INET6.
* @param address the address in the format IP[@@IFACE]
*
* @return 0 on success, errno mapping otherwise.
* @internal
*/
Eina_Error efl_net_multicast_leave(SOCKET fd, int family, const char *address);
/**
* Sets the Time-To-Live of multicast packets. <= 1 disables going
* outside of local network.
*
* @param fd socket to operate on.
* @param family the socket family of fd, AF_INET or AF_INET6.
* @param ttl the time-to-live in units.
*
* @return 0 on success, errno mapping otherwise.
* @internal
*/
Eina_Error efl_net_multicast_ttl_set(SOCKET fd, int family, uint8_t ttl);
/**
* Retrieves the current time-to-live of multicast packets.
*
* @param fd socket to operate on.
* @param family the socket family of fd, AF_INET or AF_INET6.
* @param[out] ttl returns the time-to-live in units.
*
* @return 0 on success, errno mapping otherwise.
* @internal
*/
Eina_Error efl_net_multicast_ttl_get(SOCKET fd, int family, uint8_t *ttl);
/**
* Sets if the current local address should get a copy of the packets sent.
*
* @param fd socket to operate on.
* @param family the socket family of fd, AF_INET or AF_INET6.
* @param loopback if #EINA_TRUE, enables receive of local copy. #EINA_FALSE means only remote peers will do.
*
* @return 0 on success, errno mapping otherwise.
* @internal
*/
Eina_Error efl_net_multicast_loopback_set(SOCKET fd, int family, Eina_Bool loopback);
/**
* Gets if the current local address should get a copy of the packets sent.
*
* @param fd socket to operate on.
* @param family the socket family of fd, AF_INET or AF_INET6.
* @param[out] loopback returns if #EINA_TRUE, enables receive of local copy. #EINA_FALSE means only remote peers will do.
*
* @return 0 on success, errno mapping otherwise.
* @internal
*/
Eina_Error efl_net_multicast_loopback_get(SOCKET fd, int family, Eina_Bool *loopback);
/**
* Query the size of the next UDP datagram pending on queue.
*
* @param fd socket to operate on.
* @return the size in bytes.
* @internal
*/
size_t efl_net_udp_datagram_size_query(SOCKET fd);
/* SSL abstraction API */
extern void *efl_net_ssl_context_connection_new(Efl_Net_Ssl_Context *context);
#define EFL_NET_DIALER_HTTP_BUFFER_RECEIVE_SIZE (1U << 14) /* 16Kb to receive */
#endif
|