jack2/windows/JackWinNamedPipe.cpp

422 lines
13 KiB
C++

/*
Copyright (C) 2004-2008 Grame
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "JackWinNamedPipe.h"
#include "JackError.h"
#include <assert.h>
#include <stdio.h>
#define BUFSIZE 4096
namespace Jack
{
int JackWinNamedPipeAux::ReadAux(void* data, int len)
{
DWORD read;
BOOL res = ReadFile(fNamedPipe, data, len, &read, NULL);
if (res && read == (DWORD)len) {
return 0;
} else {
jack_log("Cannot read named pipe name = %s err = %ld", fName, GetLastError());
return -1;
}
}
int JackWinNamedPipeAux::WriteAux(void* data, int len)
{
DWORD written;
BOOL res = WriteFile(fNamedPipe, data, len, &written, NULL);
if (res && written == (DWORD)len) {
return 0;
} else {
jack_log("Cannot write named pipe name = %s err = %ld", fName, GetLastError());
return -1;
}
}
/*
See :
http://answers.google.com/answers/threadview?id=430173
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365800(v=vs.85).aspx
*/
/*
int JackWinNamedPipeClient::ConnectAux()
{
fNamedPipe = CreateFile(fName, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
if (fNamedPipe == INVALID_HANDLE_VALUE) {
jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
return -1;
} else {
return 0;
}
}
*/
int JackWinNamedPipeClient::ConnectAux()
{
jack_log("JackWinNamedPipeClient::ConnectAux : fName %s", fName);
while (true) {
fNamedPipe = CreateFile(fName, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
// Break if the pipe handle is valid.
if (fNamedPipe != INVALID_HANDLE_VALUE) {
return 0;
}
// Exit if an error other than ERROR_PIPE_BUSY or ERROR_FILE_NOT_FOUND occurs.
if ((GetLastError() != ERROR_PIPE_BUSY) && (GetLastError() != ERROR_FILE_NOT_FOUND)) {
jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
return -1;
}
// All pipe instances are busy, so wait for 2 seconds.
if (!WaitNamedPipe(fName, 2000)) {
jack_error("Cannot connect to named pipe after wait = %s err = %ld", fName, GetLastError());
return -1;
}
}
}
int JackWinNamedPipeClient::Connect(const char* dir, int which)
{
snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
return ConnectAux();
}
int JackWinNamedPipeClient::Connect(const char* dir, const char* name, int which)
{
snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
return ConnectAux();
}
int JackWinNamedPipeClient::Close()
{
if (fNamedPipe != INVALID_HANDLE_VALUE) {
CloseHandle(fNamedPipe);
fNamedPipe = INVALID_HANDLE_VALUE;
return 0;
} else {
return -1;
}
}
void JackWinNamedPipeClient::SetReadTimeOut(long sec)
{
/*
COMMTIMEOUTS timeout;
if (GetCommTimeouts(fNamedPipe, &timeout)) {
jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadIntervalTimeout = %d", timeout.ReadIntervalTimeout);
jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadTotalTimeoutMultiplier = %d", timeout.ReadTotalTimeoutMultiplier);
jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadTotalTimeoutConstant = %d", timeout.ReadTotalTimeoutConstant);
} else {
jack_error("JackWinNamedPipeClient::SetReadTimeOut err %d", GetLastError());
}
*/
}
void JackWinNamedPipeClient::SetWriteTimeOut(long sec)
{
/*
COMMTIMEOUTS timeout;
if (GetCommTimeouts(fNamedPipe, &timeout)) {
jack_info("JackWinNamedPipeClient::SetWriteTimeOut WriteTotalTimeoutMultiplier = %d", timeout.WriteTotalTimeoutMultiplier);
jack_info("JackWinNamedPipeClient::SetWriteTimeOut WriteTotalTimeoutConstant = %d", timeout.WriteTotalTimeoutConstant);
}
*/
}
void JackWinNamedPipeClient::SetNonBlocking(bool onoff)
{}
JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient()
: JackWinNamedPipeClient(), fPendingIO(false), fIOState(kIdle)
{
fIOState = kIdle;
fOverlap.hEvent = CreateEvent(NULL, // default security attribute
TRUE, // manual-reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
}
JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, const char* name, bool pending)
: JackWinNamedPipeClient(pipe, name), fPendingIO(pending), fIOState(kIdle)
{
fOverlap.hEvent = CreateEvent(NULL, // default security attribute
TRUE, // manual-reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
if (!fPendingIO) {
SetEvent(fOverlap.hEvent);
}
fIOState = (fPendingIO) ? kConnecting : kReading;
}
JackWinAsyncNamedPipeClient::~JackWinAsyncNamedPipeClient()
{
CloseHandle(fOverlap.hEvent);
}
int JackWinAsyncNamedPipeClient::FinishIO()
{
DWORD success, ret;
success = GetOverlappedResult(fNamedPipe, // handle to pipe
&fOverlap, // OVERLAPPED structure
&ret, // bytes transferred
FALSE); // do not wait
switch (fIOState) {
case kConnecting:
if (!success) {
jack_error("Connection error");
return -1;
} else {
fIOState = kReading;
// Prepare connection for new client ??
}
break;
case kReading:
if (!success || ret == 0) {
return -1;
}
fIOState = kWriting;
break;
case kWriting:
if (!success || ret == 0) {
return -1;
}
fIOState = kReading;
break;
default:
break;
}
return 0;
}
int JackWinAsyncNamedPipeClient::Read(void* data, int len)
{
DWORD read;
jack_log("JackWinNamedPipeClient::Read len = %ld", len);
BOOL res = ReadFile(fNamedPipe, data, len, &read, &fOverlap);
if (res && read != 0) {
fPendingIO = false;
fIOState = kWriting;
return 0;
} else if (!res && GetLastError() == ERROR_IO_PENDING) {
fPendingIO = true;
return 0;
} else {
jack_error("Cannot read named pipe err = %ld", GetLastError());
return -1;
}
}
int JackWinAsyncNamedPipeClient::Write(void* data, int len)
{
DWORD written;
jack_log("JackWinNamedPipeClient::Write len = %ld", len);
BOOL res = WriteFile(fNamedPipe, data, len, &written, &fOverlap);
if (res && written != 0) {
fPendingIO = false;
fIOState = kWriting;
return 0;
} else if (!res && GetLastError() == ERROR_IO_PENDING) {
fPendingIO = true;
return 0;
} else {
jack_error("Cannot write named pipe err = %ld", GetLastError());
return -1;
}
}
// Server side
int JackWinNamedPipeServer::BindAux()
{
jack_log("JackWinNamedPipeServer::BindAux : fName %s", fName);
if ((fNamedPipe = CreateNamedPipe(fName,
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
INFINITE, // client time-out
NULL)) == INVALID_HANDLE_VALUE) { // no security
jack_error("Cannot bind server to pipe err = %ld", GetLastError());
return -1;
} else {
return 0;
}
}
int JackWinNamedPipeServer::Bind(const char* dir, int which)
{
snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
return BindAux();
}
int JackWinNamedPipeServer::Bind(const char* dir, const char* name, int which)
{
snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
return BindAux();
}
bool JackWinNamedPipeServer::Accept()
{
if (ConnectNamedPipe(fNamedPipe, NULL)) {
return true;
} else {
jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
if (GetLastError() == ERROR_PIPE_CONNECTED) {
jack_error("Pipe already connected = %s", fName);
return true;
} else {
return false;
}
}
}
JackWinNamedPipeClient* JackWinNamedPipeServer::AcceptClient()
{
if (ConnectNamedPipe(fNamedPipe, NULL)) {
JackWinNamedPipeClient* client = new JackWinNamedPipeClient(fNamedPipe, fName);
// Init the pipe to the default value
fNamedPipe = INVALID_HANDLE_VALUE;
return client;
} else {
switch (GetLastError()) {
case ERROR_PIPE_CONNECTED:
return new JackWinNamedPipeClient(fNamedPipe, fName);
default:
jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
return NULL;
}
}
}
int JackWinNamedPipeServer::Close()
{
jack_log("JackWinNamedPipeServer::Close");
if (fNamedPipe != INVALID_HANDLE_VALUE) {
DisconnectNamedPipe(fNamedPipe);
CloseHandle(fNamedPipe);
fNamedPipe = INVALID_HANDLE_VALUE;
return 0;
} else {
return -1;
}
}
// Server side
int JackWinAsyncNamedPipeServer::BindAux()
{
jack_log("JackWinAsyncNamedPipeServer::BindAux : fName %s", fName);
if ((fNamedPipe = CreateNamedPipe(fName,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
INFINITE, // client time-out
NULL)) == INVALID_HANDLE_VALUE) { // no security a
jack_error("Cannot bind server to pipe err = %ld", GetLastError());
return -1;
} else {
return 0;
}
}
int JackWinAsyncNamedPipeServer::Bind(const char* dir, int which)
{
snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
return BindAux();
}
int JackWinAsyncNamedPipeServer::Bind(const char* dir, const char* name, int which)
{
snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
return BindAux();
}
bool JackWinAsyncNamedPipeServer::Accept()
{
return false;
}
JackWinNamedPipeClient* JackWinAsyncNamedPipeServer::AcceptClient()
{
if (ConnectNamedPipe(fNamedPipe, NULL)) {
return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
} else {
switch (GetLastError()) {
case ERROR_IO_PENDING:
return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, true);
case ERROR_PIPE_CONNECTED:
return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
default:
jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
return NULL;
break;
}
}
}
} // end of namespace