PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/net_posix.c

https://gitlab.com/fzwoch/fodquake
C | 377 lines | 292 code | 62 blank | 23 comment | 63 complexity | 111f3e924b1e38de932134b4bbb321c2 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Copyright (C) 2008-2009 Mark Olsen
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #ifdef linux
  16. #define _GNU_SOURCE
  17. #endif
  18. #include <sys/types.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <netdb.h>
  22. #include <sys/ioctl.h>
  23. #include <unistd.h>
  24. #include <errno.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #ifdef linux
  28. #include <poll.h>
  29. #endif
  30. #include "sys_net.h"
  31. struct SysSocket
  32. {
  33. int s;
  34. int domain;
  35. };
  36. struct SysNetData *Sys_Net_Init()
  37. {
  38. return (struct SysNetData *)-1;
  39. }
  40. void Sys_Net_Shutdown(struct SysNetData *netdata)
  41. {
  42. }
  43. qboolean Sys_Net_ResolveName(struct SysNetData *netdata, const char *name, struct netaddr *address)
  44. {
  45. int r;
  46. struct addrinfo *addr;
  47. struct addrinfo *origaddr;
  48. qboolean ret;
  49. ret = false;
  50. r = getaddrinfo(name, 0, 0, &origaddr);
  51. if (r == 0)
  52. {
  53. addr = origaddr;
  54. while(addr)
  55. {
  56. if (addr->ai_family == AF_INET)
  57. {
  58. address->type = NA_IPV4;
  59. memcpy(address->addr.ipv4.address, &((struct sockaddr_in *)addr->ai_addr)->sin_addr.s_addr, 4);
  60. ret = true;
  61. break;
  62. }
  63. if (addr->ai_family == AF_INET6)
  64. {
  65. address->type = NA_IPV6;
  66. memcpy(address->addr.ipv6.address, &((struct sockaddr_in6 *)addr->ai_addr)->sin6_addr, sizeof(address->addr.ipv6.address));
  67. ret = true;
  68. break;
  69. }
  70. addr = addr->ai_next;
  71. }
  72. freeaddrinfo(origaddr);
  73. }
  74. return ret;
  75. }
  76. qboolean Sys_Net_ResolveAddress(struct SysNetData *netdata, const struct netaddr *address, char *output, unsigned int outputsize)
  77. {
  78. int r;
  79. socklen_t addrsize;
  80. union
  81. {
  82. struct sockaddr_in addr;
  83. struct sockaddr_in6 addr6;
  84. } addr;
  85. if (address->type == NA_IPV4)
  86. {
  87. addr.addr.sin_family = AF_INET;
  88. addr.addr.sin_port = htons(address->addr.ipv4.port);
  89. memcpy(&addr.addr.sin_addr.s_addr, address->addr.ipv4.address, 4);
  90. addrsize = sizeof(addr.addr);
  91. }
  92. else if (address->type == NA_IPV6)
  93. {
  94. addr.addr6.sin6_family = AF_INET6;
  95. addr.addr6.sin6_port = htons(address->addr.ipv6.port);
  96. addr.addr6.sin6_flowinfo = 0;
  97. memcpy(&addr.addr6.sin6_addr, address->addr.ipv6.address, sizeof(addr.addr6.sin6_addr));
  98. addr.addr6.sin6_scope_id = 0;
  99. addrsize = sizeof(addr.addr6);
  100. }
  101. else
  102. return false;
  103. r = getnameinfo((struct sockaddr *)&addr, addrsize, output, outputsize, 0, 0, NI_NAMEREQD);
  104. if (r == 0)
  105. return true;
  106. return false;
  107. }
  108. struct SysSocket *Sys_Net_CreateSocket(struct SysNetData *netdata, enum netaddrtype addrtype)
  109. {
  110. struct SysSocket *s;
  111. int domain;
  112. int r;
  113. int one;
  114. one = 1;
  115. if (addrtype == NA_IPV4)
  116. domain = AF_INET;
  117. else if (addrtype == NA_IPV6)
  118. domain = AF_INET6;
  119. else
  120. return 0;
  121. s = malloc(sizeof(*s));
  122. if (s)
  123. {
  124. s->s = socket(domain, SOCK_DGRAM, 0);
  125. if (s->s != -1)
  126. {
  127. r = ioctl(s->s, FIONBIO, &one);
  128. if (r == 0)
  129. {
  130. s->domain = domain;
  131. return s;
  132. }
  133. }
  134. free(s);
  135. }
  136. return 0;
  137. }
  138. void Sys_Net_DeleteSocket(struct SysNetData *netdata, struct SysSocket *socket)
  139. {
  140. close(socket->s);
  141. free(socket);
  142. }
  143. qboolean Sys_Net_Bind(struct SysNetData *netdata, struct SysSocket *socket, unsigned short port)
  144. {
  145. int r;
  146. socklen_t addrsize;
  147. union
  148. {
  149. struct sockaddr_in addr;
  150. struct sockaddr_in6 addr6;
  151. } addr;
  152. if (socket->domain == AF_INET)
  153. {
  154. addr.addr.sin_family = AF_INET;
  155. addr.addr.sin_port = htons(port);
  156. *(unsigned int *)&addr.addr.sin_addr.s_addr = 0;
  157. addrsize = sizeof(addr.addr);
  158. }
  159. else if (socket->domain == AF_INET6)
  160. {
  161. addr.addr6.sin6_family = AF_INET6;
  162. addr.addr6.sin6_port = htons(port);
  163. addr.addr6.sin6_flowinfo = 0;
  164. memset(&addr.addr6.sin6_addr, 0, sizeof(addr.addr6.sin6_addr));
  165. addr.addr6.sin6_scope_id = 0;
  166. addrsize = sizeof(addr.addr6);
  167. }
  168. else
  169. return false;
  170. r = bind(socket->s, (struct sockaddr *)&addr, addrsize);
  171. if (r == 0)
  172. return true;
  173. return false;
  174. }
  175. int Sys_Net_Send(struct SysNetData *netdata, struct SysSocket *socket, const void *data, int datalen, const struct netaddr *address)
  176. {
  177. int r;
  178. if (address)
  179. {
  180. unsigned int addrsize;
  181. union
  182. {
  183. struct sockaddr_in addr;
  184. struct sockaddr_in6 addr6;
  185. } addr;
  186. if (socket->domain == AF_INET)
  187. {
  188. addr.addr.sin_family = AF_INET;
  189. addr.addr.sin_port = htons(address->addr.ipv4.port);
  190. memcpy(&addr.addr.sin_addr.s_addr, address->addr.ipv4.address, 4);
  191. addrsize = sizeof(addr.addr);
  192. }
  193. else if (socket->domain == AF_INET6)
  194. {
  195. addr.addr6.sin6_family = AF_INET6;
  196. addr.addr6.sin6_port = htons(address->addr.ipv6.port);
  197. memcpy(&addr.addr6.sin6_addr, address->addr.ipv6.address, sizeof(addr.addr6.sin6_addr));
  198. addr.addr6.sin6_flowinfo = 0;
  199. addr.addr6.sin6_scope_id = 0;
  200. addrsize = sizeof(addr.addr6);
  201. }
  202. else
  203. return -1;
  204. r = sendto(socket->s, data, datalen, 0, (struct sockaddr *)&addr, addrsize);
  205. }
  206. else
  207. r = send(socket->s, data, datalen, 0);
  208. if (r == -1)
  209. {
  210. if (errno == EWOULDBLOCK)
  211. return 0;
  212. }
  213. return r;
  214. }
  215. int Sys_Net_Receive(struct SysNetData *netdata, struct SysSocket *socket, void *data, int datalen, struct netaddr *address)
  216. {
  217. int r;
  218. if (address)
  219. {
  220. socklen_t fromlen;
  221. union
  222. {
  223. struct sockaddr_in addr;
  224. struct sockaddr_in6 addr6;
  225. } addr;
  226. if (socket->domain == AF_INET)
  227. fromlen = sizeof(addr.addr);
  228. else if (socket->domain == AF_INET6)
  229. fromlen = sizeof(addr.addr6);
  230. r = recvfrom(socket->s, data, datalen, 0, (struct sockaddr *)&addr, &fromlen);
  231. if (r >= 0)
  232. {
  233. if (socket->domain == AF_INET)
  234. {
  235. if (fromlen != sizeof(addr.addr))
  236. return -1;
  237. address->type = NA_IPV4;
  238. address->addr.ipv4.port = htons(addr.addr.sin_port);
  239. memcpy(address->addr.ipv4.address, &addr.addr.sin_addr.s_addr, 4);
  240. }
  241. else if (socket->domain == AF_INET6)
  242. {
  243. if (fromlen != sizeof(addr.addr6))
  244. return -1;
  245. address->type = NA_IPV6;
  246. address->addr.ipv6.port = htons(addr.addr6.sin6_port);
  247. memcpy(address->addr.ipv6.address, &addr.addr6.sin6_addr, sizeof(address->addr.ipv6.address));
  248. }
  249. }
  250. }
  251. else
  252. r = recv(socket->s, data, datalen, 0);
  253. if (r == -1)
  254. {
  255. if (errno == EWOULDBLOCK)
  256. return 0;
  257. }
  258. return r;
  259. }
  260. void Sys_Net_Wait(struct SysNetData *netdata, struct SysSocket *socket, unsigned int timeout_us)
  261. {
  262. #ifndef linux
  263. /* On Linux, select() rounds up the sleeping time to the nearest X ms
  264. * even if its <sarcasm>hyperadvanced</sarcasm> NO_HZ option is set, so
  265. * this won't be useful. However, on such configurations, usleep()
  266. * works as advertised, so see below. */
  267. struct timeval tv;
  268. fd_set rfds;
  269. FD_ZERO(&rfds);
  270. FD_SET(socket->s, &rfds);
  271. tv.tv_sec = timeout_us / 1000000;
  272. tv.tv_usec = timeout_us % 1000000;
  273. select(socket->s + 1, &rfds, 0, 0, &tv);
  274. #else
  275. #if 0
  276. /* Here we trade off socket receive accuracy for sleep accuracy. */
  277. struct timeval stv;
  278. struct timeval tv;
  279. fd_set rfds;
  280. unsigned long long x;
  281. int r;
  282. gettimeofday(&stv, 0);
  283. while(1)
  284. {
  285. gettimeofday(&tv, 0);
  286. x = (tv.tv_sec * 1000000 + tv.tv_usec) - (stv.tv_sec * 1000000 + stv.tv_usec);
  287. if (x >= timeout_us)
  288. break;
  289. FD_ZERO(&rfds);
  290. FD_SET(socket->s, &rfds);
  291. tv.tv_sec = 0;
  292. tv.tv_usec = 0;
  293. r = select(socket->s + 1, &rfds, 0, 0, &tv);
  294. if (r > 0)
  295. break;
  296. x -= timeout_us;
  297. if (x > 2500)
  298. x = 2500;
  299. usleep(x);
  300. }
  301. #else
  302. struct pollfd pfd;
  303. struct timespec ts;
  304. pfd.fd = socket->s;
  305. pfd.events = POLLIN;
  306. ts.tv_sec = timeout_us/1000000;
  307. ts.tv_nsec = (timeout_us%1000000)*1000;
  308. ppoll(&pfd, 1, &ts, 0);
  309. #endif
  310. #endif
  311. }