538 lines
12 KiB
C++
538 lines
12 KiB
C++
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Microsoft Windows
|
|||
|
//
|
|||
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|||
|
//
|
|||
|
// File: sock.cxx
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#include <malloc.h>
|
|||
|
#include <mswsock.h>
|
|||
|
|
|||
|
#include <ssdp.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 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;
|
|||
|
}
|