summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Makefile.am5
-rw-r--r--common/socket.c1169
-rw-r--r--common/socket.h68
-rw-r--r--common/thread.c140
-rw-r--r--common/thread.h76
-rw-r--r--common/userpref.c3
-rw-r--r--common/utils.c530
-rw-r--r--common/utils.h64
8 files changed, 3 insertions, 2052 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
index ab01b83..1a90571 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -25,11 +25,8 @@ noinst_LTLIBRARIES = libinternalcommon.la
25libinternalcommon_la_LIBADD = 25libinternalcommon_la_LIBADD =
26libinternalcommon_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined 26libinternalcommon_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined
27libinternalcommon_la_SOURCES = \ 27libinternalcommon_la_SOURCES = \
28 socket.c socket.h \
29 thread.c thread.h \
30 debug.c debug.h \ 28 debug.c debug.h \
31 userpref.c userpref.h \ 29 userpref.c userpref.h
32 utils.c utils.h
33 30
34if WIN32 31if WIN32
35libinternalcommon_la_LIBADD += -lole32 -lws2_32 32libinternalcommon_la_LIBADD += -lole32 -lws2_32
diff --git a/common/socket.c b/common/socket.c
deleted file mode 100644
index 99a96b1..0000000
--- a/common/socket.c
+++ /dev/null
@@ -1,1169 +0,0 @@
1/*
2 * socket.c
3 *
4 * Copyright (C) 2012-2020 Nikias Bassen <nikias@gmx.li>
5 * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#include <stdio.h>
26#include <stddef.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30#include <errno.h>
31#include <sys/time.h>
32#include <sys/stat.h>
33#ifdef WIN32
34#include <winsock2.h>
35#include <ws2tcpip.h>
36#include <windows.h>
37#ifndef HAVE_GETIFADDRS
38#include <iphlpapi.h>
39#endif
40static int wsa_init = 0;
41#ifndef IFF_RUNNING
42#define IFF_RUNNING IFF_UP
43#endif
44#ifndef AI_NUMERICSERV
45#define AI_NUMERICSERV 0
46#endif
47#else
48#include <sys/socket.h>
49#include <sys/un.h>
50#include <netinet/in.h>
51#include <netinet/tcp.h>
52#include <netdb.h>
53#include <arpa/inet.h>
54#include <fcntl.h>
55#ifdef AF_INET6
56#include <net/if.h>
57#include <ifaddrs.h>
58#endif
59#endif
60#include "socket.h"
61
62#define RECV_TIMEOUT 20000
63#define SEND_TIMEOUT 10000
64#define CONNECT_TIMEOUT 5000
65
66#ifndef EAFNOSUPPORT
67#define EAFNOSUPPORT 102
68#endif
69#ifndef ECONNRESET
70#define ECONNRESET 108
71#endif
72#ifndef ETIMEDOUT
73#define ETIMEDOUT 138
74#endif
75
76static int verbose = 0;
77
78void socket_set_verbose(int level)
79{
80 verbose = level;
81}
82
83const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size)
84{
85#ifdef WIN32
86 WSADATA wsa_data;
87 if (!wsa_init) {
88 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
89 fprintf(stderr, "WSAStartup failed!\n");
90 ExitProcess(-1);
91 }
92 wsa_init = 1;
93 }
94 DWORD addr_out_len = addr_out_size;
95 DWORD addrlen = 0;
96
97 if (addr->sa_family == AF_INET) {
98 addrlen = sizeof(struct sockaddr_in);
99 }
100#ifdef AF_INET6
101 else if (addr->sa_family == AF_INET6) {
102 addrlen = sizeof(struct sockaddr_in6);
103 }
104#endif
105 else {
106 errno = EAFNOSUPPORT;
107 return NULL;
108 }
109
110 if (WSAAddressToString(addr, addrlen, NULL, addr_out, &addr_out_len) == 0) {
111 return addr_out;
112 }
113#else
114 const void *addrdata = NULL;
115
116 if (addr->sa_family == AF_INET) {
117 addrdata = &((struct sockaddr_in*)addr)->sin_addr;
118 }
119#ifdef AF_INET6
120 else if (addr->sa_family == AF_INET6) {
121 addrdata = &((struct sockaddr_in6*)addr)->sin6_addr;
122 }
123#endif
124 else {
125 errno = EAFNOSUPPORT;
126 return NULL;
127 }
128
129 if (inet_ntop(addr->sa_family, addrdata, addr_out, addr_out_size)) {
130 return addr_out;
131 }
132#endif
133 return NULL;
134}
135
136#ifndef WIN32
137int socket_create_unix(const char *filename)
138{
139 struct sockaddr_un name;
140 int sock;
141#ifdef SO_NOSIGPIPE
142 int yes = 1;
143#endif
144
145 // remove if still present
146 unlink(filename);
147
148 /* Create the socket. */
149 sock = socket(PF_UNIX, SOCK_STREAM, 0);
150 if (sock < 0) {
151 perror("socket");
152 return -1;
153 }
154
155#ifdef SO_NOSIGPIPE
156 if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
157 perror("setsockopt()");
158 socket_close(sock);
159 return -1;
160 }
161#endif
162
163 /* Bind a name to the socket. */
164 name.sun_family = AF_UNIX;
165 strncpy(name.sun_path, filename, sizeof(name.sun_path));
166 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
167
168 if (bind(sock, (struct sockaddr*)&name, sizeof(name)) < 0) {
169 perror("bind");
170 socket_close(sock);
171 return -1;
172 }
173
174 if (listen(sock, 100) < 0) {
175 perror("listen");
176 socket_close(sock);
177 return -1;
178 }
179
180 return sock;
181}
182
183int socket_connect_unix(const char *filename)
184{
185 struct sockaddr_un name;
186 int sfd = -1;
187 struct stat fst;
188#ifdef SO_NOSIGPIPE
189 int yes = 1;
190#endif
191 int bufsize = 0x20000;
192
193 // check if socket file exists...
194 if (stat(filename, &fst) != 0) {
195 if (verbose >= 2)
196 fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename,
197 strerror(errno));
198 return -1;
199 }
200 // ... and if it is a unix domain socket
201 if (!S_ISSOCK(fst.st_mode)) {
202 if (verbose >= 2)
203 fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__,
204 filename);
205 return -1;
206 }
207 // make a new socket
208 if ((sfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
209 if (verbose >= 2)
210 fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
211 return -1;
212 }
213
214 if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) {
215 perror("Could not set send buffer for socket");
216 }
217
218 if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) {
219 perror("Could not set receive buffer for socket");
220 }
221
222#ifdef SO_NOSIGPIPE
223 if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
224 perror("setsockopt()");
225 socket_close(sfd);
226 return -1;
227 }
228#endif
229 // and connect to 'filename'
230 name.sun_family = AF_UNIX;
231 strncpy(name.sun_path, filename, sizeof(name.sun_path));
232 name.sun_path[sizeof(name.sun_path) - 1] = 0;
233
234 int flags = fcntl(sfd, F_GETFL, 0);
235 fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
236
237 do {
238 if (connect(sfd, (struct sockaddr*)&name, sizeof(name)) != -1) {
239 break;
240 }
241 if (errno == EINPROGRESS) {
242 fd_set fds;
243 FD_ZERO(&fds);
244 FD_SET(sfd, &fds);
245
246 struct timeval timeout;
247 timeout.tv_sec = CONNECT_TIMEOUT / 1000;
248 timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
249 if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
250 int so_error;
251 socklen_t len = sizeof(so_error);
252 getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
253 if (so_error == 0) {
254 break;
255 }
256 }
257 }
258 socket_close(sfd);
259 sfd = -1;
260 } while (0);
261
262 if (sfd < 0) {
263 if (verbose >= 2)
264 fprintf(stderr, "%s: connect: %s\n", __func__, strerror(errno));
265 return -1;
266 }
267
268 return sfd;
269}
270#endif
271
272int socket_create(const char* addr, uint16_t port)
273{
274 int sfd = -1;
275 int yes = 1;
276 struct addrinfo hints;
277 struct addrinfo *result, *rp;
278 char portstr[8];
279 int res;
280#ifdef WIN32
281 WSADATA wsa_data;
282 if (!wsa_init) {
283 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
284 fprintf(stderr, "WSAStartup failed!\n");
285 ExitProcess(-1);
286 }
287 wsa_init = 1;
288 }
289#endif
290
291 memset(&hints, '\0', sizeof(struct addrinfo));
292 hints.ai_family = AF_UNSPEC;
293 hints.ai_socktype = SOCK_STREAM;
294 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
295 hints.ai_protocol = IPPROTO_TCP;
296
297 sprintf(portstr, "%d", port);
298
299 if (!addr) {
300 addr = "localhost";
301 }
302 res = getaddrinfo(addr, portstr, &hints, &result);
303 if (res != 0) {
304 fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res));
305 return -1;
306 }
307
308 for (rp = result; rp != NULL; rp = rp->ai_next) {
309 sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
310 if (sfd == -1) {
311 continue;
312 }
313
314 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
315 perror("setsockopt()");
316 socket_close(sfd);
317 continue;
318 }
319
320#ifdef SO_NOSIGPIPE
321 if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
322 perror("setsockopt()");
323 socket_close(sfd);
324 continue;
325 }
326#endif
327
328#if defined(AF_INET6) && defined(IPV6_V6ONLY)
329 if (rp->ai_family == AF_INET6) {
330 if (setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(int)) == -1) {
331 perror("setsockopt() IPV6_V6ONLY");
332 }
333 }
334#endif
335
336 if (bind(sfd, rp->ai_addr, rp->ai_addrlen) < 0) {
337 perror("bind()");
338 socket_close(sfd);
339 continue;
340 }
341
342 if (listen(sfd, 100) < 0) {
343 perror("listen()");
344 socket_close(sfd);
345 continue;
346 }
347 break;
348 }
349
350 freeaddrinfo(result);
351
352 if (rp == NULL) {
353 return -1;
354 }
355
356 return sfd;
357}
358
359#ifdef AF_INET6
360static uint32_t _in6_addr_scope(struct in6_addr* addr)
361{
362 uint32_t scope = 0;
363
364 if (IN6_IS_ADDR_MULTICAST(addr)) {
365 if (IN6_IS_ADDR_MC_NODELOCAL(addr)) {
366 scope = 1;
367 } else if (IN6_IS_ADDR_MC_LINKLOCAL(addr)) {
368 scope = 2;
369 } else if (IN6_IS_ADDR_MC_SITELOCAL(addr)) {
370 scope = 5;
371 }
372
373 return scope;
374 }
375
376 if (IN6_IS_ADDR_LINKLOCAL(addr)) {
377 scope = 2;
378 } else if (IN6_IS_ADDR_LOOPBACK(addr)) {
379 scope = 2;
380 } else if (IN6_IS_ADDR_SITELOCAL(addr)) {
381 scope = 5;
382 } else if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
383 scope = 0;
384 }
385
386 return scope;
387}
388
389#ifndef HAVE_GETIFADDRS
390#ifdef WIN32
391
392struct ifaddrs {
393 struct ifaddrs *ifa_next; /* Next item in list */
394 char *ifa_name; /* Name of interface */
395 unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
396 struct sockaddr *ifa_addr; /* Address of interface */
397 struct sockaddr *ifa_netmask; /* Netmask of interface */
398 union {
399 struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */
400 struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */
401 } ifa_ifu;
402#define ifa_broadaddr ifa_ifu.ifu_broadaddr
403#define ifa_dstaddr ifa_ifu.ifu_dstaddr
404 void *ifa_data; /* Address-specific data */
405};
406
407#define WORKING_BUFFER_SIZE 15000
408#define MAX_TRIES 3
409
410static void freeifaddrs(struct ifaddrs *ifa)
411{
412 if (!ifa) {
413 return;
414 }
415 free(ifa->ifa_name);
416 free(ifa->ifa_addr);
417 free(ifa->ifa_netmask);
418 free(ifa->ifa_dstaddr);
419 freeifaddrs(ifa->ifa_next);
420 free(ifa);
421}
422
423/*
424 * getifaddrs() reference implementation for win32.
425 * Heavily based on openpgm's implementation found here:
426 * https://github.com/steve-o/openpgm/blob/master/openpgm/pgm/getifaddrs.c
427 */
428static int getifaddrs(struct ifaddrs** ifap)
429{
430 struct ifaddrs* ifa = NULL;
431
432 DWORD dwRetVal = 0;
433
434 PIP_ADAPTER_ADDRESSES pAddresses = NULL;
435 ULONG outBufLen = 0;
436 ULONG Iterations = 0;
437
438 ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
439 GAA_FLAG_SKIP_ANYCAST |
440 GAA_FLAG_SKIP_DNS_SERVER |
441 GAA_FLAG_SKIP_FRIENDLY_NAME |
442 GAA_FLAG_SKIP_MULTICAST;
443
444 PIP_ADAPTER_ADDRESSES adapter = NULL;
445
446 if (!ifap) {
447 errno = EINVAL;
448 return -1;
449 }
450 *ifap = NULL;
451
452 outBufLen = WORKING_BUFFER_SIZE;
453 do {
454 pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
455 if (pAddresses == NULL) {
456 printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
457 return -1;
458 }
459 dwRetVal = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);
460 if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
461 free(pAddresses);
462 pAddresses = NULL;
463 } else {
464 break;
465 }
466 Iterations++;
467 } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
468
469 if (dwRetVal != NO_ERROR) {
470 free(pAddresses);
471 return -1;
472 }
473
474 for (adapter = pAddresses; adapter; adapter = adapter->Next) {
475 int unicastIndex = 0;
476 for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; unicast; unicast = unicast->Next, ++unicastIndex) {
477 /* ensure IP adapter */
478 if (AF_INET != unicast->Address.lpSockaddr->sa_family && AF_INET6 != unicast->Address.lpSockaddr->sa_family) {
479 continue;
480 }
481
482 if (!ifa) {
483 ifa = malloc(sizeof(struct ifaddrs));
484 if (!ifa) {
485 errno = ENOMEM;
486 free(pAddresses);
487 return -1;
488 }
489 *ifap = ifa;
490 ifa->ifa_next = NULL;
491 } else {
492 struct ifaddrs* ifanew = malloc(sizeof(struct ifaddrs));
493 if (!ifanew) {
494 freeifaddrs(*ifap);
495 free(pAddresses);
496 errno = ENOMEM;
497 return -1;
498 }
499 ifa->ifa_next = ifanew;
500 ifa = ifanew;
501 ifa->ifa_next = NULL;
502 }
503
504 /* name */
505 ifa->ifa_name = strdup(adapter->AdapterName);
506
507 /* flags */
508 ifa->ifa_flags = 0;
509 if (IfOperStatusUp == adapter->OperStatus)
510 ifa->ifa_flags |= IFF_UP;
511 if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType)
512 ifa->ifa_flags |= IFF_LOOPBACK;
513 if (!(adapter->Flags & IP_ADAPTER_NO_MULTICAST))
514 ifa->ifa_flags |= IFF_MULTICAST;
515
516 /* address */
517 ifa->ifa_addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage));
518 memcpy(ifa->ifa_addr, unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength);
519
520 /* netmask */
521 ifa->ifa_netmask = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage));
522 memset(ifa->ifa_netmask, 0, sizeof(struct sockaddr_storage));
523
524/* pre-Vista must hunt for matching prefix in linked list, otherwise use
525 * OnLinkPrefixLength from IP_ADAPTER_UNICAST_ADDRESS structure.
526 * FirstPrefix requires Windows XP SP1, from SP1 to pre-Vista provides a
527 * single adapter prefix for each IP address. Vista and later provides
528 * host IP address prefix, subnet IP address, and subnet broadcast IP
529 * address. In addition there is a multicast and broadcast address prefix.
530 */
531 ULONG prefixLength = 0;
532
533#if defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 )
534/* For a unicast IPv4 address, any value greater than 32 is an illegal
535 * value. For a unicast IPv6 address, any value greater than 128 is an
536 * illegal value. A value of 255 is commonly used to represent an illegal
537 * value.
538 *
539 * Windows 7 SP1 returns 64 for Teredo links which is incorrect.
540 */
541
542#define IN6_IS_ADDR_TEREDO(addr) \
543 (((const uint32_t *)(addr))[0] == ntohl (0x20010000))
544
545 if (AF_INET6 == unicast->Address.lpSockaddr->sa_family &&
546/* TunnelType only applies to one interface on the adapter and no
547 * convenient method is provided to determine which.
548 */
549 TUNNEL_TYPE_TEREDO == adapter->TunnelType &&
550/* Test the interface with the known Teredo network prefix.
551 */
552 IN6_IS_ADDR_TEREDO( &((struct sockaddr_in6*)(unicast->Address.lpSockaddr))->sin6_addr) &&
553/* Test that this version is actually wrong, subsequent releases from Microsoft
554 * may resolve the issue.
555 */
556 32 != unicast->OnLinkPrefixLength)
557 {
558 prefixLength = 32;
559 }
560 else
561 prefixLength = unicast->OnLinkPrefixLength;
562#else
563/* The order of linked IP_ADAPTER_UNICAST_ADDRESS structures pointed to by
564 * the FirstUnicastAddress member does not have any relationship with the
565 * order of linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix
566 * member.
567 *
568 * Example enumeration:
569 * [ no subnet ]
570 * ::1/128 - address
571 * ff00::%1/8 - multicast (no IPv6 broadcast)
572 * 127.0.0.0/8 - subnet
573 * 127.0.0.1/32 - address
574 * 127.255.255.255/32 - subnet broadcast
575 * 224.0.0.0/4 - multicast
576 * 255.255.255.255/32 - broadcast
577 *
578 * Which differs from most adapters listing three IPv6:
579 * fe80::%10/64 - subnet
580 * fe80::51e9:5fe5:4202:325a%10/128 - address
581 * ff00::%10/8 - multicast
582 *
583 * !IfOperStatusUp IPv4 addresses are skipped:
584 * fe80::%13/64 - subnet
585 * fe80::d530:946d:e8df:8c91%13/128 - address
586 * ff00::%13/8 - multicast
587 * [ no subnet ]
588 * [ no address ]
589 * 224.0.0.0/4 - multicast
590 * 255.255.255.255/32 - broadcast
591 *
592 * On PTP links no multicast or broadcast addresses are returned:
593 * [ no subnet ]
594 * fe80::5efe:10.203.9.30/128 - address
595 * [ no multicast ]
596 * [ no multicast ]
597 * [ no broadcast ]
598 *
599 * Active primary IPv6 interfaces are a bit overloaded:
600 * ::/0 - default route
601 * 2001::/32 - global subnet
602 * 2001:0:4137:9e76:2443:d6:ba87:1a2a/128 - global address
603 * fe80::/64 - link-local subnet
604 * fe80::2443:d6:ba87:1a2a/128 - link-local address
605 * ff00::/8 - multicast
606 */
607
608#define IN_LINKLOCAL(a) ((((uint32_t) (a)) & 0xaffff0000) == 0xa9fe0000)
609
610 for (IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
611 LPSOCKADDR lpSockaddr = prefix->Address.lpSockaddr;
612 if (lpSockaddr->sa_family != unicast->Address.lpSockaddr->sa_family)
613 continue;
614/* special cases */
615/* RFC2863: IPv4 interface not up */
616 if (AF_INET == lpSockaddr->sa_family && adapter->OperStatus != IfOperStatusUp) {
617/* RFC3927: link-local IPv4 always has 16-bit CIDR */
618 if (IN_LINKLOCAL( ntohl (((struct sockaddr_in*)(unicast->Address.lpSockaddr))->sin_addr.s_addr))) {
619 prefixLength = 16;
620 }
621 break;
622 }
623/* default IPv6 route */
624 if (AF_INET6 == lpSockaddr->sa_family && 0 == prefix->PrefixLength && IN6_IS_ADDR_UNSPECIFIED( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)) {
625 continue;
626 }
627/* Assume unicast address for first prefix of operational adapter */
628 if (AF_INET == lpSockaddr->sa_family)
629 if (IN_MULTICAST( ntohl (((struct sockaddr_in*)(lpSockaddr))->sin_addr.s_addr))) {
630 fprintf(stderr, "FATAL: first prefix is non a unicast address\n");
631 break;
632 }
633 if (AF_INET6 == lpSockaddr->sa_family)
634 if (IN6_IS_ADDR_MULTICAST( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)) {
635 fprintf(stderr, "FATAL: first prefix is not a unicast address\n");
636 break;
637 }
638/* Assume subnet or host IP address for XP backward compatibility */
639
640 prefixLength = prefix->PrefixLength;
641 break;
642 }
643#endif /* defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) */
644
645/* map prefix to netmask */
646 ifa->ifa_netmask->sa_family = unicast->Address.lpSockaddr->sa_family;
647 switch (unicast->Address.lpSockaddr->sa_family) {
648 case AF_INET:
649 if (0 == prefixLength || prefixLength > 32) {
650 prefixLength = 32;
651 }
652#if defined( _WIN32) && ( _WIN32_WINNT >= 0x0600 )
653/* Added in Vista, but no IPv6 equivalent. */
654 {
655 ULONG Mask;
656 ConvertLengthToIpv4Mask (prefixLength, &Mask);
657 ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr = Mask; /* network order */
658 }
659#else
660/* NB: left-shift of full bit-width is undefined in C standard. */
661 ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr = htonl( 0xffffffffU << ( 32 - prefixLength ) );
662#endif
663 break;
664
665 case AF_INET6:
666 if (0 == prefixLength || prefixLength > 128) {
667 prefixLength = 128;
668 }
669 for (LONG i = prefixLength, j = 0; i > 0; i -= 8, ++j) {
670 ((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr.s6_addr[ j ] = i >= 8 ? 0xff : (ULONG)(( 0xffU << ( 8 - i ) ) & 0xffU );
671 }
672 break;
673 default:
674 break;
675 }
676 }
677 }
678 free(pAddresses);
679
680 return 0;
681}
682#else
683#error No reference implementation for getifaddrs available for this platform.
684#endif
685#endif
686
687static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr)
688{
689 int32_t res = -1;
690 struct ifaddrs *ifaddr = NULL, *ifa = NULL;
691 uint32_t addr_scope;
692
693 /* get scope for requested address */
694 addr_scope = _in6_addr_scope(&addr->sin6_addr);
695 if (addr_scope == 0) {
696 /* global scope doesn't need a specific scope id */
697 return addr_scope;
698 }
699
700 /* get interfaces */
701 if (getifaddrs(&ifaddr) == -1) {
702 perror("getifaddrs");
703 return res;
704 }
705
706 /* loop over interfaces */
707 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
708 /* skip if no address is available */
709 if (ifa->ifa_addr == NULL) {
710 continue;
711 }
712
713 /* skip if wrong family */
714 if (ifa->ifa_addr->sa_family != AF_INET6) {
715 continue;
716 }
717
718 /* skip if not up */
719 if ((ifa->ifa_flags & IFF_UP) == 0) {
720 continue;
721 }
722
723 /* skip if not running */
724 if ((ifa->ifa_flags & IFF_RUNNING) == 0) {
725 continue;
726 }
727
728 struct sockaddr_in6* addr_in = (struct sockaddr_in6*)ifa->ifa_addr;
729
730 /* skip if scopes do not match */
731 if (_in6_addr_scope(&addr_in->sin6_addr) != addr_scope) {
732 continue;
733 }
734
735 /* use if address is equal */
736 if (memcmp(&addr->sin6_addr.s6_addr, &addr_in->sin6_addr.s6_addr, sizeof(addr_in->sin6_addr.s6_addr)) == 0) {
737 /* if scope id equals the requested one then assume it was valid */
738 if (addr->sin6_scope_id == addr_in->sin6_scope_id) {
739 res = addr_in->sin6_scope_id;
740 break;
741 }
742
743 if ((addr_in->sin6_scope_id > addr->sin6_scope_id) && (res >= 0)) {
744 // use last valid scope id as we're past the requested scope id
745 break;
746 }
747 res = addr_in->sin6_scope_id;
748 continue;
749 }
750
751 /* skip loopback interface if not already matched exactly above */
752 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
753 continue;
754 }
755
756 if ((addr_in->sin6_scope_id > addr->sin6_scope_id) && (res >= 0)) {
757 // use last valid scope id as we're past the requested scope id
758 break;
759 }
760
761 res = addr_in->sin6_scope_id;
762
763 /* if scope id equals the requested one then assume it was valid */
764 if (addr->sin6_scope_id == addr_in->sin6_scope_id) {
765 /* set the scope id of this interface as most likely candidate */
766 break;
767 }
768 }
769
770 freeifaddrs(ifaddr);
771
772 return res;
773}
774#endif
775
776int socket_connect_addr(struct sockaddr* addr, uint16_t port)
777{
778 int sfd = -1;
779 int yes = 1;
780 int bufsize = 0x20000;
781 int addrlen = 0;
782#ifdef WIN32
783 u_long l_yes = 1;
784 WSADATA wsa_data;
785 if (!wsa_init) {
786 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
787 fprintf(stderr, "WSAStartup failed!\n");
788 ExitProcess(-1);
789 }
790 wsa_init = 1;
791 }
792#endif
793
794 if (addr->sa_family == AF_INET) {
795 struct sockaddr_in* addr_in = (struct sockaddr_in*)addr;
796 addr_in->sin_port = htons(port);
797 addrlen = sizeof(struct sockaddr_in);
798 }
799#ifdef AF_INET6
800 else if (addr->sa_family == AF_INET6) {
801 struct sockaddr_in6* addr_in = (struct sockaddr_in6*)addr;
802 addr_in->sin6_port = htons(port);
803
804 /*
805 * IPv6 Routing Magic:
806 *
807 * If the scope of the address is a link-local one, IPv6 requires the
808 * scope id set to an interface number to allow proper routing. However,
809 * as the provided sockaddr might contain a wrong scope id, we must find
810 * a scope id from a suitable interface on this system or routing might
811 * fail. An IPv6 guru should have another look though...
812 */
813 addr_in->sin6_scope_id = _sockaddr_in6_scope_id(addr_in);
814
815 addrlen = sizeof(struct sockaddr_in6);
816 }
817#endif
818 else {
819 fprintf(stderr, "ERROR: Unsupported address family");
820 return -1;
821 }
822
823 sfd = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
824 if (sfd == -1) {
825 perror("socket()");
826 return -1;
827 }
828
829#ifdef SO_NOSIGPIPE
830 if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
831 perror("setsockopt()");
832 socket_close(sfd);
833 return -1;
834 }
835#endif
836
837 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
838 perror("setsockopt()");
839 socket_close(sfd);
840 return -1;
841 }
842
843#ifdef WIN32
844 ioctlsocket(sfd, FIONBIO, &l_yes);
845#else
846 int flags = fcntl(sfd, F_GETFL, 0);
847 fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
848#endif
849
850 do {
851 if (connect(sfd, addr, addrlen) != -1) {
852 break;
853 }
854#ifdef WIN32
855 if (WSAGetLastError() == WSAEWOULDBLOCK)
856#else
857 if (errno == EINPROGRESS)
858#endif
859 {
860 fd_set fds;
861 FD_ZERO(&fds);
862 FD_SET(sfd, &fds);
863
864 struct timeval timeout;
865 timeout.tv_sec = CONNECT_TIMEOUT / 1000;
866 timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
867 if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
868 int so_error;
869 socklen_t len = sizeof(so_error);
870 getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
871 if (so_error == 0) {
872 errno = 0;
873 break;
874 }
875 errno = so_error;
876 }
877 }
878 socket_close(sfd);
879 sfd = -1;
880 } while (0);
881
882 if (sfd < 0) {
883 if (verbose >= 2) {
884 char addrtxt[48];
885 socket_addr_to_string(addr, addrtxt, sizeof(addrtxt));
886 fprintf(stderr, "%s: Could not connect to %s port %d\n", __func__, addrtxt, port);
887 }
888 return -1;
889 }
890
891 if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) {
892 perror("Could not set TCP_NODELAY on socket");
893 }
894
895 if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) {
896 perror("Could not set send buffer for socket");
897 }
898
899 if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) {
900 perror("Could not set receive buffer for socket");
901 }
902
903 return sfd;
904}
905
906int socket_connect(const char *addr, uint16_t port)
907{
908 int sfd = -1;
909 int yes = 1;
910 int bufsize = 0x20000;
911 struct addrinfo hints;
912 struct addrinfo *result, *rp;
913 char portstr[8];
914 int res;
915#ifdef WIN32
916 u_long l_yes = 1;
917 WSADATA wsa_data;
918 if (!wsa_init) {
919 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
920 fprintf(stderr, "WSAStartup failed!\n");
921 ExitProcess(-1);
922 }
923 wsa_init = 1;
924 }
925#else
926 int flags = 0;
927#endif
928
929 if (!addr) {
930 errno = EINVAL;
931 return -1;
932 }
933
934 memset(&hints, '\0', sizeof(struct addrinfo));
935 hints.ai_family = AF_UNSPEC;
936 hints.ai_socktype = SOCK_STREAM;
937 hints.ai_flags = AI_NUMERICSERV;
938 hints.ai_protocol = IPPROTO_TCP;
939
940 sprintf(portstr, "%d", port);
941
942 res = getaddrinfo(addr, portstr, &hints, &result);
943 if (res != 0) {
944 fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res));
945 return -1;
946 }
947
948 for (rp = result; rp != NULL; rp = rp->ai_next) {
949 sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
950 if (sfd == -1) {
951 continue;
952 }
953
954#ifdef SO_NOSIGPIPE
955 if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
956 perror("setsockopt()");
957 socket_close(sfd);
958 return -1;
959 }
960#endif
961
962 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
963 perror("setsockopt()");
964 socket_close(sfd);
965 continue;
966 }
967
968#ifdef WIN32
969 ioctlsocket(sfd, FIONBIO, &l_yes);
970#else
971 flags = fcntl(sfd, F_GETFL, 0);
972 fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
973#endif
974
975 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) {
976 break;
977 }
978#ifdef WIN32
979 if (WSAGetLastError() == WSAEWOULDBLOCK)
980#else
981 if (errno == EINPROGRESS)
982#endif
983 {
984 fd_set fds;
985 FD_ZERO(&fds);
986 FD_SET(sfd, &fds);
987
988 struct timeval timeout;
989 timeout.tv_sec = CONNECT_TIMEOUT / 1000;
990 timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
991 if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
992 int so_error;
993 socklen_t len = sizeof(so_error);
994 getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
995 if (so_error == 0) {
996 break;
997 }
998 }
999 }
1000 socket_close(sfd);
1001 }
1002
1003 freeaddrinfo(result);
1004
1005 if (rp == NULL) {
1006 if (verbose >= 2)
1007 fprintf(stderr, "%s: Could not connect to %s:%d\n", __func__, addr, port);
1008 return -1;
1009 }
1010
1011 if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) {
1012 perror("Could not set TCP_NODELAY on socket");
1013 }
1014
1015 if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) {
1016 perror("Could not set send buffer for socket");
1017 }
1018
1019 if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) {
1020 perror("Could not set receive buffer for socket");
1021 }
1022
1023 return sfd;
1024}
1025
1026int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
1027{
1028 fd_set fds;
1029 int sret;
1030 int eagain;
1031 struct timeval to;
1032 struct timeval *pto;
1033
1034 if (fd < 0) {
1035 if (verbose >= 2)
1036 fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
1037 return -1;
1038 }
1039
1040 FD_ZERO(&fds);
1041 FD_SET(fd, &fds);
1042
1043 sret = -1;
1044
1045 do {
1046 if (timeout > 0) {
1047 to.tv_sec = (time_t) (timeout / 1000);
1048 to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
1049 pto = &to;
1050 } else {
1051 pto = NULL;
1052 }
1053 eagain = 0;
1054 switch (fdm) {
1055 case FDM_READ:
1056 sret = select(fd + 1, &fds, NULL, NULL, pto);
1057 break;
1058 case FDM_WRITE:
1059 sret = select(fd + 1, NULL, &fds, NULL, pto);
1060 break;
1061 case FDM_EXCEPT:
1062 sret = select(fd + 1, NULL, NULL, &fds, pto);
1063 break;
1064 default:
1065 return -1;
1066 }
1067
1068 if (sret < 0) {
1069 switch (errno) {
1070 case EINTR:
1071 // interrupt signal in select
1072 if (verbose >= 2)
1073 fprintf(stderr, "%s: EINTR\n", __func__);
1074 eagain = 1;
1075 break;
1076 case EAGAIN:
1077 if (verbose >= 2)
1078 fprintf(stderr, "%s: EAGAIN\n", __func__);
1079 break;
1080 default:
1081 if (verbose >= 2)
1082 fprintf(stderr, "%s: select failed: %s\n", __func__,
1083 strerror(errno));
1084 return -1;
1085 }
1086 } else if (sret == 0) {
1087 return -ETIMEDOUT;
1088 }
1089 } while (eagain);
1090
1091 return sret;
1092}
1093
1094int socket_accept(int fd, uint16_t port)
1095{
1096#ifdef WIN32
1097 int addr_len;
1098#else
1099 socklen_t addr_len;
1100#endif
1101 int result;
1102 struct sockaddr_storage addr;
1103 addr_len = sizeof(addr);
1104
1105 result = accept(fd, (struct sockaddr*)&addr, &addr_len);
1106
1107 return result;
1108}
1109
1110int socket_shutdown(int fd, int how)
1111{
1112 return shutdown(fd, how);
1113}
1114
1115int socket_close(int fd) {
1116#ifdef WIN32
1117 return closesocket(fd);
1118#else
1119 return close(fd);
1120#endif
1121}
1122
1123int socket_receive(int fd, void *data, size_t length)
1124{
1125 return socket_receive_timeout(fd, data, length, 0, RECV_TIMEOUT);
1126}
1127
1128int socket_peek(int fd, void *data, size_t length)
1129{
1130 return socket_receive_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
1131}
1132
1133int socket_receive_timeout(int fd, void *data, size_t length, int flags,
1134 unsigned int timeout)
1135{
1136 int res;
1137 int result;
1138
1139 // check if data is available
1140 res = socket_check_fd(fd, FDM_READ, timeout);
1141 if (res <= 0) {
1142 return res;
1143 }
1144 // if we get here, there _is_ data available
1145 result = recv(fd, data, length, flags);
1146 if (res > 0 && result == 0) {
1147 // but this is an error condition
1148 if (verbose >= 3)
1149 fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
1150 return -ECONNRESET;
1151 }
1152 if (result < 0) {
1153 return -errno;
1154 }
1155 return result;
1156}
1157
1158int socket_send(int fd, void *data, size_t length)
1159{
1160 int flags = 0;
1161 int res = socket_check_fd(fd, FDM_WRITE, SEND_TIMEOUT);
1162 if (res <= 0) {
1163 return res;
1164 }
1165#ifdef MSG_NOSIGNAL
1166 flags |= MSG_NOSIGNAL;
1167#endif
1168 return send(fd, data, length, flags);
1169}
diff --git a/common/socket.h b/common/socket.h
deleted file mode 100644
index 9567270..0000000
--- a/common/socket.h
+++ /dev/null
@@ -1,68 +0,0 @@
1/*
2 * socket.h
3 *
4 * Copyright (C) 2012-2020 Nikias Bassen <nikias@gmx.li>
5 * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef SOCKET_SOCKET_H
23#define SOCKET_SOCKET_H
24
25#include <stdlib.h>
26#include <stdint.h>
27
28enum fd_mode {
29 FDM_READ,
30 FDM_WRITE,
31 FDM_EXCEPT
32};
33typedef enum fd_mode fd_mode;
34
35#ifdef WIN32
36#include <winsock2.h>
37#define SHUT_RD SD_READ
38#define SHUT_WR SD_WRITE
39#define SHUT_RDWR SD_BOTH
40#else
41#include <sys/socket.h>
42#endif
43
44#ifndef WIN32
45int socket_create_unix(const char *filename);
46int socket_connect_unix(const char *filename);
47#endif
48int socket_create(const char *addr, uint16_t port);
49int socket_connect_addr(struct sockaddr *addr, uint16_t port);
50int socket_connect(const char *addr, uint16_t port);
51int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout);
52int socket_accept(int fd, uint16_t port);
53
54int socket_shutdown(int fd, int how);
55int socket_close(int fd);
56
57int socket_receive(int fd, void *data, size_t length);
58int socket_peek(int fd, void *data, size_t length);
59int socket_receive_timeout(int fd, void *data, size_t length, int flags,
60 unsigned int timeout);
61
62int socket_send(int fd, void *data, size_t length);
63
64void socket_set_verbose(int level);
65
66const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size);
67
68#endif /* SOCKET_SOCKET_H */
diff --git a/common/thread.c b/common/thread.c
deleted file mode 100644
index eb535ab..0000000
--- a/common/thread.c
+++ /dev/null
@@ -1,140 +0,0 @@
1/*
2 * thread.c
3 *
4 * Copyright (c) 2012-2019 Nikias Bassen, All Rights Reserved.
5 * Copyright (c) 2012 Martin Szulecki, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#include "thread.h"
26
27int thread_new(THREAD_T *thread, thread_func_t thread_func, void* data)
28{
29#ifdef WIN32
30 HANDLE th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, data, 0, NULL);
31 if (th == NULL) {
32 return -1;
33 }
34 *thread = th;
35 return 0;
36#else
37 int res = pthread_create(thread, NULL, thread_func, data);
38 return res;
39#endif
40}
41
42void thread_detach(THREAD_T thread)
43{
44#ifdef WIN32
45 CloseHandle(thread);
46#else
47 pthread_detach(thread);
48#endif
49}
50
51void thread_free(THREAD_T thread)
52{
53#ifdef WIN32
54 CloseHandle(thread);
55#endif
56}
57
58int thread_join(THREAD_T thread)
59{
60 /* wait for thread to complete */
61#ifdef WIN32
62 return (int)WaitForSingleObject(thread, INFINITE);
63#else
64 return pthread_join(thread, NULL);
65#endif
66}
67
68int thread_alive(THREAD_T thread)
69{
70#ifdef WIN32
71 return WaitForSingleObject(thread, 0) == WAIT_TIMEOUT;
72#else
73 return pthread_kill(thread, 0) == 0;
74#endif
75}
76
77int thread_cancel(THREAD_T thread)
78{
79#ifdef WIN32
80 return -1;
81#else
82#ifdef HAVE_PTHREAD_CANCEL
83 return pthread_cancel(thread);
84#else
85 return -1;
86#endif
87#endif
88}
89
90void mutex_init(mutex_t* mutex)
91{
92#ifdef WIN32
93 InitializeCriticalSection(mutex);
94#else
95 pthread_mutex_init(mutex, NULL);
96#endif
97}
98
99void mutex_destroy(mutex_t* mutex)
100{
101#ifdef WIN32
102 DeleteCriticalSection(mutex);
103#else
104 pthread_mutex_destroy(mutex);
105#endif
106}
107
108void mutex_lock(mutex_t* mutex)
109{
110#ifdef WIN32
111 EnterCriticalSection(mutex);
112#else
113 pthread_mutex_lock(mutex);
114#endif
115}
116
117void mutex_unlock(mutex_t* mutex)
118{
119#ifdef WIN32
120 LeaveCriticalSection(mutex);
121#else
122 pthread_mutex_unlock(mutex);
123#endif
124}
125
126void thread_once(thread_once_t *once_control, void (*init_routine)(void))
127{
128#ifdef WIN32
129 while (InterlockedExchange(&(once_control->lock), 1) != 0) {
130 Sleep(1);
131 }
132 if (!once_control->state) {
133 once_control->state = 1;
134 init_routine();
135 }
136 InterlockedExchange(&(once_control->lock), 0);
137#else
138 pthread_once(once_control, init_routine);
139#endif
140}
diff --git a/common/thread.h b/common/thread.h
deleted file mode 100644
index 23e4510..0000000
--- a/common/thread.h
+++ /dev/null
@@ -1,76 +0,0 @@
1/*
2 * thread.h
3 *
4 * Copyright (c) 2012-2019 Nikias Bassen, All Rights Reserved.
5 * Copyright (c) 2012 Martin Szulecki, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef __THREAD_H
23#define __THREAD_H
24
25#include <stddef.h>
26
27#ifdef WIN32
28#include <windows.h>
29typedef HANDLE THREAD_T;
30typedef CRITICAL_SECTION mutex_t;
31typedef volatile struct {
32 LONG lock;
33 int state;
34} thread_once_t;
35#define THREAD_ONCE_INIT {0, 0}
36#define THREAD_ID GetCurrentThreadId()
37#define THREAD_T_NULL (THREAD_T)NULL
38#else
39#include <pthread.h>
40#include <signal.h>
41typedef pthread_t THREAD_T;
42typedef pthread_mutex_t mutex_t;
43typedef pthread_once_t thread_once_t;
44#define THREAD_ONCE_INIT PTHREAD_ONCE_INIT
45#define THREAD_ID pthread_self()
46#define THREAD_T_NULL (THREAD_T)NULL
47#endif
48
49typedef void* (*thread_func_t)(void* data);
50
51int thread_new(THREAD_T* thread, thread_func_t thread_func, void* data);
52void thread_detach(THREAD_T thread);
53void thread_free(THREAD_T thread);
54int thread_join(THREAD_T thread);
55int thread_alive(THREAD_T thread);
56
57int thread_cancel(THREAD_T thread);
58
59#ifdef WIN32
60#undef HAVE_THREAD_CLEANUP
61#else
62#ifdef HAVE_PTHREAD_CANCEL
63#define HAVE_THREAD_CLEANUP 1
64#define thread_cleanup_push(routine, arg) pthread_cleanup_push(routine, arg)
65#define thread_cleanup_pop(execute) pthread_cleanup_pop(execute)
66#endif
67#endif
68
69void mutex_init(mutex_t* mutex);
70void mutex_destroy(mutex_t* mutex);
71void mutex_lock(mutex_t* mutex);
72void mutex_unlock(mutex_t* mutex);
73
74void thread_once(thread_once_t *once_control, void (*init_routine)(void));
75
76#endif
diff --git a/common/userpref.c b/common/userpref.c
index bf7e1bd..32904c7 100644
--- a/common/userpref.c
+++ b/common/userpref.c
@@ -73,9 +73,10 @@
73#include <shlobj.h> 73#include <shlobj.h>
74#endif 74#endif
75 75
76#include <libimobiledevice-glue/utils.h>
77
76#include "userpref.h" 78#include "userpref.h"
77#include "debug.h" 79#include "debug.h"
78#include "utils.h"
79 80
80#if defined(HAVE_GNUTLS) 81#if defined(HAVE_GNUTLS)
81const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { 82const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
diff --git a/common/utils.c b/common/utils.c
deleted file mode 100644
index 58dac02..0000000
--- a/common/utils.c
+++ /dev/null
@@ -1,530 +0,0 @@
1/*
2 * utils.c
3 * Miscellaneous utilities for string manipulation,
4 * file I/O and plist helper.
5 *
6 * Copyright (c) 2014-2019 Nikias Bassen, All Rights Reserved.
7 * Copyright (c) 2013-2014 Martin Szulecki, All Rights Reserved.
8 * Copyright (c) 2013 Federico Mena Quintero
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28
29#include <stdarg.h>
30#include <stdlib.h>
31#include <string.h>
32#include <time.h>
33#include <sys/time.h>
34#include <inttypes.h>
35#include <ctype.h>
36
37#include "utils.h"
38
39#ifndef HAVE_STPCPY
40/**
41 * Copy characters from one string into another
42 *
43 * @note: The strings should not overlap, as the behavior is undefined.
44 *
45 * @s1: The source string.
46 * @s2: The destination string.
47 *
48 * @return a pointer to the terminating `\0' character of @s1,
49 * or NULL if @s1 or @s2 is NULL.
50 */
51char *stpcpy(char *s1, const char *s2)
52{
53 if (s1 == NULL || s2 == NULL)
54 return NULL;
55
56 strcpy(s1, s2);
57
58 return s1 + strlen(s2);
59}
60#endif
61
62/**
63 * Concatenate strings into a newly allocated string
64 *
65 * @note: Specify NULL for the last string in the varargs list
66 *
67 * @str: The first string in the list
68 * @...: Subsequent strings. Use NULL for the last item.
69 *
70 * @return a newly allocated string, or NULL if @str is NULL. This will also
71 * return NULL and set errno to ENOMEM if memory is exhausted.
72 */
73char *string_concat(const char *str, ...)
74{
75 size_t len;
76 va_list args;
77 char *s;
78 char *result;
79 char *dest;
80
81 if (!str)
82 return NULL;
83
84 /* Compute final length */
85
86 len = strlen(str) + 1; /* plus 1 for the null terminator */
87
88 va_start(args, str);
89 s = va_arg(args, char *);
90 while (s) {
91 len += strlen(s);
92 s = va_arg(args, char*);
93 }
94 va_end(args);
95
96 /* Concat each string */
97
98 result = malloc(len);
99 if (!result)
100 return NULL; /* errno remains set */
101
102 dest = result;
103
104 dest = stpcpy(dest, str);
105
106 va_start(args, str);
107 s = va_arg(args, char *);
108 while (s) {
109 dest = stpcpy(dest, s);
110 s = va_arg(args, char *);
111 }
112 va_end(args);
113
114 return result;
115}
116
117char *string_append(char* str, ...)
118{
119 size_t len = 0;
120 size_t slen;
121 va_list args;
122 char *s;
123 char *result;
124 char *dest;
125
126 /* Compute final length */
127
128 if (str) {
129 len = strlen(str);
130 }
131 slen = len;
132 len++; /* plus 1 for the null terminator */
133
134 va_start(args, str);
135 s = va_arg(args, char *);
136 while (s) {
137 len += strlen(s);
138 s = va_arg(args, char*);
139 }
140 va_end(args);
141
142 result = realloc(str, len);
143 if (!result)
144 return NULL; /* errno remains set */
145
146 dest = result + slen;
147
148 /* Concat additional strings */
149
150 va_start(args, str);
151 s = va_arg(args, char *);
152 while (s) {
153 dest = stpcpy(dest, s);
154 s = va_arg(args, char *);
155 }
156 va_end(args);
157
158 return result;
159}
160
161char *string_build_path(const char *elem, ...)
162{
163 if (!elem)
164 return NULL;
165 va_list args;
166 int len = strlen(elem)+1;
167 va_start(args, elem);
168 char *arg = va_arg(args, char*);
169 while (arg) {
170 len += strlen(arg)+1;
171 arg = va_arg(args, char*);
172 }
173 va_end(args);
174
175 char* out = (char*)malloc(len);
176 strcpy(out, elem);
177
178 va_start(args, elem);
179 arg = va_arg(args, char*);
180 while (arg) {
181 strcat(out, "/");
182 strcat(out, arg);
183 arg = va_arg(args, char*);
184 }
185 va_end(args);
186 return out;
187}
188
189char *string_format_size(uint64_t size)
190{
191 char buf[80];
192 double sz;
193 if (size >= 1000000000000LL) {
194 sz = ((double)size / 1000000000000.0f);
195 sprintf(buf, "%0.1f TB", sz);
196 } else if (size >= 1000000000LL) {
197 sz = ((double)size / 1000000000.0f);
198 sprintf(buf, "%0.1f GB", sz);
199 } else if (size >= 1000000LL) {
200 sz = ((double)size / 1000000.0f);
201 sprintf(buf, "%0.1f MB", sz);
202 } else if (size >= 1000LL) {
203 sz = ((double)size / 1000.0f);
204 sprintf(buf, "%0.1f KB", sz);
205 } else {
206 sprintf(buf, "%d Bytes", (int)size);
207 }
208 return strdup(buf);
209}
210
211char *string_toupper(char* str)
212{
213 char *res = strdup(str);
214 unsigned int i;
215 for (i = 0; i < strlen(res); i++) {
216 res[i] = toupper(res[i]);
217 }
218 return res;
219}
220
221static int get_rand(int min, int max)
222{
223 int retval = (rand() % (max - min)) + min;
224 return retval;
225}
226
227char *generate_uuid()
228{
229 const char *chars = "ABCDEF0123456789";
230 int i = 0;
231 char *uuid = (char *) malloc(sizeof(char) * 37);
232
233 srand(time(NULL));
234
235 for (i = 0; i < 36; i++) {
236 if (i == 8 || i == 13 || i == 18 || i == 23) {
237 uuid[i] = '-';
238 continue;
239 } else {
240 uuid[i] = chars[get_rand(0, 16)];
241 }
242 }
243
244 /* make it a real string */
245 uuid[36] = '\0';
246
247 return uuid;
248}
249
250void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
251{
252 FILE *f;
253 uint64_t size;
254
255 *length = 0;
256
257 f = fopen(filename, "rb");
258 if (!f) {
259 return;
260 }
261
262 fseek(f, 0, SEEK_END);
263 size = ftell(f);
264 rewind(f);
265
266 if (size == 0) {
267 fclose(f);
268 return;
269 }
270
271 *buffer = (char*)malloc(sizeof(char)*(size+1));
272 if (fread(*buffer, sizeof(char), size, f) != size) {
273 fclose(f);
274 return;
275 }
276 fclose(f);
277
278 *length = size;
279}
280
281void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
282{
283 FILE *f;
284
285 f = fopen(filename, "wb");
286 if (f) {
287 fwrite(buffer, sizeof(char), length, f);
288 fclose(f);
289 }
290}
291
292int plist_read_from_filename(plist_t *plist, const char *filename)
293{
294 char *buffer = NULL;
295 uint64_t length;
296
297 if (!filename)
298 return 0;
299
300 buffer_read_from_filename(filename, &buffer, &length);
301
302 if (!buffer) {
303 return 0;
304 }
305
306 if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) {
307 plist_from_bin(buffer, length, plist);
308 } else {
309 plist_from_xml(buffer, length, plist);
310 }
311
312 free(buffer);
313
314 return 1;
315}
316
317int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
318{
319 char *buffer = NULL;
320 uint32_t length;
321
322 if (!plist || !filename)
323 return 0;
324
325 if (format == PLIST_FORMAT_XML)
326 plist_to_xml(plist, &buffer, &length);
327 else if (format == PLIST_FORMAT_BINARY)
328 plist_to_bin(plist, &buffer, &length);
329 else
330 return 0;
331
332 buffer_write_to_filename(filename, buffer, length);
333
334 free(buffer);
335
336 return 1;
337}
338
339static const char base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
340static const char base64_pad = '=';
341
342static char *base64encode(const unsigned char *buf, size_t size)
343{
344 if (!buf || !(size > 0)) return NULL;
345 int outlen = (size / 3) * 4;
346 char *outbuf = (char*)malloc(outlen+5); // 4 spare bytes + 1 for '\0'
347 size_t n = 0;
348 size_t m = 0;
349 unsigned char input[3];
350 unsigned int output[4];
351 while (n < size) {
352 input[0] = buf[n];
353 input[1] = (n+1 < size) ? buf[n+1] : 0;
354 input[2] = (n+2 < size) ? buf[n+2] : 0;
355 output[0] = input[0] >> 2;
356 output[1] = ((input[0] & 3) << 4) + (input[1] >> 4);
357 output[2] = ((input[1] & 15) << 2) + (input[2] >> 6);
358 output[3] = input[2] & 63;
359 outbuf[m++] = base64_str[(int)output[0]];
360 outbuf[m++] = base64_str[(int)output[1]];
361 outbuf[m++] = (n+1 < size) ? base64_str[(int)output[2]] : base64_pad;
362 outbuf[m++] = (n+2 < size) ? base64_str[(int)output[3]] : base64_pad;
363 n+=3;
364 }
365 outbuf[m] = 0; // 0-termination!
366 return outbuf;
367}
368
369static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream);
370
371static void plist_array_print_to_stream(plist_t node, int* indent_level, FILE* stream)
372{
373 /* iterate over items */
374 int i, count;
375 plist_t subnode = NULL;
376
377 count = plist_array_get_size(node);
378
379 for (i = 0; i < count; i++) {
380 subnode = plist_array_get_item(node, i);
381 fprintf(stream, "%*s", *indent_level, "");
382 fprintf(stream, "%d: ", i);
383 plist_node_print_to_stream(subnode, indent_level, stream);
384 }
385}
386
387static void plist_dict_print_to_stream(plist_t node, int* indent_level, FILE* stream)
388{
389 /* iterate over key/value pairs */
390 plist_dict_iter it = NULL;
391
392 char* key = NULL;
393 plist_t subnode = NULL;
394 plist_dict_new_iter(node, &it);
395 plist_dict_next_item(node, it, &key, &subnode);
396 while (subnode)
397 {
398 fprintf(stream, "%*s", *indent_level, "");
399 fprintf(stream, "%s", key);
400 if (plist_get_node_type(subnode) == PLIST_ARRAY)
401 fprintf(stream, "[%d]: ", plist_array_get_size(subnode));
402 else
403 fprintf(stream, ": ");
404 free(key);
405 key = NULL;
406 plist_node_print_to_stream(subnode, indent_level, stream);
407 plist_dict_next_item(node, it, &key, &subnode);
408 }
409 free(it);
410}
411
412static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream)
413{
414 char *s = NULL;
415 char *data = NULL;
416 double d;
417 uint8_t b;
418 uint64_t u = 0;
419 struct timeval tv = { 0, 0 };
420
421 plist_type t;
422
423 if (!node)
424 return;
425
426 t = plist_get_node_type(node);
427
428 switch (t) {
429 case PLIST_BOOLEAN:
430 plist_get_bool_val(node, &b);
431 fprintf(stream, "%s\n", (b ? "true" : "false"));
432 break;
433
434 case PLIST_UINT:
435 plist_get_uint_val(node, &u);
436 fprintf(stream, "%"PRIu64"\n", u);
437 break;
438
439 case PLIST_REAL:
440 plist_get_real_val(node, &d);
441 fprintf(stream, "%f\n", d);
442 break;
443
444 case PLIST_STRING:
445 plist_get_string_val(node, &s);
446 fprintf(stream, "%s\n", s);
447 free(s);
448 break;
449
450 case PLIST_KEY:
451 plist_get_key_val(node, &s);
452 fprintf(stream, "%s: ", s);
453 free(s);
454 break;
455
456 case PLIST_DATA:
457 plist_get_data_val(node, &data, &u);
458 if (u > 0) {
459 s = base64encode((unsigned char*)data, u);
460 free(data);
461 if (s) {
462 fprintf(stream, "%s\n", s);
463 free(s);
464 } else {
465 fprintf(stream, "\n");
466 }
467 } else {
468 fprintf(stream, "\n");
469 }
470 break;
471
472 case PLIST_DATE:
473 plist_get_date_val(node, (int32_t*)&tv.tv_sec, (int32_t*)&tv.tv_usec);
474 {
475 time_t ti = (time_t)tv.tv_sec + MAC_EPOCH;
476 struct tm *btime = localtime(&ti);
477 if (btime) {
478 s = (char*)malloc(24);
479 memset(s, 0, 24);
480 if (strftime(s, 24, "%Y-%m-%dT%H:%M:%SZ", btime) <= 0) {
481 free (s);
482 s = NULL;
483 }
484 }
485 }
486 if (s) {
487 fprintf(stream, "%s\n", s);
488 free(s);
489 } else {
490 fprintf(stream, "\n");
491 }
492 break;
493
494 case PLIST_ARRAY:
495 fprintf(stream, "\n");
496 (*indent_level)++;
497 plist_array_print_to_stream(node, indent_level, stream);
498 (*indent_level)--;
499 break;
500
501 case PLIST_DICT:
502 fprintf(stream, "\n");
503 (*indent_level)++;
504 plist_dict_print_to_stream(node, indent_level, stream);
505 (*indent_level)--;
506 break;
507
508 default:
509 break;
510 }
511}
512
513void plist_print_to_stream(plist_t plist, FILE* stream)
514{
515 int indent = 0;
516
517 if (!plist || !stream)
518 return;
519
520 switch (plist_get_node_type(plist)) {
521 case PLIST_DICT:
522 plist_dict_print_to_stream(plist, &indent, stream);
523 break;
524 case PLIST_ARRAY:
525 plist_array_print_to_stream(plist, &indent, stream);
526 break;
527 default:
528 plist_node_print_to_stream(plist, &indent, stream);
529 }
530}
diff --git a/common/utils.h b/common/utils.h
deleted file mode 100644
index 2c3acec..0000000
--- a/common/utils.h
+++ /dev/null
@@ -1,64 +0,0 @@
1/*
2 * utils.h
3 * Miscellaneous utilities for string manipulation,
4 * file I/O and plist helper.
5 *
6 * Copyright (c) 2014-2019 Nikias Bassen, All Rights Reserved.
7 * Copyright (c) 2013-2014 Martin Szulecki, All Rights Reserved.
8 * Copyright (c) 2013 Federico Mena Quintero
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#ifndef __UTILS_H
26#define __UTILS_H
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32#ifdef WIN32
33#include <windows.h>
34#endif
35
36#include <stdio.h>
37#include <plist/plist.h>
38
39#define MAC_EPOCH 978307200
40
41#ifndef HAVE_STPCPY
42char *stpcpy(char *s1, const char *s2);
43#endif
44char *string_concat(const char *str, ...);
45char *string_append(char *str, ...);
46char *string_build_path(const char *elem, ...);
47char *string_format_size(uint64_t size);
48char *string_toupper(char *str);
49char *generate_uuid(void);
50
51void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length);
52void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length);
53
54enum plist_format_t {
55 PLIST_FORMAT_XML,
56 PLIST_FORMAT_BINARY
57};
58
59int plist_read_from_filename(plist_t *plist, const char *filename);
60int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format);
61
62void plist_print_to_stream(plist_t plist, FILE* stream);
63
64#endif