| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2020 - Raw Material Software Limited
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    The code included in this file is provided under the terms of the ISC license
 -    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 -    To use, copy, modify, and/or distribute this software for any purpose with or
 -    without fee is hereby granted provided that the above copyright notice and
 -    this permission notice appear in all copies.
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace juce
 - {
 - 
 - struct InterprocessConnection::ConnectionThread  : public Thread
 - {
 -     ConnectionThread (InterprocessConnection& c)  : Thread ("JUCE IPC"), owner (c) {}
 -     void run() override     { owner.runThread(); }
 - 
 -     InterprocessConnection& owner;
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConnectionThread)
 - };
 - 
 - //==============================================================================
 - InterprocessConnection::InterprocessConnection (bool callbacksOnMessageThread, uint32 magicMessageHeaderNumber)
 -     : useMessageThread (callbacksOnMessageThread),
 -       magicMessageHeader (magicMessageHeaderNumber)
 - {
 -     thread.reset (new ConnectionThread (*this));
 - }
 - 
 - InterprocessConnection::~InterprocessConnection()
 - {
 -     callbackConnectionState = false;
 -     disconnect();
 -     masterReference.clear();
 -     thread.reset();
 - }
 - 
 - //==============================================================================
 - bool InterprocessConnection::connectToSocket (const String& hostName,
 -                                               int portNumber, int timeOutMillisecs)
 - {
 -     disconnect();
 - 
 -     const ScopedLock sl (pipeAndSocketLock);
 -     socket.reset (new StreamingSocket());
 - 
 -     if (socket->connect (hostName, portNumber, timeOutMillisecs))
 -     {
 -         threadIsRunning = true;
 -         connectionMadeInt();
 -         thread->startThread();
 -         return true;
 -     }
 - 
 -     socket.reset();
 -     return false;
 - }
 - 
 - bool InterprocessConnection::connectToPipe (const String& pipeName, int timeoutMs)
 - {
 -     disconnect();
 - 
 -     std::unique_ptr<NamedPipe> newPipe (new NamedPipe());
 - 
 -     if (newPipe->openExisting (pipeName))
 -     {
 -         const ScopedLock sl (pipeAndSocketLock);
 -         pipeReceiveMessageTimeout = timeoutMs;
 -         initialiseWithPipe (newPipe.release());
 -         return true;
 -     }
 - 
 -     return false;
 - }
 - 
 - bool InterprocessConnection::createPipe (const String& pipeName, int timeoutMs, bool mustNotExist)
 - {
 -     disconnect();
 - 
 -     std::unique_ptr<NamedPipe> newPipe (new NamedPipe());
 - 
 -     if (newPipe->createNewPipe (pipeName, mustNotExist))
 -     {
 -         const ScopedLock sl (pipeAndSocketLock);
 -         pipeReceiveMessageTimeout = timeoutMs;
 -         initialiseWithPipe (newPipe.release());
 -         return true;
 -     }
 - 
 -     return false;
 - }
 - 
 - void InterprocessConnection::disconnect()
 - {
 -     thread->signalThreadShouldExit();
 - 
 -     {
 -         const ScopedLock sl (pipeAndSocketLock);
 -         if (socket != nullptr)  socket->close();
 -         if (pipe != nullptr)    pipe->close();
 -     }
 - 
 -     thread->stopThread (4000);
 -     deletePipeAndSocket();
 -     connectionLostInt();
 - }
 - 
 - void InterprocessConnection::deletePipeAndSocket()
 - {
 -     const ScopedLock sl (pipeAndSocketLock);
 -     socket.reset();
 -     pipe.reset();
 - }
 - 
 - bool InterprocessConnection::isConnected() const
 - {
 -     const ScopedLock sl (pipeAndSocketLock);
 - 
 -     return ((socket != nullptr && socket->isConnected())
 -               || (pipe != nullptr && pipe->isOpen()))
 -             && threadIsRunning;
 - }
 - 
 - String InterprocessConnection::getConnectedHostName() const
 - {
 -     {
 -         const ScopedLock sl (pipeAndSocketLock);
 - 
 -         if (pipe == nullptr && socket == nullptr)
 -             return {};
 - 
 -         if (socket != nullptr && ! socket->isLocal())
 -             return socket->getHostName();
 -     }
 - 
 -     return IPAddress::local().toString();
 - }
 - 
 - //==============================================================================
 - bool InterprocessConnection::sendMessage (const MemoryBlock& message)
 - {
 -     uint32 messageHeader[2] = { ByteOrder::swapIfBigEndian (magicMessageHeader),
 -                                 ByteOrder::swapIfBigEndian ((uint32) message.getSize()) };
 - 
 -     MemoryBlock messageData (sizeof (messageHeader) + message.getSize());
 -     messageData.copyFrom (messageHeader, 0, sizeof (messageHeader));
 -     messageData.copyFrom (message.getData(), sizeof (messageHeader), message.getSize());
 - 
 -     return writeData (messageData.getData(), (int) messageData.getSize()) == (int) messageData.getSize();
 - }
 - 
 - int InterprocessConnection::writeData (void* data, int dataSize)
 - {
 -     const ScopedLock sl (pipeAndSocketLock);
 - 
 -     if (socket != nullptr)
 -         return socket->write (data, dataSize);
 - 
 -     if (pipe != nullptr)
 -         return pipe->write (data, dataSize, pipeReceiveMessageTimeout);
 - 
 -     return 0;
 - }
 - 
 - //==============================================================================
 - void InterprocessConnection::initialiseWithSocket (StreamingSocket* newSocket)
 - {
 -     jassert (socket == nullptr && pipe == nullptr);
 -     socket.reset (newSocket);
 - 
 -     threadIsRunning = true;
 -     connectionMadeInt();
 -     thread->startThread();
 - }
 - 
 - void InterprocessConnection::initialiseWithPipe (NamedPipe* newPipe)
 - {
 -     jassert (socket == nullptr && pipe == nullptr);
 -     pipe.reset (newPipe);
 - 
 -     threadIsRunning = true;
 -     connectionMadeInt();
 -     thread->startThread();
 - }
 - 
 - //==============================================================================
 - struct ConnectionStateMessage  : public MessageManager::MessageBase
 - {
 -     ConnectionStateMessage (InterprocessConnection* ipc, bool connected) noexcept
 -         : owner (ipc), connectionMade (connected)
 -     {}
 - 
 -     void messageCallback() override
 -     {
 -         if (auto* ipc = owner.get())
 -         {
 -             if (connectionMade)
 -                 ipc->connectionMade();
 -             else
 -                 ipc->connectionLost();
 -         }
 -     }
 - 
 -     WeakReference<InterprocessConnection> owner;
 -     bool connectionMade;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConnectionStateMessage)
 - };
 - 
 - void InterprocessConnection::connectionMadeInt()
 - {
 -     if (! callbackConnectionState)
 -     {
 -         callbackConnectionState = true;
 - 
 -         if (useMessageThread)
 -             (new ConnectionStateMessage (this, true))->post();
 -         else
 -             connectionMade();
 -     }
 - }
 - 
 - void InterprocessConnection::connectionLostInt()
 - {
 -     if (callbackConnectionState)
 -     {
 -         callbackConnectionState = false;
 - 
 -         if (useMessageThread)
 -             (new ConnectionStateMessage (this, false))->post();
 -         else
 -             connectionLost();
 -     }
 - }
 - 
 - struct DataDeliveryMessage  : public Message
 - {
 -     DataDeliveryMessage (InterprocessConnection* ipc, const MemoryBlock& d)
 -         : owner (ipc), data (d)
 -     {}
 - 
 -     void messageCallback() override
 -     {
 -         if (auto* ipc = owner.get())
 -             ipc->messageReceived (data);
 -     }
 - 
 -     WeakReference<InterprocessConnection> owner;
 -     MemoryBlock data;
 - };
 - 
 - void InterprocessConnection::deliverDataInt (const MemoryBlock& data)
 - {
 -     jassert (callbackConnectionState);
 - 
 -     if (useMessageThread)
 -         (new DataDeliveryMessage (this, data))->post();
 -     else
 -         messageReceived (data);
 - }
 - 
 - //==============================================================================
 - int InterprocessConnection::readData (void* data, int num)
 - {
 -     if (socket != nullptr)
 -         return socket->read (data, num, true);
 - 
 -     if (pipe != nullptr)
 -         return pipe->read (data, num, pipeReceiveMessageTimeout);
 - 
 -     jassertfalse;
 -     return -1;
 - }
 - 
 - bool InterprocessConnection::readNextMessage()
 - {
 -     uint32 messageHeader[2];
 -     auto bytes = readData (messageHeader, sizeof (messageHeader));
 - 
 -     if (bytes == (int) sizeof (messageHeader)
 -          && ByteOrder::swapIfBigEndian (messageHeader[0]) == magicMessageHeader)
 -     {
 -         auto bytesInMessage = (int) ByteOrder::swapIfBigEndian (messageHeader[1]);
 - 
 -         if (bytesInMessage > 0)
 -         {
 -             MemoryBlock messageData ((size_t) bytesInMessage, true);
 -             int bytesRead = 0;
 - 
 -             while (bytesInMessage > 0)
 -             {
 -                 if (thread->threadShouldExit())
 -                     return false;
 - 
 -                 auto numThisTime = jmin (bytesInMessage, 65536);
 -                 auto bytesIn = readData (addBytesToPointer (messageData.getData(), bytesRead), numThisTime);
 - 
 -                 if (bytesIn <= 0)
 -                     break;
 - 
 -                 bytesRead += bytesIn;
 -                 bytesInMessage -= bytesIn;
 -             }
 - 
 -             if (bytesRead >= 0)
 -                 deliverDataInt (messageData);
 -         }
 - 
 -         return true;
 -     }
 - 
 -     if (bytes < 0)
 -     {
 -         if (socket != nullptr)
 -             deletePipeAndSocket();
 - 
 -         connectionLostInt();
 -     }
 - 
 -     return false;
 - }
 - 
 - void InterprocessConnection::runThread()
 - {
 -     while (! thread->threadShouldExit())
 -     {
 -         if (socket != nullptr)
 -         {
 -             auto ready = socket->waitUntilReady (true, 100);
 - 
 -             if (ready < 0)
 -             {
 -                 deletePipeAndSocket();
 -                 connectionLostInt();
 -                 break;
 -             }
 - 
 -             if (ready == 0)
 -             {
 -                 thread->wait (1);
 -                 continue;
 -             }
 -         }
 -         else if (pipe != nullptr)
 -         {
 -             if (! pipe->isOpen())
 -             {
 -                 deletePipeAndSocket();
 -                 connectionLostInt();
 -                 break;
 -             }
 -         }
 -         else
 -         {
 -             break;
 -         }
 - 
 -         if (thread->threadShouldExit() || ! readNextMessage())
 -             break;
 -     }
 - 
 -     threadIsRunning = false;
 - }
 - 
 - } // namespace juce
 
 
  |