Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

537 lines
12 KiB

//+-------------------------------------------------------------------------
//
// 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;
}