1
2 /*
3 bctoolbox
4 Copyright (C) 2016 Belledonne Communications SARL
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "bctoolbox/logging.h"
26 #include "bctoolbox/port.h"
27 #include "bctoolbox/vconnect.h"
28 #include "bctoolbox/list.h"
29 #include "utils.h"
30
31 #if defined(_WIN32) && !defined(_WIN32_WCE)
32 #include <process.h>
33 #endif
34
35 #ifdef _MSC_VER
36 #ifndef access
37 #define access _access
38 #endif
39 #endif
40
41 #ifdef HAVE_SYS_SHM_H
42 #include <sys/shm.h>
43 #endif
44
45 #ifndef MIN
46 #define MIN(a,b) a<=b ? a : b
47 #endif
48
bctbx_libc_malloc(size_t sz)49 static void *bctbx_libc_malloc(size_t sz){
50 return malloc(sz);
51 }
52
bctbx_libc_realloc(void * ptr,size_t sz)53 static void *bctbx_libc_realloc(void *ptr, size_t sz){
54 return realloc(ptr,sz);
55 }
56
bctbx_libc_free(void * ptr)57 static void bctbx_libc_free(void*ptr){
58 free(ptr);
59 }
60
61 static bool_t allocator_used=FALSE;
62
63 static BctoolboxMemoryFunctions bctbx_allocator={
64 bctbx_libc_malloc,
65 bctbx_libc_realloc,
66 bctbx_libc_free
67 };
68
bctbx_set_memory_functions(BctoolboxMemoryFunctions * functions)69 void bctbx_set_memory_functions(BctoolboxMemoryFunctions *functions){
70 if (allocator_used){
71 bctbx_fatal("bctbx_set_memory_functions() must be called before "
72 "first use of bctbx_malloc or bctbx_realloc");
73 return;
74 }
75 bctbx_allocator=*functions;
76 }
77
bctbx_malloc(size_t sz)78 void* bctbx_malloc(size_t sz){
79 allocator_used=TRUE;
80 return bctbx_allocator.malloc_fun(sz);
81 }
82
bctbx_realloc(void * ptr,size_t sz)83 void* bctbx_realloc(void *ptr, size_t sz){
84 allocator_used=TRUE;
85 return bctbx_allocator.realloc_fun(ptr,sz);
86 }
87
bctbx_free(void * ptr)88 void bctbx_free(void* ptr){
89 bctbx_allocator.free_fun(ptr);
90 }
91
bctbx_malloc0(size_t size)92 void * bctbx_malloc0(size_t size){
93 void *ptr=bctbx_malloc(size);
94 memset(ptr,0,size);
95 return ptr;
96 }
97
bctbx_strdup(const char * tmp)98 char * bctbx_strdup(const char *tmp){
99 size_t sz;
100 char *ret;
101 if (tmp==NULL)
102 return NULL;
103 sz=strlen(tmp)+1;
104 ret=(char*)bctbx_malloc(sz);
105 strcpy(ret,tmp);
106 ret[sz-1]='\0';
107 return ret;
108 }
109
bctbx_dirname(const char * path)110 char * bctbx_dirname(const char *path) {
111 char *ptr;
112 char *dname = bctbx_strdup(path);
113 bool_t found = FALSE;
114
115 ptr = strrchr(path, '/');
116 if (ptr != NULL) {
117 dname[ptr - path] = '\0';
118 found = TRUE;
119 } else {
120 ptr = strrchr(path, '\\');
121 if (ptr != NULL) {
122 dname[ptr - path] = '\0';
123 found = TRUE;
124 }
125 }
126
127 if (found == FALSE) {
128 bctbx_free(dname);
129 return NULL;
130 }
131 return dname;
132 }
133
bctbx_basename(const char * path)134 char * bctbx_basename(const char *path) {
135 char *ptr = strrchr(path, '/');
136 if (ptr == NULL) ptr = strrchr(path, '\\');
137 if (ptr == NULL) return NULL;
138 return bctbx_strdup(ptr + 1);
139 }
140
141 /*
142 * this method is an utility method that calls fnctl() on UNIX or
143 * ioctlsocket on Win32.
144 * int retrun the result of the system method
145 */
bctbx_socket_set_non_blocking(bctbx_socket_t sock)146 int bctbx_socket_set_non_blocking(bctbx_socket_t sock){
147 #if !defined(_WIN32) && !defined(_WIN32_WCE)
148 return fcntl (sock, F_SETFL, O_NONBLOCK);
149 #else
150 unsigned long nonBlock = 1;
151 return ioctlsocket(sock, FIONBIO , &nonBlock);
152 #endif
153 }
154
155
156
bctbx_file_exist(const char * pathname)157 int bctbx_file_exist(const char *pathname) {
158 return access(pathname,F_OK);
159 }
160
161 #if !defined(_WIN32) && !defined(_WIN32_WCE)
162 /* Use UNIX inet_aton method */
163 #else
__bctbx_WIN_inet_aton(const char * cp,struct in_addr * addr)164 int __bctbx_WIN_inet_aton (const char * cp, struct in_addr * addr)
165 {
166 unsigned long retval;
167
168 retval = inet_addr (cp);
169
170 if (retval == INADDR_NONE)
171 {
172 return -1;
173 }
174 else
175 {
176 addr->S_un.S_addr = retval;
177 return 1;
178 }
179 }
180 #endif
181
bctbx_strndup(const char * str,int n)182 char *bctbx_strndup(const char *str,int n){
183 int min=MIN((int)strlen(str),n)+1;
184 char *ret=(char*)bctbx_malloc(min);
185 strncpy(ret,str,min);
186 ret[min-1]='\0';
187 return ret;
188 }
189
190 #if !defined(_WIN32) && !defined(_WIN32_WCE)
__bctbx_thread_join(bctbx_thread_t thread,void ** ptr)191 int __bctbx_thread_join(bctbx_thread_t thread, void **ptr){
192 int err=pthread_join(thread,ptr);
193 if (err!=0) {
194 bctbx_error("pthread_join error: %s",strerror(err));
195 }
196 return err;
197 }
198
__bctbx_thread_create(bctbx_thread_t * thread,pthread_attr_t * attr,void * (* routine)(void *),void * arg)199 int __bctbx_thread_create(bctbx_thread_t *thread, pthread_attr_t *attr, void * (*routine)(void*), void *arg){
200 pthread_attr_t my_attr;
201 pthread_attr_init(&my_attr);
202 if (attr)
203 my_attr = *attr;
204 #ifdef BCTBX_DEFAULT_THREAD_STACK_SIZE
205 if (BCTBX_DEFAULT_THREAD_STACK_SIZE!=0)
206 pthread_attr_setstacksize(&my_attr, BCTBX_DEFAULT_THREAD_STACK_SIZE);
207 #endif
208 return pthread_create(thread, &my_attr, routine, arg);
209 }
210
__bctbx_thread_self(void)211 unsigned long __bctbx_thread_self(void) {
212 return (unsigned long)pthread_self();
213 }
214
215 #endif
216 #if defined(_WIN32) || defined(_WIN32_WCE)
217
__bctbx_WIN_mutex_init(bctbx_mutex_t * mutex,void * attr)218 int __bctbx_WIN_mutex_init(bctbx_mutex_t *mutex, void *attr)
219 {
220 #ifdef BCTBX_WINDOWS_DESKTOP
221 *mutex=CreateMutex(NULL, FALSE, NULL);
222 #else
223 InitializeSRWLock(mutex);
224 #endif
225 return 0;
226 }
227
__bctbx_WIN_mutex_lock(bctbx_mutex_t * hMutex)228 int __bctbx_WIN_mutex_lock(bctbx_mutex_t * hMutex)
229 {
230 #ifdef BCTBX_WINDOWS_DESKTOP
231 WaitForSingleObject(*hMutex, INFINITE); /* == WAIT_TIMEOUT; */
232 #else
233 AcquireSRWLockExclusive(hMutex);
234 #endif
235 return 0;
236 }
237
__bctbx_WIN_mutex_unlock(bctbx_mutex_t * hMutex)238 int __bctbx_WIN_mutex_unlock(bctbx_mutex_t * hMutex)
239 {
240 #ifdef BCTBX_WINDOWS_DESKTOP
241 ReleaseMutex(*hMutex);
242 #else
243 ReleaseSRWLockExclusive(hMutex);
244 #endif
245 return 0;
246 }
247
__bctbx_WIN_mutex_destroy(bctbx_mutex_t * hMutex)248 int __bctbx_WIN_mutex_destroy(bctbx_mutex_t * hMutex)
249 {
250 #ifdef BCTBX_WINDOWS_DESKTOP
251 CloseHandle(*hMutex);
252 #endif
253 return 0;
254 }
255
256 typedef struct thread_param{
257 void * (*func)(void *);
258 void * arg;
259 }thread_param_t;
260
thread_starter(void * data)261 static unsigned WINAPI thread_starter(void *data){
262 thread_param_t *params=(thread_param_t*)data;
263 params->func(params->arg);
264 bctbx_free(data);
265 return 0;
266 }
267
268 #if defined _WIN32_WCE
269 # define _beginthreadex CreateThread
270 # define _endthreadex ExitThread
271 #endif
272
__bctbx_WIN_thread_create(bctbx_thread_t * th,void * attr,void * (* func)(void *),void * data)273 int __bctbx_WIN_thread_create(bctbx_thread_t *th, void *attr, void * (*func)(void *), void *data)
274 {
275 thread_param_t *params=bctbx_new(thread_param_t,1);
276 params->func=func;
277 params->arg=data;
278 *th=(HANDLE)_beginthreadex( NULL, 0, thread_starter, params, 0, NULL);
279 return 0;
280 }
281
__bctbx_WIN_thread_join(bctbx_thread_t thread_h,void ** unused)282 int __bctbx_WIN_thread_join(bctbx_thread_t thread_h, void **unused)
283 {
284 if (thread_h!=NULL)
285 {
286 WaitForSingleObjectEx(thread_h, INFINITE, FALSE);
287 CloseHandle(thread_h);
288 }
289 return 0;
290 }
291
__bctbx_WIN_thread_self(void)292 unsigned long __bctbx_WIN_thread_self(void) {
293 return (unsigned long)GetCurrentThreadId();
294 }
295
__bctbx_WIN_cond_init(bctbx_cond_t * cond,void * attr)296 int __bctbx_WIN_cond_init(bctbx_cond_t *cond, void *attr)
297 {
298 #ifdef BCTBX_WINDOWS_DESKTOP
299 *cond=CreateEvent(NULL, FALSE, FALSE, NULL);
300 #else
301 InitializeConditionVariable(cond);
302 #endif
303 return 0;
304 }
305
__bctbx_WIN_cond_wait(bctbx_cond_t * hCond,bctbx_mutex_t * hMutex)306 int __bctbx_WIN_cond_wait(bctbx_cond_t* hCond, bctbx_mutex_t * hMutex)
307 {
308 #ifdef BCTBX_WINDOWS_DESKTOP
309 //gulp: this is not very atomic ! bug here ?
310 __bctbx_WIN_mutex_unlock(hMutex);
311 WaitForSingleObject(*hCond, INFINITE);
312 __bctbx_WIN_mutex_lock(hMutex);
313 #else
314 SleepConditionVariableSRW(hCond, hMutex, INFINITE, 0);
315 #endif
316 return 0;
317 }
318
__bctbx_WIN_cond_signal(bctbx_cond_t * hCond)319 int __bctbx_WIN_cond_signal(bctbx_cond_t * hCond)
320 {
321 #ifdef BCTBX_WINDOWS_DESKTOP
322 SetEvent(*hCond);
323 #else
324 WakeConditionVariable(hCond);
325 #endif
326 return 0;
327 }
328
__bctbx_WIN_cond_broadcast(bctbx_cond_t * hCond)329 int __bctbx_WIN_cond_broadcast(bctbx_cond_t * hCond)
330 {
331 __bctbx_WIN_cond_signal(hCond);
332 return 0;
333 }
334
__bctbx_WIN_cond_destroy(bctbx_cond_t * hCond)335 int __bctbx_WIN_cond_destroy(bctbx_cond_t * hCond)
336 {
337 #ifdef BCTBX_WINDOWS_DESKTOP
338 CloseHandle(*hCond);
339 #endif
340 return 0;
341 }
342
343 #if defined(_WIN32_WCE)
344 #include <time.h>
345
bctbx_strerror(DWORD value)346 const char * bctbx_strerror(DWORD value) {
347 static TCHAR msgBuf[256];
348 FormatMessage(
349 FORMAT_MESSAGE_FROM_SYSTEM |
350 FORMAT_MESSAGE_IGNORE_INSERTS,
351 NULL,
352 value,
353 0, // Default language
354 (LPTSTR) &msgBuf,
355 0,
356 NULL
357 );
358 return (const char *)msgBuf;
359 }
360
361 int
gettimeofday(struct timeval * tv,void * tz)362 gettimeofday (struct timeval *tv, void *tz)
363 {
364 DWORD timemillis = GetTickCount();
365 tv->tv_sec = timemillis/1000;
366 tv->tv_usec = (timemillis - (tv->tv_sec*1000)) * 1000;
367 return 0;
368 }
369
370 #else
371
bctbx_gettimeofday(struct timeval * tv,void * tz)372 int bctbx_gettimeofday (struct timeval *tv, void* tz)
373 {
374 union
375 {
376 __int64 ns100; /*time since 1 Jan 1601 in 100ns units */
377 FILETIME fileTime;
378 } now;
379
380 GetSystemTimeAsFileTime (&now.fileTime);
381 tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL);
382 tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL);
383 return (0);
384 }
385
386 #endif
387
__bctbx_getWinSocketError(int error)388 const char *__bctbx_getWinSocketError(int error)
389 {
390 static char buf[256];
391 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof(buf), NULL);
392 return buf;
393 }
394
395 #ifdef _WORKAROUND_MINGW32_BUGS
gai_strerror(int errnum)396 char * WSAAPI gai_strerror(int errnum){
397 return (char*)__bctbx_getWinSocketError(errnum);
398 }
399 #endif
400
401 #endif
402
403 #ifndef _WIN32
404
405 #include <sys/socket.h>
406 #include <netdb.h>
407 #include <sys/un.h>
408 #include <sys/stat.h>
409
make_pipe_name(const char * name)410 static char *make_pipe_name(const char *name){
411 return bctbx_strdup_printf("/tmp/%s",name);
412 }
413
414 /* portable named pipes */
bctbx_server_pipe_create(const char * name)415 bctbx_socket_t bctbx_server_pipe_create(const char *name){
416 struct sockaddr_un sa;
417 char *pipename=make_pipe_name(name);
418 bctbx_socket_t sock;
419 sock=socket(AF_UNIX,SOCK_STREAM,0);
420 sa.sun_family=AF_UNIX;
421 strncpy(sa.sun_path,pipename,sizeof(sa.sun_path)-1);
422 unlink(pipename);/*in case we didn't finished properly previous time */
423 bctbx_free(pipename);
424 fchmod(sock,S_IRUSR|S_IWUSR);
425 if (bind(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){
426 bctbx_error("Failed to bind command unix socket: %s",strerror(errno));
427 return -1;
428 }
429 listen(sock,1);
430 return sock;
431 }
432
bctbx_server_pipe_accept_client(bctbx_socket_t server)433 bctbx_socket_t bctbx_server_pipe_accept_client(bctbx_socket_t server){
434 struct sockaddr_un su;
435 socklen_t ssize=sizeof(su);
436 bctbx_socket_t client_sock=accept(server,(struct sockaddr*)&su,&ssize);
437 return client_sock;
438 }
439
bctbx_server_pipe_close_client(bctbx_socket_t client)440 int bctbx_server_pipe_close_client(bctbx_socket_t client){
441 return close(client);
442 }
443
bctbx_server_pipe_close(bctbx_socket_t spipe)444 int bctbx_server_pipe_close(bctbx_socket_t spipe){
445 struct sockaddr_un sa;
446 socklen_t len=sizeof(sa);
447 int err;
448 /*this is to retrieve the name of the pipe, in order to unlink the file*/
449 err=getsockname(spipe,(struct sockaddr*)&sa,&len);
450 if (err==0){
451 unlink(sa.sun_path);
452 }else bctbx_error("getsockname(): %s",strerror(errno));
453 return close(spipe);
454 }
455
bctbx_client_pipe_connect(const char * name)456 bctbx_socket_t bctbx_client_pipe_connect(const char *name){
457 bctbx_socket_t sock = -1;
458 struct sockaddr_un sa;
459 struct stat fstats;
460 char *pipename=make_pipe_name(name);
461 uid_t uid = getuid();
462
463 // check that the creator of the pipe is us
464 if( (stat(name, &fstats) == 0) && (fstats.st_uid != uid) ){
465 bctbx_error("UID of file %s (%lu) differs from ours (%lu)", pipename, (unsigned long)fstats.st_uid, (unsigned long)uid);
466 return -1;
467 }
468
469 sock = socket(AF_UNIX,SOCK_STREAM,0);
470 sa.sun_family=AF_UNIX;
471 strncpy(sa.sun_path,pipename,sizeof(sa.sun_path)-1);
472 bctbx_free(pipename);
473 if (connect(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){
474 close(sock);
475 return -1;
476 }
477 return sock;
478 }
479
bctbx_pipe_read(bctbx_socket_t p,uint8_t * buf,int len)480 int bctbx_pipe_read(bctbx_socket_t p, uint8_t *buf, int len){
481 return read(p,buf,len);
482 }
483
bctbx_pipe_write(bctbx_socket_t p,const uint8_t * buf,int len)484 int bctbx_pipe_write(bctbx_socket_t p, const uint8_t *buf, int len){
485 return write(p,buf,len);
486 }
487
bctbx_client_pipe_close(bctbx_socket_t sock)488 int bctbx_client_pipe_close(bctbx_socket_t sock){
489 return close(sock);
490 }
491
492 #ifdef HAVE_SYS_SHM_H
493
bctbx_shm_open(unsigned int keyid,int size,int create)494 void *bctbx_shm_open(unsigned int keyid, int size, int create){
495 key_t key=keyid;
496 void *mem;
497 int perms=S_IRUSR|S_IWUSR;
498 int fd=shmget(key,size,create ? (IPC_CREAT | perms ) : perms);
499 if (fd==-1){
500 printf("shmget failed: %s\n",strerror(errno));
501 return NULL;
502 }
503 mem=shmat(fd,NULL,0);
504 if (mem==(void*)-1){
505 printf("shmat() failed: %s", strerror(errno));
506 return NULL;
507 }
508 return mem;
509 }
510
bctbx_shm_close(void * mem)511 void bctbx_shm_close(void *mem){
512 shmdt(mem);
513 }
514
515 #endif
516
517 #elif defined(_WIN32) && !defined(_WIN32_WCE)
518
make_pipe_name(const char * name)519 static char *make_pipe_name(const char *name){
520 return bctbx_strdup_printf("\\\\.\\pipe\\%s",name);
521 }
522
523 static HANDLE event=NULL;
524
525 /* portable named pipes */
bctbx_server_pipe_create(const char * name)526 bctbx_pipe_t bctbx_server_pipe_create(const char *name){
527 #ifdef BCTBX_WINDOWS_DESKTOP
528 bctbx_pipe_t h;
529 char *pipename=make_pipe_name(name);
530 h=CreateNamedPipe(pipename,PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,PIPE_TYPE_MESSAGE|PIPE_WAIT,1,
531 32768,32768,0,NULL);
532 bctbx_free(pipename);
533 if (h==INVALID_HANDLE_VALUE){
534 bctbx_error("Fail to create named pipe %s",pipename);
535 }
536 if (event==NULL) event=CreateEvent(NULL,TRUE,FALSE,NULL);
537 return h;
538 #else
539 bctbx_error("%s not supported!", __FUNCTION__);
540 return INVALID_HANDLE_VALUE;
541 #endif
542 }
543
544
545 /*this function is a bit complex because we need to wakeup someday
546 even if nobody connects to the pipe.
547 bctbx_server_pipe_close() makes this function to exit.
548 */
bctbx_server_pipe_accept_client(bctbx_pipe_t server)549 bctbx_pipe_t bctbx_server_pipe_accept_client(bctbx_pipe_t server){
550 #ifdef BCTBX_WINDOWS_DESKTOP
551 OVERLAPPED ol;
552 DWORD undef;
553 HANDLE handles[2];
554 memset(&ol,0,sizeof(ol));
555 ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
556 ConnectNamedPipe(server,&ol);
557 handles[0]=ol.hEvent;
558 handles[1]=event;
559 WaitForMultipleObjects(2,handles,FALSE,INFINITE);
560 if (GetOverlappedResult(server,&ol,&undef,FALSE)){
561 CloseHandle(ol.hEvent);
562 return server;
563 }
564 CloseHandle(ol.hEvent);
565 return INVALID_HANDLE_VALUE;
566 #else
567 bctbx_error("%s not supported!", __FUNCTION__);
568 return INVALID_HANDLE_VALUE;
569 #endif
570 }
571
bctbx_server_pipe_close_client(bctbx_pipe_t server)572 int bctbx_server_pipe_close_client(bctbx_pipe_t server){
573 #ifdef BCTBX_WINDOWS_DESKTOP
574 return DisconnectNamedPipe(server)==TRUE ? 0 : -1;
575 #else
576 bctbx_error("%s not supported!", __FUNCTION__);
577 return -1;
578 #endif
579 }
580
bctbx_server_pipe_close(bctbx_pipe_t spipe)581 int bctbx_server_pipe_close(bctbx_pipe_t spipe){
582 #ifdef BCTBX_WINDOWS_DESKTOP
583 SetEvent(event);
584 //CancelIoEx(spipe,NULL); /*vista only*/
585 return CloseHandle(spipe);
586 #else
587 bctbx_error("%s not supported!", __FUNCTION__);
588 return -1;
589 #endif
590 }
591
bctbx_client_pipe_connect(const char * name)592 bctbx_pipe_t bctbx_client_pipe_connect(const char *name){
593 #ifdef BCTBX_WINDOWS_DESKTOP
594 char *pipename=make_pipe_name(name);
595 bctbx_pipe_t hpipe = CreateFile(
596 pipename, // pipe name
597 GENERIC_READ | // read and write access
598 GENERIC_WRITE,
599 0, // no sharing
600 NULL, // default security attributes
601 OPEN_EXISTING, // opens existing pipe
602 0, // default attributes
603 NULL); // no template file
604 bctbx_free(pipename);
605 return hpipe;
606 #else
607 bctbx_error("%s not supported!", __FUNCTION__);
608 return INVALID_HANDLE_VALUE;
609 #endif
610 }
611
bctbx_pipe_read(bctbx_pipe_t p,uint8_t * buf,int len)612 int bctbx_pipe_read(bctbx_pipe_t p, uint8_t *buf, int len){
613 DWORD ret=0;
614 if (ReadFile(p,buf,len,&ret,NULL))
615 return ret;
616 /*bctbx_error("Could not read from pipe: %s",strerror(GetLastError()));*/
617 return -1;
618 }
619
bctbx_pipe_write(bctbx_pipe_t p,const uint8_t * buf,int len)620 int bctbx_pipe_write(bctbx_pipe_t p, const uint8_t *buf, int len){
621 DWORD ret=0;
622 if (WriteFile(p,buf,len,&ret,NULL))
623 return ret;
624 /*bctbx_error("Could not write to pipe: %s",strerror(GetLastError()));*/
625 return -1;
626 }
627
628
bctbx_client_pipe_close(bctbx_pipe_t sock)629 int bctbx_client_pipe_close(bctbx_pipe_t sock){
630 return CloseHandle(sock);
631 }
632
633
634 typedef struct MapInfo{
635 HANDLE h;
636 void *mem;
637 }MapInfo;
638
639 static bctbx_list_t *maplist=NULL;
640
bctbx_shm_open(unsigned int keyid,int size,int create)641 void *bctbx_shm_open(unsigned int keyid, int size, int create){
642 #ifdef BCTBX_WINDOWS_DESKTOP
643 HANDLE h;
644 char name[64];
645 void *buf;
646
647 snprintf(name,sizeof(name),"%x",keyid);
648 if (create){
649 h = CreateFileMapping(
650 INVALID_HANDLE_VALUE, // use paging file
651 NULL, // default security
652 PAGE_READWRITE, // read/write access
653 0, // maximum object size (high-order DWORD)
654 size, // maximum object size (low-order DWORD)
655 name); // name of mapping object
656 }else{
657 h = OpenFileMapping(
658 FILE_MAP_ALL_ACCESS, // read/write access
659 FALSE, // do not inherit the name
660 name); // name of mapping object
661 }
662 if (h==(HANDLE)-1) {
663 bctbx_error("Fail to open file mapping (create=%i)",create);
664 return NULL;
665 }
666 buf = (LPTSTR) MapViewOfFile(h, // handle to map object
667 FILE_MAP_ALL_ACCESS, // read/write permission
668 0,
669 0,
670 size);
671 if (buf!=NULL){
672 MapInfo *i=(MapInfo*)bctbx_new(MapInfo,1);
673 i->h=h;
674 i->mem=buf;
675 maplist=bctbx_list_append(maplist,i);
676 }else{
677 CloseHandle(h);
678 bctbx_error("MapViewOfFile failed");
679 }
680 return buf;
681 #else
682 bctbx_error("%s not supported!", __FUNCTION__);
683 return NULL;
684 #endif
685 }
686
bctbx_shm_close(void * mem)687 void bctbx_shm_close(void *mem){
688 #ifdef BCTBX_WINDOWS_DESKTOP
689 bctbx_list_t *elem;
690 for(elem=maplist;elem;elem=bctbx_list_next(elem)){
691 MapInfo *i=(MapInfo*)bctbx_list_get_data(elem);
692 if (i->mem==mem){
693 CloseHandle(i->h);
694 UnmapViewOfFile(mem);
695 bctbx_free(i);
696 maplist=bctbx_list_erase_link(maplist,elem);
697 return;
698 }
699 }
700 bctbx_error("No shared memory at %p was found.",mem);
701 #else
702 bctbx_error("%s not supported!", __FUNCTION__);
703 #endif
704 }
705
706
707 #endif
708
709
710 #ifdef __MACH__
711 #include <sys/types.h>
712 #include <sys/timeb.h>
713 #endif
714
_bctbx_get_cur_time(bctoolboxTimeSpec * ret,bool_t realtime)715 void _bctbx_get_cur_time(bctoolboxTimeSpec *ret, bool_t realtime){
716 #if defined(_WIN32_WCE) || defined(WIN32)
717 #ifdef BCTBX_WINDOWS_DESKTOP
718 DWORD timemillis;
719 # if defined(_WIN32_WCE)
720 timemillis=GetTickCount();
721 # else
722 timemillis=timeGetTime();
723 # endif
724 ret->tv_sec=timemillis/1000;
725 ret->tv_nsec=(timemillis%1000)*1000000LL;
726 #else
727 ULONGLONG timemillis = GetTickCount64();
728 ret->tv_sec = timemillis / 1000;
729 ret->tv_nsec = (timemillis % 1000) * 1000000LL;
730 #endif
731 #elif defined(__MACH__) && defined(__GNUC__) && (__GNUC__ >= 3)
732 struct timeval tv;
733 gettimeofday(&tv, NULL);
734 ret->tv_sec=tv.tv_sec;
735 ret->tv_nsec=tv.tv_usec*1000LL;
736 #elif defined(__MACH__)
737 struct timeb time_val;
738
739 ftime (&time_val);
740 ret->tv_sec = time_val.time;
741 ret->tv_nsec = time_val.millitm * 1000000LL;
742 #else
743 struct timespec ts;
744 if (clock_gettime(realtime ? CLOCK_REALTIME : CLOCK_MONOTONIC,&ts)<0){
745 bctbx_fatal("clock_gettime() doesn't work: %s",strerror(errno));
746 }
747 ret->tv_sec=ts.tv_sec;
748 ret->tv_nsec=ts.tv_nsec;
749 #endif
750 }
751
bctbx_get_utc_cur_time(bctoolboxTimeSpec * ret)752 void bctbx_get_utc_cur_time(bctoolboxTimeSpec *ret){
753 _bctbx_get_cur_time(ret, TRUE);
754 }
755
bctbx_get_cur_time(bctoolboxTimeSpec * ret)756 void bctbx_get_cur_time(bctoolboxTimeSpec *ret){
757 _bctbx_get_cur_time(ret, FALSE);
758 }
759
760
bctbx_get_cur_time_ms(void)761 uint64_t bctbx_get_cur_time_ms(void) {
762 bctoolboxTimeSpec ts;
763 _bctbx_get_cur_time(&ts, TRUE);
764 return (ts.tv_sec * 1000LL) + ((ts.tv_nsec + 500000LL) / 1000000LL);
765 }
766
bctbx_sleep_ms(int ms)767 void bctbx_sleep_ms(int ms){
768 #ifdef _WIN32
769 #ifdef BCTBX_WINDOWS_DESKTOP
770 Sleep(ms);
771 #else
772 HANDLE sleepEvent = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
773 if (!sleepEvent) return;
774 WaitForSingleObjectEx(sleepEvent, ms, FALSE);
775 CloseHandle(sleepEvent);
776 #endif
777 #else
778 struct timespec ts;
779 ts.tv_sec=ms/1000;
780 ts.tv_nsec=(ms%1000)*1000000LL;
781 nanosleep(&ts,NULL);
782 #endif
783 }
784
bctbx_sleep_until(const bctoolboxTimeSpec * ts)785 void bctbx_sleep_until(const bctoolboxTimeSpec *ts){
786 #ifdef __linux
787 struct timespec rq;
788 rq.tv_sec=ts->tv_sec;
789 rq.tv_nsec=ts->tv_nsec;
790 while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &rq, NULL)==-1 && errno==EINTR){
791 }
792 #else
793 bctoolboxTimeSpec current;
794 bctoolboxTimeSpec diff;
795 _bctbx_get_cur_time(¤t, TRUE);
796 diff.tv_sec=ts->tv_sec-current.tv_sec;
797 diff.tv_nsec=ts->tv_nsec-current.tv_nsec;
798 if (diff.tv_nsec<0){
799 diff.tv_nsec+=1000000000LL;
800 diff.tv_sec-=1;
801 }
802 #ifdef _WIN32
803 bctbx_sleep_ms((int)((diff.tv_sec * 1000LL) + (diff.tv_nsec/1000000LL)));
804 #else
805 {
806 struct timespec dur,rem;
807 dur.tv_sec=diff.tv_sec;
808 dur.tv_nsec=diff.tv_nsec;
809 while (nanosleep(&dur,&rem)==-1 && errno==EINTR){
810 dur=rem;
811 };
812 }
813 #endif
814 #endif
815 }
816
817 /**
818 * @brief Add given amount of seconds to a timeSpec structure
819 *
820 * @param[in/out] ts The timeSpec structure used as input, modified in output by increnting it according to second argument
821 * @param[in] lap In seconds, number of seconds to modify the given timeSpec, can be negative(which may set the original timeSpec to 0)
822 */
bctbx_timespec_add(bctoolboxTimeSpec * ts,const int64_t lap)823 void bctbx_timespec_add(bctoolboxTimeSpec *ts, const int64_t lap) {
824 if (lap<0 && -lap > ts->tv_sec) {
825 ts->tv_sec = 0;
826 ts->tv_nsec = 0;
827 } else {
828 ts->tv_sec += lap;
829 }
830 }
831
832 /**
833 * @brief Compares two TimeSpec s1 and s2.
834 *
835 * @param[in] s1 First time spec
836 * @param[in] s2 Second time spec
837 *
838 * @return a negative value if s1 is earlier than s2, 0 if they are equal, a positive value if s1 is later than s2
839 */
bctbx_timespec_compare(const bctoolboxTimeSpec * s1,const bctoolboxTimeSpec * s2)840 int bctbx_timespec_compare(const bctoolboxTimeSpec *s1, const bctoolboxTimeSpec *s2){
841 int64_t secdiff = s1->tv_sec - s2->tv_sec;
842 if (secdiff == 0){
843 int64_t nsec_diff = s1->tv_nsec - s2->tv_nsec;
844 if (nsec_diff < 0){
845 return -1;
846 }else if (nsec_diff > 0){
847 return 1;
848 }else return 0;
849 }else if (secdiff < 0){
850 return -1;
851 }else
852 return 1;
853 }
854
855
bctbx_time_string_to_sec(const char * timeString)856 uint32_t bctbx_time_string_to_sec(const char *timeString) {
857
858 char *p = NULL;
859 char *o = NULL;
860 int32_t n=0;
861 uint32_t ret=0;
862
863 if (timeString == NULL) {
864 return 0;
865 }
866
867 o = p = bctbx_strdup(timeString);
868
869 while (*p!='\0') {
870 n=strtol(p, &p, 10);
871 switch (*p) {
872 case '\0':
873 ret+=n;
874 break;
875
876 case 'Y':
877 ret +=n*365*24*3600;
878 p++;
879 break;
880
881 case 'M':
882 ret +=n*30*24*3600;
883 p++;
884 break;
885
886 case 'W':
887 ret +=n*7*24*3600;
888 p++;
889 break;
890
891 case 'd':
892 ret +=n*24*3600;
893 p++;
894 break;
895
896 case 'h':
897 ret +=n*3600;
898 p++;
899 break;
900
901 case 'm':
902 ret +=n*60;
903 p++;
904 break;
905
906 case 's':
907 ret+=n;
908 p++;
909 break;
910
911 default: /* just ignore any other suffix */
912 p++;
913 break;
914 }
915 }
916 bctbx_free(o);
917 return ret;
918 }
919
920 #if defined(_WIN32) && !defined(_MSC_VER)
strtok_r(char * str,const char * delim,char ** nextp)921 char* strtok_r(char *str, const char *delim, char **nextp){
922 char *ret;
923
924 if (str == NULL){
925 str = *nextp;
926 }
927 str += strspn(str, delim);
928 if (*str == '\0'){
929 return NULL;
930 }
931 ret = str;
932 str += strcspn(str, delim);
933 if (*str){
934 *str++ = '\0';
935 }
936 *nextp = str;
937 return ret;
938 }
939 #endif
940
941
942 #if defined(_WIN32) && !defined(_MSC_VER)
943 #include <wincrypt.h>
bctbx_wincrypto_random(unsigned int * rand_number)944 static int bctbx_wincrypto_random(unsigned int *rand_number){
945 static HCRYPTPROV hProv=(HCRYPTPROV)-1;
946 static int initd=0;
947
948 if (!initd){
949 if (!CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){
950 bctbx_error("bctbx_wincrypto_random(): Could not acquire a windows crypto context");
951 return -1;
952 }
953 initd=TRUE;
954 }
955 if (hProv==(HCRYPTPROV)-1)
956 return -1;
957
958 if (!CryptGenRandom(hProv,4,(BYTE*)rand_number)){
959 bctbx_error("bctbx_wincrypto_random(): CryptGenRandom() failed.");
960 return -1;
961 }
962 return 0;
963 }
964 #endif
965
bctbx_random(void)966 unsigned int bctbx_random(void){
967 #ifdef HAVE_ARC4RANDOM
968 return arc4random();
969 #elif defined(__linux) || defined(__APPLE__)
970 static int fd=-1;
971 if (fd==-1) fd=open("/dev/urandom",O_RDONLY);
972 if (fd!=-1){
973 unsigned int tmp;
974 if (read(fd,&tmp,4)!=4){
975 bctbx_error("Reading /dev/urandom failed.");
976 }else return tmp;
977 }else bctbx_error("Could not open /dev/urandom");
978 #elif defined(_WIN32)
979 static int initd=0;
980 unsigned int ret;
981 #ifdef _MSC_VER
982 /*rand_s() is pretty nice and simple function but is not wrapped by mingw.*/
983
984 if (rand_s(&ret)==0){
985 return ret;
986 }
987 #else
988 if (bctbx_wincrypto_random(&ret)==0){
989 return ret;
990 }
991 #endif
992 /* Windows's rand() is unsecure but is used as a fallback*/
993 if (!initd) {
994 struct timeval tv;
995 bctbx_gettimeofday(&tv,NULL);
996 srand((unsigned int)tv.tv_sec+tv.tv_usec);
997 initd=1;
998 bctbx_warning("bctoolbox: Random generator is using rand(), this is unsecure !");
999 }
1000 return rand()<<16 | rand();
1001 #endif
1002 /*fallback to UNIX random()*/
1003 #ifndef _WIN32
1004 return (unsigned int) random();
1005 #endif
1006 }
bctbx_is_multicast_addr(const struct sockaddr * addr)1007 bool_t bctbx_is_multicast_addr(const struct sockaddr *addr) {
1008
1009 switch (addr->sa_family) {
1010 case AF_INET:
1011 return IN_MULTICAST(ntohl(((struct sockaddr_in *) addr)->sin_addr.s_addr));
1012 case AF_INET6:
1013 return IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *) addr)->sin6_addr));
1014 default:
1015 return FALSE;
1016 }
1017
1018 }
1019
1020 #ifdef _WIN32
1021
1022
bctbx_send(bctbx_socket_t socket,const void * buffer,size_t length,int flags)1023 ssize_t bctbx_send(bctbx_socket_t socket, const void *buffer, size_t length, int flags) {
1024 return send(socket, (const char *)buffer, (int)length, flags);
1025 }
1026
bctbx_sendto(bctbx_socket_t socket,const void * message,size_t length,int flags,const struct sockaddr * dest_addr,socklen_t dest_len)1027 ssize_t bctbx_sendto(bctbx_socket_t socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len) {
1028 return sendto(socket, (const char *)message, (int)length, flags, dest_addr, (int)dest_len);
1029 }
1030
bctbx_recv(bctbx_socket_t socket,void * buffer,size_t length,int flags)1031 ssize_t bctbx_recv(bctbx_socket_t socket, void *buffer, size_t length, int flags) {
1032 return recv(socket, (char *)buffer, (int)length, flags);
1033 }
1034
bctbx_recvfrom(bctbx_socket_t socket,void * buffer,size_t length,int flags,struct sockaddr * address,socklen_t * address_len)1035 ssize_t bctbx_recvfrom(bctbx_socket_t socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len) {
1036 return recvfrom(socket, (char *)buffer, (int)length, flags, address, (int *)address_len);
1037 }
1038
bctbx_read(int fd,void * buf,size_t nbytes)1039 ssize_t bctbx_read(int fd, void *buf, size_t nbytes) {
1040 return (ssize_t)_read(fd, buf, (unsigned int)nbytes);
1041 }
1042
bctbx_write(int fd,const void * buf,size_t nbytes)1043 ssize_t bctbx_write(int fd, const void *buf, size_t nbytes) {
1044 return (ssize_t)_write(fd, buf, (unsigned int)nbytes);
1045 }
1046
1047 #else
1048
bctbx_send(bctbx_socket_t socket,const void * buffer,size_t length,int flags)1049 ssize_t bctbx_send(bctbx_socket_t socket, const void *buffer, size_t length, int flags) {
1050 return send(socket, buffer, length, flags);
1051 }
1052
bctbx_sendto(bctbx_socket_t socket,const void * message,size_t length,int flags,const struct sockaddr * dest_addr,socklen_t dest_len)1053 ssize_t bctbx_sendto(bctbx_socket_t socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len) {
1054 return sendto(socket, message, length, flags, dest_addr, dest_len);
1055 }
1056
bctbx_recv(bctbx_socket_t socket,void * buffer,size_t length,int flags)1057 ssize_t bctbx_recv(bctbx_socket_t socket, void *buffer, size_t length, int flags) {
1058 return recv(socket, buffer, length, flags);
1059 }
1060
bctbx_recvfrom(bctbx_socket_t socket,void * buffer,size_t length,int flags,struct sockaddr * address,socklen_t * address_len)1061 ssize_t bctbx_recvfrom(bctbx_socket_t socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len) {
1062 return recvfrom(socket, buffer, length, flags, address, address_len);
1063 }
1064
bctbx_read(int fd,void * buf,size_t nbytes)1065 ssize_t bctbx_read(int fd, void *buf, size_t nbytes) {
1066 return read(fd, buf, nbytes);
1067 }
1068
bctbx_write(int fd,const void * buf,size_t nbytes)1069 ssize_t bctbx_write(int fd, const void *buf, size_t nbytes) {
1070 return write(fd, buf, nbytes);
1071 }
1072
1073 #endif
1074
1075 static char allocated_by_bctbx_magic[10] = "bctbx";
1076
_bctbx_alloc_addrinfo(int ai_family,int socktype,int proto)1077 static struct addrinfo *_bctbx_alloc_addrinfo(int ai_family, int socktype, int proto){
1078 struct addrinfo *ai=(struct addrinfo*)bctbx_malloc0(sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
1079 ai->ai_family=ai_family;
1080 ai->ai_socktype=socktype;
1081 ai->ai_protocol=proto;
1082 ai->ai_addrlen=AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
1083 ai->ai_addr=(struct sockaddr*)(((unsigned char*)ai) + sizeof(struct addrinfo));
1084 ai->ai_canonname = allocated_by_bctbx_magic; /*this is the way we will recognize our own allocated addrinfo structures in bctbx_freeaddrinfo()*/
1085 return ai;
1086 }
1087
convert_to_v4mapped(const struct addrinfo * ai)1088 static struct addrinfo *convert_to_v4mapped(const struct addrinfo *ai){
1089 struct addrinfo *res=NULL;
1090 const struct addrinfo *it;
1091 struct addrinfo *v4m=NULL;
1092 struct addrinfo *last=NULL;
1093
1094 for (it=ai;it!=NULL;it=it->ai_next){
1095 struct sockaddr_in6 *sin6;
1096 struct sockaddr_in *sin;
1097 v4m=_bctbx_alloc_addrinfo(AF_INET6, it->ai_socktype, it->ai_protocol);
1098 v4m->ai_flags|=AI_V4MAPPED;
1099 sin6=(struct sockaddr_in6*)v4m->ai_addr;
1100 sin=(struct sockaddr_in*)it->ai_addr;
1101 sin6->sin6_family=AF_INET6;
1102 ((uint8_t*)&sin6->sin6_addr)[10]=0xff;
1103 ((uint8_t*)&sin6->sin6_addr)[11]=0xff;
1104 memcpy(((uint8_t*)&sin6->sin6_addr)+12,&sin->sin_addr,4);
1105 sin6->sin6_port=sin->sin_port;
1106 if (last){
1107 last->ai_next=v4m;
1108 }else{
1109 res=v4m;
1110 }
1111 last=v4m;
1112 }
1113 return res;
1114 }
1115
1116 #if defined(__ANDROID__) || defined(_WIN32)
1117
1118 /*
1119 * SHAME !!! bionic's getaddrinfo does not implement the AI_V4MAPPED flag !
1120 * It is declared in header file but rejected by the implementation.
1121 * The code below is to emulate a _compliant_ getaddrinfo for android.
1122 **/
1123
1124 /**
1125 * SHAME AGAIN !!! Win32's implementation of getaddrinfo is bogus !
1126 * it is not able to return an IPv6 addrinfo from an IPv4 address when AI_V4MAPPED is set !
1127 **/
1128
addrinfo_concat(struct addrinfo * a1,struct addrinfo * a2)1129 struct addrinfo *addrinfo_concat(struct addrinfo *a1, struct addrinfo *a2){
1130 struct addrinfo *it;
1131 struct addrinfo *last=NULL;
1132 for (it=a1;it!=NULL;it=it->ai_next){
1133 last=it;
1134 }
1135 if (last){
1136 last->ai_next=a2;
1137 return a1;
1138 }else
1139 return a2;
1140 }
1141
bctbx_getaddrinfo(const char * node,const char * service,const struct addrinfo * hints,struct addrinfo ** res)1142 int bctbx_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res){
1143 if (hints && hints->ai_family!=AF_INET && hints->ai_flags & AI_V4MAPPED){
1144 struct addrinfo *res6=NULL;
1145 struct addrinfo *res4=NULL;
1146 struct addrinfo lhints={0};
1147 int err;
1148
1149 if (hints) memcpy(&lhints,hints,sizeof(lhints));
1150
1151 lhints.ai_flags &= ~(AI_ALL | AI_V4MAPPED); /*remove the unsupported flags*/
1152 lhints.ai_family = AF_INET6;
1153 err = getaddrinfo(node, service, &lhints, &res6);
1154 if (hints->ai_flags & AI_ALL) {
1155 lhints.ai_family=AF_INET;
1156 err=getaddrinfo(node, service, &lhints, &res4);
1157 if (err==0){
1158 struct addrinfo *v4m=convert_to_v4mapped(res4);
1159 freeaddrinfo(res4);
1160 res4=v4m;
1161 }
1162 *res=addrinfo_concat(res6,res4);
1163 if (*res) err=0;
1164 }
1165 return err;
1166 }
1167 return getaddrinfo(node, service, hints, res);
1168 }
1169
1170
1171
1172 #else
1173
bctbx_getaddrinfo(const char * node,const char * service,const struct addrinfo * hints,struct addrinfo ** res)1174 int bctbx_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res){
1175 int result = getaddrinfo(node, service, hints, res);
1176 #if __APPLE__
1177 if (*res && (*res)->ai_family == AF_INET6) {
1178 struct sockaddr_in6* sockaddr = (struct sockaddr_in6*)(*res)->ai_addr;
1179 if (sockaddr->sin6_port == 0 && service) {
1180 int possible_port = atoi(service);
1181 if (possible_port > 0 && possible_port <= 65535) {
1182 bctbx_message("Apple nat64 getaddrinfo bug, fixing port to [%i]",possible_port);
1183 sockaddr->sin6_port = htons(possible_port);
1184 }
1185
1186 }
1187
1188 }
1189 #endif
1190 return result;
1191
1192 }
1193
1194 #endif
1195
bctbx_getnameinfo(const struct sockaddr * addr,socklen_t addrlen,char * host,socklen_t hostlen,char * serv,socklen_t servlen,int flags)1196 int bctbx_getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags) {
1197 #if __APPLE__
1198 /* What an unpleasant surprise... It appears getnameinfo from Apple is calling inet_ntoa internally that is not thread-safe:
1199 * https://opensource.apple.com/source/Libc/Libc-583/net/FreeBSD/inet_ntoa.c
1200 * http://www.educatedguesswork.org/2009/02/well_thats_an_unpleasant_surpr.html
1201 */
1202 int i;
1203 int err;
1204 for (i = 0; i < 50; i++) {
1205 err = getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
1206 if (!(host && strstr(host, "[inet_ntoa error]"))) return err;
1207 }
1208 return EAI_AGAIN;
1209 #else
1210 return getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
1211 #endif
1212 }
1213
_bctbx_addrinfo_to_ip_address_error(int err,char * ip,size_t ip_size)1214 static void _bctbx_addrinfo_to_ip_address_error(int err, char *ip, size_t ip_size) {
1215 bctbx_error("getnameinfo() error: %s", gai_strerror(err));
1216 strncpy(ip, "<bug!!>", ip_size);
1217 }
1218
bctbx_addrinfo_to_ip_address(const struct addrinfo * ai,char * ip,size_t ip_size,int * port)1219 int bctbx_addrinfo_to_ip_address(const struct addrinfo *ai, char *ip, size_t ip_size, int *port){
1220 char serv[16];
1221 int err=bctbx_getnameinfo(ai->ai_addr,(socklen_t)ai->ai_addrlen,ip,(socklen_t)ip_size,serv,(socklen_t)sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV);
1222 if (err!=0) _bctbx_addrinfo_to_ip_address_error(err, ip, ip_size);
1223 if (port) *port=atoi(serv);
1224 return 0;
1225 }
1226
bctbx_addrinfo_to_printable_ip_address(const struct addrinfo * ai,char * printable_ip,size_t printable_ip_size)1227 int bctbx_addrinfo_to_printable_ip_address(const struct addrinfo *ai, char *printable_ip, size_t printable_ip_size) {
1228 char ip[64];
1229 char serv[16];
1230 int err = bctbx_getnameinfo(ai->ai_addr, (socklen_t)ai->ai_addrlen, ip, sizeof(ip), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV);
1231 if (err != 0) _bctbx_addrinfo_to_ip_address_error(err, ip, sizeof(ip));
1232 if (ai->ai_family == AF_INET)
1233 snprintf(printable_ip, printable_ip_size, "%s:%s", ip, serv);
1234 else if (ai->ai_family == AF_INET6)
1235 snprintf(printable_ip, printable_ip_size, "[%s]:%s", ip, serv);
1236 return 0;
1237 }
1238
bctbx_sockaddr_to_ip_address(const struct sockaddr * sa,socklen_t salen,char * ip,size_t ip_size,int * port)1239 int bctbx_sockaddr_to_ip_address(const struct sockaddr *sa, socklen_t salen, char *ip, size_t ip_size, int *port) {
1240 struct addrinfo ai = { 0 };
1241 ai.ai_addr = (struct sockaddr*)sa;
1242 ai.ai_addrlen = salen;
1243 ai.ai_family = sa->sa_family;
1244 return bctbx_addrinfo_to_ip_address(&ai, ip, ip_size, port);
1245 }
1246
bctbx_sockaddr_to_printable_ip_address(struct sockaddr * sa,socklen_t salen,char * printable_ip,size_t printable_ip_size)1247 int bctbx_sockaddr_to_printable_ip_address(struct sockaddr *sa, socklen_t salen, char *printable_ip, size_t printable_ip_size) {
1248 if ((sa->sa_family == 0) || (salen == 0)) {
1249 snprintf(printable_ip, printable_ip_size, "no-addr");
1250 return 0;
1251 } else {
1252 struct addrinfo ai = { 0 };
1253 ai.ai_addr = sa;
1254 ai.ai_addrlen = salen;
1255 ai.ai_family = sa->sa_family;
1256 return bctbx_addrinfo_to_printable_ip_address(&ai, printable_ip, printable_ip_size);
1257 }
1258 }
1259
_bctbx_name_to_addrinfo(int family,int socktype,const char * ipaddress,int port,int numeric_only)1260 static struct addrinfo * _bctbx_name_to_addrinfo(int family, int socktype, const char *ipaddress, int port, int numeric_only){
1261 struct addrinfo *res=NULL;
1262 struct addrinfo hints={0};
1263 char serv[10];
1264 int err;
1265
1266 snprintf(serv,sizeof(serv),"%i",port);
1267 hints.ai_family=family;
1268 if (numeric_only) hints.ai_flags=AI_NUMERICSERV|AI_NUMERICHOST;
1269 hints.ai_socktype=socktype;
1270
1271 if (family == AF_INET6) {
1272 hints.ai_flags |= AI_V4MAPPED;
1273 hints.ai_flags |= AI_ALL;
1274 }
1275 err=bctbx_getaddrinfo(ipaddress,serv,&hints,&res);
1276
1277 if (err!=0){
1278 if (!numeric_only || err!=EAI_NONAME)
1279 bctbx_error("%s(%s): getaddrinfo failed: %s",__FUNCTION__, ipaddress, gai_strerror(err));
1280 return NULL;
1281 }
1282 return res;
1283 }
1284
bctbx_name_to_addrinfo(int family,int socktype,const char * name,int port)1285 struct addrinfo * bctbx_name_to_addrinfo(int family, int socktype, const char *name, int port){
1286 return _bctbx_name_to_addrinfo(family, socktype, name, port, FALSE);
1287 }
1288
bctbx_ip_address_to_addrinfo(int family,int socktype,const char * name,int port)1289 struct addrinfo * bctbx_ip_address_to_addrinfo(int family, int socktype, const char *name, int port){
1290 struct addrinfo * res = _bctbx_name_to_addrinfo(family, socktype, name, port, TRUE);
1291 #if __APPLE__
1292 /*required for nat64 on apple platform*/
1293 if (res) {
1294 /*fine, we are sure that name was an ip address, give a chance to get its nat64 form*/
1295 bctbx_freeaddrinfo(res);
1296 res = bctbx_name_to_addrinfo(family, SOCK_STREAM, name, port);
1297 }
1298 #endif
1299 return res;
1300
1301 }
1302
1303 #ifndef IN6_GET_ADDR_V4MAPPED
1304 #define IN6_GET_ADDR_V4MAPPED(sin6_addr) *(unsigned int*)((unsigned char*)(sin6_addr)+12)
1305 #endif
1306
bctbx_sockaddr_remove_v4_mapping(const struct sockaddr * v6,struct sockaddr * result,socklen_t * result_len)1307 void bctbx_sockaddr_remove_v4_mapping(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len) {
1308 if (v6->sa_family == AF_INET6) {
1309 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)v6;
1310
1311 if (IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr)) {
1312 struct sockaddr_in *in = (struct sockaddr_in *)result;
1313 result->sa_family = AF_INET;
1314 in->sin_addr.s_addr = IN6_GET_ADDR_V4MAPPED(&in6->sin6_addr);
1315 in->sin_port = in6->sin6_port;
1316 *result_len = sizeof(struct sockaddr_in);
1317 } else {
1318 if (v6 != result) memcpy(result, v6, sizeof(struct sockaddr_in6));
1319 *result_len = sizeof(struct sockaddr_in6);
1320 }
1321 } else {
1322 *result_len = sizeof(struct sockaddr_in);
1323 if (v6 != result) memcpy(result, v6, sizeof(struct sockaddr_in));
1324 }
1325 }
1326
bctbx_sockaddr_remove_nat64_mapping(const struct sockaddr * v6,struct sockaddr * result,socklen_t * result_len)1327 void bctbx_sockaddr_remove_nat64_mapping(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len) {
1328 if (v6->sa_family == AF_INET6) {
1329 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)v6;
1330
1331 if (htonl(0x0064ff9b) ==
1332 #ifdef _MSC_VER
1333 ((in6->sin6_addr.u.Word[0] << 16) & in6->sin6_addr.u.Word[1])
1334 #elif __APPLE__ || __FreeBSD__
1335 in6->sin6_addr.__u6_addr.__u6_addr32[0]
1336 #else
1337 in6->sin6_addr.s6_addr32[0]
1338 #endif
1339 ) {
1340 struct sockaddr_in *in = (struct sockaddr_in *)result;
1341 result->sa_family = AF_INET;
1342 in->sin_addr.s_addr = IN6_GET_ADDR_V4MAPPED(&in6->sin6_addr);
1343 in->sin_port = in6->sin6_port;
1344 *result_len = sizeof(struct sockaddr_in);
1345 }
1346 } else {
1347 *result_len = sizeof(struct sockaddr_in);
1348 if (v6 != result) memcpy(result, v6, sizeof(struct sockaddr_in));
1349 }
1350 }
1351
bctbx_sockaddr_ipv6_to_ipv4(const struct sockaddr * v6,struct sockaddr * result,socklen_t * result_len)1352 void bctbx_sockaddr_ipv6_to_ipv4(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len) {
1353 bctbx_sockaddr_remove_v4_mapping(v6, result, result_len);
1354 }
1355
bctbx_sockaddr_ipv4_to_ipv6(const struct sockaddr * v4,struct sockaddr * result,socklen_t * result_len)1356 void bctbx_sockaddr_ipv4_to_ipv6(const struct sockaddr *v4, struct sockaddr *result, socklen_t *result_len) {
1357 if (v4->sa_family == AF_INET) {
1358 struct addrinfo *v4m;
1359 struct addrinfo ai = { 0 };
1360 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)result;
1361 ai.ai_addr = (struct sockaddr *)v4;
1362 ai.ai_addrlen = sizeof(struct sockaddr_in);
1363 ai.ai_family = v4->sa_family;
1364 v4m = convert_to_v4mapped(&ai);
1365 *result_len = sizeof(struct sockaddr_in6);
1366 memcpy(v6, v4m->ai_addr, *result_len);
1367 bctbx_freeaddrinfo(v4m);
1368 }
1369 }
1370
bctbx_concat(const char * str,...)1371 char * bctbx_concat(const char *str, ...) {
1372 va_list ap;
1373 size_t allocated = 100;
1374 char *result = (char *) malloc (allocated);
1375
1376 if (result != NULL)
1377 {
1378 char *newp;
1379 char *wp;
1380 const char* s;
1381
1382 va_start (ap, str);
1383
1384 wp = result;
1385 for (s = str; s != NULL; s = va_arg (ap, const char *)) {
1386 size_t len = strlen (s);
1387
1388 /* Resize the allocated memory if necessary. */
1389 if (wp + len + 1 > result + allocated)
1390 {
1391 allocated = (allocated + len) * 2;
1392 newp = (char *) realloc (result, allocated);
1393 if (newp == NULL)
1394 {
1395 free (result);
1396 return NULL;
1397 }
1398 wp = newp + (wp - result);
1399 result = newp;
1400 }
1401 memcpy (wp, s, len);
1402 wp +=len;
1403 }
1404
1405 /* Terminate the result string. */
1406 *wp++ = '\0';
1407
1408 /* Resize memory to the optimal size. */
1409 newp = realloc (result, wp - result);
1410 if (newp != NULL)
1411 result = newp;
1412
1413 va_end (ap);
1414 }
1415
1416 return result;
1417 }
1418
bctbx_sockaddr_equals(const struct sockaddr * sa,const struct sockaddr * sb)1419 bool_t bctbx_sockaddr_equals(const struct sockaddr * sa, const struct sockaddr * sb) {
1420
1421 if (sa->sa_family != sb->sa_family)
1422 return FALSE;
1423
1424 if (sa->sa_family == AF_INET) {
1425 if ((((struct sockaddr_in*)sa)->sin_addr.s_addr != ((struct sockaddr_in*)sb)->sin_addr.s_addr
1426 || ((struct sockaddr_in*)sa)->sin_port != ((struct sockaddr_in*)sb)->sin_port))
1427 return FALSE;
1428 } else if (sa->sa_family == AF_INET6) {
1429 if (memcmp(&((struct sockaddr_in6*)sa)->sin6_addr
1430 , &((struct sockaddr_in6*)sb)->sin6_addr
1431 , sizeof(struct in6_addr)) !=0
1432 || ((struct sockaddr_in6*)sa)->sin6_port != ((struct sockaddr_in6*)sb)->sin6_port)
1433 return FALSE;
1434 } else {
1435 bctbx_warning ("Cannot compare family type [%d]", sa->sa_family);
1436 return FALSE;
1437 }
1438 return TRUE;
1439
1440 }
1441
ai_family_to_string(int af)1442 static const char *ai_family_to_string(int af) {
1443 switch(af) {
1444 case AF_INET: return "AF_INET";
1445 case AF_INET6: return "AF_INET6";
1446 case AF_UNSPEC: return "AF_UNSPEC";
1447 default: return "invalid address family";
1448 }
1449 }
1450
get_local_ip_for_with_connect(int type,const char * dest,int port,char * result,size_t result_len)1451 static int get_local_ip_for_with_connect(int type, const char *dest, int port, char *result, size_t result_len) {
1452 int err, tmp;
1453 struct addrinfo hints;
1454 struct addrinfo *res = NULL;
1455 struct sockaddr_storage addr;
1456 struct sockaddr *p_addr = (struct sockaddr *)&addr;
1457 bctbx_socket_t sock;
1458 socklen_t s;
1459 char port_str[6] = { 0 };
1460
1461 memset(&hints, 0, sizeof(hints));
1462 hints.ai_family = type;
1463 hints.ai_socktype = SOCK_DGRAM;
1464 /*hints.ai_flags = AI_NUMERICHOST | AI_CANONNAME;*/
1465 snprintf(port_str, sizeof(port_str), "%i", port);
1466 err = getaddrinfo(dest, port_str, &hints, &res);
1467 if (err != 0) {
1468 bctbx_error("getaddrinfo() error for %s: %s",dest, gai_strerror(err));
1469 return -1;
1470 }
1471 if (res == NULL) {
1472 bctbx_error("bug: getaddrinfo returned nothing.");
1473 return -1;
1474 }
1475 sock = socket(res->ai_family, SOCK_DGRAM, 0);
1476 if (sock == (bctbx_socket_t)-1) {
1477 bctbx_error("get_local_ip_for_with_connect() could not create [%s] socket: %s", ai_family_to_string(res->ai_family), getSocketError());
1478 return -1;
1479 }
1480 tmp = 1;
1481 err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SOCKET_OPTION_VALUE)&tmp, sizeof(int));
1482 if (err == -1) bctbx_warning("Error in setsockopt: %s", getSocketError());
1483 err = connect(sock, res->ai_addr, (int)res->ai_addrlen);
1484 if (err == -1) {
1485 /* The network isn't reachable. We don't display the error as it is the case that we want to check in normal operation. */
1486 if ( getSocketErrorCode() != BCTBX_ENETUNREACH
1487 && getSocketErrorCode() != BCTBX_EHOSTUNREACH
1488 && getSocketErrorCode() != BCTBX_EPROTOTYPE)
1489 bctbx_error("Error in connect: %s", getSocketError());
1490 freeaddrinfo(res);
1491 bctbx_socket_close(sock);
1492 return -1;
1493 }
1494 freeaddrinfo(res);
1495 res = NULL;
1496 s = sizeof(addr);
1497 err = getsockname(sock, (struct sockaddr *)&addr, &s);
1498 if (err != 0) {
1499 bctbx_error("Error in getsockname: %s", getSocketError());
1500 bctbx_socket_close(sock);
1501 return -1;
1502 }
1503 if (p_addr->sa_family == AF_INET) {
1504 struct sockaddr_in *p_sin = (struct sockaddr_in *)p_addr;
1505 if (p_sin->sin_addr.s_addr == 0) {
1506 bctbx_socket_close(sock);
1507 return -1;
1508 }
1509 }
1510 err = bctbx_getnameinfo((struct sockaddr *)&addr, s, result, (socklen_t)result_len, NULL, 0, NI_NUMERICHOST);
1511 if (err != 0) bctbx_error("getnameinfo error: %s", gai_strerror(err));
1512 /* Avoid ipv6 link-local addresses */
1513 if ((p_addr->sa_family == AF_INET6) && (strchr(result, '%') != NULL)) {
1514 strcpy(result, "::1");
1515 bctbx_socket_close(sock);
1516 return -1;
1517 }
1518 bctbx_socket_close(sock);
1519 return 0;
1520 }
1521
bctbx_get_local_ip_for(int type,const char * dest,int port,char * result,size_t result_len)1522 int bctbx_get_local_ip_for(int type, const char *dest, int port, char *result, size_t result_len) {
1523 strncpy(result, (type == AF_INET) ? "127.0.0.1" : "::1", result_len);
1524
1525 if (dest == NULL) {
1526 if (type == AF_INET) dest="87.98.157.38"; /* A public IP address */
1527 else dest = "2a00:1450:8002::68";
1528 }
1529 if (port == 0) port = 5060;
1530 return get_local_ip_for_with_connect(type, dest, port, result, result_len);
1531 }
1532
_bctbx_freeaddrinfo(struct addrinfo * res)1533 void _bctbx_freeaddrinfo(struct addrinfo *res){
1534 struct addrinfo *it,*next_it;
1535 for(it=res;it!=NULL;it=next_it){
1536 next_it=it->ai_next;
1537 bctbx_free(it);
1538 }
1539 }
1540
bctbx_freeaddrinfo(struct addrinfo * res)1541 void bctbx_freeaddrinfo(struct addrinfo *res){
1542 struct addrinfo *it;
1543 struct addrinfo *previt = NULL;
1544 struct addrinfo *beginit = res;
1545 bool_t looking_for_allocated_by_bctbx = (res->ai_canonname == allocated_by_bctbx_magic) ? TRUE : FALSE;
1546
1547 for (it = res; it != NULL; it = it->ai_next) {
1548 if ((looking_for_allocated_by_bctbx == TRUE) && (it->ai_canonname != allocated_by_bctbx_magic)) {
1549 if (previt) {
1550 previt->ai_next = NULL;
1551 _bctbx_freeaddrinfo(beginit);
1552 looking_for_allocated_by_bctbx = FALSE;
1553 beginit = it;
1554 }
1555 } else if ((looking_for_allocated_by_bctbx == FALSE) && (it->ai_canonname == allocated_by_bctbx_magic)) {
1556 if (previt) {
1557 previt->ai_next = NULL;
1558 freeaddrinfo(beginit);
1559 looking_for_allocated_by_bctbx = TRUE;
1560 beginit = it;
1561 }
1562 }
1563 previt = it;
1564 }
1565 if (looking_for_allocated_by_bctbx == TRUE) _bctbx_freeaddrinfo(beginit);
1566 else freeaddrinfo(beginit);
1567 }
1568
1569
bctbx_char_to_byte(uint8_t input_char)1570 uint8_t bctbx_char_to_byte(uint8_t input_char) {
1571 /* 0-9 */
1572 if (input_char>0x29 && input_char<0x3A) {
1573 return input_char - 0x30;
1574 }
1575
1576 /* a-f */
1577 if (input_char>0x60 && input_char<0x67) {
1578 return input_char - 0x57; /* 0x57 = 0x61(a) + 0x0A*/
1579 }
1580
1581 /* A-F */
1582 if (input_char>0x40 && input_char<0x47) {
1583 return input_char - 0x37; /* 0x37 = 0x41(a) + 0x0A*/
1584 }
1585
1586 /* shall never arrive here, string is not Hex*/
1587 return 0;
1588
1589 }
1590
bctbx_byte_to_char(uint8_t input_byte)1591 uint8_t bctbx_byte_to_char(uint8_t input_byte) {
1592 uint8_t input_byte_crop = input_byte&0x0F; /* restrict the input value to range [0-15] */
1593 /* 0-9 */
1594 if(input_byte_crop<0x0A) {
1595 return input_byte_crop+0x30;
1596 }
1597 /* a-f */
1598 return input_byte_crop + 0x57;
1599 }
1600
bctbx_str_to_uint8(uint8_t * output_bytes,const uint8_t * input_string,size_t input_string_length)1601 void bctbx_str_to_uint8(uint8_t *output_bytes, const uint8_t *input_string, size_t input_string_length) {
1602 size_t i;
1603 for (i=0; i<input_string_length/2; i++) {
1604 output_bytes[i] = (bctbx_char_to_byte(input_string[2*i]))<<4 | bctbx_char_to_byte(input_string[2*i+1]);
1605 }
1606 }
1607
bctbx_int8_to_str(uint8_t * output_string,const uint8_t * input_bytes,size_t input_bytes_length)1608 void bctbx_int8_to_str(uint8_t *output_string, const uint8_t *input_bytes, size_t input_bytes_length) {
1609 size_t i;
1610 for (i=0; i<input_bytes_length; i++) {
1611 output_string[2*i] = bctbx_byte_to_char((input_bytes[i]>>4)&0x0F);
1612 output_string[2*i+1] = bctbx_byte_to_char(input_bytes[i]&0x0F);
1613 }
1614 }
1615
bctbx_uint32_to_str(uint8_t output_string[9],uint32_t input_uint32)1616 void bctbx_uint32_to_str(uint8_t output_string[9], uint32_t input_uint32) {
1617
1618 output_string[0] = bctbx_byte_to_char((uint8_t)((input_uint32>>28)&0x0F));
1619 output_string[1] = bctbx_byte_to_char((uint8_t)((input_uint32>>24)&0x0F));
1620 output_string[2] = bctbx_byte_to_char((uint8_t)((input_uint32>>20)&0x0F));
1621 output_string[3] = bctbx_byte_to_char((uint8_t)((input_uint32>>16)&0x0F));
1622 output_string[4] = bctbx_byte_to_char((uint8_t)((input_uint32>>12)&0x0F));
1623 output_string[5] = bctbx_byte_to_char((uint8_t)((input_uint32>>8)&0x0F));
1624 output_string[6] = bctbx_byte_to_char((uint8_t)((input_uint32>>4)&0x0F));
1625 output_string[7] = bctbx_byte_to_char((uint8_t)((input_uint32)&0x0F));
1626 output_string[8] = '\0';
1627 }
1628
bctbx_str_to_uint32(const uint8_t * input_string)1629 uint32_t bctbx_str_to_uint32(const uint8_t *input_string) {
1630 return (((uint32_t)bctbx_char_to_byte(input_string[0]))<<28)
1631 | (((uint32_t)bctbx_char_to_byte(input_string[1]))<<24)
1632 | (((uint32_t)bctbx_char_to_byte(input_string[2]))<<20)
1633 | (((uint32_t)bctbx_char_to_byte(input_string[3]))<<16)
1634 | (((uint32_t)bctbx_char_to_byte(input_string[4]))<<12)
1635 | (((uint32_t)bctbx_char_to_byte(input_string[5]))<<8)
1636 | (((uint32_t)bctbx_char_to_byte(input_string[6]))<<4)
1637 | (((uint32_t)bctbx_char_to_byte(input_string[7])));
1638 }
1639
bctbx_uint64_to_str(uint8_t output_string[17],uint64_t input_uint64)1640 void bctbx_uint64_to_str(uint8_t output_string[17], uint64_t input_uint64) {
1641
1642 output_string[0] = bctbx_byte_to_char((uint8_t)((input_uint64>>60)&0x0F));
1643 output_string[1] = bctbx_byte_to_char((uint8_t)((input_uint64>>56)&0x0F));
1644 output_string[2] = bctbx_byte_to_char((uint8_t)((input_uint64>>52)&0x0F));
1645 output_string[3] = bctbx_byte_to_char((uint8_t)((input_uint64>>48)&0x0F));
1646 output_string[4] = bctbx_byte_to_char((uint8_t)((input_uint64>>44)&0x0F));
1647 output_string[5] = bctbx_byte_to_char((uint8_t)((input_uint64>>40)&0x0F));
1648 output_string[6] = bctbx_byte_to_char((uint8_t)((input_uint64>>36)&0x0F));
1649 output_string[7] = bctbx_byte_to_char((uint8_t)((input_uint64>>32)&0x0F));
1650 output_string[8] = bctbx_byte_to_char((uint8_t)((input_uint64>>28)&0x0F));
1651 output_string[9] = bctbx_byte_to_char((uint8_t)((input_uint64>>24)&0x0F));
1652 output_string[10] = bctbx_byte_to_char((uint8_t)((input_uint64>>20)&0x0F));
1653 output_string[11] = bctbx_byte_to_char((uint8_t)((input_uint64>>16)&0x0F));
1654 output_string[12] = bctbx_byte_to_char((uint8_t)((input_uint64>>12)&0x0F));
1655 output_string[13] = bctbx_byte_to_char((uint8_t)((input_uint64>>8)&0x0F));
1656 output_string[14] = bctbx_byte_to_char((uint8_t)((input_uint64>>4)&0x0F));
1657 output_string[15] = bctbx_byte_to_char((uint8_t)((input_uint64)&0x0F));
1658 output_string[16] = '\0';
1659 }
1660
bctbx_str_to_uint64(const uint8_t input_string[17])1661 uint64_t bctbx_str_to_uint64(const uint8_t input_string[17]) {
1662 return (((uint64_t)bctbx_char_to_byte(input_string[0]))<<60)
1663 | (((uint64_t)bctbx_char_to_byte(input_string[1]))<<56)
1664 | (((uint64_t)bctbx_char_to_byte(input_string[2]))<<52)
1665 | (((uint64_t)bctbx_char_to_byte(input_string[3]))<<48)
1666 | (((uint64_t)bctbx_char_to_byte(input_string[4]))<<44)
1667 | (((uint64_t)bctbx_char_to_byte(input_string[5]))<<40)
1668 | (((uint64_t)bctbx_char_to_byte(input_string[6]))<<36)
1669 | (((uint64_t)bctbx_char_to_byte(input_string[7]))<<32)
1670 | (((uint64_t)bctbx_char_to_byte(input_string[8]))<<28)
1671 | (((uint64_t)bctbx_char_to_byte(input_string[9]))<<24)
1672 | (((uint64_t)bctbx_char_to_byte(input_string[10]))<<20)
1673 | (((uint64_t)bctbx_char_to_byte(input_string[11]))<<16)
1674 | (((uint64_t)bctbx_char_to_byte(input_string[12]))<<12)
1675 | (((uint64_t)bctbx_char_to_byte(input_string[13]))<<8)
1676 | (((uint64_t)bctbx_char_to_byte(input_string[14]))<<4)
1677 | (((uint64_t)bctbx_char_to_byte(input_string[15])));
1678 }
1679