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