udpsession.cpp
上传用户:zslianheng
上传日期:2013-04-03
资源大小:946k
文件大小:7k
源码类别:

Linux/Unix编程

开发平台:

Visual C++

  1. /***************************************************************************
  2.  *                                                                         *
  3.  *   This program is free software; you can redistribute it and/or modify  *
  4.  *   it under the terms of the GNU General Public License as published by  *
  5.  *   the Free Software Foundation; either version 2 of the License, or     *
  6.  *   (at your option) any later version.                                   *
  7.  *                                                                         *
  8.  *   copyright            : (C) 2002 by Zhang Yong                         *
  9.  *   email                : z-yong163@163.com                              *
  10.  ***************************************************************************/
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <iostream>
  14. #include "udpsession.h"
  15. #include "udppacket.h"
  16. #include "icqlink.h"
  17. #define MYICQ_UDP_VER 1
  18. #define MAX_SEND_ATTEMPTS 2
  19. int UdpSession::udpSock = -1;
  20. string UdpSession::destHost;
  21. sockaddr_in UdpSession::proxyAddr;
  22. UdpSession::UdpSession(IcqLink *link, const char *name, uint32 uin)
  23. : IcqSession(link, name, uin)
  24. {
  25. memset(&destAddr, 0, sizeof(destAddr));
  26. initSession();
  27. }
  28. UdpSession::~UdpSession()
  29. {
  30. clearSendQueue();
  31. }
  32. void UdpSession::connect(uint32 ip, uint16 port)
  33. {
  34. memset(&destAddr, 0, sizeof(destAddr));
  35. destAddr.sin_family = AF_INET;
  36. destAddr.sin_addr.s_addr = htonl(ip);
  37. destAddr.sin_port = htons(port);
  38. }
  39. time_t UdpSession::checkSendQueue()
  40. {
  41. time_t now = time(NULL);
  42. while (!sendQueue.empty()) {
  43. UdpOutPacket *p = (UdpOutPacket *) sendQueue.front();
  44. if (p->expire > now)
  45. return (p->expire - now);
  46. sendQueue.pop_front();
  47. p->attempts++;
  48. if (p->attempts <= MAX_SEND_ATTEMPTS) {
  49. cout << "retransmit packet " << p->seq << endl;
  50. p->expire = now + SEND_TIMEOUT;
  51. sendDirect(p);
  52. sendQueue.push_back(p);
  53. }
  54. else {
  55. cout << "packet " << p->seq << " time out" << endl;
  56. onSendError(p);
  57. delete p;
  58. }
  59. }
  60. return SEND_TIMEOUT;
  61. }
  62. void UdpSession::clearSendQueue()
  63. {
  64. PtrList::iterator i;
  65. for (i = sendQueue.begin(); i != sendQueue.end(); i++)
  66. delete (UdpOutPacket *) *i;
  67. sendQueue.clear();
  68. }
  69. void UdpSession::initSession()
  70. {
  71. sid = (rand() & 0x7fffffff) + 1;
  72. sendSeq = (rand() & 0x3fff);
  73. recvSeq = 0;
  74. window = 0;
  75. clearSendQueue();
  76. }
  77. void UdpSession::createPacket(UdpOutPacket &out, uint16 cmd, uint16 seq, uint16 ackseq)
  78. {
  79. IcqOption &options = icqLink->options;
  80. if (options.flags.test(UF_USE_PROXY)) {
  81. switch (options.proxyType) {
  82. case PROXY_HTTP:
  83. out << (uint16) 0;
  84. break;
  85. case PROXY_SOCKS:
  86. out << (uint16) 0 << (uint8) 0;
  87. if (options.proxy[PROXY_SOCKS].resolve) {
  88. out << (uint8) 1;
  89. out.writeData((const char *) &destAddr.sin_addr.s_addr, 4);
  90. } else {
  91. uint8 len = destHost.length();
  92. out << (uint8) 3 << len;
  93. out.writeData(destHost.c_str(), len);
  94. }
  95. out.writeData((const char *) &destAddr.sin_port, 2);
  96. break;
  97. }
  98. }
  99. out << (uint16) MYICQ_UDP_VER << (uint32) 0;
  100. out << sid << seq << (uint16) ackseq << cmd << icqLink->myInfo.uin;
  101. out.beginData();
  102. }
  103. UdpOutPacket *UdpSession::createPacket(uint16 cmd, uint16 ackseq)
  104. {
  105. UdpOutPacket *p = new UdpOutPacket;
  106. p->cmd = cmd;
  107. p->seq = ++sendSeq;
  108. createPacket(*p, cmd, sendSeq, ackseq);
  109. return p;
  110. }
  111. void UdpSession::sendAckPacket(uint16 seq)
  112. {
  113. UdpOutPacket out;
  114. createPacket(out, UDP_ACK, seq);
  115. sendDirect(&out);
  116. }
  117. void UdpSession::sendDirect(UdpOutPacket *p, int s, sockaddr_in *addr)
  118. {
  119. sendto(s, p->getData(), p->getSize(), 0, (sockaddr *) addr, sizeof(sockaddr_in));
  120. }
  121. void UdpSession::sendDirect(UdpOutPacket *p)
  122. {
  123. if (icqLink->isProxyType(PROXY_SOCKS))
  124. sendDirect(p, udpSock, &proxyAddr);
  125. else
  126. sendDirect(p, udpSock, &destAddr);
  127. }
  128. void UdpSession::onSendError(UdpOutPacket *p)
  129. {
  130. icqLink->onSendError(p->seq);
  131. }
  132. uint16 UdpSession::sendPacket(UdpOutPacket *p)
  133. {
  134. p->attempts = 0;
  135. p->expire = time(NULL) + SEND_TIMEOUT;
  136. sendDirect(p);
  137. sendQueue.push_back(p);
  138. return sendSeq;
  139. }
  140. bool UdpSession::setWindow(uint16 seq)
  141. {
  142. if (seq >= recvSeq + 32 || seq < recvSeq)
  143. return false;
  144. if (seq == recvSeq) {
  145. do {
  146. recvSeq++;
  147. window >>= 1;
  148. } while (window & 0x1);
  149. } else {
  150. uint32 mask = (1 << (seq - recvSeq));
  151. if (window & mask)
  152. return false;
  153. else
  154. window |= mask;
  155. }
  156. return true;
  157. }
  158. bool UdpSession::onAck(uint16 seq)
  159. {
  160. PtrList::iterator i;
  161. for (i = sendQueue.begin(); i != sendQueue.end(); i++) {
  162. UdpOutPacket *p = (UdpOutPacket *) *i;
  163. if (p->seq == seq) {
  164. cout << "packet " << seq << " is ACKed" << endl;
  165. sendQueue.erase(i);
  166. delete p;
  167. return true;
  168. }
  169. }
  170. cout << "ACK packet " << seq << " is ignored" << endl;
  171. return false;
  172. }
  173. bool UdpSession::onPacketReceived(UdpInPacket &in)
  174. {
  175. if (in.getVersion() != MYICQ_UDP_VER) {
  176. cout << "malformed packet." << endl;
  177. return false;
  178. }
  179. if (in.getSID() != sid) {
  180. cout << "packet does not belong to this session." << endl;
  181. return false;
  182. }
  183. uint16 cmd = in.getCmd();
  184. uint16 ackseq = in.getAckSeq();
  185. uint16 seq = in.getSeq();
  186. if (ackseq)
  187. onAck(ackseq);
  188. if (!seq)
  189. return true;
  190. if (!recvSeq)
  191. recvSeq = seq;
  192. if (!setWindow(seq)) {
  193. cout << "packet " << seq << " is duplicated" << endl;
  194. return false;
  195. }
  196. return true;
  197. }
  198. bool UdpSession::onReceive()
  199. {
  200. char data[MAX_PACKET_SIZE];
  201. char *p = data;
  202. sockaddr_in addr;
  203. socklen_t addrlen = sizeof(addr);
  204. int n = ::recvfrom(udpSock, data, sizeof(data), 0, (sockaddr *) &addr, &addrlen);
  205. if (n < 0) {
  206. icqLink->onSendError(0);
  207. return false;
  208. }
  209. if (icqLink->isProxyType(PROXY_SOCKS)) {
  210. if (data[0] != 0 || data[1] != 0 || data[2] != 0 || data[3] != 1)
  211. return false;
  212. p += 10;
  213. n -= 10;
  214. }
  215. if (n < (int) sizeof(UDP_HEADER)) {
  216. cout << "packet size is too small" << endl;
  217. return false;
  218. }
  219. UdpInPacket in(p, n);
  220. uint16 cmd = in.getCmd();
  221. uint32 uin = in.getUIN();
  222. const char *name;
  223. if (cmd >= UDP_MSG_FIRST)
  224. name = ICQ_SESSION_MSG;
  225. else {
  226. name = ICQ_SESSION_SERVER;
  227. uin = 0;
  228. }
  229. UdpSession *s = (UdpSession *) icqLink->findSession(name, uin);
  230. if (!s && strcmp(name, ICQ_SESSION_SERVER) != 0) {
  231. s = (UdpSession *) icqLink->createSession(name, uin);
  232. s->sid = in.getSID();
  233. if (icqLink->isProxyType(PROXY_SOCKS)) {
  234. sockaddr_in &addr = s->destAddr;
  235. memset(&addr, 0, sizeof(addr));
  236. addr.sin_family = AF_INET;
  237. addr.sin_addr = *(in_addr *) &data[4];
  238. addr.sin_port = *(uint16 *) &data[8];
  239. } else
  240. s->destAddr = addr;
  241. }
  242. if (!s)
  243. return false;
  244. return s->onPacketReceived(in);
  245. }