PageRenderTime 42ms CodeModel.GetById 9ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 1ms

/ThirdParty/PSCommon/XnLib/Source/Win32/XnWin32Network.cpp

https://github.com/jspricke/OpenNI2
C++ | 518 lines | 319 code | 89 blank | 110 comment | 69 complexity | 5a07583c0cf7b4474d48505c7ef93666 MD5 | raw file
  1/*****************************************************************************
  2*                                                                            *
  3*  PrimeSense PSCommon Library                                               *
  4*  Copyright (C) 2012 PrimeSense Ltd.                                        *
  5*                                                                            *
  6*  This file is part of PSCommon.                                            *
  7*                                                                            *
  8*  Licensed under the Apache License, Version 2.0 (the "License");           *
  9*  you may not use this file except in compliance with the License.          *
 10*  You may obtain a copy of the License at                                   *
 11*                                                                            *
 12*      http://www.apache.org/licenses/LICENSE-2.0                            *
 13*                                                                            *
 14*  Unless required by applicable law or agreed to in writing, software       *
 15*  distributed under the License is distributed on an "AS IS" BASIS,         *
 16*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 17*  See the License for the specific language governing permissions and       *
 18*  limitations under the License.                                            *
 19*                                                                            *
 20*****************************************************************************/
 21//---------------------------------------------------------------------------
 22// Includes
 23//---------------------------------------------------------------------------
 24#include <XnOS.h>
 25#include <winsock2.h>
 26#include <xnLog.h>
 27
 28//---------------------------------------------------------------------------
 29// Global Variables
 30//---------------------------------------------------------------------------
 31static WSADATA g_xnOSNetworkWSAData;
 32static XnBool g_xnOSNetworkWasInit = FALSE;
 33
 34//---------------------------------------------------------------------------
 35// Structs
 36//---------------------------------------------------------------------------
 37/** The Xiron OS network socket structure. */ 
 38typedef struct xnOSSocket
 39{
 40	/** The OS socket handle. */ 
 41	SOCKET Socket;
 42
 43	/** The OS socket address (IP and port). */ 
 44	SOCKADDR_IN SocketAddress;
 45	XnInt32 nSocketAddressLen;
 46
 47	/** The socket type enum (UDP, TDP, etc...) */ 
 48	XnUInt32 nSocketType;
 49} xnOSSocket;
 50
 51//---------------------------------------------------------------------------
 52// Code
 53//---------------------------------------------------------------------------
 54XN_C_API XnStatus xnOSInitNetwork()
 55{
 56	// Initialize the WinSock 2.2 subsystem (if needed) and make sure it succeeded (return value is 0)
 57	if (g_xnOSNetworkWasInit == FALSE)
 58	{
 59		XnInt32 nRetVal = WSAStartup(MAKEWORD(2,2), &g_xnOSNetworkWSAData);
 60		if (nRetVal != NO_ERROR)
 61		{
 62			return(XN_STATUS_OS_NETWORK_INIT_FAILED);
 63		}
 64
 65		// Set the global network init flag as true
 66		g_xnOSNetworkWasInit = TRUE;
 67	}
 68
 69	// All is good...
 70	return (XN_STATUS_OK);
 71}
 72
 73XN_C_API XnStatus xnOSShutdownNetwork()
 74{
 75	// Was the network subsystem initialized?
 76	if (g_xnOSNetworkWasInit == TRUE)
 77	{
 78		// Cleanup the WinSock 2.2 subsystem and make sure it succeeded (return value is 0)
 79		XnInt32 nRetVal = WSACleanup();
 80		if (nRetVal == SOCKET_ERROR)
 81		{
 82			return(XN_STATUS_OS_NETWORK_SHUTDOWN_FAILED);
 83		}
 84	}
 85
 86	// Set the global network init flag as false
 87	g_xnOSNetworkWasInit = FALSE;
 88
 89	// All is good...
 90	return (XN_STATUS_OK);
 91}
 92
 93XN_C_API XnStatus xnOSCreateSocket(const XnOSSocketType SocketType, const XnChar* cpIPAddress, const XnUInt16 nPort, XN_SOCKET_HANDLE* SocketPtr)
 94{
 95	// Local function variables
 96	hostent* HostEnt = NULL;
 97	XN_SOCKET_HANDLE Socket = NULL;
 98
 99	// Validate the input/output pointers (to make sure none of them is NULL)
100	XN_VALIDATE_INPUT_PTR(cpIPAddress);
101	XN_VALIDATE_OUTPUT_PTR(SocketPtr);
102
103	XN_VALIDATE_ALIGNED_CALLOC(*SocketPtr, xnOSSocket, 1, XN_DEFAULT_MEM_ALIGN);
104
105	Socket = *SocketPtr;
106
107	if (SocketType == XN_OS_UDP_SOCKET)
108	{
109		// Create a UDP socket
110		Socket->Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
111	}
112	else if (SocketType == XN_OS_TCP_SOCKET)
113	{
114		// Create a TCP socket
115		Socket->Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
116	}
117	else
118	{
119		// Unknown socket type...
120		XN_ALIGNED_FREE_AND_NULL(Socket);
121		return (XN_STATUS_OS_NETWORK_INVALID_SOCKET_TYPE);
122	}
123
124	if (Socket->Socket == INVALID_SOCKET)
125	{
126		XN_ALIGNED_FREE_AND_NULL(Socket);
127		XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_CREATION_FAILED, XN_MASK_OS, "socket() returned WinSock error: %d", WSAGetLastError());
128	}
129
130	// Set the socket server address
131	Socket->SocketAddress.sin_family = AF_INET;
132
133	if (isalpha(cpIPAddress[0])) 
134	{
135		HostEnt = gethostbyname(cpIPAddress);
136		if (HostEnt == NULL)
137		{
138			XN_ALIGNED_FREE_AND_NULL(Socket);
139			return (XN_STATUS_OS_NETWORK_BAD_HOST_NAME);
140		}
141
142		xnOSMemCopy(&Socket->SocketAddress.sin_addr, HostEnt->h_addr, HostEnt->h_length);
143	}
144	else
145	{
146		Socket->SocketAddress.sin_addr.s_addr = inet_addr(cpIPAddress);
147	}
148
149	Socket->SocketAddress.sin_port = htons(nPort);
150
151	// Update socket address size
152	Socket->nSocketAddressLen = sizeof(Socket->SocketAddress);
153
154	// Remember the socket type
155	Socket->nSocketType = SocketType;
156
157	// All is good...
158	return (XN_STATUS_OK);
159}
160
161XN_C_API XnStatus xnOSCloseSocket(XN_SOCKET_HANDLE Socket)
162{
163	// Local function variables
164	XnInt32 nRetVal = 0;
165
166	// Validate the input/output pointers (to make sure none of them is NULL)
167	XN_VALIDATE_INPUT_PTR(Socket);
168
169	// Make sure the actual socket handle isn't NULL
170	XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
171
172	// Close the socket and make sure it succeeded (return value is 0)
173	nRetVal = closesocket(Socket->Socket);
174	if (nRetVal == SOCKET_ERROR)
175	{
176		return(XN_STATUS_OS_NETWORK_SHUTDOWN_FAILED);
177	}
178
179	XN_ALIGNED_FREE_AND_NULL(Socket);
180
181	// All is good...
182	return (XN_STATUS_OK);
183}
184
185XN_C_API XnStatus xnOSBindSocket(XN_SOCKET_HANDLE Socket)
186{
187	// Local function variables
188	XnInt32 nRetVal = 0;
189
190	// Validate the input/output pointers (to make sure none of them is NULL)
191	XN_VALIDATE_INPUT_PTR(Socket);
192
193	// Make sure the actual socket handle isn't NULL
194	XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
195
196	// Bind the socket and make sure it succeeded
197	nRetVal = bind(Socket->Socket, (SOCKADDR*)&Socket->SocketAddress, sizeof(Socket->SocketAddress));
198	if (nRetVal	== SOCKET_ERROR)
199	{
200		return(XN_STATUS_OS_NETWORK_SOCKET_BIND_FAILED);
201	}
202
203	// All is good...
204	return (XN_STATUS_OK);
205}
206
207XN_C_API XnStatus xnOSListenSocket(XN_SOCKET_HANDLE Socket)
208{
209	// Local function variables
210	XnInt32 nRetVal = 0;
211
212	// Validate the input/output pointers (to make sure none of them is NULL)
213	XN_VALIDATE_INPUT_PTR(Socket);
214
215	// Make sure the actual socket handle isn't NULL
216	XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
217
218	// Listen to the socket and make sure it succeeded
219	nRetVal = listen(Socket->Socket, SOMAXCONN);
220	if (nRetVal	== SOCKET_ERROR)
221	{
222		return(XN_STATUS_OS_NETWORK_SOCKET_LISTEN_FAILED);
223	}
224
225	// All is good...
226	return (XN_STATUS_OK);
227}
228
229static struct timeval* xnOSMillisecsToTimeVal(XnUInt32 nMilliseconds, struct timeval* pTv)
230{
231	if (nMilliseconds == XN_WAIT_INFINITE)
232	{
233		return NULL;
234	}
235
236	pTv->tv_sec = nMilliseconds / 1000; //Seconds
237	pTv->tv_usec = (nMilliseconds % 1000) * 1000; //Microseconds
238	return pTv;
239}
240
241XN_C_API XnStatus xnOSAcceptSocket(XN_SOCKET_HANDLE ListenSocket, XN_SOCKET_HANDLE* AcceptSocketPtr, XnUInt32 nMillisecondsTimeout)
242{
243	// Local function variables
244	XnInt32 nRetVal = 0;
245	struct timeval selectTimeOut;
246	struct timeval* pTimeout = xnOSMillisecsToTimeVal(nMillisecondsTimeout, &selectTimeOut);
247	fd_set fdReadHandles;
248	XN_SOCKET_HANDLE AcceptSocket = NULL;
249
250	// Validate the input/output pointers (to make sure none of them is NULL)
251	XN_VALIDATE_INPUT_PTR(ListenSocket);
252	XN_VALIDATE_OUTPUT_PTR(AcceptSocketPtr);
253
254	// Make sure the actual socket handle isn't NULL
255	XN_RET_IF_NULL(ListenSocket->Socket, XN_STATUS_OS_INVALID_SOCKET);
256
257	// Wait for connection request
258	XN_PRAGMA_START_DISABLED_WARNING_SECTION(XN_CONDITION_IS_CONST_WARNING_ID);
259	FD_ZERO(&fdReadHandles);
260	FD_SET(ListenSocket->Socket, &fdReadHandles);
261	XN_PRAGMA_STOP_DISABLED_WARNING_SECTION;
262
263	nRetVal = select(1 /* ignored */, &fdReadHandles, NULL, NULL, pTimeout);
264	if (nRetVal == 0)
265	{
266		return (XN_STATUS_OS_NETWORK_TIMEOUT);
267	}
268	else if (nRetVal == SOCKET_ERROR)
269	{
270		XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_ACCEPT_FAILED, XN_MASK_OS, "select() returned WinSock error: %d", WSAGetLastError());
271	}
272
273	// Allocate a new socket
274	XN_VALIDATE_ALIGNED_CALLOC(*AcceptSocketPtr, xnOSSocket, 1, XN_DEFAULT_MEM_ALIGN);
275
276	AcceptSocket = *AcceptSocketPtr;
277
278	// Accept the socket and make sure it succeeded
279	AcceptSocket->nSocketAddressLen = sizeof(AcceptSocket->SocketAddress);
280	AcceptSocket->Socket = accept(ListenSocket->Socket, (sockaddr*)&AcceptSocket->SocketAddress, &AcceptSocket->nSocketAddressLen);
281	if (AcceptSocket->Socket == INVALID_SOCKET)
282	{
283		xnOSCloseSocket(AcceptSocket);
284		xnOSFreeAligned(*AcceptSocketPtr);
285		return(XN_STATUS_OS_NETWORK_SOCKET_ACCEPT_FAILED);
286	}
287
288	// All is good...
289	return (XN_STATUS_OK);
290}
291
292XN_C_API XnStatus xnOSConnectSocket(XN_SOCKET_HANDLE Socket, XnUInt32 nMillisecsTimeout)
293{
294	// Local function variables
295	XnInt32 nRetVal = 0;
296	sockaddr SocketAddress;
297	fd_set fdWriteHandles;
298	fd_set fdExceptHandles;
299	struct timeval selectTimeOut;
300	struct timeval* pTimeout = xnOSMillisecsToTimeVal(nMillisecsTimeout, &selectTimeOut);
301
302	// Validate the input/output pointers (to make sure none of them is NULL)
303	XN_VALIDATE_INPUT_PTR(Socket);
304
305	// Make sure the actual socket handle isn't NULL
306	XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
307
308	// Connect to the socket and make sure it succeeded
309	xnOSMemCopy(&SocketAddress, &Socket->SocketAddress, sizeof(SocketAddress));
310
311	// if timeout is XN_SOCKET_DEFAULT_TIMEOUT, leave the socket as a blocking one
312	if (nMillisecsTimeout != XN_SOCKET_DEFAULT_TIMEOUT)
313	{
314		// Make the socket non-blocking temporarily
315		u_long nNonBlockingSocket = 1;
316		if (ioctlsocket(Socket->Socket, FIONBIO, &nNonBlockingSocket) != 0)
317		{
318			XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_CONNECT_FAILED, XN_MASK_OS, "ioctlsocket() failed with error %d", WSAGetLastError());
319		}
320	}
321
322	nRetVal = connect(Socket->Socket, &SocketAddress, sizeof(SocketAddress));
323	if ((nRetVal == SOCKET_ERROR) && (WSAGetLastError() != WSAEWOULDBLOCK))
324	{
325		xnLogError(XN_MASK_OS, "connect() failed with winsock error %d", WSAGetLastError());
326		return(XN_STATUS_OS_NETWORK_SOCKET_CONNECT_FAILED);
327	}
328
329	if (nMillisecsTimeout != XN_SOCKET_DEFAULT_TIMEOUT)
330	{
331		XN_PRAGMA_START_DISABLED_WARNING_SECTION(XN_CONDITION_IS_CONST_WARNING_ID);
332		FD_ZERO(&fdWriteHandles);
333		FD_SET(Socket->Socket, &fdWriteHandles);
334		FD_ZERO(&fdExceptHandles);
335		FD_SET(Socket->Socket, &fdExceptHandles);
336		XN_PRAGMA_STOP_DISABLED_WARNING_SECTION;
337
338		nRetVal = select(1 /* ignored */, NULL, &fdWriteHandles, &fdExceptHandles, pTimeout);
339
340		// in any case, make the socket blocking again before we check select()'s success
341		u_long nBlockingSocket = 0;
342		ioctlsocket(Socket->Socket, FIONBIO, &nBlockingSocket);
343
344		if (nRetVal == 0)
345		{
346			return (XN_STATUS_OS_NETWORK_TIMEOUT);
347		}
348		else if (nRetVal == SOCKET_ERROR)
349		{
350			XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_CONNECT_FAILED, XN_MASK_OS, "select() returned WinSock error: %d", WSAGetLastError());
351		}
352		else
353		{
354			// select returned due to socket state change. Check if an error occurred or everything is OK.
355			if (FD_ISSET(Socket->Socket, &fdExceptHandles))
356			{
357				XnUInt32 nLastError = 0;
358				XnInt32 nLastErrorSize = sizeof(nLastError);
359				getsockopt(Socket->Socket, SOL_SOCKET, SO_ERROR, (char*)&nLastError, &nLastErrorSize);
360				XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_CONNECT_FAILED, XN_MASK_OS, "Connect failed with error: %u", nLastError);
361			}
362			// else, it means it's in the writable state, which means connect succeeded.
363			XN_ASSERT(FD_ISSET(Socket->Socket, &fdWriteHandles));
364		}
365	}
366
367	// All is good...
368	return (XN_STATUS_OK);
369}
370
371XN_C_API XnStatus xnOSSetSocketBufferSize(XN_SOCKET_HANDLE Socket, const XnUInt32 nSocketBufferSize)
372{
373	// Local function variables
374	XnInt32 nOptLen = sizeof(XnUInt32);
375	XnInt32 nRetVal = 0;
376
377	// Validate the input/output pointers (to make sure none of them is NULL)
378	XN_VALIDATE_INPUT_PTR(Socket);
379
380	// Make sure the actual socket handle isn't NULL
381	XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
382
383	// Change the socket sending buffer and make sure it succeeded
384	nRetVal = setsockopt(Socket->Socket, SOL_SOCKET, SO_SNDBUF, (XnChar*)&nSocketBufferSize, nOptLen);
385	if (nRetVal	== SOCKET_ERROR)
386	{
387		return(XN_STATUS_OS_NETWORK_SOCKET_BUFFER_FAILED);
388	}
389
390	// Change the socket receive buffer and make sure it succeeded
391	nRetVal = setsockopt(Socket->Socket, SOL_SOCKET, SO_RCVBUF, (XnChar*)&nSocketBufferSize, nOptLen);
392	if (nRetVal	== SOCKET_ERROR)
393	{
394		return(XN_STATUS_OS_NETWORK_SOCKET_BUFFER_FAILED);
395	}
396
397	// All is good...
398	return (XN_STATUS_OK);
399}
400
401XN_C_API XnStatus xnOSSendNetworkBuffer(XN_SOCKET_HANDLE Socket, const XnChar* cpBuffer, const XnUInt32 nBufferSize)
402{
403	// Local function variables
404	XnInt32 nRetVal = 0;
405
406	// Validate the input/output pointers (to make sure none of them is NULL)
407	XN_VALIDATE_INPUT_PTR(Socket);
408	XN_VALIDATE_INPUT_PTR(cpBuffer);
409
410	// Make sure the actual socket handle isn't NULL
411	XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
412
413	// Send the data over our socket to the server and make sure the wanted number of bytes were actually sent
414	nRetVal = send(Socket->Socket, cpBuffer, nBufferSize, 0);
415	if (nRetVal != (int)nBufferSize)
416	{
417		return (XN_STATUS_OS_NETWORK_SEND_FAILED);
418	}
419
420	// All is good...
421	return (XN_STATUS_OK);
422}
423
424XN_C_API XnStatus xnOSSendToNetworkBuffer(XN_SOCKET_HANDLE Socket, const XnChar* cpBuffer, const XnUInt32 nBufferSize, XN_SOCKET_HANDLE SocketTo)
425{
426	// Local function variables
427	XnInt32 nRetVal = 0;
428
429	// Validate the input/output pointers (to make sure none of them is NULL)
430	XN_VALIDATE_INPUT_PTR(Socket);
431	XN_VALIDATE_INPUT_PTR(SocketTo);
432	XN_VALIDATE_INPUT_PTR(cpBuffer);
433
434	// Make sure the actual socket handle isn't NULL
435	XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
436
437	// Send the data over our UDP socket to the server and make sure the wanted number of bytes were actually sent
438	nRetVal = sendto(Socket->Socket, cpBuffer, nBufferSize, 0, (SOCKADDR*)&SocketTo->SocketAddress, sizeof(SOCKADDR));
439	if (nRetVal != (int)nBufferSize)
440	{
441		return (XN_STATUS_OS_NETWORK_SEND_FAILED);
442	}
443
444	// All is good...
445	return (XN_STATUS_OK);
446}
447
448XN_C_API XnStatus xnOSReceiveNetworkBuffer(XN_SOCKET_HANDLE Socket, XnChar* cpBuffer, XnUInt32* pnBufferSize, XnUInt32 nMillisecondsTimeout)
449{
450	// Local function variables
451	XnInt32 nRetVal = 0;
452	struct timeval selectTimeOut;
453	struct timeval* pTimeout = xnOSMillisecsToTimeVal(nMillisecondsTimeout, &selectTimeOut);
454	fd_set fdReadHandles;
455
456	// Validate the input/output pointers (to make sure none of them is NULL)
457	XN_VALIDATE_INPUT_PTR(Socket);
458	XN_VALIDATE_OUTPUT_PTR(cpBuffer);
459	XN_VALIDATE_OUTPUT_PTR(pnBufferSize);
460
461	// Make sure the actual socket handle isn't NULL
462	XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
463
464	XN_PRAGMA_START_DISABLED_WARNING_SECTION(XN_CONDITION_IS_CONST_WARNING_ID);
465	FD_ZERO(&fdReadHandles);
466	FD_SET(Socket->Socket, &fdReadHandles);
467	XN_PRAGMA_STOP_DISABLED_WARNING_SECTION;
468
469	nRetVal = select(1 /* ignored */, &fdReadHandles, NULL, NULL, pTimeout);
470	if (nRetVal == 0)
471	{
472		return (XN_STATUS_OS_NETWORK_TIMEOUT);
473	}
474	else if (nRetVal != 1)
475	{
476		XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_RECEIVE_FAILED, XN_MASK_OS, "select() failed with winsock error %d", WSAGetLastError());
477	}
478
479	// Receive the data from our socket to the buffer and make sure it succeeded
480	*pnBufferSize = recv(Socket->Socket, cpBuffer, *pnBufferSize, 0);
481	if (*pnBufferSize == 0)
482	{
483		xnLogVerbose(XN_MASK_OS, "Socket has been gracefully closed");
484		return (XN_STATUS_OS_NETWORK_CONNECTION_CLOSED);
485	}
486	else if (*pnBufferSize == SOCKET_ERROR)
487	{
488		XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_RECEIVE_FAILED, XN_MASK_OS, "recv() failed with winsock error %d", WSAGetLastError());
489	}
490
491	// All is good...
492	return (XN_STATUS_OK);
493}
494
495XN_C_API XnStatus xnOSReceiveFromNetworkBuffer(XN_SOCKET_HANDLE Socket, XnChar* cpBuffer, XnUInt32* pnBufferSize, XN_SOCKET_HANDLE* SocketFrom)
496{
497	// Local function variables
498	XnInt32 nLen = sizeof(SOCKADDR);	
499
500	// Validate the input/output pointers (to make sure none of them is NULL)
501	XN_VALIDATE_INPUT_PTR(Socket);
502	XN_VALIDATE_INPUT_PTR(SocketFrom);
503	XN_VALIDATE_OUTPUT_PTR(cpBuffer);
504	XN_VALIDATE_OUTPUT_PTR(pnBufferSize);
505
506	// Make sure the actual socket handle isn't NULL
507	XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
508
509	// Receive the data from our UDP socket to the buffer and make sure it succeeded
510	*pnBufferSize = recvfrom(Socket->Socket, cpBuffer, *pnBufferSize, 0, (SOCKADDR*)&(*SocketFrom)->SocketAddress, &nLen);
511	if (*pnBufferSize == SOCKET_ERROR)
512	{
513		return (XN_STATUS_OS_NETWORK_RECEIVE_FAILED);
514	}
515
516	// All is good...
517	return (XN_STATUS_OK);
518}