PageRenderTime 47ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/jzeaherra/xbmc-pvr-addons
C Header | 318 lines | 240 code | 40 blank | 38 comment | 69 complexity | e510f439b28c2f184372d110b403c69d MD5 | raw file
Possible License(s): GPL-3.0, AGPL-1.0, GPL-2.0, LGPL-2.1
  1. #pragma once
  2. /*
  3. * This file is part of the libCEC(R) library.
  4. *
  5. * libCEC(R) is Copyright (C) 2011-2012 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 "../os.h"
  34. #include "../util/timeutils.h"
  35. #include <stdio.h>
  36. #include <fcntl.h>
  37. #include <sys/socket.h>
  38. #include <netinet/in.h>
  39. #include <netinet/tcp.h>
  40. #include <arpa/inet.h>
  41. #include <netdb.h>
  42. #include <poll.h>
  43. /* Needed on Mac OS/X */
  44. #ifndef SOL_TCP
  45. #define SOL_TCP IPPROTO_TCP
  46. #endif
  47. namespace PLATFORM
  48. {
  49. // Standard sockets
  50. //@{
  51. inline void SocketClose(socket_t socket)
  52. {
  53. if (socket != INVALID_SOCKET_VALUE)
  54. close(socket);
  55. }
  56. inline void SocketSetBlocking(socket_t socket, bool bSetTo)
  57. {
  58. if (socket != INVALID_SOCKET_VALUE)
  59. {
  60. if (bSetTo)
  61. fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK);
  62. else
  63. fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK);
  64. }
  65. }
  66. inline ssize_t SocketWrite(socket_t socket, int *iError, void* data, size_t len)
  67. {
  68. fd_set port;
  69. if (socket == INVALID_SOCKET_VALUE)
  70. {
  71. *iError = EINVAL;
  72. return -EINVAL;
  73. }
  74. ssize_t iBytesWritten(0);
  75. struct timeval *tv(NULL);
  76. while (iBytesWritten < (ssize_t)len)
  77. {
  78. FD_ZERO(&port);
  79. FD_SET(socket, &port);
  80. int returnv = select(socket + 1, NULL, &port, NULL, tv);
  81. if (returnv < 0)
  82. {
  83. *iError = errno;
  84. return -errno;
  85. }
  86. else if (returnv == 0)
  87. {
  88. *iError = ETIMEDOUT;
  89. return -ETIMEDOUT;
  90. }
  91. returnv = write(socket, (char*)data + iBytesWritten, len - iBytesWritten);
  92. if (returnv == -1)
  93. {
  94. *iError = errno;
  95. return -errno;
  96. }
  97. iBytesWritten += returnv;
  98. }
  99. return iBytesWritten;
  100. }
  101. inline ssize_t SocketRead(socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/)
  102. {
  103. fd_set port;
  104. struct timeval timeout, *tv;
  105. ssize_t iBytesRead(0);
  106. *iError = 0;
  107. CTimeout readTimeout(iTimeoutMs);
  108. if (socket == INVALID_SOCKET_VALUE)
  109. {
  110. *iError = EINVAL;
  111. return -EINVAL;
  112. }
  113. while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || readTimeout.TimeLeft() > 0))
  114. {
  115. if (iTimeoutMs == 0)
  116. {
  117. tv = NULL;
  118. }
  119. else
  120. {
  121. long iTimeLeft = (long)readTimeout.TimeLeft();
  122. timeout.tv_sec = iTimeLeft / (long int)1000.;
  123. timeout.tv_usec = iTimeLeft % (long int)1000.;
  124. tv = &timeout;
  125. }
  126. FD_ZERO(&port);
  127. FD_SET(socket, &port);
  128. int32_t returnv = select(socket + 1, &port, NULL, NULL, tv);
  129. if (returnv == -1)
  130. {
  131. *iError = errno;
  132. return -errno;
  133. }
  134. else if (returnv == 0)
  135. {
  136. break; //nothing to read
  137. }
  138. returnv = read(socket, (char*)data + iBytesRead, len - iBytesRead);
  139. if (returnv == -1)
  140. {
  141. *iError = errno;
  142. return -errno;
  143. }
  144. iBytesRead += returnv;
  145. }
  146. return iBytesRead;
  147. }
  148. //@}
  149. // TCP
  150. //@{
  151. inline void TcpSocketClose(tcp_socket_t socket)
  152. {
  153. SocketClose(socket);
  154. }
  155. inline void TcpSocketShutdown(tcp_socket_t socket)
  156. {
  157. if (socket != INVALID_SOCKET_VALUE)
  158. shutdown(socket, SHUT_RDWR);
  159. }
  160. inline ssize_t TcpSocketWrite(tcp_socket_t socket, int *iError, void* data, size_t len)
  161. {
  162. if (socket == INVALID_SOCKET_VALUE)
  163. {
  164. *iError = EINVAL;
  165. return -1;
  166. }
  167. ssize_t iReturn = send(socket, data, len, 0);
  168. if (iReturn < (ssize_t)len)
  169. *iError = errno;
  170. return iReturn;
  171. }
  172. inline ssize_t TcpSocketRead(tcp_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/)
  173. {
  174. int64_t iNow(0), iTarget(0);
  175. ssize_t iBytesRead(0);
  176. *iError = 0;
  177. if (socket == INVALID_SOCKET_VALUE)
  178. {
  179. *iError = EINVAL;
  180. return -EINVAL;
  181. }
  182. if (iTimeoutMs > 0)
  183. {
  184. iNow = GetTimeMs();
  185. iTarget = iNow + (int64_t) iTimeoutMs;
  186. }
  187. struct pollfd fds;
  188. fds.fd = socket;
  189. fds.events = POLLIN;
  190. fds.revents = 0;
  191. while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || iTarget > iNow))
  192. {
  193. if (iTimeoutMs > 0)
  194. {
  195. int iPollResult = poll(&fds, 1, iTarget - iNow);
  196. if (iPollResult == 0)
  197. {
  198. *iError = ETIMEDOUT;
  199. return -ETIMEDOUT;
  200. }
  201. }
  202. ssize_t iReadResult = (iTimeoutMs > 0) ?
  203. recv(socket, (char*)data + iBytesRead, len - iBytesRead, MSG_DONTWAIT) :
  204. recv(socket, data, len, MSG_WAITALL);
  205. if (iReadResult < 0)
  206. {
  207. if (errno == EAGAIN && iTimeoutMs > 0)
  208. continue;
  209. *iError = errno;
  210. return -errno;
  211. }
  212. else if (iReadResult == 0 || (iReadResult != (ssize_t)len && iTimeoutMs == 0))
  213. {
  214. *iError = ECONNRESET;
  215. return -ECONNRESET;
  216. }
  217. iBytesRead += iReadResult;
  218. if (iTimeoutMs > 0)
  219. iNow = GetTimeMs();
  220. }
  221. if (iBytesRead < (ssize_t)len)
  222. *iError = ETIMEDOUT;
  223. return iBytesRead;
  224. }
  225. inline bool TcpResolveAddress(const char *strHost, uint16_t iPort, int *iError, struct addrinfo **info)
  226. {
  227. struct addrinfo hints;
  228. char service[33];
  229. memset(&hints, 0, sizeof(hints));
  230. hints.ai_family = AF_UNSPEC;
  231. hints.ai_socktype = SOCK_STREAM;
  232. hints.ai_protocol = IPPROTO_TCP;
  233. sprintf(service, "%d", iPort);
  234. *iError = getaddrinfo(strHost, service, &hints, info);
  235. return !(*iError);
  236. }
  237. inline int TcpGetSocketError(tcp_socket_t socket)
  238. {
  239. int iReturn(0);
  240. socklen_t optLen = sizeof(socket_t);
  241. getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&iReturn, &optLen);
  242. return iReturn;
  243. }
  244. inline bool TcpSetNoDelay(tcp_socket_t socket)
  245. {
  246. int iSetTo(1);
  247. setsockopt(socket, SOL_TCP, TCP_NODELAY, &iSetTo, sizeof(iSetTo));
  248. return true;
  249. }
  250. inline bool TcpConnectSocket(tcp_socket_t socket, struct addrinfo* addr, int *iError, uint64_t iTimeout = 0)
  251. {
  252. *iError = 0;
  253. int iConnectResult = connect(socket, addr->ai_addr, addr->ai_addrlen);
  254. if (iConnectResult == -1)
  255. {
  256. if (errno == EINPROGRESS)
  257. {
  258. struct pollfd pfd;
  259. pfd.fd = socket;
  260. pfd.events = POLLOUT;
  261. pfd.revents = 0;
  262. int iPollResult = poll(&pfd, 1, iTimeout);
  263. if (iPollResult == 0)
  264. *iError = ETIMEDOUT;
  265. else if (iPollResult == -1)
  266. *iError = errno;
  267. socklen_t errlen = sizeof(int);
  268. getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)iError, &errlen);
  269. }
  270. else
  271. {
  272. *iError = errno;
  273. }
  274. }
  275. return *iError == 0;
  276. }
  277. //@}
  278. }