Jack2 1.9.10

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 JackWinNamedPipeAux::ReadAux(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_log("Cannot read named pipe name = %s err = %ld", fName, GetLastError());
00039         return -1;
00040     }
00041 }
00042 
00043 int JackWinNamedPipeAux::WriteAux(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_log("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("JackWinNamedPipeClient::ConnectAux : 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 or ERROR_FILE_NOT_FOUND occurs.
00103         if ((GetLastError() != ERROR_PIPE_BUSY) && (GetLastError() != ERROR_FILE_NOT_FOUND)) {
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 after wait = %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     COMMTIMEOUTS timeout;
00143     if (GetCommTimeouts(fNamedPipe, &timeout)) {
00144         jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadIntervalTimeout = %d", timeout.ReadIntervalTimeout);
00145         jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadTotalTimeoutMultiplier = %d", timeout.ReadTotalTimeoutMultiplier);
00146         jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadTotalTimeoutConstant = %d", timeout.ReadTotalTimeoutConstant);
00147     } else {
00148         jack_error("JackWinNamedPipeClient::SetReadTimeOut err %d", GetLastError());
00149     }
00150     */
00151 }
00152 
00153 void JackWinNamedPipeClient::SetWriteTimeOut(long sec)
00154 {
00155     /*
00156     COMMTIMEOUTS timeout;
00157     if (GetCommTimeouts(fNamedPipe, &timeout)) {
00158         jack_info("JackWinNamedPipeClient::SetWriteTimeOut WriteTotalTimeoutMultiplier = %d", timeout.WriteTotalTimeoutMultiplier);
00159         jack_info("JackWinNamedPipeClient::SetWriteTimeOut WriteTotalTimeoutConstant = %d", timeout.WriteTotalTimeoutConstant);
00160     }
00161     */
00162 }
00163 
00164 void JackWinNamedPipeClient::SetNonBlocking(bool onoff)
00165 {}
00166 
00167 JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient()
00168         : JackWinNamedPipeClient(), fPendingIO(false), fIOState(kIdle)
00169 {
00170     fIOState = kIdle;
00171     fOverlap.hEvent = CreateEvent(NULL,     // default security attribute
00172                                   TRUE,     // manual-reset event
00173                                   TRUE,     // initial state = signaled
00174                                   NULL);    // unnamed event object
00175 }
00176 
00177 JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, const char* name, bool pending)
00178         : JackWinNamedPipeClient(pipe, name), fPendingIO(pending), fIOState(kIdle)
00179 {
00180     fOverlap.hEvent = CreateEvent(NULL,     // default security attribute
00181                                   TRUE,     // manual-reset event
00182                                   TRUE,     // initial state = signaled
00183                                   NULL);        // unnamed event object
00184 
00185     if (!fPendingIO) {
00186         SetEvent(fOverlap.hEvent);
00187     }
00188 
00189     fIOState = (fPendingIO) ? kConnecting : kReading;
00190 }
00191 
00192 JackWinAsyncNamedPipeClient::~JackWinAsyncNamedPipeClient()
00193 {
00194     CloseHandle(fOverlap.hEvent);
00195 }
00196 
00197 int JackWinAsyncNamedPipeClient::FinishIO()
00198 {
00199     DWORD success, ret;
00200     success = GetOverlappedResult(fNamedPipe,   // handle to pipe
00201                                   &fOverlap,    // OVERLAPPED structure
00202                                   &ret,         // bytes transferred
00203                                   FALSE);       // do not wait
00204 
00205     switch (fIOState) {
00206 
00207         case kConnecting:
00208             if (!success) {
00209                 jack_error("Conection error");
00210                 return -1;
00211             } else {
00212                 fIOState = kReading;
00213                 // Prepare connection for new client ??
00214             }
00215             break;
00216 
00217         case kReading:
00218             if (!success || ret == 0) {
00219                 return -1;
00220             }
00221             fIOState = kWriting;
00222             break;
00223 
00224         case kWriting:
00225             if (!success || ret == 0) {
00226                 return -1;
00227             }
00228             fIOState = kReading;
00229             break;
00230 
00231         default:
00232             break;
00233     }
00234 
00235     return 0;
00236 }
00237 
00238 int JackWinAsyncNamedPipeClient::Read(void* data, int len)
00239 {
00240     DWORD read;
00241     jack_log("JackWinNamedPipeClient::Read len = %ld", len);
00242     BOOL res = ReadFile(fNamedPipe, data, len, &read, &fOverlap);
00243 
00244     if (res && read != 0) {
00245         fPendingIO = false;
00246         fIOState = kWriting;
00247         return 0;
00248     } else if (!res && GetLastError() == ERROR_IO_PENDING) {
00249         fPendingIO = true;
00250         return 0;
00251     } else {
00252         jack_error("Cannot read named pipe err = %ld", GetLastError());
00253         return -1;
00254     }
00255 }
00256 
00257 int JackWinAsyncNamedPipeClient::Write(void* data, int len)
00258 {
00259     DWORD written;
00260     jack_log("JackWinNamedPipeClient::Write len = %ld", len);
00261     BOOL res = WriteFile(fNamedPipe, data, len, &written, &fOverlap);
00262 
00263     if (res && written != 0) {
00264         fPendingIO = false;
00265         fIOState = kWriting;
00266         return 0;
00267     } else if (!res && GetLastError() == ERROR_IO_PENDING) {
00268         fPendingIO = true;
00269         return 0;
00270     } else {
00271         jack_error("Cannot write named pipe err = %ld", GetLastError());
00272         return -1;
00273     }
00274 }
00275 
00276 // Server side
00277 int JackWinNamedPipeServer::BindAux()
00278 {
00279     jack_log("JackWinNamedPipeServer::BindAux : fName %s", fName);
00280 
00281     if ((fNamedPipe = CreateNamedPipe(fName,
00282                                       PIPE_ACCESS_DUPLEX,       // read/write access
00283                                       PIPE_TYPE_MESSAGE |       // message type pipe
00284                                       PIPE_READMODE_MESSAGE |   // message-read mode
00285                                       PIPE_WAIT,                // blocking mode
00286                                       PIPE_UNLIMITED_INSTANCES, // max. instances
00287                                       BUFSIZE,  // output buffer size
00288                                       BUFSIZE,  // input buffer size
00289                                       INFINITE, // client time-out
00290                                       NULL)) == INVALID_HANDLE_VALUE) { // no security
00291         jack_error("Cannot bind server to pipe err = %ld", GetLastError());
00292         return -1;
00293     } else {
00294         return 0;
00295     }
00296 }
00297 
00298 int JackWinNamedPipeServer::Bind(const char* dir, int which)
00299 {
00300      snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
00301      return BindAux();
00302 }
00303 
00304 int JackWinNamedPipeServer::Bind(const char* dir, const char* name, int which)
00305 {
00306     snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
00307     return BindAux();
00308 }
00309 
00310 bool JackWinNamedPipeServer::Accept()
00311 {
00312     if (ConnectNamedPipe(fNamedPipe, NULL)) {
00313         return true;
00314     } else {
00315         jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
00316         if (GetLastError() == ERROR_PIPE_CONNECTED) {
00317             jack_error("Pipe already connnected = %s", fName);
00318             return true;
00319         } else {
00320             return false;
00321         }
00322     }
00323 }
00324 
00325 JackWinNamedPipeClient* JackWinNamedPipeServer::AcceptClient()
00326 {
00327     if (ConnectNamedPipe(fNamedPipe, NULL)) {
00328         JackWinNamedPipeClient* client = new JackWinNamedPipeClient(fNamedPipe, fName);
00329         // Init the pipe to the default value
00330         fNamedPipe = INVALID_HANDLE_VALUE;
00331         return client;
00332     } else {
00333         switch (GetLastError()) {
00334 
00335             case ERROR_PIPE_CONNECTED:
00336                 return new JackWinNamedPipeClient(fNamedPipe, fName);
00337 
00338             default:
00339                 jack_error("Cannot connect server pipe name = %s  err = %ld", fName, GetLastError());
00340                 return NULL;
00341         }
00342     }
00343 }
00344 
00345 int JackWinNamedPipeServer::Close()
00346 {
00347     jack_log("JackWinNamedPipeServer::Close");
00348 
00349     if (fNamedPipe != INVALID_HANDLE_VALUE) {
00350         DisconnectNamedPipe(fNamedPipe);
00351         CloseHandle(fNamedPipe);
00352         fNamedPipe = INVALID_HANDLE_VALUE;
00353         return 0;
00354     } else {
00355         return -1;
00356     }
00357 }
00358 
00359 // Server side
00360 
00361 int JackWinAsyncNamedPipeServer::BindAux()
00362 {
00363     jack_log("JackWinAsyncNamedPipeServer::BindAux : fName %s", fName);
00364 
00365     if ((fNamedPipe = CreateNamedPipe(fName,
00366                                       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,  // read/write access
00367                                       PIPE_TYPE_MESSAGE |  // message type pipe
00368                                       PIPE_READMODE_MESSAGE |  // message-read mode
00369                                       PIPE_WAIT,  // blocking mode
00370                                       PIPE_UNLIMITED_INSTANCES,  // max. instances
00371                                       BUFSIZE,  // output buffer size
00372                                       BUFSIZE,  // input buffer size
00373                                       INFINITE,  // client time-out
00374                                       NULL)) == INVALID_HANDLE_VALUE) { // no security a
00375         jack_error("Cannot bind server to pipe err = %ld", GetLastError());
00376         return -1;
00377     } else {
00378         return 0;
00379     }
00380 }
00381 
00382 int JackWinAsyncNamedPipeServer::Bind(const char* dir, int which)
00383 {
00384     snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
00385     return BindAux();
00386 }
00387 
00388 int JackWinAsyncNamedPipeServer::Bind(const char* dir, const char* name, int which)
00389 {
00390     snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
00391     return BindAux();
00392 }
00393 
00394 bool JackWinAsyncNamedPipeServer::Accept()
00395 {
00396     return false;
00397 }
00398 
00399 JackWinNamedPipeClient* JackWinAsyncNamedPipeServer::AcceptClient()
00400 {
00401     if (ConnectNamedPipe(fNamedPipe, NULL)) {
00402         return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
00403     } else {
00404         switch (GetLastError()) {
00405 
00406             case ERROR_IO_PENDING:
00407                 return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, true);
00408 
00409             case ERROR_PIPE_CONNECTED:
00410                 return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
00411 
00412             default:
00413                 jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
00414                 return NULL;
00415                 break;
00416         }
00417     }
00418 }
00419 
00420 } // end of namespace
00421