| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- //
- // Copyright (c) 2008-2017 the Urho3D project.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- #include "../Precompiled.h"
- #include "../Core/Profiler.h"
- #include "../IO/NamedPipe.h"
- #include "../IO/Log.h"
- #ifdef _WIN32
- #include <windows.h>
- #else
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <signal.h>
- #include <unistd.h>
- #endif
- #include "../DebugNew.h"
- namespace Atomic
- {
- static const unsigned PIPE_BUFFER_SIZE = 65536;
- NamedPipe::NamedPipe(Context* context) :
- Object(context),
- isServer_(false),
- #ifdef _WIN32
- handle_(INVALID_HANDLE_VALUE)
- #else
- readHandle_(-1),
- writeHandle_(-1)
- #endif
- {
- }
- NamedPipe::NamedPipe(Context* context, const String& pipeName, bool isServer) :
- Object(context),
- isServer_(false),
- #ifdef _WIN32
- handle_(INVALID_HANDLE_VALUE)
- #else
- readHandle_(-1),
- writeHandle_(-1)
- #endif
- {
- Open(pipeName, isServer);
- }
- NamedPipe::~NamedPipe()
- {
- Close();
- }
- unsigned NamedPipe::Seek(unsigned position)
- {
- return 0;
- }
- #ifdef _WIN32
- static const String pipePath("\\\\.\\pipe\\");
- bool NamedPipe::Open(const String& pipeName, bool isServer)
- {
- ATOMIC_PROFILE(OpenNamedPipe);
- Close();
- isServer_ = false;
- if (isServer)
- {
- handle_ = CreateNamedPipeW(WString(pipePath + pipeName).CString(),
- PIPE_ACCESS_DUPLEX,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT,
- 1,
- PIPE_BUFFER_SIZE,
- PIPE_BUFFER_SIZE,
- 0,
- 0
- );
- if (handle_ == INVALID_HANDLE_VALUE)
- {
- ATOMIC_LOGERROR("Failed to create named pipe " + pipeName);
- return false;
- }
- else
- {
- ATOMIC_LOGDEBUG("Created named pipe " + pipeName);
- pipeName_ = pipeName;
- isServer_ = true;
- return true;
- }
- }
- else
- {
- handle_ = CreateFileW(
- WString(pipePath + pipeName).CString(),
- GENERIC_READ | GENERIC_WRITE,
- 0,
- 0,
- OPEN_EXISTING,
- 0,
- 0
- );
- if (handle_ == INVALID_HANDLE_VALUE)
- {
- ATOMIC_LOGERROR("Failed to connect to named pipe " + pipeName);
- return false;
- }
- else
- {
- ATOMIC_LOGDEBUG("Connected to named pipe " + pipeName);
- pipeName_ = pipeName;
- return true;
- }
- }
- }
- unsigned NamedPipe::Read(void* dest, unsigned size)
- {
- if (handle_ != INVALID_HANDLE_VALUE)
- {
- DWORD read = 0;
- ReadFile(handle_, dest, size, &read, 0);
- return read;
- }
- return 0;
- }
- unsigned NamedPipe::Write(const void* data, unsigned size)
- {
- if (handle_ != INVALID_HANDLE_VALUE)
- {
- DWORD written = 0;
- WriteFile(handle_, data, size, &written, 0);
- return written;
- }
- return 0;
- }
- void NamedPipe::Close()
- {
- if (handle_ != INVALID_HANDLE_VALUE)
- {
- ATOMIC_PROFILE(CloseNamedPipe);
- if (isServer_)
- {
- DisconnectNamedPipe(handle_);
- isServer_ = false;
- }
- CloseHandle(handle_);
- handle_ = INVALID_HANDLE_VALUE;
- pipeName_.Clear();
- ATOMIC_LOGDEBUG("Closed named pipe " + pipeName_);
- }
- }
- bool NamedPipe::IsOpen() const
- {
- return handle_ != INVALID_HANDLE_VALUE;
- }
- bool NamedPipe::IsEof() const
- {
- if (handle_ != INVALID_HANDLE_VALUE)
- {
- DWORD bytesAvailable = 0;
- PeekNamedPipe(handle_, 0, 0, 0, &bytesAvailable, 0);
- return bytesAvailable == 0;
- }
- else
- return true;
- }
- #else
- static const String pipePath("/tmp/");
- #define SAFE_CLOSE(handle) if (handle != -1) { close(handle); handle = -1; }
- bool NamedPipe::Open(const String& pipeName, bool isServer)
- {
- #ifdef __EMSCRIPTEN__
- ATOMIC_LOGERROR("Opening a named pipe not supported on Web platform");
- return false;
- #else
- ATOMIC_PROFILE(OpenNamedPipe);
- Close();
- isServer_ = false;
- String serverReadName = pipePath + pipeName + "SR";
- String clientReadName = pipePath + pipeName + "CR";
- // Make sure SIGPIPE is ignored and will not lead to process termination
- signal(SIGPIPE, SIG_IGN);
- if (isServer)
- {
- mkfifo(serverReadName.CString(), 0660);
- mkfifo(clientReadName.CString(), 0660);
- readHandle_ = open(serverReadName.CString(), O_RDONLY | O_NDELAY);
- writeHandle_ = open(clientReadName.CString(), O_WRONLY | O_NDELAY);
- if (readHandle_ == -1 && writeHandle_ == -1)
- {
- ATOMIC_LOGERROR("Failed to create named pipe " + pipeName);
- SAFE_CLOSE(readHandle_);
- SAFE_CLOSE(writeHandle_);
- unlink(serverReadName.CString());
- unlink(clientReadName.CString());
- return false;
- }
- else
- {
- ATOMIC_LOGDEBUG("Created named pipe " + pipeName);
- pipeName_ = pipeName;
- isServer_ = true;
- return true;
- }
- }
- else
- {
- readHandle_ = open(clientReadName.CString(), O_RDONLY | O_NDELAY);
- writeHandle_ = open(serverReadName.CString(), O_WRONLY | O_NDELAY);
- if (readHandle_ == -1 && writeHandle_ == -1)
- {
- ATOMIC_LOGERROR("Failed to connect to named pipe " + pipeName);
- SAFE_CLOSE(readHandle_);
- SAFE_CLOSE(writeHandle_);
- return false;
- }
- else
- {
- ATOMIC_LOGDEBUG("Connected to named pipe " + pipeName);
- pipeName_ = pipeName;
- return true;
- }
- }
- #endif
- }
- unsigned NamedPipe::Read(void* dest, unsigned size)
- {
- // Attempt to open late if only the write handle is open yet
- if (readHandle_ == -1 && writeHandle_ != -1)
- {
- if (isServer_)
- readHandle_ = open((pipePath + pipeName_ + "SR").CString(), O_RDONLY | O_NDELAY);
- else
- readHandle_ = open((pipePath + pipeName_ + "CR").CString(), O_RDONLY | O_NDELAY);
- }
- if (readHandle_ != -1)
- {
- ssize_t readNow = read(readHandle_, dest, size);
- return readNow < 0 ? 0 : (unsigned)readNow;
- }
- else
- return 0;
- }
- unsigned NamedPipe::Write(const void* data, unsigned size)
- {
- // Attempt to open late if only the read handle is open yet
- if (writeHandle_ == -1 && readHandle_ != -1)
- {
- if (isServer_)
- writeHandle_ = open((pipePath + pipeName_ + "CR").CString(), O_WRONLY | O_NDELAY);
- else
- writeHandle_ = open((pipePath + pipeName_ + "SR").CString(), O_WRONLY | O_NDELAY);
- }
- // Loop until all bytes written in case of partial write
- if (writeHandle_ != -1)
- {
- ssize_t written = 0;
- while (written < (ssize_t)size)
- {
- ssize_t writtenNow = write(writeHandle_, ((const unsigned char*)data) + written, size - written);
- if (writtenNow < 0)
- return 0; // Error while writing
- written += writtenNow;
- }
- return (unsigned)written;
- }
- else
- return 0;
- }
- void NamedPipe::Close()
- {
- if (readHandle_ != -1 || writeHandle_ != -1)
- {
- ATOMIC_PROFILE(CloseNamedPipe);
- SAFE_CLOSE(readHandle_);
- SAFE_CLOSE(writeHandle_);
- if (isServer_)
- {
- String serverReadName = pipePath + pipeName_ + "SR";
- String clientReadName = pipePath + pipeName_ + "CR";
- unlink(serverReadName.CString());
- unlink(clientReadName.CString());
- isServer_ = false;
- }
- pipeName_.Clear();
- }
- }
- bool NamedPipe::IsOpen() const
- {
- return readHandle_ != -1 || writeHandle_ != -1;
- }
- bool NamedPipe::IsEof() const
- {
- #ifdef __EMSCRIPTEN__
- return true;
- #else
- // Attempt to open late if only the write handle is open yet
- if (readHandle_ == -1 && writeHandle_ != -1)
- {
- if (isServer_)
- readHandle_ = open((pipePath + pipeName_ + "SR").CString(), O_RDONLY | O_NDELAY);
- else
- readHandle_ = open((pipePath + pipeName_ + "CR").CString(), O_RDONLY | O_NDELAY);
- }
- if (readHandle_ != -1)
- {
- fd_set set;
- FD_ZERO(&set);
- FD_SET(readHandle_, &set);
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 1000; // 1ms timeout for select
- return select(readHandle_ + 1, &set, 0, 0, &timeout) <= 0;
- }
- else
- return true;
- #endif
- }
- #endif
- }
|