//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: sock.cxx // //-------------------------------------------------------------------------- #include "precomp.h" #include #include #include #define dwENUM_REST 100 // time to rest between successive // IRLMP_ENUMDEVICES queries #define dwCONN_REST 100 // time to rest between successive // connect() calls #define MAX_DEVICE_COUNT 20 #define nMAX_TARGETS 8 #define nMAX_ENUM_RETRIES 100 #define nMAX_CONN_RETRIES 10 #define nSOCKET_MAXCONN 2 #define dwWRITEABLE_TIMEOUT 10000 #define SOCKET_RECEIVE_TIMEOUT (1000 * 60 * 10) #define SINGLE_INST_MUTEX L"IRMutex_1A8452B5_A526_443C_8172_D29657B89F57" FILE_TRANSFER* InitializeSocket( char ServiceName[] ) { int nSize; INT nRet; WORD wWinsockVersion; WSADATA wsadata; SOCKET listenSocket; FILE_TRANSFER* Transfer; wWinsockVersion = MAKEWORD( 2, 0 ); nRet = WSAStartup( wWinsockVersion, &wsadata ); if( 0 != nRet ) { goto lErr; } SOCKADDR_IRDA saListen; // // establish listen socket // listenSocket = socket( AF_IRDA, SOCK_STREAM, 0 ); if( INVALID_SOCKET == listenSocket ) { UINT uErr = (UINT)WSAGetLastError(); DbgLog3( SEV_ERROR, "listen on %s socket() failed with %d [0x%x]", ServiceName, uErr, uErr); goto lErr; } DbgLog2( SEV_INFO, "listen on %s socket ID: %ld", ServiceName, (DWORD)listenSocket ); saListen.irdaAddressFamily = AF_IRDA; *(UINT *)saListen.irdaDeviceID = 0; lstrcpyA( saListen.irdaServiceName, ServiceName ); nRet = bind( listenSocket, (const struct sockaddr *)&saListen, sizeof(saListen) ); if( SOCKET_ERROR == nRet ) { UINT uErr = (UINT)WSAGetLastError(); DbgLog3( SEV_ERROR, "listen on %s setsockopt failed with %d [0x%x]", ServiceName, uErr, uErr); goto lErr; } nRet = listen( listenSocket, nSOCKET_MAXCONN ); if( SOCKET_ERROR == nRet ) { UINT uErr = (UINT)WSAGetLastError(); DbgLog3( SEV_ERROR, "listen on %s listen() failed with %d [0x%x]", ServiceName, uErr, uErr); goto lErr; } Transfer=ListenForTransfer(listenSocket,TYPE_IRDA); if (Transfer == NULL) { closesocket(listenSocket); } return Transfer; lErr: return NULL; } DWORD FILE_TRANSFER::Sock_EstablishConnection( DWORD dwDeviceID, OBEX_DEVICE_TYPE DeviceType ) { FILE_TRANSFER * transfer; _state = CONNECTING; if (DeviceType == TYPE_IRDA) { SOCKADDR_IRDA saRemote; saRemote.irdaAddressFamily = AF_IRDA; *(UINT *)saRemote.irdaDeviceID = dwDeviceID; lstrcpyA( saRemote.irdaServiceName, SERVICE_NAME_1 ); if ( 0 == connect( _socket, (const struct sockaddr *) &saRemote, sizeof(saRemote))) { return 0; } lstrcpyA( saRemote.irdaServiceName, SERVICE_NAME_2 ); if ( 0 == connect( _socket, (const struct sockaddr *) &saRemote, sizeof(saRemote))) { return 0; } } else { sockaddr_in Address; ZeroMemory(&Address,sizeof(Address)); Address.sin_family=AF_INET; Address.sin_port=650; Address.sin_addr.S_un.S_addr=dwDeviceID; if ( 0 == connect( _socket, (const struct sockaddr *) &Address, sizeof(Address))) { return 0; } } return GetLastError(); } DWORD FILE_TRANSFER::SyncAccept( VOID ) { DWORD status = 0; DWORD bytes = 0; DWORD dwEventStatus = 0; EVENT_LOG EventLog(WS_EVENT_SOURCE,&dwEventStatus); int size; SOCKADDR_IRDA s; sockaddr_in Address; BOOL bResult; status = 0; while (!m_StopListening) { _state = ACCEPTING; _dataXferRecv.dwFileSent = 0; if (m_DeviceType == TYPE_IRDA) { size = sizeof(SOCKADDR_IRDA); _socket = accept( m_ListenSocket, (sockaddr *) &s, &size ); } else { size=sizeof(Address); _socket = accept( m_ListenSocket, (sockaddr *) &Address, &size ); } if ( INVALID_SOCKET == _socket ) { if (!m_StopListening) { // // the thread has been request to stop listening for incoming connection // if (!dwEventStatus) { EventLog.ReportError(CAT_IRXFER, MC_IRXFER_LISTEN_FAILED, WSAGetLastError()); } Sleep(1 * 1000); } continue; } // // we are handling an incoming connection, don't suspend on timeout during the transfer // SetThreadExecutionState( ES_SYSTEM_REQUIRED | ES_CONTINUOUS ); _state = READING; // // Record the machine name for later use. // if (m_DeviceType == TYPE_IRDA) { RecordDeviceName( &s ); } else { RecordIpDeviceName( &Address ); } _fCancelled=FALSE; do { if (_fCancelled) { #if DBG DbgPrint("irmon: receive canceled\n"); #endif status = ERROR_CANCELLED; break; } DWORD BytesToRead=Store_GetSize(_dataRecv.lpStore)-Store_GetDataUsed(_dataRecv.lpStore); bytes = recv( _socket, (char *) _buffer, BytesToRead, 0 ); if (SOCKET_ERROR == bytes) { if (_dataRecv.state == osCONN) { // // workaround for nokia cell phones that drop the irda connection after sending // the file. If we are not in the middle of a file transfer then just left it close // normally // status = 0; break; } else { if (!dwEventStatus) { EventLog.ReportError(CAT_IRXFER, MC_IRXFER_RECV_FAILED, WSAGetLastError()); } } status = GetLastError(); break; } if (0 == bytes) { status = 0; break; } HANDLE MutexHandle; MutexHandle=OpenMutex(SYNCHRONIZE,FALSE,SINGLE_INST_MUTEX); if (MutexHandle == NULL) { // // start the ui app, so we have something to rpc to. // LaunchUi( g_UiCommandLine ); } else { // // The app is already running // CloseHandle(MutexHandle); } DbgLog1(SEV_FUNCTION,"SyncAccept(): Recv: %d bytes", bytes); ASSERT( _guard == GUARD_MAGIC ); _dataXferRecv.dwFileSent += bytes; Obex_ReceiveData( xferRECV, _buffer, bytes ); while (Obex_ConsumePackets( xferRECV, &status )) { if (status != ERROR_SUCCESS) { break; } } if (status == 0xffffffff) { status = 0; } } while (status == STATUS_SUCCESS); DbgLog1( status ? SEV_ERROR : SEV_INFO, "Obex_Consume returned %d", status); // // Clean up OBEX data. // HandleClosure( status ); status = 0; if (_socket != INVALID_SOCKET) { closesocket(_socket); _socket=INVALID_SOCKET; } // // done with this connection, allow idle suspend // SetThreadExecutionState( ES_CONTINUOUS ); } #if DBG DbgPrint("IRMON: accept thread exiting\n"); #endif DecrementRefCount(); return 0; } error_status_t FILE_TRANSFER::Sock_CheckForReply( long timeout ) { int bytes; long seconds; long msec; fd_set FdSet; timeval BerkeleyTimeout; FD_ZERO( &FdSet ); FD_SET( _socket, &FdSet ); if (timeout == TIMEOUT_INFINITE) { int Result=0; while (Result == 0) { msec = 0; seconds = 5; BerkeleyTimeout.tv_sec = seconds; BerkeleyTimeout.tv_usec = msec * 1000; Result=select(0, &FdSet, NULL, NULL, &BerkeleyTimeout); // if (0 == Result) { // // return ERROR_TIMEOUT; // } if (_fCancelled) { return ERROR_OPERATION_ABORTED; } } } else { msec = timeout % 1000; seconds = timeout / 1000; BerkeleyTimeout.tv_sec = seconds; BerkeleyTimeout.tv_usec = msec * 1000; DbgLog1(SEV_INFO, "sock_checkForReply: timeout %ld", timeout); if (0 == select(0, &FdSet, NULL, NULL, &BerkeleyTimeout)) { return ERROR_TIMEOUT; } } bytes = recv( _socket, (char *) _buffer, cbSOCK_BUFFER_SIZE, 0 ); if (bytes == SOCKET_ERROR) { return GetLastError(); } else if (bytes == 0) { return WSAECONNRESET; } else { DbgLog1(SEV_FUNCTION,"Sock_CheckForReply(): Recv: %d bytes", bytes); Obex_ReceiveData( xferSEND, _buffer, bytes ); return 0; } return 0; } DWORD AcceptThreadStartRoutine( PVOID Context ) { FILE_TRANSFER * transfer=(FILE_TRANSFER *)Context; return transfer->SyncAccept(); } FILE_TRANSFER * ListenForTransfer( SOCKET ListenSocket, OBEX_DEVICE_TYPE DeviceType ) { FILE_TRANSFER * transfer; BOOL bResult; ULONG ThreadId; HANDLE ThreadHandle; transfer = new FILE_TRANSFER; if (transfer == NULL) { return NULL; } bResult=transfer->Xfer_Init(0, 0, dialWin95,DeviceType,FALSE,ListenSocket); if (!bResult) { delete transfer; return NULL; } ThreadHandle=CreateThread( 0, 0, AcceptThreadStartRoutine, (PVOID) transfer, 0, &ThreadId ); if (ThreadHandle == NULL) { delete transfer; return NULL; } CloseHandle(ThreadHandle); return transfer; } void FILE_TRANSFER::HandleClosure( DWORD error ) { if (!error) { _state = CLOSING; } if (_state == ACCEPTING || _state == READING ) { SendReplyWin32( 0, error ); } if (_fInUiReceiveList) { _fInUiReceiveList = FALSE; ReceiveFinished( rpcBinding, _cookie, error ); } if (error) { Xfer_FileAbort(); // just in case a file is being received } Obex_Reset(); // reset the state machine } error_status_t FILE_TRANSFER::Sock_Request( LPVOID lpvData, DWORD dwDataSize ) { if (send( _socket, (char *) lpvData, dwDataSize, 0) != (int) dwDataSize) { return GetLastError(); } DbgLog1(SEV_FUNCTION,"Sock_Request(): Send: %d bytes", dwDataSize); return 0; } error_status_t FILE_TRANSFER::Sock_Respond( LPVOID lpvData, DWORD dwDataSize ) { if (send( _socket, (char *) lpvData, dwDataSize, 0) != (int) dwDataSize) { return GetLastError(); } DbgLog1(SEV_FUNCTION,"Sock_Respond(): Send: %d bytes", dwDataSize); return 0; }