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(&current, 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