mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
split the socket class into StreamingSocket and DatagramSocket
This commit is contained in:
parent
93e504eb85
commit
29421641be
8 changed files with 568 additions and 186 deletions
|
|
@ -13,6 +13,7 @@ Changelist for version 1.45
|
|||
- audio plugins: new methods AudioFilterBase::beginParameterChangeGesture() and endParameterChangeGesture() let you tell the host when a parameter-change action starts and finishes.
|
||||
- new class: FileSearchPathListComponent, for letting the user edit a FileSearchPath.
|
||||
- added a critical section option to ReferenceCountedArray
|
||||
- refactored and added features to the Socket class, replacing it with StreamableSocket (basically the same as the original class), and DatagramSocket.
|
||||
|
||||
==============================================================================
|
||||
Changelist for version 1.44
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ bool InterprocessConnection::connectToSocket (const String& hostName,
|
|||
disconnect();
|
||||
|
||||
const ScopedLock sl (pipeAndSocketLock);
|
||||
socket = new Socket();
|
||||
socket = new StreamingSocket();
|
||||
|
||||
if (socket->connect (hostName, portNumber, timeOutMillisecs))
|
||||
{
|
||||
|
|
@ -186,7 +186,7 @@ bool InterprocessConnection::sendMessage (const MemoryBlock& message)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void InterprocessConnection::initialiseWithSocket (Socket* const socket_)
|
||||
void InterprocessConnection::initialiseWithSocket (StreamingSocket* const socket_)
|
||||
{
|
||||
jassert (socket == 0);
|
||||
socket = socket_;
|
||||
|
|
@ -324,7 +324,7 @@ void InterprocessConnection::run()
|
|||
{
|
||||
if (socket != 0)
|
||||
{
|
||||
const int ready = socket->isReady (0);
|
||||
const int ready = socket->waitUntilReady (true, 0);
|
||||
|
||||
if (ready < 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ public:
|
|||
|
||||
private:
|
||||
CriticalSection pipeAndSocketLock;
|
||||
Socket* socket;
|
||||
StreamingSocket* socket;
|
||||
NamedPipe* pipe;
|
||||
bool callbackConnectionState;
|
||||
const bool useMessageThread;
|
||||
|
|
@ -190,7 +190,7 @@ private:
|
|||
//==============================================================================
|
||||
friend class InterprocessConnectionServer;
|
||||
|
||||
void initialiseWithSocket (Socket* const socket_);
|
||||
void initialiseWithSocket (StreamingSocket* const socket_);
|
||||
void initialiseWithPipe (NamedPipe* const pipe_);
|
||||
|
||||
void handleMessage (const Message& message);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ bool InterprocessConnectionServer::beginWaitingForSocket (const int portNumber)
|
|||
{
|
||||
stop();
|
||||
|
||||
socket = new Socket();
|
||||
socket = new StreamingSocket();
|
||||
|
||||
if (socket->createListener (portNumber))
|
||||
{
|
||||
|
|
@ -81,7 +81,7 @@ void InterprocessConnectionServer::run()
|
|||
{
|
||||
while ((! threadShouldExit()) && socket != 0)
|
||||
{
|
||||
Socket* const clientSocket = socket->waitForNextConnection();
|
||||
StreamingSocket* const clientSocket = socket->waitForNextConnection();
|
||||
|
||||
if (clientSocket != 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public:
|
|||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
Socket* volatile socket;
|
||||
StreamingSocket* volatile socket;
|
||||
|
||||
void run();
|
||||
|
||||
|
|
|
|||
|
|
@ -83,10 +83,22 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI()
|
|||
}
|
||||
}
|
||||
|
||||
#if JUCE_WIN32
|
||||
// This is imported from the sockets code..
|
||||
typedef int (__stdcall juce_CloseWin32SocketLibCall) (void);
|
||||
extern juce_CloseWin32SocketLibCall* juce_CloseWin32SocketLib;
|
||||
#endif
|
||||
|
||||
void JUCE_PUBLIC_FUNCTION shutdownJuce_NonGUI()
|
||||
{
|
||||
if (juceInitialisedNonGUI)
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
// need to shut down sockets if they were used..
|
||||
if (juce_CloseWin32SocketLib != 0)
|
||||
(*juce_CloseWin32SocketLib)();
|
||||
#endif
|
||||
|
||||
LocalisedStrings::setCurrentMappings (0);
|
||||
Thread::stopAllThreads (3000);
|
||||
|
||||
|
|
|
|||
|
|
@ -62,76 +62,62 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../../threads/juce_Thread.h"
|
||||
|
||||
|
||||
#if JUCE_WIN32
|
||||
static CriticalSection socketInitLock;
|
||||
static int numActiveSockets = 0;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
Socket::Socket()
|
||||
: portNumber (0),
|
||||
handle (-1),
|
||||
connected (false),
|
||||
isListener (false)
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
const ScopedLock sl (socketInitLock);
|
||||
|
||||
if (numActiveSockets++ == 0)
|
||||
typedef int (__stdcall juce_CloseWin32SocketLibCall) (void);
|
||||
juce_CloseWin32SocketLibCall* juce_CloseWin32SocketLib = 0;
|
||||
|
||||
static void initWin32Sockets()
|
||||
{
|
||||
static CriticalSection lock;
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
if (juce_CloseWin32SocketLib == 0)
|
||||
{
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD (1, 1);
|
||||
const WORD wVersionRequested = MAKEWORD (1, 1);
|
||||
WSAStartup (wVersionRequested, &wsaData);
|
||||
|
||||
juce_CloseWin32SocketLib = &WSACleanup;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Socket::Socket (const String& hostName_, const int portNumber_, const int handle_)
|
||||
: hostName (hostName_),
|
||||
portNumber (portNumber_),
|
||||
handle (handle_),
|
||||
connected (true),
|
||||
isListener (false)
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
socketInitLock.enter();
|
||||
++numActiveSockets;
|
||||
socketInitLock.exit();
|
||||
#endif
|
||||
|
||||
resetSocketOptions();
|
||||
}
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
close();
|
||||
|
||||
#if JUCE_WIN32
|
||||
const ScopedLock sl (socketInitLock);
|
||||
|
||||
if (--numActiveSockets == 0)
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool Socket::resetSocketOptions()
|
||||
static bool resetSocketOptions (const int handle, const bool isDatagram) throw()
|
||||
{
|
||||
if (handle <= 0)
|
||||
return false;
|
||||
|
||||
const int sndBufSize = 65536;
|
||||
const int rcvBufSize = 65536;
|
||||
const int one = 1;
|
||||
|
||||
return setsockopt (handle, SOL_SOCKET, SO_RCVBUF, (const char*) &rcvBufSize, sizeof (int)) == 0
|
||||
&& setsockopt (handle, SOL_SOCKET, SO_SNDBUF, (const char*) &sndBufSize, sizeof (int)) == 0
|
||||
&& setsockopt (handle, IPPROTO_TCP, TCP_NODELAY, (const char*) &one, sizeof (int)) == 0;
|
||||
&& (isDatagram || (setsockopt (handle, IPPROTO_TCP, TCP_NODELAY, (const char*) &one, sizeof (int)) == 0));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int Socket::read (void* destBuffer, const int maxBytesToRead)
|
||||
static bool bindSocketToPort (const int handle, const int port) throw()
|
||||
{
|
||||
if (isListener || ! connected)
|
||||
return -1;
|
||||
if (handle == 0 || port <= 0)
|
||||
return false;
|
||||
|
||||
struct sockaddr_in servTmpAddr;
|
||||
zerostruct (servTmpAddr);
|
||||
servTmpAddr.sin_family = PF_INET;
|
||||
servTmpAddr.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||
servTmpAddr.sin_port = htons ((uint16) port);
|
||||
|
||||
return bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) >= 0;
|
||||
}
|
||||
|
||||
static int readSocket (const int handle,
|
||||
void* const destBuffer, const int maxBytesToRead,
|
||||
bool volatile& connected) throw()
|
||||
{
|
||||
int bytesRead = 0;
|
||||
|
||||
while (bytesRead < maxBytesToRead)
|
||||
|
|
@ -162,7 +148,178 @@ int Socket::read (void* destBuffer, const int maxBytesToRead)
|
|||
return bytesRead;
|
||||
}
|
||||
|
||||
int Socket::write (const void* sourceBuffer, int numBytesToWrite)
|
||||
static int waitForReadiness (const int handle, const bool forReading,
|
||||
const int timeoutMsecs) throw()
|
||||
{
|
||||
struct timeval timeout;
|
||||
struct timeval* timeoutp;
|
||||
|
||||
if (timeoutMsecs >= 0)
|
||||
{
|
||||
timeout.tv_sec = timeoutMsecs / 1000;
|
||||
timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
|
||||
timeoutp = &timeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeoutp = 0;
|
||||
}
|
||||
|
||||
fd_set rset, wset;
|
||||
FD_ZERO (&rset);
|
||||
FD_SET (handle, &rset);
|
||||
FD_ZERO (&wset);
|
||||
FD_SET (handle, &wset);
|
||||
|
||||
fd_set* const prset = forReading ? &rset : 0;
|
||||
fd_set* const pwset = forReading ? 0 : &wset;
|
||||
|
||||
#if JUCE_WIN32
|
||||
if (select (handle + 1, prset, pwset, 0, timeoutp) < 0)
|
||||
return -1;
|
||||
#else
|
||||
int result;
|
||||
while ((result = select (handle + 1, prset, pwset, 0, timeoutp)) < 0
|
||||
&& errno == EINTR)
|
||||
{
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
if ((forReading && FD_ISSET (handle, &rset))
|
||||
|| ((! forReading) && FD_ISSET (handle, &wset)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool setSocketBlockingState (const int handle, const bool shouldBlock) throw()
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
u_long nonBlocking = shouldBlock ? 0 : 1;
|
||||
|
||||
if (ioctlsocket (handle, FIONBIO, &nonBlocking) != 0)
|
||||
return false;
|
||||
#else
|
||||
int socketFlags = fcntl (handle, F_GETFL, 0);
|
||||
|
||||
if (socketFlags == -1)
|
||||
return false;
|
||||
|
||||
if (shouldBlock)
|
||||
socketFlags &= ~O_NONBLOCK;
|
||||
else
|
||||
socketFlags |= O_NONBLOCK;
|
||||
|
||||
if (fcntl (handle, F_SETFL, socketFlags) != 0)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool connectSocket (int volatile& handle,
|
||||
const bool isDatagram,
|
||||
void** serverAddress,
|
||||
const String& hostName,
|
||||
const int portNumber,
|
||||
const int timeOutMillisecs) throw()
|
||||
{
|
||||
struct hostent* const hostEnt = gethostbyname (hostName);
|
||||
|
||||
if (hostEnt == 0)
|
||||
return false;
|
||||
|
||||
struct in_addr targetAddress;
|
||||
memcpy (&targetAddress.s_addr,
|
||||
*(hostEnt->h_addr_list),
|
||||
sizeof (targetAddress.s_addr));
|
||||
|
||||
struct sockaddr_in servTmpAddr;
|
||||
zerostruct (servTmpAddr);
|
||||
servTmpAddr.sin_family = PF_INET;
|
||||
servTmpAddr.sin_addr = targetAddress;
|
||||
servTmpAddr.sin_port = htons ((uint16) portNumber);
|
||||
|
||||
handle = (int) socket (AF_INET, isDatagram ? SOCK_DGRAM : SOCK_STREAM, 0);
|
||||
|
||||
if (handle < 0)
|
||||
return false;
|
||||
|
||||
if (isDatagram)
|
||||
{
|
||||
*serverAddress = new struct sockaddr_in();
|
||||
*((struct sockaddr_in*) *serverAddress) = servTmpAddr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
setSocketBlockingState (handle, false);
|
||||
|
||||
const int result = ::connect (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in));
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
if (result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
#else
|
||||
if (result == EINPROGRESS)
|
||||
#endif
|
||||
{
|
||||
if (waitForReadiness (handle, false, timeOutMillisecs) != 1)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
setSocketBlockingState (handle, true);
|
||||
resetSocketOptions (handle, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
StreamingSocket::StreamingSocket()
|
||||
: portNumber (0),
|
||||
handle (-1),
|
||||
connected (false),
|
||||
isListener (false)
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
initWin32Sockets();
|
||||
#endif
|
||||
}
|
||||
|
||||
StreamingSocket::StreamingSocket (const String& hostName_,
|
||||
const int portNumber_,
|
||||
const int handle_)
|
||||
: hostName (hostName_),
|
||||
portNumber (portNumber_),
|
||||
handle (handle_),
|
||||
connected (true),
|
||||
isListener (false)
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
initWin32Sockets();
|
||||
#endif
|
||||
|
||||
resetSocketOptions (handle_, false);
|
||||
}
|
||||
|
||||
StreamingSocket::~StreamingSocket()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int StreamingSocket::read (void* destBuffer, const int maxBytesToRead)
|
||||
{
|
||||
return (connected && ! isListener) ? readSocket (handle, destBuffer, maxBytesToRead, connected)
|
||||
: -1;
|
||||
}
|
||||
|
||||
int StreamingSocket::write (const void* sourceBuffer, const int numBytesToWrite)
|
||||
{
|
||||
if (isListener || ! connected)
|
||||
return -1;
|
||||
|
|
@ -182,53 +339,22 @@ int Socket::write (const void* sourceBuffer, int numBytesToWrite)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
int Socket::isReady (int timeoutMsecs)
|
||||
int StreamingSocket::waitUntilReady (const bool readyForReading,
|
||||
const int timeoutMsecs) const
|
||||
{
|
||||
if (! connected)
|
||||
return -1;
|
||||
|
||||
struct timeval timeout;
|
||||
struct timeval* timeoutp;
|
||||
|
||||
if (timeoutMsecs >= 0)
|
||||
{
|
||||
timeout.tv_sec = timeoutMsecs / 1000;
|
||||
timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
|
||||
timeoutp = &timeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeoutp = 0;
|
||||
}
|
||||
|
||||
fd_set readbits;
|
||||
FD_ZERO (&readbits);
|
||||
FD_SET (handle, &readbits);
|
||||
|
||||
#if JUCE_WIN32
|
||||
if (select (handle + 1, &readbits, 0, 0, timeoutp) < 0)
|
||||
return -1;
|
||||
#else
|
||||
int result;
|
||||
while ((result = select (handle + 1, &readbits, 0, 0, timeoutp)) < 0
|
||||
&& errno == EINTR)
|
||||
{
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
if (FD_ISSET (handle, &readbits))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return connected ? waitForReadiness (handle, readyForReading, timeoutMsecs)
|
||||
: -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool Socket::connect (const String& newHostName,
|
||||
int newPortNumber,
|
||||
int timeOutMillisecs)
|
||||
bool StreamingSocket::bindToPort (const int port)
|
||||
{
|
||||
return bindSocketToPort (handle, port);
|
||||
}
|
||||
|
||||
bool StreamingSocket::connect (const String& remoteHostName,
|
||||
const int remotePortNumber,
|
||||
const int timeOutMillisecs)
|
||||
{
|
||||
if (isListener)
|
||||
{
|
||||
|
|
@ -239,51 +365,14 @@ bool Socket::connect (const String& newHostName,
|
|||
if (connected)
|
||||
close();
|
||||
|
||||
hostName = newHostName;
|
||||
portNumber = newPortNumber;
|
||||
hostName = remoteHostName;
|
||||
portNumber = remotePortNumber;
|
||||
isListener = false;
|
||||
|
||||
struct hostent* hostEnt = gethostbyname (hostName);
|
||||
connected = connectSocket (handle, false, 0, remoteHostName,
|
||||
remotePortNumber, timeOutMillisecs);
|
||||
|
||||
if (! hostEnt)
|
||||
return false;
|
||||
|
||||
struct in_addr targetAddress;
|
||||
memcpy (&targetAddress.s_addr,
|
||||
*(hostEnt->h_addr_list),
|
||||
sizeof (targetAddress.s_addr));
|
||||
|
||||
struct sockaddr_in servTmpAddr;
|
||||
zerostruct (servTmpAddr);
|
||||
servTmpAddr.sin_family = PF_INET;
|
||||
servTmpAddr.sin_addr = targetAddress;
|
||||
servTmpAddr.sin_port = htons ((uint16) portNumber);
|
||||
|
||||
handle = (int) socket (AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (handle < 0)
|
||||
return false;
|
||||
|
||||
while (timeOutMillisecs > 0 || timeOutMillisecs < 0)
|
||||
{
|
||||
if (handle < 0)
|
||||
return false;
|
||||
|
||||
if (::connect (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) >= 0)
|
||||
{
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeOutMillisecs > 0)
|
||||
{
|
||||
const int timeToSleep = jmin (timeOutMillisecs, 1000);
|
||||
timeOutMillisecs -= timeToSleep;
|
||||
Thread::sleep (timeToSleep);
|
||||
}
|
||||
}
|
||||
|
||||
if (! (connected && resetSocketOptions()))
|
||||
if (! (connected && resetSocketOptions (handle, false)))
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
|
|
@ -292,10 +381,11 @@ bool Socket::connect (const String& newHostName,
|
|||
return true;
|
||||
}
|
||||
|
||||
void Socket::close()
|
||||
void StreamingSocket::close()
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
closesocket (handle);
|
||||
connected = false;
|
||||
#else
|
||||
if (connected)
|
||||
{
|
||||
|
|
@ -304,7 +394,7 @@ void Socket::close()
|
|||
if (isListener)
|
||||
{
|
||||
// need to do this to interrupt the accept() function..
|
||||
Socket temp;
|
||||
StreamingSocket temp;
|
||||
temp.connect ("localhost", portNumber, 1000);
|
||||
}
|
||||
}
|
||||
|
|
@ -315,12 +405,11 @@ void Socket::close()
|
|||
hostName = String::empty;
|
||||
portNumber = 0;
|
||||
handle = -1;
|
||||
connected = false;
|
||||
isListener = false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool Socket::createListener (int newPortNumber)
|
||||
bool StreamingSocket::createListener (const int newPortNumber)
|
||||
{
|
||||
if (connected)
|
||||
close();
|
||||
|
|
@ -354,7 +443,7 @@ bool Socket::createListener (int newPortNumber)
|
|||
return true;
|
||||
}
|
||||
|
||||
Socket* Socket::waitForNextConnection()
|
||||
StreamingSocket* StreamingSocket::waitForNextConnection() const
|
||||
{
|
||||
jassert (isListener || ! connected); // to call this method, you first have to use createListener() to
|
||||
// prepare this socket as a listener.
|
||||
|
|
@ -371,15 +460,153 @@ Socket* Socket::waitForNextConnection()
|
|||
const int newSocket = (int) accept (handle, &address, &len);
|
||||
|
||||
if (newSocket >= 0 && connected)
|
||||
return new Socket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
|
||||
portNumber, newSocket);
|
||||
return new StreamingSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
|
||||
portNumber, newSocket);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool StreamingSocket::isLocal() const throw()
|
||||
{
|
||||
return hostName == T("127.0.0.1");
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
DatagramSocket::DatagramSocket (const int localPortNumber)
|
||||
: portNumber (0),
|
||||
handle (-1),
|
||||
connected (false),
|
||||
serverAddress (0)
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
initWin32Sockets();
|
||||
#endif
|
||||
|
||||
bindToPort (localPortNumber);
|
||||
}
|
||||
|
||||
DatagramSocket::DatagramSocket (const String& hostName_, const int portNumber_,
|
||||
const int handle_, const int localPortNumber)
|
||||
: hostName (hostName_),
|
||||
portNumber (portNumber_),
|
||||
handle (handle_),
|
||||
connected (true),
|
||||
serverAddress (0)
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
initWin32Sockets();
|
||||
#endif
|
||||
|
||||
resetSocketOptions (handle_, true);
|
||||
bindToPort (localPortNumber);
|
||||
}
|
||||
|
||||
DatagramSocket::~DatagramSocket()
|
||||
{
|
||||
close();
|
||||
|
||||
delete ((struct sockaddr_in*) serverAddress);
|
||||
serverAddress = 0;
|
||||
}
|
||||
|
||||
void DatagramSocket::close()
|
||||
{
|
||||
#if JUCE_WIN32
|
||||
closesocket (handle);
|
||||
connected = false;
|
||||
#else
|
||||
connected = false;
|
||||
::close (handle);
|
||||
#endif
|
||||
|
||||
hostName = String::empty;
|
||||
portNumber = 0;
|
||||
handle = -1;
|
||||
}
|
||||
|
||||
bool DatagramSocket::bindToPort (const int port)
|
||||
{
|
||||
return bindSocketToPort (handle, port);
|
||||
}
|
||||
|
||||
bool DatagramSocket::connect (const String& remoteHostName,
|
||||
const int remotePortNumber,
|
||||
const int timeOutMillisecs)
|
||||
{
|
||||
if (connected)
|
||||
close();
|
||||
|
||||
hostName = remoteHostName;
|
||||
portNumber = remotePortNumber;
|
||||
|
||||
connected = connectSocket (handle, true, &serverAddress,
|
||||
remoteHostName, remotePortNumber,
|
||||
timeOutMillisecs);
|
||||
|
||||
if (! (connected && resetSocketOptions (handle, true)))
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DatagramSocket* DatagramSocket::waitForNextConnection() const
|
||||
{
|
||||
struct sockaddr address;
|
||||
|
||||
#if defined (JUCE_LINUX) || (defined (JUCE_MAC) && ! MACOS_10_2_OR_EARLIER)
|
||||
socklen_t len = sizeof (sockaddr);
|
||||
#else
|
||||
int len = sizeof (sockaddr);
|
||||
#endif
|
||||
|
||||
while (waitUntilReady (true, -1) == 1)
|
||||
{
|
||||
char buf[1];
|
||||
|
||||
if (recvfrom (handle, buf, 0, 0, &address, &len) > 0)
|
||||
{
|
||||
return new DatagramSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
|
||||
ntohs (((struct sockaddr_in*) &address)->sin_port),
|
||||
-1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool Socket::isLocal() const throw()
|
||||
int DatagramSocket::waitUntilReady (const bool readyForReading,
|
||||
const int timeoutMsecs) const
|
||||
{
|
||||
return connected ? waitForReadiness (handle, readyForReading, timeoutMsecs)
|
||||
: -1;
|
||||
}
|
||||
|
||||
int DatagramSocket::read (void* destBuffer, const int maxBytesToRead)
|
||||
{
|
||||
return connected ? readSocket (handle, destBuffer, maxBytesToRead, connected)
|
||||
: -1;
|
||||
}
|
||||
|
||||
int DatagramSocket::write (const void* sourceBuffer, const int numBytesToWrite)
|
||||
{
|
||||
// You need to call connect() first to set the server address..
|
||||
jassert (serverAddress != 0 && connected);
|
||||
|
||||
return connected ? sendto (handle, (const char*) sourceBuffer,
|
||||
numBytesToWrite, 0,
|
||||
(const struct sockaddr*) serverAddress,
|
||||
sizeof (struct sockaddr_in))
|
||||
: -1;
|
||||
}
|
||||
|
||||
bool DatagramSocket::isLocal() const throw()
|
||||
{
|
||||
return hostName == T("127.0.0.1");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,14 +37,14 @@
|
|||
|
||||
//==============================================================================
|
||||
/**
|
||||
A wrapper for a socket.
|
||||
A wrapper for a streaming (TCP) socket.
|
||||
|
||||
Allows low-level use of sockets; for an easier-to-use messaging layer on top of
|
||||
This allows low-level use of sockets; for an easier-to-use messaging layer on top of
|
||||
sockets, you could also try the InterprocessConnection class.
|
||||
|
||||
@see InterprocessConnection, InterprocessConnectionServer
|
||||
@see DatagramSocket, InterprocessConnection, InterprocessConnectionServer
|
||||
*/
|
||||
class JUCE_API Socket
|
||||
class JUCE_API StreamingSocket
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
|
@ -57,49 +57,37 @@ public:
|
|||
enters "listener" mode, and can be used to spawn new sockets for each connection
|
||||
that comes along.
|
||||
*/
|
||||
Socket();
|
||||
StreamingSocket();
|
||||
|
||||
/** Destructor. */
|
||||
~Socket();
|
||||
~StreamingSocket();
|
||||
|
||||
//==============================================================================
|
||||
// Tests if the socket is ready
|
||||
// Returns: 1 == yes, 0 == no, -1 == error
|
||||
int isReady (int timeoutMsecs = 0);
|
||||
/** Binds the socket to the specified local port.
|
||||
|
||||
//==============================================================================
|
||||
/** Reads bytes from the socket (blocking).
|
||||
|
||||
Returns the number of bytes read, or -1 if there was an error.
|
||||
@returns true on success; false may indicate that another socket is already bound
|
||||
on the same port
|
||||
*/
|
||||
int read (void* destBuffer, const int maxBytesToRead);
|
||||
bool bindToPort (const int localPortNumber);
|
||||
|
||||
/** Writes bytes to the socket from a buffer.
|
||||
|
||||
This may block on error conditions.
|
||||
|
||||
Returns the number of bytes written, or -1 if there was an error.
|
||||
*/
|
||||
int write (const void* sourceBuffer, int numBytesToWrite);
|
||||
|
||||
//==============================================================================
|
||||
/** Tries to connect the socket to hostname:port.
|
||||
|
||||
Returns true if it succeeds.
|
||||
If timeOutMillisecs is 0, then this method will block until the operating system
|
||||
rejects the connection (which could take a long time).
|
||||
|
||||
@returns true if it succeeds.
|
||||
@see isConnected
|
||||
*/
|
||||
bool connect (const String& hostname,
|
||||
int portNumber,
|
||||
int timeOutMillisecs = 3000);
|
||||
bool connect (const String& remoteHostname,
|
||||
const int remotePortNumber,
|
||||
const int timeOutMillisecs = 3000);
|
||||
|
||||
/** True if the socket is currently connected. */
|
||||
bool isConnected() const throw() { return connected; }
|
||||
|
||||
/** Closes the connection. */
|
||||
void close();
|
||||
|
||||
//==============================================================================
|
||||
/** True if the socket is currently connected. */
|
||||
bool isConnected() const throw() { return connected; }
|
||||
|
||||
/** Returns the name of the currently connected host. */
|
||||
const String& getHostName() const throw() { return hostName; }
|
||||
|
||||
|
|
@ -109,6 +97,39 @@ public:
|
|||
/** True if the socket is connected to this machine rather than over the network. */
|
||||
bool isLocal() const throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Waits until the socket is ready for reading or writing.
|
||||
|
||||
If readyForReading is true, it will wait until the socket is ready for
|
||||
reading; if false, it will wait until it's ready for writing.
|
||||
|
||||
If the timeout is < 0, it will wait forever, or else will give up after
|
||||
the specified time.
|
||||
|
||||
If the socket is ready on return, this returns 1. If it times-out before
|
||||
the socket becomes ready, it returns 0. If an error occurs, it returns -1.
|
||||
*/
|
||||
int waitUntilReady (const bool readyForReading,
|
||||
const int timeoutMsecs) const;
|
||||
|
||||
/** Reads bytes from the socket (blocking).
|
||||
|
||||
Note that this method will block unless you have checked the socket is ready
|
||||
for reading before calling it (see the waitUntilReady() method).
|
||||
|
||||
@returns the number of bytes read, or -1 if there was an error.
|
||||
*/
|
||||
int read (void* destBuffer, const int maxBytesToRead);
|
||||
|
||||
/** Writes bytes to the socket from a buffer.
|
||||
|
||||
Note that this method will block unless you have checked the socket is ready
|
||||
for writing before calling it (see the waitUntilReady() method).
|
||||
|
||||
@returns the number of bytes written, or -1 if there was an error.
|
||||
*/
|
||||
int write (const void* sourceBuffer, const int numBytesToWrite);
|
||||
|
||||
//==============================================================================
|
||||
/** Puts this socket into "listener" mode.
|
||||
|
||||
|
|
@ -120,7 +141,7 @@ public:
|
|||
|
||||
@see waitForNextConnection
|
||||
*/
|
||||
bool createListener (int portNumber);
|
||||
bool createListener (const int portNumber);
|
||||
|
||||
/** When in "listener" mode, this waits for a connection and spawns it as a new
|
||||
socket.
|
||||
|
|
@ -131,7 +152,7 @@ public:
|
|||
|
||||
@see createListener
|
||||
*/
|
||||
Socket* waitForNextConnection();
|
||||
StreamingSocket* waitForNextConnection() const;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -142,11 +163,132 @@ private:
|
|||
int volatile portNumber, handle;
|
||||
bool connected, isListener;
|
||||
|
||||
Socket (const String& hostname, const int portNumber, const int handle);
|
||||
Socket (const Socket&);
|
||||
const Socket& operator= (const Socket&);
|
||||
StreamingSocket (const String& hostname, const int portNumber, const int handle);
|
||||
StreamingSocket (const StreamingSocket&);
|
||||
const StreamingSocket& operator= (const StreamingSocket&);
|
||||
};
|
||||
|
||||
bool resetSocketOptions();
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A wrapper for a datagram (UDP) socket.
|
||||
|
||||
This allows low-level use of sockets; for an easier-to-use messaging layer on top of
|
||||
sockets, you could also try the InterprocessConnection class.
|
||||
|
||||
@see StreamingSocket, InterprocessConnection, InterprocessConnectionServer
|
||||
*/
|
||||
class JUCE_API DatagramSocket
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/**
|
||||
Creates an (uninitialised) datagram socket.
|
||||
|
||||
The localPortNumber is the port on which to bind this socket. If this value is 0,
|
||||
the port number is assigned by the operating system.
|
||||
|
||||
To use the socket for sending, call the connect() method. This will not immediately
|
||||
make a connection, but will save the destination you've provided. After this, you can
|
||||
call read() or write().
|
||||
|
||||
To wait for other sockets to connect to this one, call waitForNextConnection().
|
||||
*/
|
||||
DatagramSocket (const int localPortNumber);
|
||||
|
||||
/** Destructor. */
|
||||
~DatagramSocket();
|
||||
|
||||
//==============================================================================
|
||||
/** Binds the socket to the specified local port.
|
||||
|
||||
@returns true on success; false may indicate that another socket is already bound
|
||||
on the same port
|
||||
*/
|
||||
bool bindToPort (const int localPortNumber);
|
||||
|
||||
/** Tries to connect the socket to hostname:port.
|
||||
|
||||
If timeOutMillisecs is 0, then this method will block until the operating system
|
||||
rejects the connection (which could take a long time).
|
||||
|
||||
@returns true if it succeeds.
|
||||
@see isConnected
|
||||
*/
|
||||
bool connect (const String& remoteHostname,
|
||||
const int remotePortNumber,
|
||||
const int timeOutMillisecs = 3000);
|
||||
|
||||
/** True if the socket is currently connected. */
|
||||
bool isConnected() const throw() { return connected; }
|
||||
|
||||
/** Closes the connection. */
|
||||
void close();
|
||||
|
||||
/** Returns the name of the currently connected host. */
|
||||
const String& getHostName() const throw() { return hostName; }
|
||||
|
||||
/** Returns the port number that's currently open. */
|
||||
int getPort() const throw() { return portNumber; }
|
||||
|
||||
/** True if the socket is connected to this machine rather than over the network. */
|
||||
bool isLocal() const throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Waits until the socket is ready for reading or writing.
|
||||
|
||||
If readyForReading is true, it will wait until the socket is ready for
|
||||
reading; if false, it will wait until it's ready for writing.
|
||||
|
||||
If the timeout is < 0, it will wait forever, or else will give up after
|
||||
the specified time.
|
||||
|
||||
If the socket is ready on return, this returns 1. If it times-out before
|
||||
the socket becomes ready, it returns 0. If an error occurs, it returns -1.
|
||||
*/
|
||||
int waitUntilReady (const bool readyForReading,
|
||||
const int timeoutMsecs) const;
|
||||
|
||||
/** Reads bytes from the socket (blocking).
|
||||
|
||||
Note that this method will block unless you have checked the socket is ready
|
||||
for reading before calling it (see the waitUntilReady() method).
|
||||
|
||||
@returns the number of bytes read, or -1 if there was an error.
|
||||
*/
|
||||
int read (void* destBuffer, const int maxBytesToRead);
|
||||
|
||||
/** Writes bytes to the socket from a buffer.
|
||||
|
||||
Note that this method will block unless you have checked the socket is ready
|
||||
for writing before calling it (see the waitUntilReady() method).
|
||||
|
||||
@returns the number of bytes written, or -1 if there was an error.
|
||||
*/
|
||||
int write (const void* sourceBuffer, const int numBytesToWrite);
|
||||
|
||||
//==============================================================================
|
||||
/** This waits for incoming data to be sent, and returns a socket that can be used
|
||||
to read it.
|
||||
|
||||
The object that gets returned is owned by the caller, and can't be used for
|
||||
sending, but can be used to read the data.
|
||||
*/
|
||||
DatagramSocket* waitForNextConnection() const;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
String hostName;
|
||||
int volatile portNumber, handle;
|
||||
bool connected;
|
||||
void* serverAddress;
|
||||
|
||||
DatagramSocket (const String& hostname, const int portNumber, const int handle, const int localPortNumber);
|
||||
DatagramSocket (const DatagramSocket&);
|
||||
const DatagramSocket& operator= (const DatagramSocket&);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue