|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: sock.cxx
//
//--------------------------------------------------------------------------
#include "precomp.h"
#include <malloc.h>
#include <mswsock.h>
#include <irmonftp.h>
#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 8
#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=INVALID_SOCKET; FILE_TRANSFER* Transfer; HANDLE FileMapping; PVOID FileView=NULL;
LPWSAPROTOCOL_INFO ProtocolInfo;
wWinsockVersion = MAKEWORD( 2, 0 );
nRet = WSAStartup( wWinsockVersion, &wsadata );
if ( 0 != nRet ) {
goto lErr; }
FileMapping=OpenFileMapping( FILE_MAP_READ, FALSE, TEXT("Global\\Irmon-shared-memory") );
if (FileMapping != NULL) {
FileView=MapViewOfFile( FileMapping, FILE_MAP_READ, 0, 0, 0 );
CloseHandle(FileMapping);
} else {
DbgPrint("irftp: could not open shared mem %d\n",GetLastError()); }
ProtocolInfo=(LPWSAPROTOCOL_INFO)FileView;
if (ProtocolInfo != NULL) {
if (lstrcmpA(ServiceName,SERVICE_NAME_2) == 0) {
ProtocolInfo++; }
listenSocket=WSASocket(FROM_PROTOCOL_INFO,FROM_PROTOCOL_INFO ,FROM_PROTOCOL_INFO ,ProtocolInfo, NULL, 0);
UnmapViewOfFile(FileView); }
if (listenSocket == INVALID_SOCKET) { //
// establish listen socket
//
SOCKADDR_IRDA saListen;
DbgPrint("irftp: WSASocketFailed %d\n",WSAGetLastError());
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;
StringCbCopyA(saListen.irdaServiceName,sizeof(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); closesocket(listenSocket);
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);
closesocket(listenSocket); goto lErr; } } else {
}
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;
StringCbCopyA(saRemote.irdaServiceName,sizeof(saRemote.irdaServiceName), SERVICE_NAME_1 );
if ( 0 == connect( _socket, (const struct sockaddr *) &saRemote, sizeof(saRemote))) {
return 0; }
StringCbCopyA(saRemote.irdaServiceName,sizeof(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 WSAGetLastError(); }
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.
//
RecordDeviceName( &s );
_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( NULL);
} 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( NULL, 80000, AcceptThreadStartRoutine, (PVOID) transfer, STACK_SIZE_PARAM_IS_A_RESERVATION, &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; }
|