예제 #1
0
void __cdecl CMsnProto::MSNServerThread(void* arg)
{
	ThreadData* info = (ThreadData*)arg;
	if (info->mIsMainThread)
		isConnectSuccess = false;

	int tPortNumber = -1;
	{
		char* tPortDelim = strrchr(info->mServer, ':');
		if (tPortDelim != NULL) {
			*tPortDelim = '\0';
			if ((tPortNumber = atoi(tPortDelim + 1)) == 0)
				tPortNumber = -1;
			else if (usingGateway && !(tPortNumber == 80 || tPortNumber == 443))
				usingGateway = false;
		}
	}

	if (usingGateway) {
		if (info->mServer[0] == 0)
			mir_strcpy(info->mServer, MSN_DEFAULT_LOGIN_SERVER);
		else if (info->mIsMainThread)
			mir_strcpy(info->mGatewayIP, info->mServer);

		if (info->gatewayType)
			mir_strcpy(info->mGatewayIP, info->mServer);
		else {
			if (info->mGatewayIP[0] == 0 && db_get_static(NULL, m_szModuleName, "GatewayServer", info->mGatewayIP, sizeof(info->mGatewayIP)))
				mir_strcpy(info->mGatewayIP, MSN_DEFAULT_GATEWAY);
		}
	}
	else {
		if (info->mServer[0] == 0 && db_get_static(NULL, m_szModuleName, "DirectServer", info->mServer, sizeof(info->mServer)))
			mir_strcpy(info->mServer, MSN_DEFAULT_LOGIN_SERVER);
	}

	NETLIBOPENCONNECTION tConn = { 0 };
	tConn.cbSize = sizeof(tConn);
	tConn.flags = NLOCF_V2;
	tConn.timeout = 5;

	if (usingGateway) {
		tConn.flags |= NLOCF_HTTPGATEWAY;
		tConn.szHost = info->mGatewayIP;
		tConn.wPort = MSN_DEFAULT_GATEWAY_PORT;
	}
	else {
		tConn.flags = NLOCF_SSL;
		tConn.szHost = info->mServer;
		tConn.wPort = MSN_DEFAULT_PORT;
	}
	if (tPortNumber != -1)
		tConn.wPort = (WORD)tPortNumber;

	debugLogA("Thread started: server='%s:%d', type=%d", tConn.szHost, tConn.wPort, info->mType);

	info->s = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)m_hNetlibUser, (LPARAM)&tConn);
	if (info->s == NULL) {
		debugLogA("Connection Failed (%d) server='%s:%d'", WSAGetLastError(), tConn.szHost, tConn.wPort);

		switch (info->mType) {
		case SERVER_NOTIFICATION:
			goto LBL_Exit;
			break;

		case SERVER_SWITCHBOARD:
			if (info->mCaller) msnNsThread->sendPacket("XFR", "SB");
			break;
		}
		return;
	}

	if (usingGateway)
		CallService(MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM(info->s), info->mGatewayTimeout);

	debugLogA("Connected with handle=%08X", info->s);

	if (info->mType == SERVER_NOTIFICATION) 
		info->sendPacketPayload("CNT", "CON", "<connect>%s%s%s<ver>2</ver><agent><os>winnt</os><osVer>5.2</osVer><proc>x86</proc><lcid>en-us</lcid></agent></connect>\r\n",
		*info->mState?"<xfr><state>":"", *info->mState?info->mState:"", *info->mState?"</state></xfr>":"");
	else if (info->mType == SERVER_SWITCHBOARD) {
		info->sendPacket(info->mCaller ? "USR" : "ANS", "%s;%s %s", MyOptions.szEmail, MyOptions.szMachineGuid, info->mCookie);
	}
	else if (info->mType == SERVER_FILETRANS && info->mCaller == 0) {
		info->send("VER MSNFTP\r\n", 12);
	}

	if (info->mIsMainThread) {
		msnNsThread = info;
	}

	debugLogA("Entering main recv loop");
	info->mBytesInData = 0;
	for (;;) {
		int recvResult = info->recv(info->mData + info->mBytesInData, info->mDataSize - info->mBytesInData);
		if (recvResult == SOCKET_ERROR) {
			debugLogA("Connection %08p [%08X] was abortively closed", info->s, GetCurrentThreadId());
			break;
		}

		if (!recvResult) {
			debugLogA("Connection %08p [%08X] was gracefully closed", info->s, GetCurrentThreadId());
			break;
		}

		info->mBytesInData += recvResult;

#ifdef OBSOLETE
		if (info->mCaller == 1 && info->mType == SERVER_FILETRANS) {
			if (MSN_HandleMSNFTP(info, info->mData))
				break;
		}
		else 
#endif
		{
			for (;;) {
				char* peol = strchr(info->mData, '\r');
				if (peol == NULL)
					break;

				int msgLen = (int)(peol - info->mData);
				if (info->mBytesInData < msgLen + 2)
					break;  //wait for full line end

				char msg[1024];
				strncpy_s(msg, info->mData, msgLen);

				if (*++peol != '\n')
					debugLogA("Dodgy line ending to command: ignoring");
				else
					peol++;

				info->mBytesInData -= peol - info->mData;
				memmove(info->mData, peol, info->mBytesInData);
				debugLogA("RECV: %s", msg);

				if (!isalnum(msg[0]) || !isalnum(msg[1]) || !isalnum(msg[2]) || (msg[3] && msg[3] != ' ')) {
					debugLogA("Invalid command name");
					continue;
				}

				if (info->mType != SERVER_FILETRANS) {
					int handlerResult;
					if (isdigit(msg[0]) && isdigit(msg[1]) && isdigit(msg[2]))   //all error messages
						handlerResult = MSN_HandleErrors(info, msg);
					else
						handlerResult = MSN_HandleCommands(info, msg);

					if (handlerResult) {
						if (info->sessionClosed) goto LBL_Exit;
						info->sendTerminate();
					}
				}
#ifdef OBSOLETE
				else
					if (MSN_HandleMSNFTP(info, msg))
						goto LBL_Exit;
#endif
			}
		}

		if (info->mBytesInData == info->mDataSize) {
			if (!ReallocInfoBuffer(info, info->mDataSize*2)) {
				debugLogA("sizeof(data) is too small: the longest line won't fit");
				break;
			}
		}
	}

LBL_Exit:
	if (info->mIsMainThread) {
		/*
		if (!isConnectSuccess && !usingGateway && m_iDesiredStatus != ID_STATUS_OFFLINE) {
			msnNsThread = NULL;
			usingGateway = true;

			ThreadData* newThread = new ThreadData;
			newThread->mType = SERVER_NOTIFICATION;
			newThread->mIsMainThread = true;

			newThread->startThread(&CMsnProto::MSNServerThread, this);
		}
		else*/ {
			if (hKeepAliveThreadEvt) {
				msnPingTimeout *= -1;
				SetEvent(hKeepAliveThreadEvt);
			}

			if (info->s == NULL)
				ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK);
			else {
#ifdef OBSOLETE
				p2p_cancelAllSessions();
#endif
				MSN_CloseConnections();
			}

			if (hHttpsConnection) {
				Netlib_CloseHandle(hHttpsConnection);
				hHttpsConnection = NULL;
			}

			MSN_GoOffline();
			msnNsThread = NULL;
		}
	}

	debugLogA("Thread [%08X] ending now", GetCurrentThreadId());
}
예제 #2
0
void __cdecl MSNServerThread( ThreadData* info )
{
	if ( !sttRedirectorWasChecked ) {
		sttRedirectorWasChecked = true;
		MSN_StartThread(( pThreadFunc )msn_RedirectorThread, NULL );
	}

	NETLIBOPENCONNECTION tConn = { 0 };
	tConn.cbSize = sizeof( tConn );
	tConn.flags = NLOCF_V2;

 	char* tPortDelim = strrchr( info->mServer, ':' );
	if ( tPortDelim != NULL )
		*tPortDelim = '\0';

	if ( MyOptions.UseGateway && !MyOptions.UseProxy ) {
		tConn.szHost = MSN_DEFAULT_GATEWAY;
		tConn.wPort = 80;
	}
	else {
		tConn.szHost = info->mServer;
		tConn.wPort = MSN_DEFAULT_PORT;

		if ( tPortDelim != NULL ) {
			int tPortNumber;
			if ( sscanf( tPortDelim+1, "%d", &tPortNumber ) == 1 )
				tConn.wPort = ( WORD )tPortNumber;
	}	}

	MSN_DebugLog( "Thread started: server='%s', type=%d", tConn.szHost, info->mType );

	info->s = ( HANDLE )MSN_CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM )hNetlibUser, ( LPARAM )&tConn );
	if ( info->s == NULL ) {
		MSN_DebugLog( "Connection Failed (%d)", WSAGetLastError() );

		switch ( info->mType ) {
		case SERVER_NOTIFICATION:
		case SERVER_DISPATCH:
			MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER );
			MSN_GoOffline();
			break;
		}

		return;
	}

	if ( MyOptions.UseGateway )
		MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( info->s ), 2 );

	MSN_DebugLog( "Connected with handle=%08X", info->s );

	if ( info->mType == SERVER_DISPATCH || info->mType == SERVER_NOTIFICATION ) {
		if ( MyOptions.UseMSNP11 )
			info->sendPacket( "VER", "MSNP11 MSNP10 CVR0" );
		else
			info->sendPacket( "VER", "MSNP10 MSNP9 CVR0" );
	}
	else if ( info->mType == SERVER_SWITCHBOARD ) {
		char tEmail[ MSN_MAX_EMAIL_LEN ];
		MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof( tEmail ));
		info->sendPacket( info->mCaller ? "USR" : "ANS", "%s %s", tEmail, info->mCookie );
	}
	else if ( info->mType == SERVER_FILETRANS && info->mCaller == 0 ) {
		info->send( "VER MSNFTP\r\n", 12 );
	}

	if ( info->mIsMainThread ) {
		MSN_EnableMenuItems( TRUE );

		msnPingTimeout = msnPingTimeoutCurrent;

		msnNsThread = info;
		if (hKeepAliveThreadEvt == NULL) {
			hKeepAliveThreadEvt = ::CreateEvent( NULL, TRUE, FALSE, NULL );
			MSN_StartThread(( pThreadFunc )msn_keepAliveThread, NULL );
	}	}

	MSN_DebugLog( "Entering main recv loop" );
	info->mBytesInData = 0;
	while ( TRUE ) {
		int handlerResult;

		int recvResult = info->recv( info->mData + info->mBytesInData, sizeof( info->mData ) - info->mBytesInData );
		if ( recvResult == SOCKET_ERROR ) {
			MSN_DebugLog( "Connection %08p [%d] was abortively closed", info->s, GetCurrentThreadId());
			break;
		}

		if ( !recvResult ) {
			MSN_DebugLog( "Connection %08p [%d] was gracefully closed", info->s, GetCurrentThreadId());
			break;
		}

		info->mBytesInData += recvResult;

		if ( info->mCaller == 1 && info->mType == SERVER_FILETRANS ) {
			handlerResult = MSN_HandleMSNFTP( info, info->mData );
			if ( handlerResult )
				break;
		}
		else {
			while( TRUE ) {
				char* peol = strchr(info->mData,'\r');
				if ( peol == NULL )
					break;

				if ( info->mBytesInData < peol-info->mData+2 )
					break;  //wait for full line end

				char msg[ sizeof(info->mData) ];
				memcpy( msg, info->mData, peol-info->mData ); msg[ peol-info->mData ] = 0;

				if ( *++peol != '\n' )
					MSN_DebugLog( "Dodgy line ending to command: ignoring" );
				else
					peol++;

				info->mBytesInData -= peol - info->mData;
				memmove( info->mData, peol, info->mBytesInData );
				MSN_DebugLog( "RECV:%s", msg );

				if ( !isalnum( msg[0] ) || !isalnum(msg[1]) || !isalnum(msg[2]) || (msg[3] && msg[3]!=' ')) {
					MSN_DebugLog( "Invalid command name" );
					continue;
				}

				if ( info->mType != SERVER_FILETRANS ) {
					if ( isdigit(msg[0]) && isdigit(msg[1]) && isdigit(msg[2]))   //all error messages
						handlerResult = MSN_HandleErrors( info, msg );
					else
						handlerResult = MSN_HandleCommands( info, msg );
				}
				else handlerResult = MSN_HandleMSNFTP( info, msg );

				if ( handlerResult )
					goto LBL_Exit;
		}	}

		if ( info->mBytesInData == sizeof( info->mData )) {
			MSN_DebugLog( "sizeof(data) is too small: the longest line won't fit" );
			break;
	}	}

LBL_Exit:
	if ( info->mIsMainThread ) {
		MSN_GoOffline();
		msnNsThread = NULL;
		if ( hKeepAliveThreadEvt )
			SetEvent( hKeepAliveThreadEvt );
	}

	MSN_DebugLog( "Thread [%d] ending now", GetCurrentThreadId() );
}