PageRenderTime 67ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/src/base/system.c

https://gitlab.com/uDDRace/tCatch
C | 2018 lines | 1668 code | 281 blank | 69 comment | 362 complexity | 2fdf5ca24622c44766c019dc9eb17780 MD5 | raw file
  1. /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
  2. /* If you are missing that file, acquire a complete release at teeworlds.com. */
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <stdarg.h>
  6. #include <string.h>
  7. #include <ctype.h>
  8. #include <time.h>
  9. #include "system.h"
  10. #if defined(CONF_FAMILY_UNIX)
  11. #include <sys/time.h>
  12. #include <unistd.h>
  13. /* unix net includes */
  14. #include <sys/stat.h>
  15. #include <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <sys/ioctl.h>
  18. #include <errno.h>
  19. #include <netdb.h>
  20. #include <netinet/in.h>
  21. #include <fcntl.h>
  22. #include <pthread.h>
  23. #include <arpa/inet.h>
  24. #include <dirent.h>
  25. #if defined(CONF_PLATFORM_MACOSX)
  26. #include <Carbon/Carbon.h>
  27. #endif
  28. #elif defined(CONF_FAMILY_WINDOWS)
  29. #define WIN32_LEAN_AND_MEAN
  30. #define _WIN32_WINNT 0x0501 /* required for mingw to get getaddrinfo to work */
  31. #include <windows.h>
  32. #include <winsock2.h>
  33. #include <ws2tcpip.h>
  34. #include <fcntl.h>
  35. #include <direct.h>
  36. #include <errno.h>
  37. #else
  38. #error NOT IMPLEMENTED
  39. #endif
  40. #if defined(CONF_PLATFORM_SOLARIS)
  41. #include <sys/filio.h>
  42. #endif
  43. #if defined(__cplusplus)
  44. extern "C" {
  45. #endif
  46. IOHANDLE io_stdin() { return (IOHANDLE)stdin; }
  47. IOHANDLE io_stdout() { return (IOHANDLE)stdout; }
  48. IOHANDLE io_stderr() { return (IOHANDLE)stderr; }
  49. static DBG_LOGGER loggers[16];
  50. static int num_loggers = 0;
  51. static NETSTATS network_stats = {0};
  52. static MEMSTATS memory_stats = {0};
  53. static NETSOCKET invalid_socket = {NETTYPE_INVALID, -1, -1};
  54. void dbg_logger(DBG_LOGGER logger)
  55. {
  56. loggers[num_loggers++] = logger;
  57. }
  58. void dbg_assert_imp(const char *filename, int line, int test, const char *msg)
  59. {
  60. if(!test)
  61. {
  62. dbg_msg("assert", "%s(%d): %s", filename, line, msg);
  63. dbg_break();
  64. }
  65. }
  66. void dbg_break()
  67. {
  68. *((volatile unsigned*)0) = 0x0;
  69. }
  70. void dbg_msg(const char *sys, const char *fmt, ...)
  71. {
  72. va_list args;
  73. char str[1024*4];
  74. char *msg;
  75. int i, len;
  76. str_format(str, sizeof(str), "[%08x][%s]: ", (int)time(0), sys);
  77. len = strlen(str);
  78. msg = (char *)str + len;
  79. va_start(args, fmt);
  80. #if defined(CONF_FAMILY_WINDOWS)
  81. _vsnprintf(msg, sizeof(str)-len, fmt, args);
  82. #else
  83. vsnprintf(msg, sizeof(str)-len, fmt, args);
  84. #endif
  85. va_end(args);
  86. for(i = 0; i < num_loggers; i++)
  87. loggers[i](str);
  88. }
  89. static void logger_stdout(const char *line)
  90. {
  91. printf("%s\n", line);
  92. fflush(stdout);
  93. }
  94. static void logger_debugger(const char *line)
  95. {
  96. #if defined(CONF_FAMILY_WINDOWS)
  97. OutputDebugString(line);
  98. OutputDebugString("\n");
  99. #endif
  100. }
  101. static IOHANDLE logfile = 0;
  102. static void logger_file(const char *line)
  103. {
  104. io_write(logfile, line, strlen(line));
  105. io_write_newline(logfile);
  106. io_flush(logfile);
  107. }
  108. void dbg_logger_stdout() { dbg_logger(logger_stdout); }
  109. void dbg_logger_debugger() { dbg_logger(logger_debugger); }
  110. void dbg_logger_file(const char *filename)
  111. {
  112. logfile = io_open(filename, IOFLAG_WRITE);
  113. if(logfile)
  114. dbg_logger(logger_file);
  115. else
  116. dbg_msg("dbg/logger", "failed to open '%s' for logging", filename);
  117. }
  118. /* */
  119. typedef struct MEMHEADER
  120. {
  121. const char *filename;
  122. int line;
  123. int size;
  124. struct MEMHEADER *prev;
  125. struct MEMHEADER *next;
  126. } MEMHEADER;
  127. typedef struct MEMTAIL
  128. {
  129. int guard;
  130. } MEMTAIL;
  131. static struct MEMHEADER *first = 0;
  132. static const int MEM_GUARD_VAL = 0xbaadc0de;
  133. void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned alignment)
  134. {
  135. /* TODO: fix alignment */
  136. /* TODO: add debugging */
  137. MEMTAIL *tail;
  138. MEMHEADER *header = (struct MEMHEADER *)malloc(size+sizeof(MEMHEADER)+sizeof(MEMTAIL));
  139. dbg_assert(header != 0, "mem_alloc failure");
  140. if(!header)
  141. return NULL;
  142. tail = (struct MEMTAIL *)(((char*)(header+1))+size);
  143. header->size = size;
  144. header->filename = filename;
  145. header->line = line;
  146. memory_stats.allocated += header->size;
  147. memory_stats.total_allocations++;
  148. memory_stats.active_allocations++;
  149. tail->guard = MEM_GUARD_VAL;
  150. header->prev = (MEMHEADER *)0;
  151. header->next = first;
  152. if(first)
  153. first->prev = header;
  154. first = header;
  155. /*dbg_msg("mem", "++ %p", header+1); */
  156. return header+1;
  157. }
  158. void mem_free(void *p)
  159. {
  160. if(p)
  161. {
  162. MEMHEADER *header = (MEMHEADER *)p - 1;
  163. MEMTAIL *tail = (MEMTAIL *)(((char*)(header+1))+header->size);
  164. if(tail->guard != MEM_GUARD_VAL)
  165. dbg_msg("mem", "!! %p", p);
  166. /* dbg_msg("mem", "-- %p", p); */
  167. memory_stats.allocated -= header->size;
  168. memory_stats.active_allocations--;
  169. if(header->prev)
  170. header->prev->next = header->next;
  171. else
  172. first = header->next;
  173. if(header->next)
  174. header->next->prev = header->prev;
  175. free(header);
  176. }
  177. }
  178. void mem_debug_dump(IOHANDLE file)
  179. {
  180. char buf[1024];
  181. MEMHEADER *header = first;
  182. if(!file)
  183. file = io_open("memory.txt", IOFLAG_WRITE);
  184. if(file)
  185. {
  186. while(header)
  187. {
  188. str_format(buf, sizeof(buf), "%s(%d): %d", header->filename, header->line, header->size);
  189. io_write(file, buf, strlen(buf));
  190. io_write_newline(file);
  191. header = header->next;
  192. }
  193. io_close(file);
  194. }
  195. }
  196. void mem_copy(void *dest, const void *source, unsigned size)
  197. {
  198. memcpy(dest, source, size);
  199. }
  200. void mem_move(void *dest, const void *source, unsigned size)
  201. {
  202. memmove(dest, source, size);
  203. }
  204. void mem_zero(void *block,unsigned size)
  205. {
  206. memset(block, 0, size);
  207. }
  208. int mem_check_imp()
  209. {
  210. MEMHEADER *header = first;
  211. while(header)
  212. {
  213. MEMTAIL *tail = (MEMTAIL *)(((char*)(header+1))+header->size);
  214. if(tail->guard != MEM_GUARD_VAL)
  215. {
  216. dbg_msg("mem", "Memory check failed at %s(%d): %d", header->filename, header->line, header->size);
  217. return 0;
  218. }
  219. header = header->next;
  220. }
  221. return 1;
  222. }
  223. IOHANDLE io_open(const char *filename, int flags)
  224. {
  225. if(flags == IOFLAG_READ)
  226. {
  227. #if defined(CONF_FAMILY_WINDOWS)
  228. // check for filename case sensitive
  229. WIN32_FIND_DATA finddata;
  230. HANDLE handle;
  231. int length;
  232. length = str_length(filename);
  233. if(!filename || !length || filename[length-1] == '\\')
  234. return 0x0;
  235. handle = FindFirstFile(filename, &finddata);
  236. if(handle == INVALID_HANDLE_VALUE)
  237. return 0x0;
  238. else if(str_comp(filename+length-str_length(finddata.cFileName), finddata.cFileName) != 0)
  239. {
  240. FindClose(handle);
  241. return 0x0;
  242. }
  243. FindClose(handle);
  244. #endif
  245. return (IOHANDLE)fopen(filename, "rb");
  246. }
  247. if(flags == IOFLAG_WRITE)
  248. return (IOHANDLE)fopen(filename, "wb");
  249. return 0x0;
  250. }
  251. unsigned io_read(IOHANDLE io, void *buffer, unsigned size)
  252. {
  253. return fread(buffer, 1, size, (FILE*)io);
  254. }
  255. unsigned io_skip(IOHANDLE io, int size)
  256. {
  257. fseek((FILE*)io, size, SEEK_CUR);
  258. return size;
  259. }
  260. int io_seek(IOHANDLE io, int offset, int origin)
  261. {
  262. int real_origin;
  263. switch(origin)
  264. {
  265. case IOSEEK_START:
  266. real_origin = SEEK_SET;
  267. break;
  268. case IOSEEK_CUR:
  269. real_origin = SEEK_CUR;
  270. break;
  271. case IOSEEK_END:
  272. real_origin = SEEK_END;
  273. break;
  274. default:
  275. return -1;
  276. }
  277. return fseek((FILE*)io, offset, real_origin);
  278. }
  279. long int io_tell(IOHANDLE io)
  280. {
  281. return ftell((FILE*)io);
  282. }
  283. long int io_length(IOHANDLE io)
  284. {
  285. long int length;
  286. io_seek(io, 0, IOSEEK_END);
  287. length = io_tell(io);
  288. io_seek(io, 0, IOSEEK_START);
  289. return length;
  290. }
  291. unsigned io_write(IOHANDLE io, const void *buffer, unsigned size)
  292. {
  293. return fwrite(buffer, 1, size, (FILE*)io);
  294. }
  295. unsigned io_write_newline(IOHANDLE io)
  296. {
  297. #if defined(CONF_FAMILY_WINDOWS)
  298. return fwrite("\r\n", 1, 2, (FILE*)io);
  299. #else
  300. return fwrite("\n", 1, 1, (FILE*)io);
  301. #endif
  302. }
  303. int io_close(IOHANDLE io)
  304. {
  305. fclose((FILE*)io);
  306. return 1;
  307. }
  308. int io_flush(IOHANDLE io)
  309. {
  310. fflush((FILE*)io);
  311. return 0;
  312. }
  313. void *thread_create(void (*threadfunc)(void *), void *u)
  314. {
  315. #if defined(CONF_FAMILY_UNIX)
  316. pthread_t id;
  317. pthread_create(&id, NULL, (void *(*)(void*))threadfunc, u);
  318. return (void*)id;
  319. #elif defined(CONF_FAMILY_WINDOWS)
  320. return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadfunc, u, 0, NULL);
  321. #else
  322. #error not implemented
  323. #endif
  324. }
  325. void thread_wait(void *thread)
  326. {
  327. #if defined(CONF_FAMILY_UNIX)
  328. pthread_join((pthread_t)thread, NULL);
  329. #elif defined(CONF_FAMILY_WINDOWS)
  330. WaitForSingleObject((HANDLE)thread, INFINITE);
  331. #else
  332. #error not implemented
  333. #endif
  334. }
  335. void thread_destroy(void *thread)
  336. {
  337. #if defined(CONF_FAMILY_UNIX)
  338. void *r = 0;
  339. pthread_join((pthread_t)thread, &r);
  340. #else
  341. /*#error not implemented*/
  342. #endif
  343. }
  344. void thread_yield()
  345. {
  346. #if defined(CONF_FAMILY_UNIX)
  347. sched_yield();
  348. #elif defined(CONF_FAMILY_WINDOWS)
  349. Sleep(0);
  350. #else
  351. #error not implemented
  352. #endif
  353. }
  354. void thread_sleep(int milliseconds)
  355. {
  356. #if defined(CONF_FAMILY_UNIX)
  357. usleep(milliseconds*1000);
  358. #elif defined(CONF_FAMILY_WINDOWS)
  359. Sleep(milliseconds);
  360. #else
  361. #error not implemented
  362. #endif
  363. }
  364. void thread_detach(void *thread)
  365. {
  366. #if defined(CONF_FAMILY_UNIX)
  367. pthread_detach((pthread_t)(thread));
  368. #elif defined(CONF_FAMILY_WINDOWS)
  369. CloseHandle(thread);
  370. #else
  371. #error not implemented
  372. #endif
  373. }
  374. #if defined(CONF_FAMILY_UNIX)
  375. typedef pthread_mutex_t LOCKINTERNAL;
  376. #elif defined(CONF_FAMILY_WINDOWS)
  377. typedef CRITICAL_SECTION LOCKINTERNAL;
  378. #else
  379. #error not implemented on this platform
  380. #endif
  381. LOCK lock_create()
  382. {
  383. LOCKINTERNAL *lock = (LOCKINTERNAL*)mem_alloc(sizeof(LOCKINTERNAL), 4);
  384. #if defined(CONF_FAMILY_UNIX)
  385. pthread_mutex_init(lock, 0x0);
  386. #elif defined(CONF_FAMILY_WINDOWS)
  387. InitializeCriticalSection((LPCRITICAL_SECTION)lock);
  388. #else
  389. #error not implemented on this platform
  390. #endif
  391. return (LOCK)lock;
  392. }
  393. void lock_destroy(LOCK lock)
  394. {
  395. #if defined(CONF_FAMILY_UNIX)
  396. pthread_mutex_destroy((LOCKINTERNAL *)lock);
  397. #elif defined(CONF_FAMILY_WINDOWS)
  398. DeleteCriticalSection((LPCRITICAL_SECTION)lock);
  399. #else
  400. #error not implemented on this platform
  401. #endif
  402. mem_free(lock);
  403. }
  404. int lock_try(LOCK lock)
  405. {
  406. #if defined(CONF_FAMILY_UNIX)
  407. return pthread_mutex_trylock((LOCKINTERNAL *)lock);
  408. #elif defined(CONF_FAMILY_WINDOWS)
  409. return !TryEnterCriticalSection((LPCRITICAL_SECTION)lock);
  410. #else
  411. #error not implemented on this platform
  412. #endif
  413. }
  414. void lock_wait(LOCK lock)
  415. {
  416. #if defined(CONF_FAMILY_UNIX)
  417. pthread_mutex_lock((LOCKINTERNAL *)lock);
  418. #elif defined(CONF_FAMILY_WINDOWS)
  419. EnterCriticalSection((LPCRITICAL_SECTION)lock);
  420. #else
  421. #error not implemented on this platform
  422. #endif
  423. }
  424. void lock_release(LOCK lock)
  425. {
  426. #if defined(CONF_FAMILY_UNIX)
  427. pthread_mutex_unlock((LOCKINTERNAL *)lock);
  428. #elif defined(CONF_FAMILY_WINDOWS)
  429. LeaveCriticalSection((LPCRITICAL_SECTION)lock);
  430. #else
  431. #error not implemented on this platform
  432. #endif
  433. }
  434. #if !defined(CONF_PLATFORM_MACOSX)
  435. #if defined(CONF_FAMILY_UNIX)
  436. void semaphore_init(SEMAPHORE *sem) { sem_init(sem, 0, 0); }
  437. void semaphore_wait(SEMAPHORE *sem) { sem_wait(sem); }
  438. void semaphore_signal(SEMAPHORE *sem) { sem_post(sem); }
  439. void semaphore_destroy(SEMAPHORE *sem) { sem_destroy(sem); }
  440. #elif defined(CONF_FAMILY_WINDOWS)
  441. void semaphore_init(SEMAPHORE *sem) { *sem = CreateSemaphore(0, 0, 10000, 0); }
  442. void semaphore_wait(SEMAPHORE *sem) { WaitForSingleObject((HANDLE)*sem, INFINITE); }
  443. void semaphore_signal(SEMAPHORE *sem) { ReleaseSemaphore((HANDLE)*sem, 1, NULL); }
  444. void semaphore_destroy(SEMAPHORE *sem) { CloseHandle((HANDLE)*sem); }
  445. #else
  446. #error not implemented on this platform
  447. #endif
  448. #endif
  449. /* ----- time ----- */
  450. int64 time_get()
  451. {
  452. #if defined(CONF_FAMILY_UNIX)
  453. struct timeval val;
  454. gettimeofday(&val, NULL);
  455. return (int64)val.tv_sec*(int64)1000000+(int64)val.tv_usec;
  456. #elif defined(CONF_FAMILY_WINDOWS)
  457. static int64 last = 0;
  458. int64 t;
  459. QueryPerformanceCounter((PLARGE_INTEGER)&t);
  460. if(t<last) /* for some reason, QPC can return values in the past */
  461. return last;
  462. last = t;
  463. return t;
  464. #else
  465. #error not implemented
  466. #endif
  467. }
  468. int64 time_freq()
  469. {
  470. #if defined(CONF_FAMILY_UNIX)
  471. return 1000000;
  472. #elif defined(CONF_FAMILY_WINDOWS)
  473. int64 t;
  474. QueryPerformanceFrequency((PLARGE_INTEGER)&t);
  475. return t;
  476. #else
  477. #error not implemented
  478. #endif
  479. }
  480. /* ----- network ----- */
  481. static void netaddr_to_sockaddr_in(const NETADDR *src, struct sockaddr_in *dest)
  482. {
  483. mem_zero(dest, sizeof(struct sockaddr_in));
  484. if(src->type != NETTYPE_IPV4)
  485. {
  486. dbg_msg("system", "couldn't convert NETADDR of type %d to ipv4", src->type);
  487. return;
  488. }
  489. dest->sin_family = AF_INET;
  490. dest->sin_port = htons(src->port);
  491. mem_copy(&dest->sin_addr.s_addr, src->ip, 4);
  492. }
  493. static void netaddr_to_sockaddr_in6(const NETADDR *src, struct sockaddr_in6 *dest)
  494. {
  495. mem_zero(dest, sizeof(struct sockaddr_in6));
  496. if(src->type != NETTYPE_IPV6)
  497. {
  498. dbg_msg("system", "couldn't not convert NETADDR of type %d to ipv6", src->type);
  499. return;
  500. }
  501. dest->sin6_family = AF_INET6;
  502. dest->sin6_port = htons(src->port);
  503. mem_copy(&dest->sin6_addr.s6_addr, src->ip, 16);
  504. }
  505. static void sockaddr_to_netaddr(const struct sockaddr *src, NETADDR *dst)
  506. {
  507. if(src->sa_family == AF_INET)
  508. {
  509. mem_zero(dst, sizeof(NETADDR));
  510. dst->type = NETTYPE_IPV4;
  511. dst->port = htons(((struct sockaddr_in*)src)->sin_port);
  512. mem_copy(dst->ip, &((struct sockaddr_in*)src)->sin_addr.s_addr, 4);
  513. }
  514. else if(src->sa_family == AF_INET6)
  515. {
  516. mem_zero(dst, sizeof(NETADDR));
  517. dst->type = NETTYPE_IPV6;
  518. dst->port = htons(((struct sockaddr_in6*)src)->sin6_port);
  519. mem_copy(dst->ip, &((struct sockaddr_in6*)src)->sin6_addr.s6_addr, 16);
  520. }
  521. else
  522. {
  523. mem_zero(dst, sizeof(struct sockaddr));
  524. dbg_msg("system", "couldn't convert sockaddr of family %d", src->sa_family);
  525. }
  526. }
  527. int net_addr_comp(const NETADDR *a, const NETADDR *b)
  528. {
  529. return mem_comp(a, b, sizeof(NETADDR));
  530. }
  531. void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_port)
  532. {
  533. if(addr->type == NETTYPE_IPV4)
  534. {
  535. if(add_port != 0)
  536. str_format(string, max_length, "%d.%d.%d.%d:%d", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3], addr->port);
  537. else
  538. str_format(string, max_length, "%d.%d.%d.%d", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3]);
  539. }
  540. else if(addr->type == NETTYPE_IPV6)
  541. {
  542. if(add_port != 0)
  543. str_format(string, max_length, "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
  544. (addr->ip[0]<<8)|addr->ip[1], (addr->ip[2]<<8)|addr->ip[3], (addr->ip[4]<<8)|addr->ip[5], (addr->ip[6]<<8)|addr->ip[7],
  545. (addr->ip[8]<<8)|addr->ip[9], (addr->ip[10]<<8)|addr->ip[11], (addr->ip[12]<<8)|addr->ip[13], (addr->ip[14]<<8)|addr->ip[15],
  546. addr->port);
  547. else
  548. str_format(string, max_length, "[%x:%x:%x:%x:%x:%x:%x:%x]",
  549. (addr->ip[0]<<8)|addr->ip[1], (addr->ip[2]<<8)|addr->ip[3], (addr->ip[4]<<8)|addr->ip[5], (addr->ip[6]<<8)|addr->ip[7],
  550. (addr->ip[8]<<8)|addr->ip[9], (addr->ip[10]<<8)|addr->ip[11], (addr->ip[12]<<8)|addr->ip[13], (addr->ip[14]<<8)|addr->ip[15]);
  551. }
  552. else
  553. str_format(string, max_length, "unknown type %d", addr->type);
  554. }
  555. static int priv_net_extract(const char *hostname, char *host, int max_host, int *port)
  556. {
  557. int i;
  558. *port = 0;
  559. host[0] = 0;
  560. if(hostname[0] == '[')
  561. {
  562. // ipv6 mode
  563. for(i = 1; i < max_host && hostname[i] && hostname[i] != ']'; i++)
  564. host[i-1] = hostname[i];
  565. host[i-1] = 0;
  566. if(hostname[i] != ']') // malformatted
  567. return -1;
  568. i++;
  569. if(hostname[i] == ':')
  570. *port = atol(hostname+i+1);
  571. }
  572. else
  573. {
  574. // generic mode (ipv4, hostname etc)
  575. for(i = 0; i < max_host-1 && hostname[i] && hostname[i] != ':'; i++)
  576. host[i] = hostname[i];
  577. host[i] = 0;
  578. if(hostname[i] == ':')
  579. *port = atol(hostname+i+1);
  580. }
  581. return 0;
  582. }
  583. int net_host_lookup(const char *hostname, NETADDR *addr, int types)
  584. {
  585. struct addrinfo hints;
  586. struct addrinfo *result;
  587. int e;
  588. char host[256];
  589. int port = 0;
  590. if(priv_net_extract(hostname, host, sizeof(host), &port))
  591. return -1;
  592. /*
  593. dbg_msg("host lookup", "host='%s' port=%d %d", host, port, types);
  594. */
  595. mem_zero(&hints, sizeof(hints));
  596. hints.ai_family = AF_UNSPEC;
  597. if(types == NETTYPE_IPV4)
  598. hints.ai_family = AF_INET;
  599. else if(types == NETTYPE_IPV6)
  600. hints.ai_family = AF_INET6;
  601. e = getaddrinfo(host, NULL, &hints, &result);
  602. if(e != 0 || !result)
  603. return -1;
  604. sockaddr_to_netaddr(result->ai_addr, addr);
  605. freeaddrinfo(result);
  606. addr->port = port;
  607. return 0;
  608. }
  609. static int parse_int(int *out, const char **str)
  610. {
  611. int i = 0;
  612. *out = 0;
  613. if(**str < '0' || **str > '9')
  614. return -1;
  615. i = **str - '0';
  616. (*str)++;
  617. while(1)
  618. {
  619. if(**str < '0' || **str > '9')
  620. {
  621. *out = i;
  622. return 0;
  623. }
  624. i = (i*10) + (**str - '0');
  625. (*str)++;
  626. }
  627. return 0;
  628. }
  629. static int parse_char(char c, const char **str)
  630. {
  631. if(**str != c) return -1;
  632. (*str)++;
  633. return 0;
  634. }
  635. static int parse_uint8(unsigned char *out, const char **str)
  636. {
  637. int i;
  638. if(parse_int(&i, str) != 0) return -1;
  639. if(i < 0 || i > 0xff) return -1;
  640. *out = i;
  641. return 0;
  642. }
  643. static int parse_uint16(unsigned short *out, const char **str)
  644. {
  645. int i;
  646. if(parse_int(&i, str) != 0) return -1;
  647. if(i < 0 || i > 0xffff) return -1;
  648. *out = i;
  649. return 0;
  650. }
  651. int net_addr_from_str(NETADDR *addr, const char *string)
  652. {
  653. const char *str = string;
  654. mem_zero(addr, sizeof(NETADDR));
  655. if(str[0] == '[')
  656. {
  657. /* ipv6 */
  658. struct sockaddr_in6 sa6;
  659. char buf[128];
  660. int i;
  661. str++;
  662. for(i = 0; i < 127 && str[i] && str[i] != ']'; i++)
  663. buf[i] = str[i];
  664. buf[i] = 0;
  665. str += i;
  666. #if defined(CONF_FAMILY_WINDOWS)
  667. {
  668. int size;
  669. sa6.sin6_family = AF_INET6;
  670. size = (int)sizeof(sa6);
  671. if(WSAStringToAddress(buf, AF_INET6, NULL, (struct sockaddr *)&sa6, &size) != 0)
  672. return -1;
  673. }
  674. #else
  675. if(inet_pton(AF_INET6, buf, &sa6) != 1)
  676. return -1;
  677. #endif
  678. sockaddr_to_netaddr((struct sockaddr *)&sa6, addr);
  679. if(*str == ']')
  680. {
  681. str++;
  682. if(*str == ':')
  683. {
  684. str++;
  685. if(parse_uint16(&addr->port, &str))
  686. return -1;
  687. }
  688. }
  689. else
  690. return -1;
  691. return 0;
  692. }
  693. else
  694. {
  695. /* ipv4 */
  696. if(parse_uint8(&addr->ip[0], &str)) return -1;
  697. if(parse_char('.', &str)) return -1;
  698. if(parse_uint8(&addr->ip[1], &str)) return -1;
  699. if(parse_char('.', &str)) return -1;
  700. if(parse_uint8(&addr->ip[2], &str)) return -1;
  701. if(parse_char('.', &str)) return -1;
  702. if(parse_uint8(&addr->ip[3], &str)) return -1;
  703. if(*str == ':')
  704. {
  705. str++;
  706. if(parse_uint16(&addr->port, &str)) return -1;
  707. }
  708. addr->type = NETTYPE_IPV4;
  709. }
  710. return 0;
  711. }
  712. static void priv_net_close_socket(int sock)
  713. {
  714. #if defined(CONF_FAMILY_WINDOWS)
  715. closesocket(sock);
  716. #else
  717. close(sock);
  718. #endif
  719. }
  720. static int priv_net_close_all_sockets(NETSOCKET sock)
  721. {
  722. /* close down ipv4 */
  723. if(sock.ipv4sock >= 0)
  724. {
  725. priv_net_close_socket(sock.ipv4sock);
  726. sock.ipv4sock = -1;
  727. sock.type &= ~NETTYPE_IPV4;
  728. }
  729. /* close down ipv6 */
  730. if(sock.ipv6sock >= 0)
  731. {
  732. priv_net_close_socket(sock.ipv6sock);
  733. sock.ipv6sock = -1;
  734. sock.type &= ~NETTYPE_IPV6;
  735. }
  736. return 0;
  737. }
  738. static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, int sockaddrlen)
  739. {
  740. int sock, e;
  741. /* create socket */
  742. sock = socket(domain, type, 0);
  743. if(sock < 0)
  744. {
  745. #if defined(CONF_FAMILY_WINDOWS)
  746. char buf[128];
  747. int error = WSAGetLastError();
  748. if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, 0, buf, sizeof(buf), 0) == 0)
  749. buf[0] = 0;
  750. dbg_msg("net", "failed to create socket with domain %d and type %d (%d '%s')", domain, type, error, buf);
  751. #else
  752. dbg_msg("net", "failed to create socket with domain %d and type %d (%d '%s')", domain, type, errno, strerror(errno));
  753. #endif
  754. return -1;
  755. }
  756. /* set to IPv6 only if thats what we are creating */
  757. #if defined(IPV6_V6ONLY) /* windows sdk 6.1 and higher */
  758. if(domain == AF_INET6)
  759. {
  760. int ipv6only = 1;
  761. setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&ipv6only, sizeof(ipv6only));
  762. }
  763. #endif
  764. /* bind the socket */
  765. e = bind(sock, addr, sockaddrlen);
  766. if(e != 0)
  767. {
  768. #if defined(CONF_FAMILY_WINDOWS)
  769. char buf[128];
  770. int error = WSAGetLastError();
  771. if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, 0, buf, sizeof(buf), 0) == 0)
  772. buf[0] = 0;
  773. dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, error, buf);
  774. #else
  775. dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, errno, strerror(errno));
  776. #endif
  777. priv_net_close_socket(sock);
  778. return -1;
  779. }
  780. /* return the newly created socket */
  781. return sock;
  782. }
  783. NETSOCKET net_udp_create(NETADDR bindaddr)
  784. {
  785. NETSOCKET sock = invalid_socket;
  786. NETADDR tmpbindaddr = bindaddr;
  787. int broadcast = 1;
  788. int recvsize = 65536;
  789. if(bindaddr.type&NETTYPE_IPV4)
  790. {
  791. struct sockaddr_in addr;
  792. int socket = -1;
  793. /* bind, we should check for error */
  794. tmpbindaddr.type = NETTYPE_IPV4;
  795. netaddr_to_sockaddr_in(&tmpbindaddr, &addr);
  796. socket = priv_net_create_socket(AF_INET, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr));
  797. if(socket >= 0)
  798. {
  799. sock.type |= NETTYPE_IPV4;
  800. sock.ipv4sock = socket;
  801. /* set boardcast */
  802. setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));
  803. /* set receive buffer size */
  804. setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvsize, sizeof(recvsize));
  805. }
  806. }
  807. if(bindaddr.type&NETTYPE_IPV6)
  808. {
  809. struct sockaddr_in6 addr;
  810. int socket = -1;
  811. /* bind, we should check for error */
  812. tmpbindaddr.type = NETTYPE_IPV6;
  813. netaddr_to_sockaddr_in6(&tmpbindaddr, &addr);
  814. socket = priv_net_create_socket(AF_INET6, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr));
  815. if(socket >= 0)
  816. {
  817. sock.type |= NETTYPE_IPV6;
  818. sock.ipv6sock = socket;
  819. /* set boardcast */
  820. setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));
  821. /* set receive buffer size */
  822. setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvsize, sizeof(recvsize));
  823. }
  824. }
  825. /* set non-blocking */
  826. net_set_non_blocking(sock);
  827. /* return */
  828. return sock;
  829. }
  830. int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size)
  831. {
  832. int d = -1;
  833. if(addr->type&NETTYPE_IPV4)
  834. {
  835. if(sock.ipv4sock >= 0)
  836. {
  837. struct sockaddr_in sa;
  838. if(addr->type&NETTYPE_LINK_BROADCAST)
  839. {
  840. mem_zero(&sa, sizeof(sa));
  841. sa.sin_port = htons(addr->port);
  842. sa.sin_family = AF_INET;
  843. sa.sin_addr.s_addr = INADDR_BROADCAST;
  844. }
  845. else
  846. netaddr_to_sockaddr_in(addr, &sa);
  847. d = sendto((int)sock.ipv4sock, (const char*)data, size, 0, (struct sockaddr *)&sa, sizeof(sa));
  848. }
  849. else
  850. dbg_msg("net", "can't sent ipv4 traffic to this socket");
  851. }
  852. if(addr->type&NETTYPE_IPV6)
  853. {
  854. if(sock.ipv6sock >= 0)
  855. {
  856. struct sockaddr_in6 sa;
  857. if(addr->type&NETTYPE_LINK_BROADCAST)
  858. {
  859. mem_zero(&sa, sizeof(sa));
  860. sa.sin6_port = htons(addr->port);
  861. sa.sin6_family = AF_INET6;
  862. sa.sin6_addr.s6_addr[0] = 0xff; /* multicast */
  863. sa.sin6_addr.s6_addr[1] = 0x02; /* link local scope */
  864. sa.sin6_addr.s6_addr[15] = 1; /* all nodes */
  865. }
  866. else
  867. netaddr_to_sockaddr_in6(addr, &sa);
  868. d = sendto((int)sock.ipv6sock, (const char*)data, size, 0, (struct sockaddr *)&sa, sizeof(sa));
  869. }
  870. else
  871. dbg_msg("net", "can't sent ipv6 traffic to this socket");
  872. }
  873. /*
  874. else
  875. dbg_msg("net", "can't sent to network of type %d", addr->type);
  876. */
  877. /*if(d < 0)
  878. {
  879. char addrstr[256];
  880. net_addr_str(addr, addrstr, sizeof(addrstr));
  881. dbg_msg("net", "sendto error (%d '%s')", errno, strerror(errno));
  882. dbg_msg("net", "\tsock = %d %x", sock, sock);
  883. dbg_msg("net", "\tsize = %d %x", size, size);
  884. dbg_msg("net", "\taddr = %s", addrstr);
  885. }*/
  886. network_stats.sent_bytes += size;
  887. network_stats.sent_packets++;
  888. return d;
  889. }
  890. int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize)
  891. {
  892. char sockaddrbuf[128];
  893. socklen_t fromlen;// = sizeof(sockaddrbuf);
  894. int bytes = 0;
  895. if(bytes == 0 && sock.ipv4sock >= 0)
  896. {
  897. fromlen = sizeof(struct sockaddr_in);
  898. bytes = recvfrom(sock.ipv4sock, (char*)data, maxsize, 0, (struct sockaddr *)&sockaddrbuf, &fromlen);
  899. }
  900. if(bytes <= 0 && sock.ipv6sock >= 0)
  901. {
  902. fromlen = sizeof(struct sockaddr_in6);
  903. bytes = recvfrom(sock.ipv6sock, (char*)data, maxsize, 0, (struct sockaddr *)&sockaddrbuf, &fromlen);
  904. }
  905. if(bytes > 0)
  906. {
  907. sockaddr_to_netaddr((struct sockaddr *)&sockaddrbuf, addr);
  908. network_stats.recv_bytes += bytes;
  909. network_stats.recv_packets++;
  910. return bytes;
  911. }
  912. else if(bytes == 0)
  913. return 0;
  914. return -1; /* error */
  915. }
  916. int net_udp_close(NETSOCKET sock)
  917. {
  918. return priv_net_close_all_sockets(sock);
  919. }
  920. NETSOCKET net_tcp_create(NETADDR bindaddr)
  921. {
  922. NETSOCKET sock = invalid_socket;
  923. NETADDR tmpbindaddr = bindaddr;
  924. if(bindaddr.type&NETTYPE_IPV4)
  925. {
  926. struct sockaddr_in addr;
  927. int socket = -1;
  928. /* bind, we should check for error */
  929. tmpbindaddr.type = NETTYPE_IPV4;
  930. netaddr_to_sockaddr_in(&tmpbindaddr, &addr);
  931. socket = priv_net_create_socket(AF_INET, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr));
  932. if(socket >= 0)
  933. {
  934. sock.type |= NETTYPE_IPV4;
  935. sock.ipv4sock = socket;
  936. }
  937. }
  938. if(bindaddr.type&NETTYPE_IPV6)
  939. {
  940. struct sockaddr_in6 addr;
  941. int socket = -1;
  942. /* bind, we should check for error */
  943. tmpbindaddr.type = NETTYPE_IPV6;
  944. netaddr_to_sockaddr_in6(&tmpbindaddr, &addr);
  945. socket = priv_net_create_socket(AF_INET6, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr));
  946. if(socket >= 0)
  947. {
  948. sock.type |= NETTYPE_IPV6;
  949. sock.ipv6sock = socket;
  950. }
  951. }
  952. /* return */
  953. return sock;
  954. }
  955. int net_set_non_blocking(NETSOCKET sock)
  956. {
  957. unsigned long mode = 1;
  958. if(sock.ipv4sock >= 0)
  959. {
  960. #if defined(CONF_FAMILY_WINDOWS)
  961. ioctlsocket(sock.ipv4sock, FIONBIO, (unsigned long *)&mode);
  962. #else
  963. ioctl(sock.ipv4sock, FIONBIO, (unsigned long *)&mode);
  964. #endif
  965. }
  966. if(sock.ipv6sock >= 0)
  967. {
  968. #if defined(CONF_FAMILY_WINDOWS)
  969. ioctlsocket(sock.ipv6sock, FIONBIO, (unsigned long *)&mode);
  970. #else
  971. ioctl(sock.ipv6sock, FIONBIO, (unsigned long *)&mode);
  972. #endif
  973. }
  974. return 0;
  975. }
  976. int net_set_blocking(NETSOCKET sock)
  977. {
  978. unsigned long mode = 0;
  979. if(sock.ipv4sock >= 0)
  980. {
  981. #if defined(CONF_FAMILY_WINDOWS)
  982. ioctlsocket(sock.ipv4sock, FIONBIO, (unsigned long *)&mode);
  983. #else
  984. ioctl(sock.ipv4sock, FIONBIO, (unsigned long *)&mode);
  985. #endif
  986. }
  987. if(sock.ipv6sock >= 0)
  988. {
  989. #if defined(CONF_FAMILY_WINDOWS)
  990. ioctlsocket(sock.ipv6sock, FIONBIO, (unsigned long *)&mode);
  991. #else
  992. ioctl(sock.ipv6sock, FIONBIO, (unsigned long *)&mode);
  993. #endif
  994. }
  995. return 0;
  996. }
  997. int net_tcp_listen(NETSOCKET sock, int backlog)
  998. {
  999. int err = -1;
  1000. if(sock.ipv4sock >= 0)
  1001. err = listen(sock.ipv4sock, backlog);
  1002. if(sock.ipv6sock >= 0)
  1003. err = listen(sock.ipv6sock, backlog);
  1004. return err;
  1005. }
  1006. int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a)
  1007. {
  1008. int s;
  1009. socklen_t sockaddr_len;
  1010. *new_sock = invalid_socket;
  1011. if(sock.ipv4sock >= 0)
  1012. {
  1013. struct sockaddr_in addr;
  1014. sockaddr_len = sizeof(addr);
  1015. s = accept(sock.ipv4sock, (struct sockaddr *)&addr, &sockaddr_len);
  1016. if (s != -1)
  1017. {
  1018. sockaddr_to_netaddr((const struct sockaddr *)&addr, a);
  1019. new_sock->type = NETTYPE_IPV4;
  1020. new_sock->ipv4sock = s;
  1021. return s;
  1022. }
  1023. }
  1024. if(sock.ipv6sock >= 0)
  1025. {
  1026. struct sockaddr_in6 addr;
  1027. sockaddr_len = sizeof(addr);
  1028. s = accept(sock.ipv6sock, (struct sockaddr *)&addr, &sockaddr_len);
  1029. if (s != -1)
  1030. {
  1031. sockaddr_to_netaddr((const struct sockaddr *)&addr, a);
  1032. new_sock->type = NETTYPE_IPV6;
  1033. new_sock->ipv6sock = s;
  1034. return s;
  1035. }
  1036. }
  1037. return -1;
  1038. }
  1039. int net_tcp_connect(NETSOCKET sock, const NETADDR *a)
  1040. {
  1041. if(a->type&NETTYPE_IPV4)
  1042. {
  1043. struct sockaddr_in addr;
  1044. netaddr_to_sockaddr_in(a, &addr);
  1045. return connect(sock.ipv4sock, (struct sockaddr *)&addr, sizeof(addr));
  1046. }
  1047. if(a->type&NETTYPE_IPV6)
  1048. {
  1049. struct sockaddr_in6 addr;
  1050. netaddr_to_sockaddr_in6(a, &addr);
  1051. return connect(sock.ipv6sock, (struct sockaddr *)&addr, sizeof(addr));
  1052. }
  1053. return -1;
  1054. }
  1055. int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr)
  1056. {
  1057. int res = 0;
  1058. net_set_non_blocking(sock);
  1059. res = net_tcp_connect(sock, &bindaddr);
  1060. net_set_blocking(sock);
  1061. return res;
  1062. }
  1063. int net_tcp_send(NETSOCKET sock, const void *data, int size)
  1064. {
  1065. int bytes = -1;
  1066. if(sock.ipv4sock >= 0)
  1067. bytes = send((int)sock.ipv4sock, (const char*)data, size, 0);
  1068. if(sock.ipv6sock >= 0)
  1069. bytes = send((int)sock.ipv6sock, (const char*)data, size, 0);
  1070. return bytes;
  1071. }
  1072. int net_tcp_recv(NETSOCKET sock, void *data, int maxsize)
  1073. {
  1074. int bytes = -1;
  1075. if(sock.ipv4sock >= 0)
  1076. bytes = recv((int)sock.ipv4sock, (char*)data, maxsize, 0);
  1077. if(sock.ipv6sock >= 0)
  1078. bytes = recv((int)sock.ipv6sock, (char*)data, maxsize, 0);
  1079. return bytes;
  1080. }
  1081. int net_tcp_close(NETSOCKET sock)
  1082. {
  1083. return priv_net_close_all_sockets(sock);
  1084. }
  1085. int net_errno()
  1086. {
  1087. #if defined(CONF_FAMILY_WINDOWS)
  1088. return WSAGetLastError();
  1089. #else
  1090. return errno;
  1091. #endif
  1092. }
  1093. int net_would_block()
  1094. {
  1095. #if defined(CONF_FAMILY_WINDOWS)
  1096. return net_errno() == WSAEWOULDBLOCK;
  1097. #else
  1098. return net_errno() == EWOULDBLOCK;
  1099. #endif
  1100. }
  1101. int net_init()
  1102. {
  1103. #if defined(CONF_FAMILY_WINDOWS)
  1104. WSADATA wsaData;
  1105. int err = WSAStartup(MAKEWORD(1, 1), &wsaData);
  1106. dbg_assert(err == 0, "network initialization failed.");
  1107. return err==0?0:1;
  1108. #endif
  1109. return 0;
  1110. }
  1111. int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user)
  1112. {
  1113. #if defined(CONF_FAMILY_WINDOWS)
  1114. WIN32_FIND_DATA finddata;
  1115. HANDLE handle;
  1116. char buffer[1024*2];
  1117. int length;
  1118. str_format(buffer, sizeof(buffer), "%s/*", dir);
  1119. handle = FindFirstFileA(buffer, &finddata);
  1120. if (handle == INVALID_HANDLE_VALUE)
  1121. return 0;
  1122. str_format(buffer, sizeof(buffer), "%s/", dir);
  1123. length = str_length(buffer);
  1124. /* add all the entries */
  1125. do
  1126. {
  1127. str_copy(buffer+length, finddata.cFileName, (int)sizeof(buffer)-length);
  1128. if(cb(finddata.cFileName, fs_is_dir(buffer), type, user))
  1129. break;
  1130. }
  1131. while (FindNextFileA(handle, &finddata));
  1132. FindClose(handle);
  1133. return 0;
  1134. #else
  1135. struct dirent *entry;
  1136. char buffer[1024*2];
  1137. int length;
  1138. DIR *d = opendir(dir);
  1139. if(!d)
  1140. return 0;
  1141. str_format(buffer, sizeof(buffer), "%s/", dir);
  1142. length = str_length(buffer);
  1143. while((entry = readdir(d)) != NULL)
  1144. {
  1145. str_copy(buffer+length, entry->d_name, (int)sizeof(buffer)-length);
  1146. if(cb(entry->d_name, fs_is_dir(buffer), type, user))
  1147. break;
  1148. }
  1149. /* close the directory and return */
  1150. closedir(d);
  1151. return 0;
  1152. #endif
  1153. }
  1154. int fs_storage_path(const char *appname, char *path, int max)
  1155. {
  1156. #if defined(CONF_FAMILY_WINDOWS)
  1157. char *home = getenv("APPDATA");
  1158. if(!home)
  1159. return -1;
  1160. _snprintf(path, max, "%s/%s", home, appname);
  1161. return 0;
  1162. #else
  1163. char *home = getenv("HOME");
  1164. #if !defined(CONF_PLATFORM_MACOSX)
  1165. int i;
  1166. #endif
  1167. if(!home)
  1168. return -1;
  1169. #if defined(CONF_PLATFORM_MACOSX)
  1170. snprintf(path, max, "%s/Library/Application Support/%s", home, appname);
  1171. #else
  1172. snprintf(path, max, "%s/.%s", home, appname);
  1173. for(i = strlen(home)+2; path[i]; i++)
  1174. path[i] = tolower(path[i]);
  1175. #endif
  1176. return 0;
  1177. #endif
  1178. }
  1179. int fs_makedir(const char *path)
  1180. {
  1181. #if defined(CONF_FAMILY_WINDOWS)
  1182. if(_mkdir(path) == 0)
  1183. return 0;
  1184. if(errno == EEXIST)
  1185. return 0;
  1186. return -1;
  1187. #else
  1188. if(mkdir(path, 0755) == 0)
  1189. return 0;
  1190. if(errno == EEXIST)
  1191. return 0;
  1192. return -1;
  1193. #endif
  1194. }
  1195. int fs_is_dir(const char *path)
  1196. {
  1197. #if defined(CONF_FAMILY_WINDOWS)
  1198. /* TODO: do this smarter */
  1199. WIN32_FIND_DATA finddata;
  1200. HANDLE handle;
  1201. char buffer[1024*2];
  1202. str_format(buffer, sizeof(buffer), "%s/*", path);
  1203. if ((handle = FindFirstFileA(buffer, &finddata)) == INVALID_HANDLE_VALUE)
  1204. return 0;
  1205. FindClose(handle);
  1206. return 1;
  1207. #else
  1208. struct stat sb;
  1209. if (stat(path, &sb) == -1)
  1210. return 0;
  1211. if (S_ISDIR(sb.st_mode))
  1212. return 1;
  1213. else
  1214. return 0;
  1215. #endif
  1216. }
  1217. int fs_chdir(const char *path)
  1218. {
  1219. if(fs_is_dir(path))
  1220. {
  1221. if(chdir(path))
  1222. return 1;
  1223. else
  1224. return 0;
  1225. }
  1226. else
  1227. return 1;
  1228. }
  1229. char *fs_getcwd(char *buffer, int buffer_size)
  1230. {
  1231. if(buffer == 0)
  1232. return 0;
  1233. #if defined(CONF_FAMILY_WINDOWS)
  1234. return _getcwd(buffer, buffer_size);
  1235. #else
  1236. return getcwd(buffer, buffer_size);
  1237. #endif
  1238. }
  1239. int fs_parent_dir(char *path)
  1240. {
  1241. char *parent = 0;
  1242. for(; *path; ++path)
  1243. {
  1244. if(*path == '/' || *path == '\\')
  1245. parent = path;
  1246. }
  1247. if(parent)
  1248. {
  1249. *parent = 0;
  1250. return 0;
  1251. }
  1252. return 1;
  1253. }
  1254. int fs_remove(const char *filename)
  1255. {
  1256. if(remove(filename) != 0)
  1257. return 1;
  1258. return 0;
  1259. }
  1260. int fs_rename(const char *oldname, const char *newname)
  1261. {
  1262. if(rename(oldname, newname) != 0)
  1263. return 1;
  1264. return 0;
  1265. }
  1266. void swap_endian(void *data, unsigned elem_size, unsigned num)
  1267. {
  1268. char *src = (char*) data;
  1269. char *dst = src + (elem_size - 1);
  1270. while(num)
  1271. {
  1272. unsigned n = elem_size>>1;
  1273. char tmp;
  1274. while(n)
  1275. {
  1276. tmp = *src;
  1277. *src = *dst;
  1278. *dst = tmp;
  1279. src++;
  1280. dst--;
  1281. n--;
  1282. }
  1283. src = src + (elem_size>>1);
  1284. dst = src + (elem_size - 1);
  1285. num--;
  1286. }
  1287. }
  1288. int net_socket_read_wait(NETSOCKET sock, int time)
  1289. {
  1290. struct timeval tv;
  1291. fd_set readfds;
  1292. int sockid;
  1293. tv.tv_sec = 0;
  1294. tv.tv_usec = 1000*time;
  1295. sockid = 0;
  1296. FD_ZERO(&readfds);
  1297. if(sock.ipv4sock >= 0)
  1298. {
  1299. FD_SET(sock.ipv4sock, &readfds);
  1300. sockid = sock.ipv4sock;
  1301. }
  1302. if(sock.ipv6sock >= 0)
  1303. {
  1304. FD_SET(sock.ipv6sock, &readfds);
  1305. if(sock.ipv6sock > sockid)
  1306. sockid = sock.ipv6sock;
  1307. }
  1308. /* don't care about writefds and exceptfds */
  1309. select(sockid+1, &readfds, NULL, NULL, &tv);
  1310. if(sock.ipv4sock >= 0 && FD_ISSET(sock.ipv4sock, &readfds))
  1311. return 1;
  1312. if(sock.ipv6sock >= 0 && FD_ISSET(sock.ipv6sock, &readfds))
  1313. return 1;
  1314. return 0;
  1315. }
  1316. int time_timestamp()
  1317. {
  1318. return time(0);
  1319. }
  1320. void str_append(char *dst, const char *src, int dst_size)
  1321. {
  1322. int s = strlen(dst);
  1323. int i = 0;
  1324. while(s < dst_size)
  1325. {
  1326. dst[s] = src[i];
  1327. if(!src[i]) /* check for null termination */
  1328. break;
  1329. s++;
  1330. i++;
  1331. }
  1332. dst[dst_size-1] = 0; /* assure null termination */
  1333. }
  1334. void str_copy(char *dst, const char *src, int dst_size)
  1335. {
  1336. strncpy(dst, src, dst_size);
  1337. dst[dst_size-1] = 0; /* assure null termination */
  1338. }
  1339. int str_length(const char *str)
  1340. {
  1341. return (int)strlen(str);
  1342. }
  1343. void str_format(char *buffer, int buffer_size, const char *format, ...)
  1344. {
  1345. #if defined(CONF_FAMILY_WINDOWS)
  1346. va_list ap;
  1347. va_start(ap, format);
  1348. _vsnprintf(buffer, buffer_size, format, ap);
  1349. va_end(ap);
  1350. #else
  1351. va_list ap;
  1352. va_start(ap, format);
  1353. vsnprintf(buffer, buffer_size, format, ap);
  1354. va_end(ap);
  1355. #endif
  1356. buffer[buffer_size-1] = 0; /* assure null termination */
  1357. }
  1358. /* makes sure that the string only contains the characters between 32 and 127 */
  1359. void str_sanitize_strong(char *str_in)
  1360. {
  1361. unsigned char *str = (unsigned char *)str_in;
  1362. while(*str)
  1363. {
  1364. *str &= 0x7f;
  1365. if(*str < 32)
  1366. *str = 32;
  1367. str++;
  1368. }
  1369. }
  1370. /* makes sure that the string only contains the characters between 32 and 255 */
  1371. void str_sanitize_cc(char *str_in)
  1372. {
  1373. unsigned char *str = (unsigned char *)str_in;
  1374. while(*str)
  1375. {
  1376. if(*str < 32)
  1377. *str = ' ';
  1378. str++;
  1379. }
  1380. }
  1381. /* makes sure that the string only contains the characters between 32 and 255 + \r\n\t */
  1382. void str_sanitize(char *str_in)
  1383. {
  1384. unsigned char *str = (unsigned char *)str_in;
  1385. while(*str)
  1386. {
  1387. if(*str < 32 && !(*str == '\r') && !(*str == '\n') && !(*str == '\t'))
  1388. *str = ' ';
  1389. str++;
  1390. }
  1391. }
  1392. char *str_skip_to_whitespace(char *str)
  1393. {
  1394. while(*str && (*str != ' ' && *str != '\t' && *str != '\n'))
  1395. str++;
  1396. return str;
  1397. }
  1398. char *str_skip_whitespaces(char *str)
  1399. {
  1400. while(*str && (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r'))
  1401. str++;
  1402. return str;
  1403. }
  1404. /* case */
  1405. int str_comp_nocase(const char *a, const char *b)
  1406. {
  1407. #if defined(CONF_FAMILY_WINDOWS)
  1408. return _stricmp(a,b);
  1409. #else
  1410. return strcasecmp(a,b);
  1411. #endif
  1412. }
  1413. int str_comp_nocase_num(const char *a, const char *b, const int num)
  1414. {
  1415. #if defined(CONF_FAMILY_WINDOWS)
  1416. return _strnicmp(a, b, num);
  1417. #else
  1418. return strncasecmp(a, b, num);
  1419. #endif
  1420. }
  1421. int str_comp(const char *a, const char *b)
  1422. {
  1423. return strcmp(a, b);
  1424. }
  1425. int str_comp_num(const char *a, const char *b, const int num)
  1426. {
  1427. return strncmp(a, b, num);
  1428. }
  1429. int str_comp_filenames(const char *a, const char *b)
  1430. {
  1431. int result;
  1432. for(; *a && *b; ++a, ++b)
  1433. {
  1434. if(*a >= '0' && *a <= '9' && *b >= '0' && *b <= '9')
  1435. {
  1436. result = 0;
  1437. do
  1438. {
  1439. if(!result)
  1440. result = *a - *b;
  1441. ++a; ++b;
  1442. }
  1443. while(*a >= '0' && *a <= '9' && *b >= '0' && *b <= '9');
  1444. if(*a >= '0' && *a <= '9')
  1445. return 1;
  1446. else if(*b >= '0' && *b <= '9')
  1447. return -1;
  1448. else if(result)
  1449. return result;
  1450. }
  1451. if(*a != *b)
  1452. break;
  1453. }
  1454. return *a - *b;
  1455. }
  1456. const char *str_find_nocase(const char *haystack, const char *needle)
  1457. {
  1458. while(*haystack) /* native implementation */
  1459. {
  1460. const char *a = haystack;
  1461. const char *b = needle;
  1462. while(*a && *b && tolower(*a) == tolower(*b))
  1463. {
  1464. a++;
  1465. b++;
  1466. }
  1467. if(!(*b))
  1468. return haystack;
  1469. haystack++;
  1470. }
  1471. return 0;
  1472. }
  1473. const char *str_find(const char *haystack, const char *needle)
  1474. {
  1475. while(*haystack) /* native implementation */
  1476. {
  1477. const char *a = haystack;
  1478. const char *b = needle;
  1479. while(*a && *b && *a == *b)
  1480. {
  1481. a++;
  1482. b++;
  1483. }
  1484. if(!(*b))
  1485. return haystack;
  1486. haystack++;
  1487. }
  1488. return 0;
  1489. }
  1490. void str_hex(char *dst, int dst_size, const void *data, int data_size)
  1491. {
  1492. static const char hex[] = "0123456789ABCDEF";
  1493. int b;
  1494. for(b = 0; b < data_size && b < dst_size/4-4; b++)
  1495. {
  1496. dst[b*3] = hex[((const unsigned char *)data)[b]>>4];
  1497. dst[b*3+1] = hex[((const unsigned char *)data)[b]&0xf];
  1498. dst[b*3+2] = ' ';
  1499. dst[b*3+3] = 0;
  1500. }
  1501. }
  1502. void str_timestamp(char *buffer, int buffer_size)
  1503. {
  1504. time_t time_data;
  1505. struct tm *time_info;
  1506. time(&time_data);
  1507. time_info = localtime(&time_data);
  1508. strftime(buffer, buffer_size, "%Y-%m-%d_%H-%M-%S", time_info);
  1509. buffer[buffer_size-1] = 0; /* assure null termination */
  1510. }
  1511. int mem_comp(const void *a, const void *b, int size)
  1512. {
  1513. return memcmp(a,b,size);
  1514. }
  1515. const MEMSTATS *mem_stats()
  1516. {
  1517. return &memory_stats;
  1518. }
  1519. void net_stats(NETSTATS *stats_inout)
  1520. {
  1521. *stats_inout = network_stats;
  1522. }
  1523. void gui_messagebox(const char *title, const char *message)
  1524. {
  1525. #if defined(CONF_PLATFORM_MACOSX)
  1526. DialogRef theItem;
  1527. DialogItemIndex itemIndex;
  1528. /* FIXME: really needed? can we rely on glfw? */
  1529. /* HACK - get events without a bundle */
  1530. ProcessSerialNumber psn;
  1531. GetCurrentProcess(&psn);
  1532. TransformProcessType(&psn,kProcessTransformToForegroundApplication);
  1533. SetFrontProcess(&psn);
  1534. /* END HACK */
  1535. CreateStandardAlert(kAlertStopAlert,
  1536. CFStringCreateWithCString(NULL, title, kCFStringEncodingASCII),
  1537. CFStringCreateWithCString(NULL, message, kCFStringEncodingASCII),
  1538. NULL,
  1539. &theItem);
  1540. RunStandardAlert(theItem, NULL, &itemIndex);
  1541. #elif defined(CONF_FAMILY_UNIX)
  1542. static char cmd[1024];
  1543. int err;
  1544. /* use xmessage which is available on nearly every X11 system */
  1545. snprintf(cmd, sizeof(cmd), "xmessage -center -title '%s' '%s'",
  1546. title,
  1547. message);
  1548. err = system(cmd);
  1549. dbg_msg("gui/msgbox", "result = %i", err);
  1550. #elif defined(CONF_FAMILY_WINDOWS)
  1551. MessageBox(NULL,
  1552. message,
  1553. title,
  1554. MB_ICONEXCLAMATION | MB_OK);
  1555. #else
  1556. /* this is not critical */
  1557. #warning not implemented
  1558. #endif
  1559. }
  1560. int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; }
  1561. char str_uppercase(char c)
  1562. {
  1563. if(c >= 'a' && c <= 'z')
  1564. return 'A' + (c-'a');
  1565. return c;
  1566. }
  1567. int str_toint(const char *str) { return atoi(str); }
  1568. float str_tofloat(const char *str) { return atof(str); }
  1569. void init_rand() { srand(time(NULL)); }
  1570. int irand() { return rand(); }
  1571. const char *str_utf8_skip_whitespaces(const char *str)
  1572. {
  1573. const char *str_old;
  1574. int code;
  1575. while(*str)
  1576. {
  1577. str_old = str;
  1578. code = str_utf8_decode(&str);
  1579. // check if unicode is not empty
  1580. if(code > 0x20 && code != 0xA0 && code != 0x034F && (code < 0x2000 || code > 0x200F) && (code < 0x2028 || code > 0x202F) &&
  1581. (code < 0x205F || code > 0x2064) && (code < 0x206A || code > 0x206F) && (code < 0xFE00 || code > 0xFE0F) &&
  1582. code != 0xFEFF && (code < 0xFFF9 || code > 0xFFFC))
  1583. {
  1584. return str_old;
  1585. }
  1586. }
  1587. return str;
  1588. }
  1589. static int str_utf8_isstart(char c)
  1590. {
  1591. if((c&0xC0) == 0x80) /* 10xxxxxx */
  1592. return 0;
  1593. return 1;
  1594. }
  1595. int str_utf8_rewind(const char *str, int cursor)
  1596. {
  1597. while(cursor)
  1598. {
  1599. cursor--;
  1600. if(str_utf8_isstart(*(str + cursor)))
  1601. break;
  1602. }
  1603. return cursor;
  1604. }
  1605. int str_utf8_forward(const char *str, int cursor)
  1606. {
  1607. const char *buf = str + cursor;
  1608. if(!buf[0])
  1609. return cursor;
  1610. if((*buf&0x80) == 0x0) /* 0xxxxxxx */
  1611. return cursor+1;
  1612. else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
  1613. {
  1614. if(!buf[1]) return cursor+1;
  1615. return cursor+2;
  1616. }
  1617. else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
  1618. {
  1619. if(!buf[1]) return cursor+1;
  1620. if(!buf[2]) return cursor+2;
  1621. return cursor+3;
  1622. }
  1623. else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
  1624. {
  1625. if(!buf[1]) return cursor+1;
  1626. if(!buf[2]) return cursor+2;
  1627. if(!buf[3]) return cursor+3;
  1628. return cursor+4;
  1629. }
  1630. /* invalid */
  1631. return cursor+1;
  1632. }
  1633. int str_utf8_encode(char *ptr, int chr)
  1634. {
  1635. /* encode */
  1636. if(chr <= 0x7F)
  1637. {
  1638. ptr[0] = (char)chr;
  1639. return 1;
  1640. }
  1641. else if(chr <= 0x7FF)
  1642. {
  1643. ptr[0] = 0xC0|((chr>>6)&0x1F);
  1644. ptr[1] = 0x80|(chr&0x3F);
  1645. return 2;
  1646. }
  1647. else if(chr <= 0xFFFF)
  1648. {
  1649. ptr[0] = 0xE0|((chr>>12)&0x0F);
  1650. ptr[1] = 0x80|((chr>>6)&0x3F);
  1651. ptr[2] = 0x80|(chr&0x3F);
  1652. return 3;
  1653. }
  1654. else if(chr <= 0x10FFFF)
  1655. {
  1656. ptr[0] = 0xF0|((chr>>18)&0x07);
  1657. ptr[1] = 0x80|((chr>>12)&0x3F);
  1658. ptr[2] = 0x80|((chr>>6)&0x3F);
  1659. ptr[3] = 0x80|(chr&0x3F);
  1660. return 4;
  1661. }
  1662. return 0;
  1663. }
  1664. int str_utf8_decode(const char **ptr)
  1665. {
  1666. const char *buf = *ptr;
  1667. int ch = 0;
  1668. do
  1669. {
  1670. if((*buf&0x80) == 0x0) /* 0xxxxxxx */
  1671. {
  1672. ch = *buf;
  1673. buf++;
  1674. }
  1675. else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
  1676. {
  1677. ch = (*buf++ & 0x3F) << 6; if(!(*buf)) break;
  1678. ch += (*buf++ & 0x3F);
  1679. if(ch == 0) ch = -1;
  1680. }
  1681. else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
  1682. {
  1683. ch = (*buf++ & 0x1F) << 12; if(!(*buf)) break;
  1684. ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
  1685. ch += (*buf++ & 0x3F);
  1686. if(ch == 0) ch = -1;
  1687. }
  1688. else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
  1689. {
  1690. ch = (*buf++ & 0x0F) << 18; if(!(*buf)) break;
  1691. ch += (*buf++ & 0x3F) << 12; if(!(*buf)) break;
  1692. ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
  1693. ch += (*buf++ & 0x3F);
  1694. if(ch == 0) ch = -1;
  1695. }
  1696. else
  1697. {
  1698. /* invalid */
  1699. buf++;
  1700. break;
  1701. }
  1702. *ptr = buf;
  1703. return ch;
  1704. } while(0);
  1705. /* out of bounds */
  1706. *ptr = buf;
  1707. return -1;
  1708. }
  1709. int str_utf8_check(const char *str)
  1710. {
  1711. while(*str)
  1712. {
  1713. if((*str&0x80) == 0x0)
  1714. str++;
  1715. else if((*str&0xE0) == 0xC0 && (*(str+1)&0xC0) == 0x80)
  1716. str += 2;
  1717. else if((*str&0xF0) == 0xE0 && (*(str+1)&0xC0) == 0x80 && (*(str+2)&0xC0) == 0x80)
  1718. str += 3;
  1719. else if((*str&0xF8) == 0xF0 && (*(str+1)&0xC0) == 0x80 && (*(str+2)&0xC0) == 0x80 && (*(str+3)&0xC0) == 0x80)
  1720. str += 4;
  1721. else
  1722. return 0;
  1723. }
  1724. return 1;
  1725. }
  1726. unsigned str_quickhash(const char *str)
  1727. {
  1728. unsigned hash = 5381;
  1729. for(; *str; str++)
  1730. hash = ((hash << 5) + hash) + (*str); /* hash * 33 + c */
  1731. return hash;
  1732. }
  1733. #if defined(__cplusplus)
  1734. }
  1735. #endif