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