Jack2  1.9.8
JackWinNamedPipe.cpp
00001 /*
00002  Copyright (C) 2004-2008 Grame
00003 
00004  This program is free software; you can redistribute it and/or modify
00005  it under the terms of the GNU Lesser General Public License as published by
00006  the Free Software Foundation; either version 2.1 of the License, or
00007  (at your option) any later version.
00008 
00009  This program is distributed in the hope that it will be useful,
00010  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  GNU Lesser General Public License for more details.
00013 
00014  You should have received a copy of the GNU Lesser General Public License
00015  along with this program; if not, write to the Free Software
00016  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 
00018  */
00019 
00020 
00021 #include "JackWinNamedPipe.h"
00022 #include "JackError.h"
00023 #include <assert.h>
00024 #include <stdio.h>
00025 
00026 #define BUFSIZE 4096
00027 
00028 namespace Jack
00029 {
00030 
00031 int JackWinNamedPipe::Read(void* data, int len)
00032 {
00033     DWORD read;
00034     BOOL res = ReadFile(fNamedPipe, data, len, &read, NULL);
00035     if (res && read == (DWORD)len) {
00036         return 0;
00037     } else {
00038         jack_error("Cannot read named pipe name = %s err = %ld", fName, GetLastError());
00039         return -1;
00040     }
00041 }
00042 
00043 int JackWinNamedPipe::Write(void* data, int len)
00044 {
00045     DWORD written;
00046     BOOL res = WriteFile(fNamedPipe, data, len, &written, NULL);
00047     if (res && written == (DWORD)len) {
00048         return 0;
00049     } else {
00050         jack_error("Cannot write named pipe name = %s err = %ld", fName, GetLastError());
00051         return -1;
00052     }
00053 }
00054 
00055 /*
00056 See :
00057     http://answers.google.com/answers/threadview?id=430173
00058     http://msdn.microsoft.com/en-us/library/windows/desktop/aa365800(v=vs.85).aspx
00059 */
00060 
00061 /*
00062 int JackWinNamedPipeClient::ConnectAux()
00063 {
00064     fNamedPipe = CreateFile(fName,                       // pipe name
00065                             GENERIC_READ |   // read and write access
00066                             GENERIC_WRITE,
00067                             0,               // no sharing
00068                             NULL,            // default security attributes
00069                             OPEN_EXISTING,   // opens existing pipe
00070                             0,               // default attributes
00071                             NULL);          // no template file
00072 
00073     if (fNamedPipe == INVALID_HANDLE_VALUE) {
00074         jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
00075         return -1;
00076     } else {
00077         return 0;
00078     }
00079 }
00080 */
00081 
00082 int JackWinNamedPipeClient::ConnectAux()
00083 {
00084     jack_log("Connect: fName %s", fName);
00085 
00086     while (true) {
00087 
00088         fNamedPipe = CreateFile(fName,                   // pipe name
00089                                 GENERIC_READ |   // read and write access
00090                                 GENERIC_WRITE,
00091                                 0,               // no sharing
00092                                 NULL,            // default security attributes
00093                                 OPEN_EXISTING,   // opens existing pipe
00094                                 0,               // default attributes
00095                                 NULL);           // no template file
00096 
00097         // Break if the pipe handle is valid.
00098         if (fNamedPipe != INVALID_HANDLE_VALUE) {
00099             return 0;
00100         }
00101 
00102         // Exit if an error other than ERROR_PIPE_BUSY occurs.
00103         if (GetLastError() != ERROR_PIPE_BUSY) {
00104             jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
00105             return -1;
00106         }
00107 
00108         // All pipe instances are busy, so wait for 2 seconds.
00109         if (!WaitNamedPipe(fName, 2000)) {
00110             jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
00111             return -1;
00112         }
00113     }
00114 }
00115 
00116 int JackWinNamedPipeClient::Connect(const char* dir, int which)
00117 {
00118     snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
00119     return ConnectAux();
00120 }
00121 
00122 int JackWinNamedPipeClient::Connect(const char* dir, const char* name, int which)
00123 {
00124     snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
00125     return ConnectAux();
00126 }
00127 
00128 int JackWinNamedPipeClient::Close()
00129 {
00130     if (fNamedPipe != INVALID_HANDLE_VALUE) {
00131         CloseHandle(fNamedPipe);
00132         fNamedPipe = INVALID_HANDLE_VALUE;
00133         return 0;
00134     } else {
00135         return -1;
00136     }
00137 }
00138 
00139 void JackWinNamedPipeClient::SetReadTimeOut(long sec)
00140 {}
00141 
00142 void JackWinNamedPipeClient::SetWriteTimeOut(long sec)
00143 {}
00144 
00145 JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient()
00146         : JackWinNamedPipeClient(), fPendingIO(false), fIOState(kIdle)
00147 {
00148     fIOState = kIdle;
00149     fOverlap.hEvent = CreateEvent(NULL,     // default security attribute
00150                                   TRUE,     // manual-reset event
00151                                   TRUE,     // initial state = signaled
00152                                   NULL);    // unnamed event object
00153 }
00154 
00155 JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, const char* name, bool pending)
00156         : JackWinNamedPipeClient(pipe, name), fPendingIO(pending), fIOState(kIdle)
00157 {
00158     fOverlap.hEvent = CreateEvent(NULL,     // default security attribute
00159                                   TRUE,     // manual-reset event
00160                                   TRUE,     // initial state = signaled
00161                                   NULL);        // unnamed event object
00162 
00163     if (!fPendingIO) {
00164         SetEvent(fOverlap.hEvent);
00165     }
00166 
00167     fIOState = (fPendingIO) ? kConnecting : kReading;
00168 }
00169 
00170 JackWinAsyncNamedPipeClient::~JackWinAsyncNamedPipeClient()
00171 {
00172     CloseHandle(fOverlap.hEvent);
00173 }
00174 
00175 int JackWinAsyncNamedPipeClient::FinishIO()
00176 {
00177     DWORD success, ret;
00178     success = GetOverlappedResult(fNamedPipe,   // handle to pipe
00179                                   &fOverlap,    // OVERLAPPED structure
00180                                   &ret,         // bytes transferred
00181                                   FALSE);       // do not wait
00182 
00183     switch (fIOState) {
00184 
00185         case kConnecting:
00186             if (!success) {
00187                 jack_error("Conection error");
00188                 return -1;
00189             } else {
00190                 fIOState = kReading;
00191                 // Prepare connection for new client ??
00192             }
00193             break;
00194 
00195         case kReading:
00196             if (!success || ret == 0) {
00197                 return -1;
00198             }
00199             fIOState = kWriting;
00200             break;
00201 
00202         case kWriting:
00203             if (!success || ret == 0) {
00204                 return -1;
00205             }
00206             fIOState = kReading;
00207             break;
00208 
00209         default:
00210             break;
00211     }
00212 
00213     return 0;
00214 }
00215 
00216 int JackWinAsyncNamedPipeClient::Read(void* data, int len)
00217 {
00218     DWORD read;
00219     jack_log("JackWinNamedPipeClient::Read len = %ld", len);
00220     BOOL res = ReadFile(fNamedPipe, data, len, &read, &fOverlap);
00221 
00222     if (res && read != 0) {
00223         fPendingIO = false;
00224         fIOState = kWriting;
00225         return 0;
00226     } else if (!res && GetLastError() == ERROR_IO_PENDING) {
00227         fPendingIO = true;
00228         return 0;
00229     } else {
00230         jack_error("Cannot read named pipe err = %ld", GetLastError());
00231         return -1;
00232     }
00233 }
00234 
00235 int JackWinAsyncNamedPipeClient::Write(void* data, int len)
00236 {
00237     DWORD written;
00238     jack_log("JackWinNamedPipeClient::Write len = %ld", len);
00239     BOOL res = WriteFile(fNamedPipe, data, len, &written, &fOverlap);
00240 
00241     if (res && written != 0) {
00242         fPendingIO = false;
00243         fIOState = kWriting;
00244         return 0;
00245     } else if (!res && GetLastError() == ERROR_IO_PENDING) {
00246         fPendingIO = true;
00247         return 0;
00248     } else {
00249         jack_error("Cannot write named pipe err = %ld", GetLastError());
00250         return -1;
00251     }
00252 }
00253 
00254 // Server side
00255 int JackWinNamedPipeServer::BindAux()
00256 {
00257     jack_log("Bind: fName %s", fName);
00258 
00259     if ((fNamedPipe = CreateNamedPipe(fName,
00260                                       PIPE_ACCESS_DUPLEX,       // read/write access
00261                                       PIPE_TYPE_MESSAGE |       // message type pipe
00262                                       PIPE_READMODE_MESSAGE |   // message-read mode
00263                                       PIPE_WAIT,                // blocking mode
00264                                       PIPE_UNLIMITED_INSTANCES, // max. instances
00265                                       BUFSIZE,  // output buffer size
00266                                       BUFSIZE,  // input buffer size
00267                                       INFINITE, // client time-out
00268                                       NULL)) == INVALID_HANDLE_VALUE) { // no security
00269         jack_error("Cannot bind server to pipe err = %ld", GetLastError());
00270         return -1;
00271     } else {
00272         return 0;
00273     }
00274 }
00275 
00276 int JackWinNamedPipeServer::Bind(const char* dir, int which)
00277 {
00278      snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
00279      return BindAux();
00280 }
00281 
00282 int JackWinNamedPipeServer::Bind(const char* dir, const char* name, int which)
00283 {
00284     snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
00285     return BindAux();
00286 }
00287 
00288 bool JackWinNamedPipeServer::Accept()
00289 {
00290     if (ConnectNamedPipe(fNamedPipe, NULL)) {
00291         return true;
00292     } else {
00293         jack_error("Cannot bind server pipe name = %s err = %ld", fName, GetLastError());
00294         if (GetLastError() == ERROR_PIPE_CONNECTED) {
00295             jack_error("pipe already connnected = %s ", fName);
00296             return true;
00297         } else {
00298             return false;
00299         }
00300     }
00301 }
00302 
00303 JackWinNamedPipeClient* JackWinNamedPipeServer::AcceptClient()
00304 {
00305     if (ConnectNamedPipe(fNamedPipe, NULL)) {
00306         JackWinNamedPipeClient* client = new JackWinNamedPipeClient(fNamedPipe, fName);
00307         // Init the pipe to the default value
00308         fNamedPipe = INVALID_HANDLE_VALUE;
00309         return client;
00310     } else {
00311         switch (GetLastError()) {
00312 
00313             case ERROR_PIPE_CONNECTED:
00314                 return new JackWinNamedPipeClient(fNamedPipe, fName);
00315 
00316             default:
00317                 jack_error("Cannot connect server pipe name = %s  err = %ld", fName, GetLastError());
00318                 return NULL;
00319                 break;
00320         }
00321     }
00322 }
00323 
00324 int JackWinNamedPipeServer::Close()
00325 {
00326     jack_log("JackWinNamedPipeServer::Close");
00327 
00328     if (fNamedPipe != INVALID_HANDLE_VALUE) {
00329         DisconnectNamedPipe(fNamedPipe);
00330         CloseHandle(fNamedPipe);
00331         fNamedPipe = INVALID_HANDLE_VALUE;
00332         return 0;
00333     } else {
00334         return -1;
00335     }
00336 }
00337 
00338 // Server side
00339 
00340 int JackWinAsyncNamedPipeServer::BindAux()
00341 {
00342     jack_log("Bind: fName %s", fName);
00343 
00344     if ((fNamedPipe = CreateNamedPipe(fName,
00345                                       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,  // read/write access
00346                                       PIPE_TYPE_MESSAGE |  // message type pipe
00347                                       PIPE_READMODE_MESSAGE |  // message-read mode
00348                                       PIPE_WAIT,  // blocking mode
00349                                       PIPE_UNLIMITED_INSTANCES,  // max. instances
00350                                       BUFSIZE,  // output buffer size
00351                                       BUFSIZE,  // input buffer size
00352                                       INFINITE,  // client time-out
00353                                       NULL)) == INVALID_HANDLE_VALUE) { // no security a
00354         jack_error("Cannot bind server to pipe err = %ld", GetLastError());
00355         return -1;
00356     } else {
00357         return 0;
00358     }
00359 }
00360 
00361 int JackWinAsyncNamedPipeServer::Bind(const char* dir, int which)
00362 {
00363     snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
00364     return BindAux();
00365 }
00366 
00367 int JackWinAsyncNamedPipeServer::Bind(const char* dir, const char* name, int which)
00368 {
00369     snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
00370     return BindAux();
00371 }
00372 
00373 bool JackWinAsyncNamedPipeServer::Accept()
00374 {
00375     return false;
00376 }
00377 
00378 JackWinNamedPipeClient* JackWinAsyncNamedPipeServer::AcceptClient()
00379 {
00380     if (ConnectNamedPipe(fNamedPipe, NULL)) {
00381         return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
00382     } else {
00383         switch (GetLastError()) {
00384 
00385             case ERROR_IO_PENDING:
00386                 return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, true);
00387 
00388             case ERROR_PIPE_CONNECTED:
00389                 return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
00390 
00391             default:
00392                 jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
00393                 return NULL;
00394                 break;
00395         }
00396     }
00397 }
00398 
00399 } // end of namespace
00400