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

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

https://github.com/spike008t/libcec
C Header | 301 lines | 226 code | 39 blank | 36 comment | 60 complexity | f3b816fa454d43d58d7d130fdce6ff59 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 <ws2spi.h>
  36. #include <ws2ipdef.h>
  37. #include <ws2tcpip.h>
  38. #define SHUT_RDWR SD_BOTH
  39. #ifndef ETIMEDOUT
  40. #define ETIMEDOUT 138
  41. #endif
  42. namespace PLATFORM
  43. {
  44. #ifndef MSG_WAITALL
  45. #define MSG_WAITALL 0x8
  46. #endif
  47. inline int GetSocketError(void)
  48. {
  49. int error = WSAGetLastError();
  50. switch(error)
  51. {
  52. case WSAEINPROGRESS: return EINPROGRESS;
  53. case WSAECONNRESET : return ECONNRESET;
  54. case WSAETIMEDOUT : return ETIMEDOUT;
  55. case WSAEWOULDBLOCK: return EAGAIN;
  56. default : return error;
  57. }
  58. }
  59. // Serial port
  60. //@{
  61. inline void SerialSocketClose(serial_socket_t socket)
  62. {
  63. if (socket != INVALID_HANDLE_VALUE)
  64. CloseHandle(socket);
  65. }
  66. inline ssize_t SerialSocketWrite(serial_socket_t socket, int *iError, void* data, size_t len)
  67. {
  68. if (len != (DWORD)len)
  69. {
  70. *iError = EINVAL;
  71. return -1;
  72. }
  73. DWORD iBytesWritten(0);
  74. if (socket != INVALID_HANDLE_VALUE)
  75. {
  76. if (!WriteFile(socket, data, (DWORD)len, &iBytesWritten, NULL))
  77. {
  78. *iError = GetLastError();
  79. return -1;
  80. }
  81. return (ssize_t)iBytesWritten;
  82. }
  83. return -1;
  84. }
  85. inline ssize_t SerialSocketRead(serial_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/)
  86. {
  87. if (len != (DWORD)len)
  88. {
  89. *iError = EINVAL;
  90. return -1;
  91. }
  92. DWORD iBytesRead(0);
  93. if (socket != INVALID_HANDLE_VALUE)
  94. {
  95. if(!ReadFile(socket, data, (DWORD)len, &iBytesRead, NULL) != 0)
  96. {
  97. *iError = GetLastError();
  98. return -1;
  99. }
  100. return (ssize_t)iBytesRead;
  101. }
  102. return -1;
  103. }
  104. //@}
  105. // TCP
  106. //@{
  107. inline void TcpSocketSetBlocking(tcp_socket_t socket, bool bSetTo)
  108. {
  109. u_long iSetTo = bSetTo ? 0 : 1;
  110. ioctlsocket(socket, FIONBIO, &iSetTo);
  111. }
  112. inline void TcpSocketClose(tcp_socket_t socket)
  113. {
  114. closesocket(socket);
  115. }
  116. inline void TcpSocketShutdown(tcp_socket_t socket)
  117. {
  118. if (socket != INVALID_SOCKET &&
  119. socket != SOCKET_ERROR)
  120. shutdown(socket, SHUT_RDWR);
  121. }
  122. inline ssize_t TcpSocketWrite(tcp_socket_t socket, int *iError, void* data, size_t len)
  123. {
  124. if (socket == INVALID_SOCKET ||
  125. socket == SOCKET_ERROR ||
  126. len != (int)len)
  127. {
  128. *iError = EINVAL;
  129. return -1;
  130. }
  131. ssize_t iReturn = send(socket, (char*)data, (int)len, 0);
  132. if (iReturn < (ssize_t)len)
  133. *iError = GetSocketError();
  134. return iReturn;
  135. }
  136. inline ssize_t TcpSocketRead(tcp_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/)
  137. {
  138. int64_t iNow(0), iTarget(0);
  139. ssize_t iBytesRead(0);
  140. *iError = 0;
  141. if (socket == INVALID_SOCKET ||
  142. socket == SOCKET_ERROR ||
  143. len != (int)len)
  144. {
  145. *iError = EINVAL;
  146. return -1;
  147. }
  148. if (iTimeoutMs > 0)
  149. {
  150. iNow = GetTimeMs();
  151. iTarget = iNow + (int64_t) iTimeoutMs;
  152. }
  153. fd_set fd_read;
  154. struct timeval tv;
  155. while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || iTarget > iNow))
  156. {
  157. if (iTimeoutMs > 0)
  158. {
  159. tv.tv_sec = (long)(iTimeoutMs / 1000);
  160. tv.tv_usec = 1000 * (long)(iTimeoutMs % 1000);
  161. FD_ZERO(&fd_read);
  162. #pragma warning(disable:4127) /* disable 'conditional expression is constant' */
  163. FD_SET(socket, &fd_read);
  164. #pragma warning(default:4127)
  165. if (select((int)socket + 1, &fd_read, NULL, NULL, &tv) == 0)
  166. {
  167. *iError = ETIMEDOUT;
  168. return ETIMEDOUT;
  169. }
  170. TcpSocketSetBlocking(socket, false);
  171. }
  172. ssize_t iReadResult = (iTimeoutMs > 0) ?
  173. recv(socket, (char*)data + iBytesRead, (int)(len - iBytesRead), 0) :
  174. recv(socket, (char*)data, (int)len, MSG_WAITALL);
  175. *iError = GetSocketError();
  176. if (iTimeoutMs > 0)
  177. {
  178. TcpSocketSetBlocking(socket, true);
  179. iNow = GetTimeMs();
  180. }
  181. if (iReadResult < 0)
  182. {
  183. if (*iError == EAGAIN && iTimeoutMs > 0)
  184. continue;
  185. return -1;
  186. }
  187. else if (iReadResult == 0 || (iReadResult != (ssize_t)len && iTimeoutMs == 0))
  188. {
  189. *iError = ECONNRESET;
  190. return -1;
  191. }
  192. iBytesRead += iReadResult;
  193. }
  194. if (iBytesRead < (ssize_t)len && *iError == 0)
  195. *iError = ETIMEDOUT;
  196. return iBytesRead;
  197. }
  198. inline bool TcpResolveAddress(const char *strHost, uint16_t iPort, int *iError, struct addrinfo **info)
  199. {
  200. struct addrinfo hints;
  201. char service[33];
  202. memset(&hints, 0, sizeof(hints));
  203. hints.ai_family = AF_UNSPEC;
  204. hints.ai_socktype = SOCK_STREAM;
  205. hints.ai_protocol = IPPROTO_TCP;
  206. sprintf(service, "%d", iPort);
  207. *iError = getaddrinfo(strHost, service, &hints, info);
  208. return !(*iError);
  209. }
  210. inline int TcpGetSocketError(tcp_socket_t socket)
  211. {
  212. int iReturn(0);
  213. socklen_t optLen = sizeof(tcp_socket_t);
  214. getsockopt(socket, SOL_SOCKET, SO_ERROR, (char *)&iReturn, &optLen);
  215. return iReturn;
  216. }
  217. inline bool TcpSetNoDelay(tcp_socket_t socket)
  218. {
  219. int iSetTo(1);
  220. setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&iSetTo, sizeof(iSetTo));
  221. return true;
  222. }
  223. inline bool TcpConnectSocket(tcp_socket_t socket, struct addrinfo* addr, int *iError, uint64_t iTimeout = 0)
  224. {
  225. TcpSocketSetBlocking(socket, false);
  226. *iError = 0;
  227. int iConnectResult = connect(socket, addr->ai_addr, (int)addr->ai_addrlen);
  228. if (iConnectResult == -1)
  229. {
  230. if (GetSocketError() == EINPROGRESS ||
  231. GetSocketError() == EAGAIN)
  232. {
  233. fd_set fd_write, fd_except;
  234. struct timeval tv;
  235. tv.tv_sec = (long)(iTimeout / 1000);
  236. tv.tv_usec = 1000 * (long)(iTimeout % 1000);
  237. FD_ZERO(&fd_write);
  238. FD_ZERO(&fd_except);
  239. #pragma warning(disable:4127) /* disable 'conditional expression is constant' */
  240. FD_SET(socket, &fd_write);
  241. FD_SET(socket, &fd_except);
  242. #pragma warning(default:4127)
  243. int iPollResult = select(sizeof(socket)*8, NULL, &fd_write, &fd_except, &tv);
  244. if (iPollResult == 0)
  245. *iError = ETIMEDOUT;
  246. else if (iPollResult == -1)
  247. *iError = GetSocketError();
  248. else
  249. {
  250. socklen_t errlen = sizeof(int);
  251. getsockopt(socket, SOL_SOCKET, SO_ERROR, (char *)iError, &errlen);
  252. }
  253. }
  254. else
  255. {
  256. *iError = GetSocketError();
  257. }
  258. }
  259. TcpSocketSetBlocking(socket, true);
  260. return *iError == 0;
  261. }
  262. }