⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 udpsession.cpp

📁 qq的源程序代码
💻 CPP
字号:
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   copyright            : (C) 2002 by Zhang Yong                         *
 *   email                : z-yong163@163.com                              *
 ***************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <iostream>

#include "udpsession.h"
#include "udppacket.h"
#include "icqlink.h"

#define MYICQ_UDP_VER			1
#define MAX_SEND_ATTEMPTS		2


int UdpSession::udpSock = -1;
string UdpSession::destHost;
sockaddr_in UdpSession::proxyAddr;


UdpSession::UdpSession(IcqLink *link, const char *name, uint32 uin)
: IcqSession(link, name, uin)
{
	memset(&destAddr, 0, sizeof(destAddr));

	initSession();
}

UdpSession::~UdpSession()
{
	clearSendQueue();
}

void UdpSession::connect(uint32 ip, uint16 port)
{
	memset(&destAddr, 0, sizeof(destAddr));
	destAddr.sin_family = AF_INET;
	destAddr.sin_addr.s_addr = htonl(ip);
	destAddr.sin_port = htons(port);
}

time_t UdpSession::checkSendQueue()
{
	time_t now = time(NULL);

	while (!sendQueue.empty()) {
		UdpOutPacket *p = (UdpOutPacket *) sendQueue.front();
		if (p->expire > now)
			return (p->expire - now);

		sendQueue.pop_front();
		p->attempts++;
		if (p->attempts <= MAX_SEND_ATTEMPTS) {
			cout << "retransmit packet " << p->seq << endl;

			p->expire = now + SEND_TIMEOUT;
			sendDirect(p);
			sendQueue.push_back(p);
		}
		else {
			cout << "packet " << p->seq << " time out" << endl;
			
			onSendError(p);
			delete p;
		}
	}
	return SEND_TIMEOUT;
}

void UdpSession::clearSendQueue()
{
	PtrList::iterator i;
	for (i = sendQueue.begin(); i != sendQueue.end(); i++)
		delete (UdpOutPacket *) *i;
	sendQueue.clear();
}

void UdpSession::initSession()
{
	sid = (rand() & 0x7fffffff) + 1;
	sendSeq = (rand() & 0x3fff);
	recvSeq = 0;
	window = 0;

	clearSendQueue();
}

void UdpSession::createPacket(UdpOutPacket &out, uint16 cmd, uint16 seq, uint16 ackseq)
{
	IcqOption &options = icqLink->options;

	if (options.flags.test(UF_USE_PROXY)) {
		switch (options.proxyType) {
		case PROXY_HTTP:
			out << (uint16) 0;
			break;

		case PROXY_SOCKS:
			out << (uint16) 0 << (uint8) 0;
			if (options.proxy[PROXY_SOCKS].resolve) {
				out << (uint8) 1;
				out.writeData((const char *) &destAddr.sin_addr.s_addr, 4);
			} else {
				uint8 len = destHost.length();
				out << (uint8) 3 << len;
				out.writeData(destHost.c_str(), len);
			}
			out.writeData((const char *) &destAddr.sin_port, 2);
			break;
		}
	}
	out << (uint16) MYICQ_UDP_VER << (uint32) 0;
	out << sid << seq << (uint16) ackseq << cmd << icqLink->myInfo.uin;
	out.beginData();
}

UdpOutPacket *UdpSession::createPacket(uint16 cmd, uint16 ackseq)
{
	UdpOutPacket *p = new UdpOutPacket;
	p->cmd = cmd;
	p->seq = ++sendSeq;
	createPacket(*p, cmd, sendSeq, ackseq);
	return p;
}

void UdpSession::sendAckPacket(uint16 seq)
{
	UdpOutPacket out;
	createPacket(out, UDP_ACK, seq);
	sendDirect(&out);
}

void UdpSession::sendDirect(UdpOutPacket *p, int s, sockaddr_in *addr)
{
	sendto(s, p->getData(), p->getSize(), 0, (sockaddr *) addr, sizeof(sockaddr_in));
}

void UdpSession::sendDirect(UdpOutPacket *p)
{
	if (icqLink->isProxyType(PROXY_SOCKS))
		sendDirect(p, udpSock, &proxyAddr);
	else
		sendDirect(p, udpSock, &destAddr);
}

void UdpSession::onSendError(UdpOutPacket *p)
{
	icqLink->onSendError(p->seq);
}

uint16 UdpSession::sendPacket(UdpOutPacket *p)
{
	p->attempts = 0;
	p->expire = time(NULL) + SEND_TIMEOUT;
	sendDirect(p);
	sendQueue.push_back(p);
	return sendSeq;
}

bool UdpSession::setWindow(uint16 seq)
{
	if (seq >= recvSeq + 32 || seq < recvSeq)
		return false;

	if (seq == recvSeq) {
		do {
			recvSeq++;
			window >>= 1;
		} while (window & 0x1);
	} else {
		uint32 mask = (1 << (seq - recvSeq));
		if (window & mask)
			return false;
		else
			window |= mask;
	}
	return true;
}

bool UdpSession::onAck(uint16 seq)
{
	PtrList::iterator i;
	for (i = sendQueue.begin(); i != sendQueue.end(); i++) {
		UdpOutPacket *p = (UdpOutPacket *) *i;
		if (p->seq == seq) {
			cout << "packet " << seq << " is ACKed" << endl;
			sendQueue.erase(i);
			delete p;
			return true;
		}
	}

	cout << "ACK packet " << seq << " is ignored" << endl;
	return false;
}

bool UdpSession::onPacketReceived(UdpInPacket &in)
{
	if (in.getVersion() != MYICQ_UDP_VER) {
		cout << "malformed packet." << endl;
		return false;
	}

	if (in.getSID() != sid) {
		cout << "packet does not belong to this session." << endl;
		return false;
	}

	uint16 cmd = in.getCmd();
	uint16 ackseq = in.getAckSeq();
	uint16 seq = in.getSeq();

	if (ackseq)
		onAck(ackseq);
	if (!seq)
		return true;

	if (!recvSeq)
		recvSeq = seq;
	if (!setWindow(seq)) {
		cout << "packet " << seq << " is duplicated" << endl;
		return false;
	}
	return true;
}

bool UdpSession::onReceive()
{
	char data[MAX_PACKET_SIZE];
	char *p = data;
	sockaddr_in addr;
	socklen_t addrlen = sizeof(addr);

	int n = ::recvfrom(udpSock, data, sizeof(data), 0, (sockaddr *) &addr, &addrlen);
	if (n < 0) {
		icqLink->onSendError(0);
		return false;
	}
	if (icqLink->isProxyType(PROXY_SOCKS)) {
		if (data[0] != 0 || data[1] != 0 || data[2] != 0 || data[3] != 1)
			return false;

		p += 10;
		n -= 10;
	}

	if (n < (int) sizeof(UDP_HEADER)) {
		cout << "packet size is too small" << endl;
		return false;
	}

	UdpInPacket in(p, n);
	uint16 cmd = in.getCmd();
	uint32 uin = in.getUIN();
	const char *name;

	if (cmd >= UDP_MSG_FIRST)
		name = ICQ_SESSION_MSG;
	else {
		name = ICQ_SESSION_SERVER;
		uin = 0;
	}

	UdpSession *s = (UdpSession *) icqLink->findSession(name, uin);
	if (!s && strcmp(name, ICQ_SESSION_SERVER) != 0) {
		s = (UdpSession *) icqLink->createSession(name, uin);
		s->sid = in.getSID();

		if (icqLink->isProxyType(PROXY_SOCKS)) {
			sockaddr_in &addr = s->destAddr;
			memset(&addr, 0, sizeof(addr));
			addr.sin_family = AF_INET;
			addr.sin_addr = *(in_addr *) &data[4];
			addr.sin_port = *(uint16 *) &data[8];
		} else
			s->destAddr = addr;
	}
	if (!s)
		return false;

	return s->onPacketReceived(in);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -