UDPsocket.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // =STS=> UDPsocket.cpp[1732].aa11 open SMID:11
  2. //////////////////////////////////////////////////////////////////////
  3. //
  4. // (c) Copyright 2003 Cyberkinetics, Inc.
  5. //
  6. // $Workfile: UDPsocket.cpp $
  7. // $Archive: /Cerebus/WindowsApps/Central/UDPsocket.cpp $
  8. // $Revision: 1 $
  9. // $Date: 1/05/04 4:29p $
  10. // $Author: Kkorver $
  11. //
  12. // $NoKeywords: $
  13. //
  14. //////////////////////////////////////////////////////////////////////
  15. #include "StdAfx.h"
  16. #include "debugmacs.h"
  17. #include "UDPsocket.h"
  18. #ifdef WIN32
  19. #include <conio.h>
  20. typedef int socklen_t;
  21. #else
  22. #include <arpa/inet.h>
  23. #include <fcntl.h>
  24. #include <errno.h>
  25. #include <unistd.h>
  26. typedef struct sockaddr SOCKADDR;
  27. #define INVALID_SOCKET -1
  28. #define SOCKET_ERROR -1
  29. #define FAR
  30. #define SD_BOTH SHUT_RDWR
  31. #endif
  32. //////////////////////////////////////////////////////////////////////
  33. // Construction/Destruction
  34. //////////////////////////////////////////////////////////////////////
  35. UDPSocket::UDPSocket() :
  36. m_nStartupOptionsFlags(OPT_NONE), m_bVerbose(false)
  37. {
  38. inst_sock = INVALID_SOCKET;
  39. }
  40. UDPSocket::~UDPSocket()
  41. {
  42. if (inst_sock != INVALID_SOCKET)
  43. Close();
  44. }
  45. // Author & Date: Ehsan Azar 12 March 2010
  46. // Purpose: Open a network UDP socket
  47. // Inputs:
  48. // nStartupOptionsFlags - the network startup option
  49. // nRange - the maximum allowed increments to the given IP address of the instrument to automatically connect to
  50. // bVerbose - verbose mode
  51. // szInIP - the IP of the instrument through which connects to me
  52. // szOutIP - the IP of the instrument to connect to (it could be a subnet)
  53. // bBroadcast - establish a broadcast socket
  54. // bDontRoute - establish a direct socket with no routing or gateway
  55. // bNonBlocking - establish a non-blocking socket
  56. // nRecBufSize - the system receive-buffer size allocated for this socket
  57. // nInPort - the input port through which instrument connects to me
  58. // nOutPort - the output port to connect to in order to connect to the instrument
  59. // nPacketSize - the maximum packet size that we receive
  60. // Outputs:
  61. // Returns the error code (0 means success)
  62. cbRESULT UDPSocket::Open(STARTUP_OPTIONS nStartupOptionsFlags, int nRange, bool bVerbose, LPCSTR szInIP,
  63. LPCSTR szOutIP, bool bBroadcast, bool bDontRoute, bool bNonBlocking,
  64. int nRecBufSize, int nInPort, int nOutPort, int nPacketSize)
  65. {
  66. m_bVerbose = bVerbose;
  67. m_nPacketSize = nPacketSize;
  68. m_nStartupOptionsFlags = nStartupOptionsFlags;
  69. #ifdef WIN32
  70. // Initialize Winsock 2.2
  71. WSADATA data;
  72. if (WSAStartup (MAKEWORD(2,0), &data) != 0)
  73. return cbRESULT_SOCKERR;
  74. #endif
  75. // Create Socket for Receiving the Data Stream
  76. #ifdef WIN32
  77. inst_sock = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0);
  78. #else
  79. inst_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  80. #endif
  81. if (inst_sock == INVALID_SOCKET)
  82. {
  83. Close();
  84. return cbRESULT_SOCKERR;
  85. }
  86. BOOL opt_val = TRUE;
  87. socklen_t opt_len = sizeof(BOOL);
  88. if (bBroadcast)
  89. {
  90. if (setsockopt(inst_sock, SOL_SOCKET, SO_BROADCAST, (char*)&opt_val, opt_len) != 0)
  91. {
  92. Close();
  93. return cbRESULT_SOCKOPTERR;
  94. }
  95. }
  96. if (bDontRoute)
  97. {
  98. if (setsockopt(inst_sock, SOL_SOCKET, SO_DONTROUTE, (char*)&opt_val, opt_len) != 0)
  99. {
  100. Close();
  101. return cbRESULT_SOCKOPTERR;
  102. }
  103. }
  104. if (nRecBufSize > 0)
  105. {
  106. // Set the data stream input buffer size
  107. opt_len = sizeof(int);
  108. int data_buff_size = nRecBufSize;
  109. if (setsockopt(inst_sock, SOL_SOCKET, SO_RCVBUF, (char*)&data_buff_size, opt_len) != 0)
  110. {
  111. Close();
  112. #ifdef __APPLE__
  113. return cbRESULT_SOCKMEMERR;
  114. #else
  115. return cbRESULT_SOCKOPTERR;
  116. #endif
  117. }
  118. if (getsockopt(inst_sock, SOL_SOCKET, SO_RCVBUF, (char *)&data_buff_size, &opt_len) != 0)
  119. {
  120. Close();
  121. return cbRESULT_SOCKOPTERR;
  122. }
  123. #ifdef __linux__
  124. // Linux returns double the requested size up to twice the rmem_max
  125. data_buff_size /= 2;
  126. #endif
  127. if (data_buff_size < nRecBufSize)
  128. {
  129. // to increase buffer
  130. // sysctl -w net.core.rmem_max=8388608
  131. // or
  132. // nvram boot-args="ncl=65536"
  133. // sysctl -w kern.ipc.maxsockbuf=8388608
  134. Close();
  135. return cbRESULT_SOCKMEMERR;
  136. }
  137. }
  138. if (bNonBlocking)
  139. {
  140. // Set the data socket to non-blocking operation
  141. #ifdef WIN32
  142. u_long arg_val = 1;
  143. if (ioctlsocket(inst_sock, FIONBIO, &arg_val) == SOCKET_ERROR)
  144. #else
  145. if (fcntl(inst_sock, F_SETFL, O_NONBLOCK))
  146. #endif
  147. {
  148. Close();
  149. return cbRESULT_SOCKOPTERR;
  150. }
  151. }
  152. // Attempt to bind Data Stream Socket to lowest address in range 192.168.137.1 to XXX.16
  153. BOOL socketbound = FALSE;
  154. SOCKADDR_IN inst_sockaddr;
  155. memset(&inst_sockaddr, 0, sizeof(inst_sockaddr));
  156. inst_sockaddr.sin_family = AF_INET;
  157. inst_sockaddr.sin_port = htons(nInPort); // Neuroflow Data Port
  158. #ifdef __APPLE__
  159. inst_sockaddr.sin_len = sizeof(inst_sockaddr);
  160. #endif
  161. if (szInIP == 0)
  162. inst_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  163. else
  164. inst_sockaddr.sin_addr.s_addr = inet_addr(szInIP);
  165. int nCount = 0;
  166. do
  167. {
  168. if (bind(inst_sock, (struct sockaddr FAR *)&inst_sockaddr, sizeof(inst_sockaddr)) == 0)
  169. socketbound = TRUE;
  170. else
  171. {
  172. // increment the last ip number
  173. inst_sockaddr.sin_addr.s_addr = htonl(ntohl(inst_sockaddr.sin_addr.s_addr) + 1);
  174. }
  175. nCount++;
  176. } while( (!socketbound) && (nCount <= nRange));
  177. if (socketbound)
  178. {
  179. // Set up transmission target address
  180. dest_sockaddr.sin_family = AF_INET;
  181. dest_sockaddr.sin_port = htons(nOutPort); // Neuroflow Control Port
  182. dest_sockaddr.sin_addr.s_addr = inet_addr(szOutIP); // Subnet Broadcast
  183. }
  184. else
  185. {
  186. if (OPT_NONE == nStartupOptionsFlags)
  187. {
  188. // if no valid address was found to bind the socket, shut her down and return error
  189. Close();
  190. return cbRESULT_SOCKBIND;
  191. }
  192. else
  193. {
  194. // if no valid address was found to bind the socket, just connect on any available
  195. // interface
  196. if (m_bVerbose)
  197. _cprintf("Warning: could not bind to socket on the subnet...\n");
  198. opt_len = sizeof(BOOL);
  199. if (setsockopt(inst_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt_val, opt_len) != 0)
  200. {
  201. if(m_bVerbose)
  202. _cprintf("Error enabling address re-used\n");
  203. Close();
  204. return cbRESULT_SOCKOPTERR;
  205. }
  206. // Bind to the broadcast address
  207. if (OPT_LOOPBACK == nStartupOptionsFlags)
  208. inst_sockaddr.sin_addr.s_addr = inet_addr(LOOPBACK_ADDRESS);
  209. else
  210. inst_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  211. int result = bind(inst_sock, (struct sockaddr FAR *)&inst_sockaddr, sizeof(inst_sockaddr));
  212. if (result == 0)
  213. {
  214. // Set up transmission target address
  215. //
  216. // Assume there's no cerebus subnet, so control packets should go to
  217. // broadcast
  218. dest_sockaddr.sin_family = AF_INET;
  219. dest_sockaddr.sin_port = htons(nOutPort); // Neuroflow Control Port
  220. if (OPT_LOOPBACK == nStartupOptionsFlags)
  221. dest_sockaddr.sin_addr.s_addr = inet_addr(LOOPBACK_BROADCAST);
  222. else
  223. dest_sockaddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
  224. } else { // if we still can't bind, it's an error
  225. Close();
  226. return cbRESULT_SOCKBIND;
  227. }
  228. }
  229. }
  230. if(m_bVerbose) {
  231. _cprintf("Successfully initialized network socket, bound to %s:%d\n",
  232. inet_ntoa(inst_sockaddr.sin_addr),(int)(ntohs(inst_sockaddr.sin_port)));
  233. _cprintf("Sending control packets to %s:%d\n",
  234. inet_ntoa(dest_sockaddr.sin_addr),(int)(ntohs(dest_sockaddr.sin_port)));
  235. }
  236. return cbRESULT_OK;
  237. }
  238. // Author & Date: Ehsan Azar 13 Aug 2010
  239. // Purpose: Change destination port number.
  240. // Inputs:
  241. // nOutPort - new port number
  242. void UDPSocket::OutPort(int nOutPort)
  243. {
  244. dest_sockaddr.sin_port = htons(nOutPort);
  245. }
  246. void UDPSocket::Close()
  247. {
  248. shutdown(inst_sock, SD_BOTH); // shutdown communication
  249. #ifdef WIN32
  250. closesocket(inst_sock);
  251. WSACleanup();
  252. #else
  253. close(inst_sock);
  254. #endif
  255. inst_sock = INVALID_SOCKET;
  256. }
  257. int UDPSocket::Recv(void * packet) const
  258. {
  259. int ret = recv(inst_sock, (char*)packet, m_nPacketSize, 0);
  260. if (ret != SOCKET_ERROR)
  261. return ret; // This is actual size returned
  262. else
  263. {
  264. int err = 0;
  265. #ifdef WIN32
  266. err = ::WSAGetLastError();
  267. if (err == WSAEWOULDBLOCK)
  268. return 0;
  269. TRACE("Socket Recv error was %i\n", err);
  270. #else
  271. err = errno;
  272. if (err == EAGAIN)
  273. return 0;
  274. TRACE("Socket Recv error was %i\n", err);
  275. #endif
  276. return 0;
  277. }
  278. }
  279. int UDPSocket::Send(void *ppkt, int cbBytes) const
  280. {
  281. int sendRet = sendto(inst_sock, (const char *)ppkt, cbBytes, 0,
  282. (SOCKADDR*)&dest_sockaddr, sizeof(dest_sockaddr));
  283. #ifdef WIN32
  284. DEBUG_CODE
  285. (
  286. if (sendRet == SOCKET_ERROR) {
  287. TRACE("Socket Send error was %i\n", ::WSAGetLastError());
  288. }
  289. )
  290. #else
  291. DEBUG_CODE
  292. (
  293. if (sendRet == SOCKET_ERROR) {
  294. TRACE("Socket Send error was %i\n", errno);
  295. }
  296. )
  297. #endif
  298. return sendRet;
  299. }