The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

630 lines
18KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../../core/juce_TargetPlatform.h"
  19. #if JUCE_WINDOWS
  20. #include <winsock2.h>
  21. #include <ws2tcpip.h>
  22. #if JUCE_MSVC
  23. #pragma warning (push)
  24. #pragma warning (disable : 4127 4389 4018)
  25. #endif
  26. #else
  27. #if JUCE_LINUX || JUCE_ANDROID
  28. #include <sys/types.h>
  29. #include <sys/socket.h>
  30. #include <sys/errno.h>
  31. #include <unistd.h>
  32. #include <netinet/in.h>
  33. #endif
  34. #include <fcntl.h>
  35. #include <netdb.h>
  36. #include <arpa/inet.h>
  37. #include <netinet/tcp.h>
  38. #ifndef AI_NUMERICSERV // (missing in older Mac SDKs)
  39. #define AI_NUMERICSERV 0x1000
  40. #endif
  41. #endif
  42. #include "../../core/juce_StandardHeader.h"
  43. BEGIN_JUCE_NAMESPACE
  44. #include "juce_Socket.h"
  45. #include "../../threads/juce_ScopedLock.h"
  46. #include "../../threads/juce_Thread.h"
  47. #include "../../utilities/juce_DeletedAtShutdown.h"
  48. #if JUCE_WINDOWS
  49. typedef int juce_socklen_t;
  50. #else
  51. typedef socklen_t juce_socklen_t;
  52. #endif
  53. //==============================================================================
  54. namespace SocketHelpers
  55. {
  56. #if JUCE_WINDOWS
  57. class WinSocketStarter : public DeletedAtShutdown
  58. {
  59. public:
  60. WinSocketStarter()
  61. {
  62. WSADATA wsaData;
  63. const WORD wVersionRequested = MAKEWORD (1, 1);
  64. WSAStartup (wVersionRequested, &wsaData);
  65. }
  66. ~WinSocketStarter()
  67. {
  68. WSACleanup();
  69. clearSingletonInstance();
  70. }
  71. juce_DeclareSingleton (WinSocketStarter, false);
  72. };
  73. juce_ImplementSingleton (WinSocketStarter);
  74. void initSockets() { WinSocketStarter::getInstance(); }
  75. #else
  76. void initSockets() {}
  77. #endif
  78. bool resetSocketOptions (const int handle, const bool isDatagram, const bool allowBroadcast) throw()
  79. {
  80. const int sndBufSize = 65536;
  81. const int rcvBufSize = 65536;
  82. const int one = 1;
  83. return handle > 0
  84. && setsockopt (handle, SOL_SOCKET, SO_RCVBUF, (const char*) &rcvBufSize, sizeof (rcvBufSize)) == 0
  85. && setsockopt (handle, SOL_SOCKET, SO_SNDBUF, (const char*) &sndBufSize, sizeof (sndBufSize)) == 0
  86. && (isDatagram ? ((! allowBroadcast) || setsockopt (handle, SOL_SOCKET, SO_BROADCAST, (const char*) &one, sizeof (one)) == 0)
  87. : (setsockopt (handle, IPPROTO_TCP, TCP_NODELAY, (const char*) &one, sizeof (one)) == 0));
  88. }
  89. bool bindSocketToPort (const int handle, const int port) throw()
  90. {
  91. if (handle <= 0 || port <= 0)
  92. return false;
  93. struct sockaddr_in servTmpAddr;
  94. zerostruct (servTmpAddr);
  95. servTmpAddr.sin_family = PF_INET;
  96. servTmpAddr.sin_addr.s_addr = htonl (INADDR_ANY);
  97. servTmpAddr.sin_port = htons ((uint16) port);
  98. return bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) >= 0;
  99. }
  100. int readSocket (const int handle,
  101. void* const destBuffer, const int maxBytesToRead,
  102. bool volatile& connected,
  103. const bool blockUntilSpecifiedAmountHasArrived) throw()
  104. {
  105. int bytesRead = 0;
  106. while (bytesRead < maxBytesToRead)
  107. {
  108. int bytesThisTime;
  109. #if JUCE_WINDOWS
  110. bytesThisTime = recv (handle, static_cast<char*> (destBuffer) + bytesRead, maxBytesToRead - bytesRead, 0);
  111. #else
  112. while ((bytesThisTime = (int) ::read (handle, addBytesToPointer (destBuffer, bytesRead), maxBytesToRead - bytesRead)) < 0
  113. && errno == EINTR
  114. && connected)
  115. {
  116. }
  117. #endif
  118. if (bytesThisTime <= 0 || ! connected)
  119. {
  120. if (bytesRead == 0)
  121. bytesRead = -1;
  122. break;
  123. }
  124. bytesRead += bytesThisTime;
  125. if (! blockUntilSpecifiedAmountHasArrived)
  126. break;
  127. }
  128. return bytesRead;
  129. }
  130. int waitForReadiness (const int handle, const bool forReading, const int timeoutMsecs) throw()
  131. {
  132. struct timeval timeout;
  133. struct timeval* timeoutp;
  134. if (timeoutMsecs >= 0)
  135. {
  136. timeout.tv_sec = timeoutMsecs / 1000;
  137. timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
  138. timeoutp = &timeout;
  139. }
  140. else
  141. {
  142. timeoutp = 0;
  143. }
  144. fd_set rset, wset;
  145. FD_ZERO (&rset);
  146. FD_SET (handle, &rset);
  147. FD_ZERO (&wset);
  148. FD_SET (handle, &wset);
  149. fd_set* const prset = forReading ? &rset : 0;
  150. fd_set* const pwset = forReading ? 0 : &wset;
  151. #if JUCE_WINDOWS
  152. if (select (handle + 1, prset, pwset, 0, timeoutp) < 0)
  153. return -1;
  154. #else
  155. {
  156. int result;
  157. while ((result = select (handle + 1, prset, pwset, 0, timeoutp)) < 0
  158. && errno == EINTR)
  159. {
  160. }
  161. if (result < 0)
  162. return -1;
  163. }
  164. #endif
  165. {
  166. int opt;
  167. juce_socklen_t len = sizeof (opt);
  168. if (getsockopt (handle, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0
  169. || opt != 0)
  170. return -1;
  171. }
  172. return FD_ISSET (handle, forReading ? &rset : &wset) ? 1 : 0;
  173. }
  174. bool setSocketBlockingState (const int handle, const bool shouldBlock) throw()
  175. {
  176. #if JUCE_WINDOWS
  177. u_long nonBlocking = shouldBlock ? 0 : 1;
  178. return ioctlsocket (handle, FIONBIO, &nonBlocking) == 0;
  179. #else
  180. int socketFlags = fcntl (handle, F_GETFL, 0);
  181. if (socketFlags == -1)
  182. return false;
  183. if (shouldBlock)
  184. socketFlags &= ~O_NONBLOCK;
  185. else
  186. socketFlags |= O_NONBLOCK;
  187. return fcntl (handle, F_SETFL, socketFlags) == 0;
  188. #endif
  189. }
  190. bool connectSocket (int volatile& handle,
  191. const bool isDatagram,
  192. void** serverAddress,
  193. const String& hostName,
  194. const int portNumber,
  195. const int timeOutMillisecs) throw()
  196. {
  197. struct addrinfo hints;
  198. zerostruct (hints);
  199. hints.ai_family = AF_UNSPEC;
  200. hints.ai_socktype = isDatagram ? SOCK_DGRAM : SOCK_STREAM;
  201. hints.ai_flags = AI_NUMERICSERV;
  202. struct addrinfo* info = 0;
  203. if (getaddrinfo (hostName.toUTF8(), String (portNumber).toUTF8(), &hints, &info) != 0 || info == 0)
  204. return false;
  205. if (handle < 0)
  206. handle = (int) socket (info->ai_family, info->ai_socktype, 0);
  207. if (handle < 0)
  208. {
  209. freeaddrinfo (info);
  210. return false;
  211. }
  212. if (isDatagram)
  213. {
  214. struct sockaddr* s = new struct sockaddr();
  215. *s = *(info->ai_addr);
  216. *serverAddress = s;
  217. freeaddrinfo (info);
  218. return true;
  219. }
  220. setSocketBlockingState (handle, false);
  221. const int result = ::connect (handle, info->ai_addr, info->ai_addrlen);
  222. freeaddrinfo (info);
  223. if (result < 0)
  224. {
  225. #if JUCE_WINDOWS
  226. if (result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
  227. #else
  228. if (errno == EINPROGRESS)
  229. #endif
  230. {
  231. if (waitForReadiness (handle, false, timeOutMillisecs) != 1)
  232. {
  233. setSocketBlockingState (handle, true);
  234. return false;
  235. }
  236. }
  237. }
  238. setSocketBlockingState (handle, true);
  239. resetSocketOptions (handle, false, false);
  240. return true;
  241. }
  242. }
  243. //==============================================================================
  244. StreamingSocket::StreamingSocket()
  245. : portNumber (0),
  246. handle (-1),
  247. connected (false),
  248. isListener (false)
  249. {
  250. SocketHelpers::initSockets();
  251. }
  252. StreamingSocket::StreamingSocket (const String& hostName_,
  253. const int portNumber_,
  254. const int handle_)
  255. : hostName (hostName_),
  256. portNumber (portNumber_),
  257. handle (handle_),
  258. connected (true),
  259. isListener (false)
  260. {
  261. SocketHelpers::initSockets();
  262. SocketHelpers::resetSocketOptions (handle_, false, false);
  263. }
  264. StreamingSocket::~StreamingSocket()
  265. {
  266. close();
  267. }
  268. //==============================================================================
  269. int StreamingSocket::read (void* destBuffer, const int maxBytesToRead, const bool blockUntilSpecifiedAmountHasArrived)
  270. {
  271. return (connected && ! isListener) ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, connected, blockUntilSpecifiedAmountHasArrived)
  272. : -1;
  273. }
  274. int StreamingSocket::write (const void* sourceBuffer, const int numBytesToWrite)
  275. {
  276. if (isListener || ! connected)
  277. return -1;
  278. #if JUCE_WINDOWS
  279. return send (handle, (const char*) sourceBuffer, numBytesToWrite, 0);
  280. #else
  281. int result;
  282. while ((result = (int) ::write (handle, sourceBuffer, numBytesToWrite)) < 0
  283. && errno == EINTR)
  284. {
  285. }
  286. return result;
  287. #endif
  288. }
  289. //==============================================================================
  290. int StreamingSocket::waitUntilReady (const bool readyForReading,
  291. const int timeoutMsecs) const
  292. {
  293. return connected ? SocketHelpers::waitForReadiness (handle, readyForReading, timeoutMsecs)
  294. : -1;
  295. }
  296. //==============================================================================
  297. bool StreamingSocket::bindToPort (const int port)
  298. {
  299. return SocketHelpers::bindSocketToPort (handle, port);
  300. }
  301. bool StreamingSocket::connect (const String& remoteHostName,
  302. const int remotePortNumber,
  303. const int timeOutMillisecs)
  304. {
  305. if (isListener)
  306. {
  307. jassertfalse; // a listener socket can't connect to another one!
  308. return false;
  309. }
  310. if (connected)
  311. close();
  312. hostName = remoteHostName;
  313. portNumber = remotePortNumber;
  314. isListener = false;
  315. connected = SocketHelpers::connectSocket (handle, false, 0, remoteHostName,
  316. remotePortNumber, timeOutMillisecs);
  317. if (! (connected && SocketHelpers::resetSocketOptions (handle, false, false)))
  318. {
  319. close();
  320. return false;
  321. }
  322. return true;
  323. }
  324. void StreamingSocket::close()
  325. {
  326. #if JUCE_WINDOWS
  327. if (handle != SOCKET_ERROR || connected)
  328. closesocket (handle);
  329. connected = false;
  330. #else
  331. if (connected)
  332. {
  333. connected = false;
  334. if (isListener)
  335. {
  336. // need to do this to interrupt the accept() function..
  337. StreamingSocket temp;
  338. temp.connect ("localhost", portNumber, 1000);
  339. }
  340. }
  341. if (handle != -1)
  342. ::close (handle);
  343. #endif
  344. hostName = String::empty;
  345. portNumber = 0;
  346. handle = -1;
  347. isListener = false;
  348. }
  349. //==============================================================================
  350. bool StreamingSocket::createListener (const int newPortNumber, const String& localHostName)
  351. {
  352. if (connected)
  353. close();
  354. hostName = "listener";
  355. portNumber = newPortNumber;
  356. isListener = true;
  357. struct sockaddr_in servTmpAddr;
  358. zerostruct (servTmpAddr);
  359. servTmpAddr.sin_family = PF_INET;
  360. servTmpAddr.sin_addr.s_addr = htonl (INADDR_ANY);
  361. if (localHostName.isNotEmpty())
  362. servTmpAddr.sin_addr.s_addr = ::inet_addr (localHostName.toUTF8());
  363. servTmpAddr.sin_port = htons ((uint16) portNumber);
  364. handle = (int) socket (AF_INET, SOCK_STREAM, 0);
  365. if (handle < 0)
  366. return false;
  367. const int reuse = 1;
  368. setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse));
  369. if (bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) < 0
  370. || listen (handle, SOMAXCONN) < 0)
  371. {
  372. close();
  373. return false;
  374. }
  375. connected = true;
  376. return true;
  377. }
  378. StreamingSocket* StreamingSocket::waitForNextConnection() const
  379. {
  380. jassert (isListener || ! connected); // to call this method, you first have to use createListener() to
  381. // prepare this socket as a listener.
  382. if (connected && isListener)
  383. {
  384. struct sockaddr address;
  385. juce_socklen_t len = sizeof (sockaddr);
  386. const int newSocket = (int) accept (handle, &address, &len);
  387. if (newSocket >= 0 && connected)
  388. return new StreamingSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
  389. portNumber, newSocket);
  390. }
  391. return 0;
  392. }
  393. bool StreamingSocket::isLocal() const throw()
  394. {
  395. return hostName == "127.0.0.1";
  396. }
  397. //==============================================================================
  398. //==============================================================================
  399. DatagramSocket::DatagramSocket (const int localPortNumber, const bool allowBroadcast_)
  400. : portNumber (0),
  401. handle (-1),
  402. connected (true),
  403. allowBroadcast (allowBroadcast_),
  404. serverAddress (0)
  405. {
  406. SocketHelpers::initSockets();
  407. handle = (int) socket (AF_INET, SOCK_DGRAM, 0);
  408. bindToPort (localPortNumber);
  409. }
  410. DatagramSocket::DatagramSocket (const String& hostName_, const int portNumber_,
  411. const int handle_, const int localPortNumber)
  412. : hostName (hostName_),
  413. portNumber (portNumber_),
  414. handle (handle_),
  415. connected (true),
  416. allowBroadcast (false),
  417. serverAddress (0)
  418. {
  419. SocketHelpers::initSockets();
  420. SocketHelpers::resetSocketOptions (handle_, true, allowBroadcast);
  421. bindToPort (localPortNumber);
  422. }
  423. DatagramSocket::~DatagramSocket()
  424. {
  425. close();
  426. delete static_cast <struct sockaddr*> (serverAddress);
  427. serverAddress = 0;
  428. }
  429. void DatagramSocket::close()
  430. {
  431. #if JUCE_WINDOWS
  432. closesocket (handle);
  433. connected = false;
  434. #else
  435. connected = false;
  436. ::close (handle);
  437. #endif
  438. hostName = String::empty;
  439. portNumber = 0;
  440. handle = -1;
  441. }
  442. bool DatagramSocket::bindToPort (const int port)
  443. {
  444. return SocketHelpers::bindSocketToPort (handle, port);
  445. }
  446. bool DatagramSocket::connect (const String& remoteHostName,
  447. const int remotePortNumber,
  448. const int timeOutMillisecs)
  449. {
  450. if (connected)
  451. close();
  452. hostName = remoteHostName;
  453. portNumber = remotePortNumber;
  454. connected = SocketHelpers::connectSocket (handle, true, &serverAddress,
  455. remoteHostName, remotePortNumber,
  456. timeOutMillisecs);
  457. if (! (connected && SocketHelpers::resetSocketOptions (handle, true, allowBroadcast)))
  458. {
  459. close();
  460. return false;
  461. }
  462. return true;
  463. }
  464. DatagramSocket* DatagramSocket::waitForNextConnection() const
  465. {
  466. struct sockaddr address;
  467. juce_socklen_t len = sizeof (sockaddr);
  468. while (waitUntilReady (true, -1) == 1)
  469. {
  470. char buf[1];
  471. if (recvfrom (handle, buf, 0, 0, &address, &len) > 0)
  472. {
  473. return new DatagramSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
  474. ntohs (((struct sockaddr_in*) &address)->sin_port),
  475. -1, -1);
  476. }
  477. }
  478. return 0;
  479. }
  480. //==============================================================================
  481. int DatagramSocket::waitUntilReady (const bool readyForReading,
  482. const int timeoutMsecs) const
  483. {
  484. return connected ? SocketHelpers::waitForReadiness (handle, readyForReading, timeoutMsecs)
  485. : -1;
  486. }
  487. int DatagramSocket::read (void* destBuffer, const int maxBytesToRead, const bool blockUntilSpecifiedAmountHasArrived)
  488. {
  489. return connected ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, connected, blockUntilSpecifiedAmountHasArrived)
  490. : -1;
  491. }
  492. int DatagramSocket::write (const void* sourceBuffer, const int numBytesToWrite)
  493. {
  494. // You need to call connect() first to set the server address..
  495. jassert (serverAddress != 0 && connected);
  496. return connected ? (int) sendto (handle, (const char*) sourceBuffer,
  497. numBytesToWrite, 0,
  498. (const struct sockaddr*) serverAddress,
  499. sizeof (struct sockaddr_in))
  500. : -1;
  501. }
  502. bool DatagramSocket::isLocal() const throw()
  503. {
  504. return hostName == "127.0.0.1";
  505. }
  506. #if JUCE_MSVC
  507. #pragma warning (pop)
  508. #endif
  509. END_JUCE_NAMESPACE