PageRenderTime 45ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/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
Possible License(s): Apache-2.0, LGPL-2.1
  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. // Global Variables
  29. //---------------------------------------------------------------------------
  30. static WSADATA g_xnOSNetworkWSAData;
  31. static XnBool g_xnOSNetworkWasInit = FALSE;
  32. //---------------------------------------------------------------------------
  33. // Structs
  34. //---------------------------------------------------------------------------
  35. /** The Xiron OS network socket structure. */
  36. typedef struct xnOSSocket
  37. {
  38. /** The OS socket handle. */
  39. SOCKET Socket;
  40. /** The OS socket address (IP and port). */
  41. SOCKADDR_IN SocketAddress;
  42. XnInt32 nSocketAddressLen;
  43. /** The socket type enum (UDP, TDP, etc...) */
  44. XnUInt32 nSocketType;
  45. } xnOSSocket;
  46. //---------------------------------------------------------------------------
  47. // Code
  48. //---------------------------------------------------------------------------
  49. XN_C_API XnStatus xnOSInitNetwork()
  50. {
  51. // Initialize the WinSock 2.2 subsystem (if needed) and make sure it succeeded (return value is 0)
  52. if (g_xnOSNetworkWasInit == FALSE)
  53. {
  54. XnInt32 nRetVal = WSAStartup(MAKEWORD(2,2), &g_xnOSNetworkWSAData);
  55. if (nRetVal != NO_ERROR)
  56. {
  57. return(XN_STATUS_OS_NETWORK_INIT_FAILED);
  58. }
  59. // Set the global network init flag as true
  60. g_xnOSNetworkWasInit = TRUE;
  61. }
  62. // All is good...
  63. return (XN_STATUS_OK);
  64. }
  65. XN_C_API XnStatus xnOSShutdownNetwork()
  66. {
  67. // Was the network subsystem initialized?
  68. if (g_xnOSNetworkWasInit == TRUE)
  69. {
  70. // Cleanup the WinSock 2.2 subsystem and make sure it succeeded (return value is 0)
  71. XnInt32 nRetVal = WSACleanup();
  72. if (nRetVal == SOCKET_ERROR)
  73. {
  74. return(XN_STATUS_OS_NETWORK_SHUTDOWN_FAILED);
  75. }
  76. }
  77. // Set the global network init flag as false
  78. g_xnOSNetworkWasInit = FALSE;
  79. // All is good...
  80. return (XN_STATUS_OK);
  81. }
  82. XN_C_API XnStatus xnOSCreateSocket(const XnOSSocketType SocketType, const XnChar* cpIPAddress, const XnUInt16 nPort, XN_SOCKET_HANDLE* SocketPtr)
  83. {
  84. // Local function variables
  85. hostent* HostEnt = NULL;
  86. XN_SOCKET_HANDLE Socket = NULL;
  87. // Validate the input/output pointers (to make sure none of them is NULL)
  88. XN_VALIDATE_INPUT_PTR(cpIPAddress);
  89. XN_VALIDATE_OUTPUT_PTR(SocketPtr);
  90. XN_VALIDATE_ALIGNED_CALLOC(*SocketPtr, xnOSSocket, 1, XN_DEFAULT_MEM_ALIGN);
  91. Socket = *SocketPtr;
  92. if (SocketType == XN_OS_UDP_SOCKET)
  93. {
  94. // Create a UDP socket
  95. Socket->Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  96. }
  97. else if (SocketType == XN_OS_TCP_SOCKET)
  98. {
  99. // Create a TCP socket
  100. Socket->Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  101. }
  102. else
  103. {
  104. // Unknown socket type...
  105. XN_ALIGNED_FREE_AND_NULL(Socket);
  106. return (XN_STATUS_OS_NETWORK_INVALID_SOCKET_TYPE);
  107. }
  108. if (Socket->Socket == INVALID_SOCKET)
  109. {
  110. XN_ALIGNED_FREE_AND_NULL(Socket);
  111. XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_CREATION_FAILED, XN_MASK_OS, "socket() returned WinSock error: %d", WSAGetLastError());
  112. }
  113. // Set the socket server address
  114. Socket->SocketAddress.sin_family = AF_INET;
  115. if (isalpha(cpIPAddress[0]))
  116. {
  117. HostEnt = gethostbyname(cpIPAddress);
  118. if (HostEnt == NULL)
  119. {
  120. XN_ALIGNED_FREE_AND_NULL(Socket);
  121. return (XN_STATUS_OS_NETWORK_BAD_HOST_NAME);
  122. }
  123. xnOSMemCopy(&Socket->SocketAddress.sin_addr, HostEnt->h_addr, HostEnt->h_length);
  124. }
  125. else
  126. {
  127. Socket->SocketAddress.sin_addr.s_addr = inet_addr(cpIPAddress);
  128. }
  129. Socket->SocketAddress.sin_port = htons(nPort);
  130. // Update socket address size
  131. Socket->nSocketAddressLen = sizeof(Socket->SocketAddress);
  132. // Remember the socket type
  133. Socket->nSocketType = SocketType;
  134. // All is good...
  135. return (XN_STATUS_OK);
  136. }
  137. XN_C_API XnStatus xnOSCloseSocket(XN_SOCKET_HANDLE Socket)
  138. {
  139. // Local function variables
  140. XnInt32 nRetVal = 0;
  141. // Validate the input/output pointers (to make sure none of them is NULL)
  142. XN_VALIDATE_INPUT_PTR(Socket);
  143. // Make sure the actual socket handle isn't NULL
  144. XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  145. // Close the socket and make sure it succeeded (return value is 0)
  146. nRetVal = closesocket(Socket->Socket);
  147. if (nRetVal == SOCKET_ERROR)
  148. {
  149. return(XN_STATUS_OS_NETWORK_SHUTDOWN_FAILED);
  150. }
  151. XN_ALIGNED_FREE_AND_NULL(Socket);
  152. // All is good...
  153. return (XN_STATUS_OK);
  154. }
  155. XN_C_API XnStatus xnOSBindSocket(XN_SOCKET_HANDLE Socket)
  156. {
  157. // Local function variables
  158. XnInt32 nRetVal = 0;
  159. // Validate the input/output pointers (to make sure none of them is NULL)
  160. XN_VALIDATE_INPUT_PTR(Socket);
  161. // Make sure the actual socket handle isn't NULL
  162. XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  163. // Bind the socket and make sure it succeeded
  164. nRetVal = bind(Socket->Socket, (SOCKADDR*)&Socket->SocketAddress, sizeof(Socket->SocketAddress));
  165. if (nRetVal == SOCKET_ERROR)
  166. {
  167. return(XN_STATUS_OS_NETWORK_SOCKET_BIND_FAILED);
  168. }
  169. // All is good...
  170. return (XN_STATUS_OK);
  171. }
  172. XN_C_API XnStatus xnOSListenSocket(XN_SOCKET_HANDLE Socket)
  173. {
  174. // Local function variables
  175. XnInt32 nRetVal = 0;
  176. // Validate the input/output pointers (to make sure none of them is NULL)
  177. XN_VALIDATE_INPUT_PTR(Socket);
  178. // Make sure the actual socket handle isn't NULL
  179. XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  180. // Listen to the socket and make sure it succeeded
  181. nRetVal = listen(Socket->Socket, SOMAXCONN);
  182. if (nRetVal == SOCKET_ERROR)
  183. {
  184. return(XN_STATUS_OS_NETWORK_SOCKET_LISTEN_FAILED);
  185. }
  186. // All is good...
  187. return (XN_STATUS_OK);
  188. }
  189. static struct timeval* xnOSMillisecsToTimeVal(XnUInt32 nMilliseconds, struct timeval* pTv)
  190. {
  191. if (nMilliseconds == XN_WAIT_INFINITE)
  192. {
  193. return NULL;
  194. }
  195. pTv->tv_sec = nMilliseconds / 1000; //Seconds
  196. pTv->tv_usec = (nMilliseconds % 1000) * 1000; //Microseconds
  197. return pTv;
  198. }
  199. XN_C_API XnStatus xnOSAcceptSocket(XN_SOCKET_HANDLE ListenSocket, XN_SOCKET_HANDLE* AcceptSocketPtr, XnUInt32 nMillisecondsTimeout)
  200. {
  201. // Local function variables
  202. XnInt32 nRetVal = 0;
  203. struct timeval selectTimeOut;
  204. struct timeval* pTimeout = xnOSMillisecsToTimeVal(nMillisecondsTimeout, &selectTimeOut);
  205. fd_set fdReadHandles;
  206. XN_SOCKET_HANDLE AcceptSocket = NULL;
  207. // Validate the input/output pointers (to make sure none of them is NULL)
  208. XN_VALIDATE_INPUT_PTR(ListenSocket);
  209. XN_VALIDATE_OUTPUT_PTR(AcceptSocketPtr);
  210. // Make sure the actual socket handle isn't NULL
  211. XN_RET_IF_NULL(ListenSocket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  212. // Wait for connection request
  213. XN_PRAGMA_START_DISABLED_WARNING_SECTION(XN_CONDITION_IS_CONST_WARNING_ID);
  214. FD_ZERO(&fdReadHandles);
  215. FD_SET(ListenSocket->Socket, &fdReadHandles);
  216. XN_PRAGMA_STOP_DISABLED_WARNING_SECTION;
  217. nRetVal = select(1 /* ignored */, &fdReadHandles, NULL, NULL, pTimeout);
  218. if (nRetVal == 0)
  219. {
  220. return (XN_STATUS_OS_NETWORK_TIMEOUT);
  221. }
  222. else if (nRetVal == SOCKET_ERROR)
  223. {
  224. XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_ACCEPT_FAILED, XN_MASK_OS, "select() returned WinSock error: %d", WSAGetLastError());
  225. }
  226. // Allocate a new socket
  227. XN_VALIDATE_ALIGNED_CALLOC(*AcceptSocketPtr, xnOSSocket, 1, XN_DEFAULT_MEM_ALIGN);
  228. AcceptSocket = *AcceptSocketPtr;
  229. // Accept the socket and make sure it succeeded
  230. AcceptSocket->nSocketAddressLen = sizeof(AcceptSocket->SocketAddress);
  231. AcceptSocket->Socket = accept(ListenSocket->Socket, (sockaddr*)&AcceptSocket->SocketAddress, &AcceptSocket->nSocketAddressLen);
  232. if (AcceptSocket->Socket == INVALID_SOCKET)
  233. {
  234. xnOSCloseSocket(AcceptSocket);
  235. xnOSFreeAligned(*AcceptSocketPtr);
  236. return(XN_STATUS_OS_NETWORK_SOCKET_ACCEPT_FAILED);
  237. }
  238. // All is good...
  239. return (XN_STATUS_OK);
  240. }
  241. XN_C_API XnStatus xnOSConnectSocket(XN_SOCKET_HANDLE Socket, XnUInt32 nMillisecsTimeout)
  242. {
  243. // Local function variables
  244. XnInt32 nRetVal = 0;
  245. sockaddr SocketAddress;
  246. fd_set fdWriteHandles;
  247. fd_set fdExceptHandles;
  248. struct timeval selectTimeOut;
  249. struct timeval* pTimeout = xnOSMillisecsToTimeVal(nMillisecsTimeout, &selectTimeOut);
  250. // Validate the input/output pointers (to make sure none of them is NULL)
  251. XN_VALIDATE_INPUT_PTR(Socket);
  252. // Make sure the actual socket handle isn't NULL
  253. XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  254. // Connect to the socket and make sure it succeeded
  255. xnOSMemCopy(&SocketAddress, &Socket->SocketAddress, sizeof(SocketAddress));
  256. // if timeout is XN_SOCKET_DEFAULT_TIMEOUT, leave the socket as a blocking one
  257. if (nMillisecsTimeout != XN_SOCKET_DEFAULT_TIMEOUT)
  258. {
  259. // Make the socket non-blocking temporarily
  260. u_long nNonBlockingSocket = 1;
  261. if (ioctlsocket(Socket->Socket, FIONBIO, &nNonBlockingSocket) != 0)
  262. {
  263. XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_CONNECT_FAILED, XN_MASK_OS, "ioctlsocket() failed with error %d", WSAGetLastError());
  264. }
  265. }
  266. nRetVal = connect(Socket->Socket, &SocketAddress, sizeof(SocketAddress));
  267. if ((nRetVal == SOCKET_ERROR) && (WSAGetLastError() != WSAEWOULDBLOCK))
  268. {
  269. xnLogError(XN_MASK_OS, "connect() failed with winsock error %d", WSAGetLastError());
  270. return(XN_STATUS_OS_NETWORK_SOCKET_CONNECT_FAILED);
  271. }
  272. if (nMillisecsTimeout != XN_SOCKET_DEFAULT_TIMEOUT)
  273. {
  274. XN_PRAGMA_START_DISABLED_WARNING_SECTION(XN_CONDITION_IS_CONST_WARNING_ID);
  275. FD_ZERO(&fdWriteHandles);
  276. FD_SET(Socket->Socket, &fdWriteHandles);
  277. FD_ZERO(&fdExceptHandles);
  278. FD_SET(Socket->Socket, &fdExceptHandles);
  279. XN_PRAGMA_STOP_DISABLED_WARNING_SECTION;
  280. nRetVal = select(1 /* ignored */, NULL, &fdWriteHandles, &fdExceptHandles, pTimeout);
  281. // in any case, make the socket blocking again before we check select()'s success
  282. u_long nBlockingSocket = 0;
  283. ioctlsocket(Socket->Socket, FIONBIO, &nBlockingSocket);
  284. if (nRetVal == 0)
  285. {
  286. return (XN_STATUS_OS_NETWORK_TIMEOUT);
  287. }
  288. else if (nRetVal == SOCKET_ERROR)
  289. {
  290. XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_CONNECT_FAILED, XN_MASK_OS, "select() returned WinSock error: %d", WSAGetLastError());
  291. }
  292. else
  293. {
  294. // select returned due to socket state change. Check if an error occurred or everything is OK.
  295. if (FD_ISSET(Socket->Socket, &fdExceptHandles))
  296. {
  297. XnUInt32 nLastError = 0;
  298. XnInt32 nLastErrorSize = sizeof(nLastError);
  299. getsockopt(Socket->Socket, SOL_SOCKET, SO_ERROR, (char*)&nLastError, &nLastErrorSize);
  300. XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_SOCKET_CONNECT_FAILED, XN_MASK_OS, "Connect failed with error: %u", nLastError);
  301. }
  302. // else, it means it's in the writable state, which means connect succeeded.
  303. XN_ASSERT(FD_ISSET(Socket->Socket, &fdWriteHandles));
  304. }
  305. }
  306. // All is good...
  307. return (XN_STATUS_OK);
  308. }
  309. XN_C_API XnStatus xnOSSetSocketBufferSize(XN_SOCKET_HANDLE Socket, const XnUInt32 nSocketBufferSize)
  310. {
  311. // Local function variables
  312. XnInt32 nOptLen = sizeof(XnUInt32);
  313. XnInt32 nRetVal = 0;
  314. // Validate the input/output pointers (to make sure none of them is NULL)
  315. XN_VALIDATE_INPUT_PTR(Socket);
  316. // Make sure the actual socket handle isn't NULL
  317. XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  318. // Change the socket sending buffer and make sure it succeeded
  319. nRetVal = setsockopt(Socket->Socket, SOL_SOCKET, SO_SNDBUF, (XnChar*)&nSocketBufferSize, nOptLen);
  320. if (nRetVal == SOCKET_ERROR)
  321. {
  322. return(XN_STATUS_OS_NETWORK_SOCKET_BUFFER_FAILED);
  323. }
  324. // Change the socket receive buffer and make sure it succeeded
  325. nRetVal = setsockopt(Socket->Socket, SOL_SOCKET, SO_RCVBUF, (XnChar*)&nSocketBufferSize, nOptLen);
  326. if (nRetVal == SOCKET_ERROR)
  327. {
  328. return(XN_STATUS_OS_NETWORK_SOCKET_BUFFER_FAILED);
  329. }
  330. // All is good...
  331. return (XN_STATUS_OK);
  332. }
  333. XN_C_API XnStatus xnOSSendNetworkBuffer(XN_SOCKET_HANDLE Socket, const XnChar* cpBuffer, const XnUInt32 nBufferSize)
  334. {
  335. // Local function variables
  336. XnInt32 nRetVal = 0;
  337. // Validate the input/output pointers (to make sure none of them is NULL)
  338. XN_VALIDATE_INPUT_PTR(Socket);
  339. XN_VALIDATE_INPUT_PTR(cpBuffer);
  340. // Make sure the actual socket handle isn't NULL
  341. XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  342. // Send the data over our socket to the server and make sure the wanted number of bytes were actually sent
  343. nRetVal = send(Socket->Socket, cpBuffer, nBufferSize, 0);
  344. if (nRetVal != (int)nBufferSize)
  345. {
  346. return (XN_STATUS_OS_NETWORK_SEND_FAILED);
  347. }
  348. // All is good...
  349. return (XN_STATUS_OK);
  350. }
  351. XN_C_API XnStatus xnOSSendToNetworkBuffer(XN_SOCKET_HANDLE Socket, const XnChar* cpBuffer, const XnUInt32 nBufferSize, XN_SOCKET_HANDLE SocketTo)
  352. {
  353. // Local function variables
  354. XnInt32 nRetVal = 0;
  355. // Validate the input/output pointers (to make sure none of them is NULL)
  356. XN_VALIDATE_INPUT_PTR(Socket);
  357. XN_VALIDATE_INPUT_PTR(SocketTo);
  358. XN_VALIDATE_INPUT_PTR(cpBuffer);
  359. // Make sure the actual socket handle isn't NULL
  360. XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  361. // Send the data over our UDP socket to the server and make sure the wanted number of bytes were actually sent
  362. nRetVal = sendto(Socket->Socket, cpBuffer, nBufferSize, 0, (SOCKADDR*)&SocketTo->SocketAddress, sizeof(SOCKADDR));
  363. if (nRetVal != (int)nBufferSize)
  364. {
  365. return (XN_STATUS_OS_NETWORK_SEND_FAILED);
  366. }
  367. // All is good...
  368. return (XN_STATUS_OK);
  369. }
  370. XN_C_API XnStatus xnOSReceiveNetworkBuffer(XN_SOCKET_HANDLE Socket, XnChar* cpBuffer, XnUInt32* pnBufferSize, XnUInt32 nMillisecondsTimeout)
  371. {
  372. // Local function variables
  373. XnInt32 nRetVal = 0;
  374. struct timeval selectTimeOut;
  375. struct timeval* pTimeout = xnOSMillisecsToTimeVal(nMillisecondsTimeout, &selectTimeOut);
  376. fd_set fdReadHandles;
  377. // Validate the input/output pointers (to make sure none of them is NULL)
  378. XN_VALIDATE_INPUT_PTR(Socket);
  379. XN_VALIDATE_OUTPUT_PTR(cpBuffer);
  380. XN_VALIDATE_OUTPUT_PTR(pnBufferSize);
  381. // Make sure the actual socket handle isn't NULL
  382. XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  383. XN_PRAGMA_START_DISABLED_WARNING_SECTION(XN_CONDITION_IS_CONST_WARNING_ID);
  384. FD_ZERO(&fdReadHandles);
  385. FD_SET(Socket->Socket, &fdReadHandles);
  386. XN_PRAGMA_STOP_DISABLED_WARNING_SECTION;
  387. nRetVal = select(1 /* ignored */, &fdReadHandles, NULL, NULL, pTimeout);
  388. if (nRetVal == 0)
  389. {
  390. return (XN_STATUS_OS_NETWORK_TIMEOUT);
  391. }
  392. else if (nRetVal != 1)
  393. {
  394. XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_RECEIVE_FAILED, XN_MASK_OS, "select() failed with winsock error %d", WSAGetLastError());
  395. }
  396. // Receive the data from our socket to the buffer and make sure it succeeded
  397. *pnBufferSize = recv(Socket->Socket, cpBuffer, *pnBufferSize, 0);
  398. if (*pnBufferSize == 0)
  399. {
  400. xnLogVerbose(XN_MASK_OS, "Socket has been gracefully closed");
  401. return (XN_STATUS_OS_NETWORK_CONNECTION_CLOSED);
  402. }
  403. else if (*pnBufferSize == SOCKET_ERROR)
  404. {
  405. XN_LOG_ERROR_RETURN(XN_STATUS_OS_NETWORK_RECEIVE_FAILED, XN_MASK_OS, "recv() failed with winsock error %d", WSAGetLastError());
  406. }
  407. // All is good...
  408. return (XN_STATUS_OK);
  409. }
  410. XN_C_API XnStatus xnOSReceiveFromNetworkBuffer(XN_SOCKET_HANDLE Socket, XnChar* cpBuffer, XnUInt32* pnBufferSize, XN_SOCKET_HANDLE* SocketFrom)
  411. {
  412. // Local function variables
  413. XnInt32 nLen = sizeof(SOCKADDR);
  414. // Validate the input/output pointers (to make sure none of them is NULL)
  415. XN_VALIDATE_INPUT_PTR(Socket);
  416. XN_VALIDATE_INPUT_PTR(SocketFrom);
  417. XN_VALIDATE_OUTPUT_PTR(cpBuffer);
  418. XN_VALIDATE_OUTPUT_PTR(pnBufferSize);
  419. // Make sure the actual socket handle isn't NULL
  420. XN_RET_IF_NULL(Socket->Socket, XN_STATUS_OS_INVALID_SOCKET);
  421. // Receive the data from our UDP socket to the buffer and make sure it succeeded
  422. *pnBufferSize = recvfrom(Socket->Socket, cpBuffer, *pnBufferSize, 0, (SOCKADDR*)&(*SocketFrom)->SocketAddress, &nLen);
  423. if (*pnBufferSize == SOCKET_ERROR)
  424. {
  425. return (XN_STATUS_OS_NETWORK_RECEIVE_FAILED);
  426. }
  427. // All is good...
  428. return (XN_STATUS_OK);
  429. }