PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/lib/platform/posix/os-socket.h

https://github.com/spike008t/libcec
C Header | 341 lines | 259 code | 44 blank | 38 comment | 74 complexity | 072ac99da1ab4c3ed1b6c035c5b74728 MD5 | raw file
Possible License(s): GPL-2.0
  1. #pragma once
  2. /*
  3. * This file is part of the libCEC(R) library.
  4. *
  5. * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
  6. * libCEC(R) is an original work, containing original code.
  7. *
  8. * libCEC(R) is a trademark of Pulse-Eight Limited.
  9. *
  10. * This program is dual-licensed; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. *
  24. *
  25. * Alternatively, you can license this library under a commercial license,
  26. * please contact Pulse-Eight Licensing for more information.
  27. *
  28. * For more information contact:
  29. * Pulse-Eight Licensing <license@pulse-eight.com>
  30. * http://www.pulse-eight.com/
  31. * http://www.pulse-eight.net/
  32. */
  33. #include "lib/platform/os.h"
  34. #include "lib/platform/util/timeutils.h"
  35. #include <stdio.h>
  36. #include <fcntl.h>
  37. #include <sys/ioctl.h>
  38. #include <sys/socket.h>
  39. #include <netinet/in.h>
  40. #include <netinet/tcp.h>
  41. #include <arpa/inet.h>
  42. #include <netdb.h>
  43. #include <poll.h>
  44. /* Needed on Mac OS/X */
  45. #ifndef SOL_TCP
  46. #define SOL_TCP IPPROTO_TCP
  47. #endif
  48. namespace PLATFORM
  49. {
  50. // Standard sockets
  51. //@{
  52. inline void SocketClose(socket_t socket)
  53. {
  54. if (socket != INVALID_SOCKET_VALUE)
  55. close(socket);
  56. }
  57. inline void SocketSetBlocking(socket_t socket, bool bSetTo)
  58. {
  59. if (socket != INVALID_SOCKET_VALUE)
  60. {
  61. if (bSetTo)
  62. fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK);
  63. else
  64. fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK);
  65. }
  66. }
  67. inline ssize_t SocketWrite(socket_t socket, int *iError, void* data, size_t len)
  68. {
  69. fd_set port;
  70. if (socket == INVALID_SOCKET_VALUE)
  71. {
  72. *iError = EINVAL;
  73. return -EINVAL;
  74. }
  75. ssize_t iBytesWritten(0);
  76. struct timeval *tv(NULL);
  77. while (iBytesWritten < (ssize_t)len)
  78. {
  79. FD_ZERO(&port);
  80. FD_SET(socket, &port);
  81. ssize_t returnv = (ssize_t)select(socket + 1, NULL, &port, NULL, tv);
  82. if (returnv < 0)
  83. {
  84. *iError = errno;
  85. return -errno;
  86. }
  87. else if (returnv == 0)
  88. {
  89. *iError = ETIMEDOUT;
  90. return -ETIMEDOUT;
  91. }
  92. returnv = write(socket, (char*)data + iBytesWritten, len - iBytesWritten);
  93. if (returnv == -1)
  94. {
  95. *iError = errno;
  96. return -errno;
  97. }
  98. iBytesWritten += returnv;
  99. }
  100. return iBytesWritten;
  101. }
  102. inline ssize_t SocketRead(socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/)
  103. {
  104. fd_set port;
  105. struct timeval timeout, *tv;
  106. int64_t iNow(0), iTarget(0);
  107. ssize_t iBytesRead(0);
  108. *iError = 0;
  109. if (socket == INVALID_SOCKET_VALUE)
  110. {
  111. *iError = EINVAL;
  112. return -EINVAL;
  113. }
  114. if (iTimeoutMs > 0)
  115. {
  116. iNow = GetTimeMs();
  117. iTarget = iNow + (int64_t) iTimeoutMs;
  118. }
  119. while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || iTarget > iNow))
  120. {
  121. if (iTimeoutMs == 0)
  122. {
  123. tv = NULL;
  124. }
  125. else
  126. {
  127. timeout.tv_sec = ((long int)iTarget - (long int)iNow) / (long int)1000.;
  128. timeout.tv_usec = ((long int)iTarget - (long int)iNow) % (long int)1000.;
  129. tv = &timeout;
  130. }
  131. FD_ZERO(&port);
  132. FD_SET(socket, &port);
  133. ssize_t returnv = (ssize_t)select(socket + 1, &port, NULL, NULL, tv);
  134. if (returnv == -1)
  135. {
  136. *iError = errno;
  137. return -errno;
  138. }
  139. else if (returnv == 0)
  140. {
  141. break; //nothing to read
  142. }
  143. returnv = read(socket, (char*)data + iBytesRead, len - iBytesRead);
  144. if (returnv == -1)
  145. {
  146. *iError = errno;
  147. return -errno;
  148. }
  149. iBytesRead += returnv;
  150. if (iTimeoutMs > 0)
  151. iNow = GetTimeMs();
  152. }
  153. return iBytesRead;
  154. }
  155. inline int SocketIoctl(socket_t socket, int *iError, int request, void* data)
  156. {
  157. if (socket == INVALID_SOCKET_VALUE)
  158. {
  159. *iError = EINVAL;
  160. return -1;
  161. }
  162. int iReturn = ioctl(socket, request, data);
  163. if (iReturn < 0)
  164. *iError = errno;
  165. return iReturn;
  166. }
  167. //@}
  168. // TCP
  169. //@{
  170. inline void TcpSocketClose(tcp_socket_t socket)
  171. {
  172. SocketClose(socket);
  173. }
  174. inline void TcpSocketShutdown(tcp_socket_t socket)
  175. {
  176. if (socket != INVALID_SOCKET_VALUE)
  177. shutdown(socket, SHUT_RDWR);
  178. }
  179. inline ssize_t TcpSocketWrite(tcp_socket_t socket, int *iError, void* data, size_t len)
  180. {
  181. if (socket == INVALID_SOCKET_VALUE)
  182. {
  183. *iError = EINVAL;
  184. return -1;
  185. }
  186. ssize_t iReturn = send(socket, data, len, 0);
  187. if (iReturn < (ssize_t)len)
  188. *iError = errno;
  189. return iReturn;
  190. }
  191. inline ssize_t TcpSocketRead(tcp_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/)
  192. {
  193. int64_t iNow(0), iTarget(0);
  194. ssize_t iBytesRead(0);
  195. *iError = 0;
  196. if (socket == INVALID_SOCKET_VALUE)
  197. {
  198. *iError = EINVAL;
  199. return -EINVAL;
  200. }
  201. if (iTimeoutMs > 0)
  202. {
  203. iNow = GetTimeMs();
  204. iTarget = iNow + (int64_t) iTimeoutMs;
  205. }
  206. struct pollfd fds;
  207. fds.fd = socket;
  208. fds.events = POLLIN;
  209. fds.revents = 0;
  210. while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || iTarget > iNow))
  211. {
  212. if (iTimeoutMs > 0)
  213. {
  214. int iPollResult = poll(&fds, 1, (int)(iTarget - iNow));
  215. if (iPollResult == 0)
  216. {
  217. *iError = ETIMEDOUT;
  218. return -ETIMEDOUT;
  219. }
  220. }
  221. ssize_t iReadResult = (iTimeoutMs > 0) ?
  222. recv(socket, (char*)data + iBytesRead, len - iBytesRead, MSG_DONTWAIT) :
  223. recv(socket, data, len, MSG_WAITALL);
  224. if (iReadResult < 0)
  225. {
  226. if (errno == EAGAIN && iTimeoutMs > 0)
  227. continue;
  228. *iError = errno;
  229. return -errno;
  230. }
  231. else if (iReadResult == 0 || (iReadResult != (ssize_t)len && iTimeoutMs == 0))
  232. {
  233. *iError = ECONNRESET;
  234. return -ECONNRESET;
  235. }
  236. iBytesRead += iReadResult;
  237. if (iTimeoutMs > 0)
  238. iNow = GetTimeMs();
  239. }
  240. if (iBytesRead < (ssize_t)len)
  241. *iError = ETIMEDOUT;
  242. return iBytesRead;
  243. }
  244. inline bool TcpResolveAddress(const char *strHost, uint16_t iPort, int *iError, struct addrinfo **info)
  245. {
  246. struct addrinfo hints;
  247. char service[33];
  248. memset(&hints, 0, sizeof(hints));
  249. hints.ai_family = AF_UNSPEC;
  250. hints.ai_socktype = SOCK_STREAM;
  251. hints.ai_protocol = IPPROTO_TCP;
  252. sprintf(service, "%d", iPort);
  253. *iError = getaddrinfo(strHost, service, &hints, info);
  254. return !(*iError);
  255. }
  256. inline int TcpGetSocketError(tcp_socket_t socket)
  257. {
  258. int iReturn(0);
  259. socklen_t optLen = sizeof(socket_t);
  260. getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&iReturn, &optLen);
  261. return iReturn;
  262. }
  263. inline bool TcpSetNoDelay(tcp_socket_t socket)
  264. {
  265. int iSetTo(1);
  266. setsockopt(socket, SOL_TCP, TCP_NODELAY, &iSetTo, sizeof(iSetTo));
  267. return true;
  268. }
  269. inline bool TcpConnectSocket(tcp_socket_t socket, struct addrinfo* addr, int *iError, uint64_t iTimeout = 0)
  270. {
  271. *iError = 0;
  272. int iConnectResult = connect(socket, addr->ai_addr, addr->ai_addrlen);
  273. if (iConnectResult == -1)
  274. {
  275. if (errno == EINPROGRESS)
  276. {
  277. struct pollfd pfd;
  278. pfd.fd = socket;
  279. pfd.events = POLLOUT;
  280. pfd.revents = 0;
  281. int iPollResult = poll(&pfd, 1, (int)iTimeout);
  282. if (iPollResult == 0)
  283. *iError = ETIMEDOUT;
  284. else if (iPollResult == -1)
  285. *iError = errno;
  286. socklen_t errlen = sizeof(int);
  287. getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)iError, &errlen);
  288. }
  289. else
  290. {
  291. *iError = errno;
  292. }
  293. }
  294. return *iError == 0;
  295. }
  296. //@}
  297. }