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.

633 lines
17KB

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