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.

614 lines
18KB

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