rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 Filename : OVR_Unix_Socket.cpp
|
nuclear@0
|
4 Content : Berkley sockets networking implementation
|
nuclear@0
|
5 Created : July 1, 2014
|
nuclear@0
|
6 Authors : Kevin Jenkins
|
nuclear@0
|
7
|
nuclear@0
|
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
12 which is provided at the time of installation or download, or which
|
nuclear@0
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
14
|
nuclear@0
|
15 You may obtain a copy of the License at
|
nuclear@0
|
16
|
nuclear@0
|
17 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
18
|
nuclear@0
|
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
20 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
22 See the License for the specific language governing permissions and
|
nuclear@0
|
23 limitations under the License.
|
nuclear@0
|
24
|
nuclear@0
|
25 ************************************************************************************/
|
nuclear@0
|
26
|
nuclear@0
|
27 #include "OVR_Unix_Socket.h"
|
nuclear@0
|
28 #include "../Kernel/OVR_Std.h"
|
nuclear@0
|
29 #include "../Kernel/OVR_Allocator.h"
|
nuclear@0
|
30 #include "../Kernel/OVR_Threads.h" // Thread::MSleep
|
nuclear@0
|
31 #include "../Kernel/OVR_Log.h"
|
nuclear@0
|
32
|
nuclear@0
|
33 #include <errno.h>
|
nuclear@0
|
34
|
nuclear@0
|
35 namespace OVR { namespace Net {
|
nuclear@0
|
36
|
nuclear@0
|
37 //-----------------------------------------------------------------------------
|
nuclear@0
|
38 // BerkleySocket
|
nuclear@0
|
39
|
nuclear@0
|
40 void BerkleySocket::Close()
|
nuclear@0
|
41 {
|
nuclear@0
|
42 if (TheSocket != INVALID_SOCKET)
|
nuclear@0
|
43 {
|
nuclear@0
|
44 close(TheSocket);
|
nuclear@0
|
45 TheSocket = INVALID_SOCKET;
|
nuclear@0
|
46 }
|
nuclear@0
|
47 }
|
nuclear@0
|
48
|
nuclear@0
|
49 SInt32 BerkleySocket::GetSockname(SockAddr *pSockAddrOut)
|
nuclear@0
|
50 {
|
nuclear@0
|
51 struct sockaddr_in6 sa;
|
nuclear@0
|
52 memset(&sa,0,sizeof(sa));
|
nuclear@0
|
53 socklen_t size = sizeof(sa);
|
nuclear@0
|
54 SInt32 i = getsockname(TheSocket, (sockaddr*)&sa, &size);
|
nuclear@0
|
55 if (i>=0)
|
nuclear@0
|
56 {
|
nuclear@0
|
57 pSockAddrOut->Set(&sa);
|
nuclear@0
|
58 }
|
nuclear@0
|
59 return i;
|
nuclear@0
|
60 }
|
nuclear@0
|
61
|
nuclear@0
|
62
|
nuclear@0
|
63 //-----------------------------------------------------------------------------
|
nuclear@0
|
64 // BitStream overloads for SockAddr
|
nuclear@0
|
65
|
nuclear@0
|
66 BitStream& operator<<(BitStream& out, SockAddr& in)
|
nuclear@0
|
67 {
|
nuclear@0
|
68 out.WriteBits((const unsigned char*) &in.Addr6, sizeof(in.Addr6)*8, true);
|
nuclear@0
|
69 return out;
|
nuclear@0
|
70 }
|
nuclear@0
|
71
|
nuclear@0
|
72 BitStream& operator>>(BitStream& in, SockAddr& out)
|
nuclear@0
|
73 {
|
nuclear@0
|
74 bool success = in.ReadBits((unsigned char*) &out.Addr6, sizeof(out.Addr6)*8, true);
|
nuclear@0
|
75 OVR_ASSERT(success);
|
nuclear@0
|
76 OVR_UNUSED(success);
|
nuclear@0
|
77 return in;
|
nuclear@0
|
78 }
|
nuclear@0
|
79
|
nuclear@0
|
80
|
nuclear@0
|
81 //-----------------------------------------------------------------------------
|
nuclear@0
|
82 // SockAddr
|
nuclear@0
|
83
|
nuclear@0
|
84 SockAddr::SockAddr()
|
nuclear@0
|
85 {
|
nuclear@0
|
86 }
|
nuclear@0
|
87
|
nuclear@0
|
88 SockAddr::SockAddr(SockAddr* address)
|
nuclear@0
|
89 {
|
nuclear@0
|
90 Set(&address->Addr6);
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 SockAddr::SockAddr(sockaddr_storage* storage)
|
nuclear@0
|
94 {
|
nuclear@0
|
95 Set(storage);
|
nuclear@0
|
96 }
|
nuclear@0
|
97
|
nuclear@0
|
98 SockAddr::SockAddr(sockaddr_in6* address)
|
nuclear@0
|
99 {
|
nuclear@0
|
100 Set(address);
|
nuclear@0
|
101 }
|
nuclear@0
|
102
|
nuclear@0
|
103 SockAddr::SockAddr(const char* hostAddress, UInt16 port, int sockType)
|
nuclear@0
|
104 {
|
nuclear@0
|
105 Set(hostAddress, port, sockType);
|
nuclear@0
|
106 }
|
nuclear@0
|
107
|
nuclear@0
|
108 void SockAddr::Set(const sockaddr_storage* storage)
|
nuclear@0
|
109 {
|
nuclear@0
|
110 memcpy(&Addr6, storage, sizeof(Addr6));
|
nuclear@0
|
111 }
|
nuclear@0
|
112
|
nuclear@0
|
113 void SockAddr::Set(const sockaddr_in6* address)
|
nuclear@0
|
114 {
|
nuclear@0
|
115 memcpy(&Addr6, address, sizeof(Addr6));
|
nuclear@0
|
116 }
|
nuclear@0
|
117
|
nuclear@0
|
118 void SockAddr::Set(const char* hostAddress, UInt16 port, int sockType)
|
nuclear@0
|
119 {
|
nuclear@0
|
120 memset(&Addr6, 0, sizeof(Addr6));
|
nuclear@0
|
121
|
nuclear@0
|
122 struct addrinfo hints;
|
nuclear@0
|
123
|
nuclear@0
|
124 // make sure the struct is empty
|
nuclear@0
|
125 memset(&hints, 0, sizeof (addrinfo));
|
nuclear@0
|
126
|
nuclear@0
|
127 hints.ai_socktype = sockType; // SOCK_DGRAM or SOCK_STREAM
|
nuclear@0
|
128 hints.ai_flags = AI_PASSIVE; // fill in my IP for me
|
nuclear@0
|
129 hints.ai_family = AF_UNSPEC ;
|
nuclear@0
|
130
|
nuclear@0
|
131 if (SOCK_DGRAM == sockType)
|
nuclear@0
|
132 {
|
nuclear@0
|
133 hints.ai_protocol = IPPROTO_UDP;
|
nuclear@0
|
134 }
|
nuclear@0
|
135 else if (SOCK_STREAM == sockType)
|
nuclear@0
|
136 {
|
nuclear@0
|
137 hints.ai_protocol = IPPROTO_TCP;
|
nuclear@0
|
138 }
|
nuclear@0
|
139
|
nuclear@0
|
140 struct addrinfo* servinfo = NULL; // will point to the results
|
nuclear@0
|
141
|
nuclear@0
|
142 char portStr[32];
|
nuclear@0
|
143 OVR_itoa(port, portStr, sizeof(portStr), 10);
|
nuclear@0
|
144 int errcode = getaddrinfo(hostAddress, portStr, &hints, &servinfo);
|
nuclear@0
|
145
|
nuclear@0
|
146 if (0 != errcode)
|
nuclear@0
|
147 {
|
nuclear@0
|
148 OVR::LogError("getaddrinfo error: %s", gai_strerror(errcode));
|
nuclear@0
|
149 }
|
nuclear@0
|
150
|
nuclear@0
|
151 OVR_ASSERT(servinfo);
|
nuclear@0
|
152
|
nuclear@0
|
153 if (servinfo)
|
nuclear@0
|
154 {
|
nuclear@0
|
155 memcpy(&Addr6, servinfo->ai_addr, sizeof(Addr6));
|
nuclear@0
|
156
|
nuclear@0
|
157 freeaddrinfo(servinfo);
|
nuclear@0
|
158 }
|
nuclear@0
|
159 }
|
nuclear@0
|
160
|
nuclear@0
|
161 UInt16 SockAddr::GetPort()
|
nuclear@0
|
162 {
|
nuclear@0
|
163 return htons(Addr6.sin6_port);
|
nuclear@0
|
164 }
|
nuclear@0
|
165
|
nuclear@0
|
166 String SockAddr::ToString(bool writePort, char portDelineator) const
|
nuclear@0
|
167 {
|
nuclear@0
|
168 char dest[INET6_ADDRSTRLEN + 1];
|
nuclear@0
|
169
|
nuclear@0
|
170 int ret = getnameinfo((struct sockaddr*)&Addr6,
|
nuclear@0
|
171 sizeof(struct sockaddr_in6),
|
nuclear@0
|
172 dest,
|
nuclear@0
|
173 INET6_ADDRSTRLEN,
|
nuclear@0
|
174 NULL,
|
nuclear@0
|
175 0,
|
nuclear@0
|
176 NI_NUMERICHOST);
|
nuclear@0
|
177 if (ret != 0)
|
nuclear@0
|
178 {
|
nuclear@0
|
179 dest[0] = '\0';
|
nuclear@0
|
180 }
|
nuclear@0
|
181
|
nuclear@0
|
182 if (writePort)
|
nuclear@0
|
183 {
|
nuclear@0
|
184 unsigned char ch[2];
|
nuclear@0
|
185 ch[0]=portDelineator;
|
nuclear@0
|
186 ch[1]=0;
|
nuclear@0
|
187 OVR_strcat(dest, 16, (const char*) ch);
|
nuclear@0
|
188 OVR_itoa(ntohs(Addr6.sin6_port), dest+strlen(dest), 16, 10);
|
nuclear@0
|
189 }
|
nuclear@0
|
190
|
nuclear@0
|
191 return String(dest);
|
nuclear@0
|
192 }
|
nuclear@0
|
193 bool SockAddr::IsLocalhost() const
|
nuclear@0
|
194 {
|
nuclear@0
|
195 static const unsigned char localhost_bytes[] =
|
nuclear@0
|
196 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
nuclear@0
|
197
|
nuclear@0
|
198 return memcmp(Addr6.sin6_addr.s6_addr, localhost_bytes, 16) == 0;
|
nuclear@0
|
199 }
|
nuclear@0
|
200 bool SockAddr::operator==( const SockAddr& right ) const
|
nuclear@0
|
201 {
|
nuclear@0
|
202 return memcmp(&Addr6, &right.Addr6, sizeof(Addr6)) == 0;
|
nuclear@0
|
203 }
|
nuclear@0
|
204
|
nuclear@0
|
205 bool SockAddr::operator!=( const SockAddr& right ) const
|
nuclear@0
|
206 {
|
nuclear@0
|
207 return !(*this == right);
|
nuclear@0
|
208 }
|
nuclear@0
|
209
|
nuclear@0
|
210 bool SockAddr::operator>( const SockAddr& right ) const
|
nuclear@0
|
211 {
|
nuclear@0
|
212 return memcmp(&Addr6, &right.Addr6, sizeof(Addr6)) > 0;
|
nuclear@0
|
213 }
|
nuclear@0
|
214
|
nuclear@0
|
215 bool SockAddr::operator<( const SockAddr& right ) const
|
nuclear@0
|
216 {
|
nuclear@0
|
217 return memcmp(&Addr6, &right.Addr6, sizeof(Addr6)) < 0;
|
nuclear@0
|
218 }
|
nuclear@0
|
219
|
nuclear@0
|
220
|
nuclear@0
|
221 // Returns true on success
|
nuclear@0
|
222 static bool SetSocketOptions(SocketHandle sock)
|
nuclear@0
|
223 {
|
nuclear@0
|
224 bool failed = false;
|
nuclear@0
|
225 int sock_opt;
|
nuclear@0
|
226 int sockError = 0;
|
nuclear@0
|
227
|
nuclear@0
|
228 // This doubles the max throughput rate
|
nuclear@0
|
229 sock_opt=1024*256;
|
nuclear@0
|
230 sockError = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, ( char * ) & sock_opt, sizeof ( sock_opt ) );
|
nuclear@0
|
231 if (sockError != 0)
|
nuclear@0
|
232 {
|
nuclear@0
|
233 int errsv = errno;
|
nuclear@0
|
234 OVR::LogError("[Socket] Failed SO_RCVBUF setsockopt, errno: %d", errsv);
|
nuclear@0
|
235 failed = true;
|
nuclear@0
|
236 }
|
nuclear@0
|
237
|
nuclear@0
|
238 // This doesn't make much difference: 10% maybe
|
nuclear@0
|
239 // Not supported on console 2
|
nuclear@0
|
240 sock_opt=1024*16;
|
nuclear@0
|
241 sockError = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, ( char * ) & sock_opt, sizeof ( sock_opt ) );
|
nuclear@0
|
242 if (sockError != 0)
|
nuclear@0
|
243 {
|
nuclear@0
|
244 int errsv = errno;
|
nuclear@0
|
245 OVR::LogError("[Socket] Failed SO_SNDBUF setsockopt, errno: %d", errsv);
|
nuclear@0
|
246 failed = true;
|
nuclear@0
|
247 }
|
nuclear@0
|
248
|
nuclear@0
|
249 // NOTE: This should be OVR_OS_BSD, not Mac.
|
nuclear@0
|
250 #ifdef OVR_OS_MAC
|
nuclear@0
|
251 int value = 1;
|
nuclear@0
|
252 sockError = setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));
|
nuclear@0
|
253 if (sockError != 0)
|
nuclear@0
|
254 {
|
nuclear@0
|
255 int errsv = errno;
|
nuclear@0
|
256 OVR::LogError("[Socket] Failed SO_NOSIGPIPE setsockopt, errno: %d", errsv);
|
nuclear@0
|
257 failed = true;
|
nuclear@0
|
258 }
|
nuclear@0
|
259 #endif
|
nuclear@0
|
260
|
nuclear@0
|
261 // Reuse address is only needed for posix platforms, as it is the default
|
nuclear@0
|
262 // on Windows platforms.
|
nuclear@0
|
263 int optval = 1;
|
nuclear@0
|
264 sockError = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
|
nuclear@0
|
265 if (sockError != 0)
|
nuclear@0
|
266 {
|
nuclear@0
|
267 int errsv = errno;
|
nuclear@0
|
268 OVR::LogError("[Socket] Failed SO_REUSEADDR setsockopt, errno: %d", errsv);
|
nuclear@0
|
269 failed = true;
|
nuclear@0
|
270 }
|
nuclear@0
|
271
|
nuclear@0
|
272 return !failed;
|
nuclear@0
|
273 }
|
nuclear@0
|
274
|
nuclear@0
|
275 void _Ioctlsocket(SocketHandle sock, unsigned long nonblocking)
|
nuclear@0
|
276 {
|
nuclear@0
|
277 int flags = fcntl(sock, F_GETFL, 0);
|
nuclear@0
|
278 if (flags < 0) return; // return false
|
nuclear@0
|
279 if (nonblocking == 0) { flags &= ~O_NONBLOCK; }
|
nuclear@0
|
280 else { flags |= O_NONBLOCK; }
|
nuclear@0
|
281 fcntl(sock, F_SETFL, flags);
|
nuclear@0
|
282 }
|
nuclear@0
|
283
|
nuclear@0
|
284 static SocketHandle BindShared(int ai_family, int ai_socktype, BerkleyBindParameters *pBindParameters)
|
nuclear@0
|
285 {
|
nuclear@0
|
286 SocketHandle sock;
|
nuclear@0
|
287
|
nuclear@0
|
288 struct addrinfo hints;
|
nuclear@0
|
289 memset(&hints, 0, sizeof (addrinfo)); // make sure the struct is empty
|
nuclear@0
|
290 hints.ai_family = ai_family;
|
nuclear@0
|
291 hints.ai_socktype = ai_socktype;
|
nuclear@0
|
292 hints.ai_flags = AI_PASSIVE; // fill in my IP for me
|
nuclear@0
|
293 struct addrinfo *servinfo=0, *aip; // will point to the results
|
nuclear@0
|
294 char portStr[32];
|
nuclear@0
|
295 OVR_itoa(pBindParameters->Port, portStr, sizeof(portStr), 10);
|
nuclear@0
|
296
|
nuclear@0
|
297 int errcode = 0;
|
nuclear@0
|
298 if (!pBindParameters->Address.IsEmpty())
|
nuclear@0
|
299 errcode = getaddrinfo(pBindParameters->Address.ToCStr(), portStr, &hints, &servinfo);
|
nuclear@0
|
300 else
|
nuclear@0
|
301 errcode = getaddrinfo(0, portStr, &hints, &servinfo);
|
nuclear@0
|
302
|
nuclear@0
|
303 if (0 != errcode)
|
nuclear@0
|
304 {
|
nuclear@0
|
305 OVR::LogError("getaddrinfo error: %s", gai_strerror(errcode));
|
nuclear@0
|
306 }
|
nuclear@0
|
307
|
nuclear@0
|
308 for (aip = servinfo; aip != NULL; aip = aip->ai_next)
|
nuclear@0
|
309 {
|
nuclear@0
|
310 // Open socket. The address type depends on what
|
nuclear@0
|
311 // getaddrinfo() gave us.
|
nuclear@0
|
312 sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
|
nuclear@0
|
313 if (sock != 0)
|
nuclear@0
|
314 {
|
nuclear@0
|
315 SetSocketOptions(sock);
|
nuclear@0
|
316 int ret = bind( sock, aip->ai_addr, (int) aip->ai_addrlen );
|
nuclear@0
|
317 if (ret>=0)
|
nuclear@0
|
318 {
|
nuclear@0
|
319 // The actual socket is always non-blocking
|
nuclear@0
|
320 // I control blocking or not using WSAEventSelect
|
nuclear@0
|
321 _Ioctlsocket(sock, 1);
|
nuclear@0
|
322 freeaddrinfo(servinfo);
|
nuclear@0
|
323 return sock;
|
nuclear@0
|
324 }
|
nuclear@0
|
325 else
|
nuclear@0
|
326 {
|
nuclear@0
|
327 close(sock);
|
nuclear@0
|
328 }
|
nuclear@0
|
329 }
|
nuclear@0
|
330 }
|
nuclear@0
|
331
|
nuclear@0
|
332 if (servinfo) { freeaddrinfo(servinfo); }
|
nuclear@0
|
333 return INVALID_SOCKET;
|
nuclear@0
|
334 }
|
nuclear@0
|
335
|
nuclear@0
|
336
|
nuclear@0
|
337 //-----------------------------------------------------------------------------
|
nuclear@0
|
338 // UDPSocket
|
nuclear@0
|
339
|
nuclear@0
|
340 UDPSocket::UDPSocket()
|
nuclear@0
|
341 {
|
nuclear@0
|
342 RecvBuf = new UByte[RecvBufSize];
|
nuclear@0
|
343 }
|
nuclear@0
|
344
|
nuclear@0
|
345 UDPSocket::~UDPSocket()
|
nuclear@0
|
346 {
|
nuclear@0
|
347 delete[] RecvBuf;
|
nuclear@0
|
348 }
|
nuclear@0
|
349
|
nuclear@0
|
350 SocketHandle UDPSocket::Bind(BerkleyBindParameters *pBindParameters)
|
nuclear@0
|
351 {
|
nuclear@0
|
352 SocketHandle s = BindShared(AF_INET6, SOCK_DGRAM, pBindParameters);
|
nuclear@0
|
353 if (s < 0)
|
nuclear@0
|
354 return s;
|
nuclear@0
|
355
|
nuclear@0
|
356 Close();
|
nuclear@0
|
357 TheSocket = s;
|
nuclear@0
|
358
|
nuclear@0
|
359 return TheSocket;
|
nuclear@0
|
360 }
|
nuclear@0
|
361
|
nuclear@0
|
362 void UDPSocket::OnRecv(SocketEvent_UDP* eventHandler, UByte* pData, int bytesRead, SockAddr* address)
|
nuclear@0
|
363 {
|
nuclear@0
|
364 eventHandler->UDP_OnRecv(this, pData, bytesRead, address);
|
nuclear@0
|
365 }
|
nuclear@0
|
366
|
nuclear@0
|
367 int UDPSocket::Send(const void* pData, int bytes, SockAddr* address)
|
nuclear@0
|
368 {
|
nuclear@0
|
369 // NOTE: This should be OVR_OS_BSD
|
nuclear@0
|
370 #ifdef OVR_OS_MAC
|
nuclear@0
|
371 int flags = 0;
|
nuclear@0
|
372 #else
|
nuclear@0
|
373 int flags = MSG_NOSIGNAL;
|
nuclear@0
|
374 #endif
|
nuclear@0
|
375
|
nuclear@0
|
376 return (int)sendto(TheSocket, (const char*)pData, bytes, flags, (const sockaddr*)&address->Addr6, sizeof(address->Addr6));
|
nuclear@0
|
377 }
|
nuclear@0
|
378
|
nuclear@0
|
379 void UDPSocket::Poll(SocketEvent_UDP *eventHandler)
|
nuclear@0
|
380 {
|
nuclear@0
|
381 struct sockaddr_storage win32_addr;
|
nuclear@0
|
382 socklen_t fromlen;
|
nuclear@0
|
383 int bytesRead;
|
nuclear@0
|
384
|
nuclear@0
|
385 // FIXME: Implement blocking poll wait for UDP
|
nuclear@0
|
386
|
nuclear@0
|
387 // While some bytes are read,
|
nuclear@0
|
388 while (fromlen = sizeof(win32_addr), // Must set fromlen each time
|
nuclear@0
|
389 bytesRead = (int)recvfrom(TheSocket, (char*)RecvBuf, RecvBufSize, 0, (sockaddr*)&win32_addr, &fromlen),
|
nuclear@0
|
390 bytesRead > 0)
|
nuclear@0
|
391 {
|
nuclear@0
|
392 SockAddr address(&win32_addr); // Wrap address
|
nuclear@0
|
393
|
nuclear@0
|
394 OnRecv(eventHandler, RecvBuf, bytesRead, &address);
|
nuclear@0
|
395 }
|
nuclear@0
|
396 }
|
nuclear@0
|
397
|
nuclear@0
|
398
|
nuclear@0
|
399 //-----------------------------------------------------------------------------
|
nuclear@0
|
400 // TCPSocket
|
nuclear@0
|
401
|
nuclear@0
|
402 TCPSocket::TCPSocket()
|
nuclear@0
|
403 {
|
nuclear@0
|
404 IsConnecting = false;
|
nuclear@0
|
405 IsListenSocket = false;
|
nuclear@0
|
406 }
|
nuclear@0
|
407 TCPSocket::TCPSocket(SocketHandle boundHandle, bool isListenSocket)
|
nuclear@0
|
408 {
|
nuclear@0
|
409 TheSocket = boundHandle;
|
nuclear@0
|
410 IsListenSocket = isListenSocket;
|
nuclear@0
|
411 IsConnecting = false;
|
nuclear@0
|
412 SetSocketOptions(TheSocket);
|
nuclear@0
|
413
|
nuclear@0
|
414 // The actual socket is always non-blocking
|
nuclear@0
|
415 _Ioctlsocket(TheSocket, 1);
|
nuclear@0
|
416 }
|
nuclear@0
|
417
|
nuclear@0
|
418 TCPSocket::~TCPSocket()
|
nuclear@0
|
419 {
|
nuclear@0
|
420 }
|
nuclear@0
|
421
|
nuclear@0
|
422 void TCPSocket::OnRecv(SocketEvent_TCP* eventHandler, UByte* pData, int bytesRead)
|
nuclear@0
|
423 {
|
nuclear@0
|
424 eventHandler->TCP_OnRecv(this, pData, bytesRead);
|
nuclear@0
|
425 }
|
nuclear@0
|
426
|
nuclear@0
|
427 SocketHandle TCPSocket::Bind(BerkleyBindParameters* pBindParameters)
|
nuclear@0
|
428 {
|
nuclear@0
|
429 SocketHandle s = BindShared(AF_INET6, SOCK_STREAM, pBindParameters);
|
nuclear@0
|
430 if (s < 0)
|
nuclear@0
|
431 return s;
|
nuclear@0
|
432
|
nuclear@0
|
433 Close();
|
nuclear@0
|
434
|
nuclear@0
|
435 SetBlockingTimeout(pBindParameters->blockingTimeout);
|
nuclear@0
|
436 TheSocket = s;
|
nuclear@0
|
437
|
nuclear@0
|
438 return TheSocket;
|
nuclear@0
|
439 }
|
nuclear@0
|
440
|
nuclear@0
|
441 int TCPSocket::Listen()
|
nuclear@0
|
442 {
|
nuclear@0
|
443 if (IsListenSocket)
|
nuclear@0
|
444 {
|
nuclear@0
|
445 return 0;
|
nuclear@0
|
446 }
|
nuclear@0
|
447
|
nuclear@0
|
448 int i = listen(TheSocket, SOMAXCONN);
|
nuclear@0
|
449 if (i >= 0)
|
nuclear@0
|
450 {
|
nuclear@0
|
451 IsListenSocket = true;
|
nuclear@0
|
452 }
|
nuclear@0
|
453
|
nuclear@0
|
454 return i;
|
nuclear@0
|
455 }
|
nuclear@0
|
456
|
nuclear@0
|
457 int TCPSocket::Connect(SockAddr* address)
|
nuclear@0
|
458 {
|
nuclear@0
|
459 int retval;
|
nuclear@0
|
460
|
nuclear@0
|
461 retval = connect(TheSocket, (struct sockaddr *) &address->Addr6, sizeof(address->Addr6));
|
nuclear@0
|
462 if (retval < 0)
|
nuclear@0
|
463 {
|
nuclear@0
|
464 int errsv = errno;
|
nuclear@0
|
465 // EINPROGRESS should not be checked on windows but should
|
nuclear@0
|
466 // be checked on POSIX platforms.
|
nuclear@0
|
467 if (errsv == EWOULDBLOCK || errsv == EINPROGRESS)
|
nuclear@0
|
468 {
|
nuclear@0
|
469 IsConnecting = true;
|
nuclear@0
|
470 return 0;
|
nuclear@0
|
471 }
|
nuclear@0
|
472
|
nuclear@0
|
473 OVR::LogText( "TCPSocket::Connect failed:Error code - %d\n", errsv );
|
nuclear@0
|
474 }
|
nuclear@0
|
475
|
nuclear@0
|
476 return retval;
|
nuclear@0
|
477 }
|
nuclear@0
|
478
|
nuclear@0
|
479 int TCPSocket::Send(const void* pData, int bytes)
|
nuclear@0
|
480 {
|
nuclear@0
|
481 if (bytes <= 0)
|
nuclear@0
|
482 {
|
nuclear@0
|
483 return 0;
|
nuclear@0
|
484 }
|
nuclear@0
|
485 else
|
nuclear@0
|
486 {
|
nuclear@0
|
487 return (int)send(TheSocket, (const char*)pData, bytes, 0);
|
nuclear@0
|
488 }
|
nuclear@0
|
489 }
|
nuclear@0
|
490
|
nuclear@0
|
491
|
nuclear@0
|
492 //// TCPSocketPollState
|
nuclear@0
|
493
|
nuclear@0
|
494 TCPSocketPollState::TCPSocketPollState()
|
nuclear@0
|
495 {
|
nuclear@0
|
496 FD_ZERO(&readFD);
|
nuclear@0
|
497 FD_ZERO(&exceptionFD);
|
nuclear@0
|
498 FD_ZERO(&writeFD);
|
nuclear@0
|
499 largestDescriptor = INVALID_SOCKET;
|
nuclear@0
|
500 }
|
nuclear@0
|
501
|
nuclear@0
|
502 bool TCPSocketPollState::IsValid() const
|
nuclear@0
|
503 {
|
nuclear@0
|
504 return largestDescriptor != INVALID_SOCKET;
|
nuclear@0
|
505 }
|
nuclear@0
|
506
|
nuclear@0
|
507 void TCPSocketPollState::Add(TCPSocket* tcpSocket)
|
nuclear@0
|
508 {
|
nuclear@0
|
509 if (!tcpSocket)
|
nuclear@0
|
510 {
|
nuclear@0
|
511 return;
|
nuclear@0
|
512 }
|
nuclear@0
|
513
|
nuclear@0
|
514 SocketHandle handle = tcpSocket->GetSocketHandle();
|
nuclear@0
|
515
|
nuclear@0
|
516 if (handle == INVALID_SOCKET)
|
nuclear@0
|
517 {
|
nuclear@0
|
518 return;
|
nuclear@0
|
519 }
|
nuclear@0
|
520
|
nuclear@0
|
521 if (largestDescriptor == INVALID_SOCKET ||
|
nuclear@0
|
522 largestDescriptor < handle)
|
nuclear@0
|
523 {
|
nuclear@0
|
524 largestDescriptor = handle;
|
nuclear@0
|
525 }
|
nuclear@0
|
526
|
nuclear@0
|
527 FD_SET(handle, &readFD);
|
nuclear@0
|
528 FD_SET(handle, &exceptionFD);
|
nuclear@0
|
529
|
nuclear@0
|
530 if (tcpSocket->IsConnecting)
|
nuclear@0
|
531 {
|
nuclear@0
|
532 FD_SET(handle, &writeFD);
|
nuclear@0
|
533 }
|
nuclear@0
|
534 }
|
nuclear@0
|
535
|
nuclear@0
|
536 bool TCPSocketPollState::Poll(long usec, long seconds)
|
nuclear@0
|
537 {
|
nuclear@0
|
538 timeval tv;
|
nuclear@0
|
539 tv.tv_sec = seconds;
|
nuclear@0
|
540 tv.tv_usec = (int)usec;
|
nuclear@0
|
541
|
nuclear@0
|
542 return select(largestDescriptor + 1, &readFD, &writeFD, &exceptionFD, &tv) > 0;
|
nuclear@0
|
543 }
|
nuclear@0
|
544
|
nuclear@0
|
545 void TCPSocketPollState::HandleEvent(TCPSocket* tcpSocket, SocketEvent_TCP* eventHandler)
|
nuclear@0
|
546 {
|
nuclear@0
|
547 if (!tcpSocket || !eventHandler)
|
nuclear@0
|
548 {
|
nuclear@0
|
549 return;
|
nuclear@0
|
550 }
|
nuclear@0
|
551
|
nuclear@0
|
552 SocketHandle handle = tcpSocket->GetSocketHandle();
|
nuclear@0
|
553
|
nuclear@0
|
554 if (tcpSocket->IsConnecting && FD_ISSET(handle, &writeFD))
|
nuclear@0
|
555 {
|
nuclear@0
|
556 tcpSocket->IsConnecting = false;
|
nuclear@0
|
557 eventHandler->TCP_OnConnected(tcpSocket);
|
nuclear@0
|
558 }
|
nuclear@0
|
559
|
nuclear@0
|
560 if (FD_ISSET(handle, &readFD))
|
nuclear@0
|
561 {
|
nuclear@0
|
562 if (!tcpSocket->IsListenSocket)
|
nuclear@0
|
563 {
|
nuclear@0
|
564 static const int BUFF_SIZE = 8096;
|
nuclear@0
|
565 char data[BUFF_SIZE];
|
nuclear@0
|
566
|
nuclear@0
|
567 int bytesRead = (int)recv(handle, data, BUFF_SIZE, 0);
|
nuclear@0
|
568 if (bytesRead > 0)
|
nuclear@0
|
569 {
|
nuclear@0
|
570 tcpSocket->OnRecv(eventHandler, (UByte*)data, bytesRead);
|
nuclear@0
|
571 }
|
nuclear@0
|
572 else // Disconnection event:
|
nuclear@0
|
573 {
|
nuclear@0
|
574 tcpSocket->IsConnecting = false;
|
nuclear@0
|
575 eventHandler->TCP_OnClosed(tcpSocket);
|
nuclear@0
|
576 }
|
nuclear@0
|
577 }
|
nuclear@0
|
578 else
|
nuclear@0
|
579 {
|
nuclear@0
|
580 struct sockaddr_storage sockAddr;
|
nuclear@0
|
581 socklen_t sockAddrSize = sizeof(sockAddr);
|
nuclear@0
|
582
|
nuclear@0
|
583 SocketHandle newSock = accept(handle, (sockaddr*)&sockAddr, (socklen_t*)&sockAddrSize);
|
nuclear@0
|
584 if (newSock > 0)
|
nuclear@0
|
585 {
|
nuclear@0
|
586 SockAddr sa(&sockAddr);
|
nuclear@0
|
587 eventHandler->TCP_OnAccept(tcpSocket, &sa, newSock);
|
nuclear@0
|
588 }
|
nuclear@0
|
589 }
|
nuclear@0
|
590 }
|
nuclear@0
|
591
|
nuclear@0
|
592 if (FD_ISSET(handle, &exceptionFD))
|
nuclear@0
|
593 {
|
nuclear@0
|
594 tcpSocket->IsConnecting = false;
|
nuclear@0
|
595 eventHandler->TCP_OnClosed(tcpSocket);
|
nuclear@0
|
596 }
|
nuclear@0
|
597 }
|
nuclear@0
|
598
|
nuclear@0
|
599
|
nuclear@0
|
600 }} // namespace OVR::Net
|