DWORD WINAPI IPCListener::IPCListenerLoop( IPCSharedData *arg ) { PeerList *list = arg->list; LockableOffset *loffset = arg->offset; HANDLE pipe = INVALID_HANDLE_VALUE; uint8_t tmp[NPIPE_MAX_MSG_SZ]; OVERLAPPED pipe_ol; HANDLE ol_event; enum { PIPE_CLOSED, PIPE_UNCONNECT, PIPE_CONNECT_PENDING, PIPE_CONNECT, PIPE_READ_PENDING } pipe_state; // Open named pipe char pipename[64]; strncpy_s( pipename, 64, PIPE_PREFIX, 63 ); strncpy_s( pipename+strlen(pipename), 64-strlen(pipename), P802_1AS_PIPENAME, 63-strlen(pipename) ); ol_event = CreateEvent( NULL, true, false, NULL ); pipe_state = PIPE_CLOSED; DWORD retval = -1; while( !exit_waiting ) { int err; DWORD ret; if( pipe_state < PIPE_UNCONNECT ) { if( pipe != INVALID_HANDLE_VALUE ) { DisconnectNamedPipe( pipe ); CloseHandle( pipe ); } pipe = CreateNamedPipe( pipename, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE , PIPE_UNLIMITED_INSTANCES, OUTSTANDING_MESSAGES*NPIPE_MAX_SERVER_MSG_SZ, OUTSTANDING_MESSAGES*NPIPE_MAX_MSG_SZ, 0, NULL ); if( pipe == INVALID_HANDLE_VALUE ) { XPTPD_ERROR( "Open pipe error (%s): %d", pipename, GetLastError() ); goto do_error; } pipe_state = PIPE_UNCONNECT; } else if( pipe_state < PIPE_CONNECT ) { if( pipe_state != PIPE_CONNECT_PENDING ) { memset( &pipe_ol, 0, sizeof( pipe_ol )); pipe_ol.hEvent = ol_event; if( ResetEvent( ol_event ) == 0 ) goto do_error; if( ConnectNamedPipe( pipe, &pipe_ol ) != 0 ) { // Successfully connected pipe_state = PIPE_CONNECT; continue; } else { err = GetLastError(); switch( err ) { default: XPTPD_ERROR( "Attempt to connect on Pipe failed, %d", err ); goto do_error; case ERROR_PIPE_CONNECTED: pipe_state = PIPE_CONNECT; continue; case ERROR_IO_PENDING: pipe_state = PIPE_CONNECT_PENDING; } } } ret = WaitForSingleObject( ol_event, 200 ); switch( ret ) { case WAIT_OBJECT_0: pipe_state = PIPE_CONNECT; case WAIT_TIMEOUT: continue; default: goto do_error; } } else { // We're connected long readlen; if( pipe_state < PIPE_READ_PENDING ) { // Wait for message - Read Base Message ((WindowsNPipeMessage *)tmp)->init(); if( ResetEvent( ol_event ) == 0 ) goto do_error; if(( readlen = ((WindowsNPipeMessage *)tmp)->read_ol( pipe, 0, ol_event )) == -1 ) { err = GetLastError(); switch( err ) { default: XPTPD_ERROR( "Failed to read from pipe @%u,%d", __LINE__, err ); goto do_error; case ERROR_BROKEN_PIPE: pipe_state = PIPE_CLOSED; continue; case ERROR_IO_PENDING: ; } } // Fall through to here whether data is available or not pipe_state = PIPE_READ_PENDING; } ret = WaitForSingleObject( ol_event, 200 ); switch( ret ) { default: goto do_error; case WAIT_TIMEOUT: continue; case WAIT_OBJECT_0: if(( readlen = ((WinNPipeCtrlMessage *)tmp)->read_ol_complete( pipe )) == -1 ) { err = GetLastError(); if( err == ERROR_BROKEN_PIPE ) { pipe_state = PIPE_CLOSED; continue; } XPTPD_ERROR( "Failed to read from pipe @%u,%d", __LINE__, err ); goto do_error; } switch( ((WindowsNPipeMessage *)tmp)->getType() ) { case CTRL_MSG: ((WinNPipeCtrlMessage *)tmp)->init(); if(( readlen = ((WinNPipeCtrlMessage *)tmp)->read( pipe, readlen )) == -1 ) { XPTPD_ERROR( "Failed to read from pipe @%u", __LINE__ ); goto do_error; } //readlen may not be set properly ?? // Attempt to add or remove from the list switch( ((WinNPipeCtrlMessage *)tmp)->getCtrlWhich() ) { default: XPTPD_ERROR( "Recvd CTRL cmd specifying illegal operation @%u", __LINE__ ); goto do_error; case ADD_PEER: if( !list->IsReady() || !list->add( ((WinNPipeCtrlMessage *)tmp)->getPeerAddr() ) ) { XPTPD_ERROR( "Failed to add peer @%u", __LINE__ ); } break; case REMOVE_PEER: if( !list->IsReady() || !list->remove( ((WinNPipeCtrlMessage *)tmp)->getPeerAddr() ) ) { XPTPD_ERROR( "Failed to remove peer @%u", __LINE__ ); } break; } break; case OFFSET_MSG: ((WinNPipeQueryMessage *)tmp)->init(); if(( readlen = ((WinNPipeQueryMessage *)tmp)->read( pipe, readlen )) == -1 ) { XPTPD_ERROR( "Failed to read from pipe @%u", __LINE__ ); goto do_error; } // Create an offset message and send it loffset->get(); if( loffset->isReady() ) ((WinNPipeOffsetUpdateMessage *)tmp)->init((Offset *)loffset); else ((WinNPipeOffsetUpdateMessage *)tmp)->init(); loffset->put(); ((WinNPipeOffsetUpdateMessage *)tmp)->write(pipe); break; default: XPTPD_ERROR( "Recvd Unknown Message" ); // Is this recoverable? goto do_error; } pipe_state = PIPE_CONNECT; } } } retval = 0; // Exit normally do_error: // Close Named Pipe if( pipe != INVALID_HANDLE_VALUE ) CloseHandle( pipe ); return retval; }