wsocket.cpp
上传用户:chn_coc
上传日期:2007-12-20
资源大小:563k
文件大小:10k
源码类别:

P2P编程

开发平台:

Windows_Unix

  1. // ------------------------------------------------ // File : wsocket.cpp // Date: 4-apr-2002 // Author: giles // Desc:  // Windows version of ClientSocket. Handles the nitty gritty of actually // reading and writing TCP // // (c) 2002 peercast.org // ------------------------------------------------ // 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. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the // GNU General Public License for more details. // ------------------------------------------------
  2. // TODO: fix socket closing
  3. #include "winsock2.h"
  4. #include <windows.h> #include <stdio.h> #include "wsocket.h" #include "stats.h"
  5. // --------------------------------------------------
  6. void WSAClientSocket::init()
  7. {
  8. WORD wVersionRequested;
  9. WSADATA wsaData;
  10. int err;
  11.     
  12. wVersionRequested = MAKEWORD( 2, 0 );
  13. err = WSAStartup( wVersionRequested, &wsaData );
  14. if ( err != 0 ) throw SockException("Unable to init sockets");     //LOG4("WSAStartup:  OK"); } // -------------------------------------------------- bool ClientSocket::getHostname(char *str,unsigned int ip) { HOSTENT *he; ip = htonl(ip); he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET); if (he) { strcpy(str,he->h_name); return true; }else return false; } // -------------------------------------------------- unsigned int ClientSocket::getIP(char *name) { char szHostName[256]; if (!name) { if (gethostname(szHostName, sizeof(szHostName))==0) name = szHostName; else return 0; } HOSTENT *he = WSAClientSocket::resolveHost(name); if (!he) return 0; LPSTR lpAddr = he->h_addr_list[0]; if (lpAddr) { struct in_addr  inAddr; memmove (&inAddr, lpAddr, 4); return inAddr.S_un.S_un_b.s_b1<<24 |    inAddr.S_un.S_un_b.s_b2<<16 |    inAddr.S_un.S_un_b.s_b3<<8 |    inAddr.S_un.S_un_b.s_b4; } return 0; } // --------------------------------------------------
  15. void WSAClientSocket::setLinger(int sec)
  16. {
  17. linger linger;
  18. linger.l_onoff = (sec>0)?1:0;
  19.     linger.l_linger = sec;
  20. if (setsockopt(sockNum, SOL_SOCKET, SO_LINGER, (const char *)&linger, sizeof (linger)) == -1) 
  21. throw SockException("Unable to set LINGER");
  22. }
  23. // -------------------------------------------------- void WSAClientSocket::setBlocking(bool yes) { unsigned long op = yes ? 0 : 1; if (ioctlsocket(sockNum, FIONBIO, &op) == SOCKET_ERROR) throw SockException("Can`t set blocking"); } // -------------------------------------------------- void WSAClientSocket::setNagle(bool on) {     int nodelay = (on==false); if (setsockopt(sockNum, SOL_SOCKET, TCP_NODELAY, (char *)&nodelay, sizeof nodelay) == -1)  throw SockException("Unable to set NODELAY"); } // -------------------------------------------------- void WSAClientSocket::setReuse(bool yes) { unsigned long op = yes ? 1 : 0; if (setsockopt(sockNum,SOL_SOCKET,SO_REUSEADDR,(char *)&op,sizeof(unsigned long)) == -1)  throw SockException("Unable to set REUSE"); } // -------------------------------------------------- HOSTENT *WSAClientSocket::resolveHost(const char *hostName) { HOSTENT *he; if ((he = gethostbyname(hostName)) == NULL) { // if failed, try using gethostbyaddr instead unsigned long ip = inet_addr(hostName); if (ip == INADDR_NONE) return NULL; if ((he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET)) == NULL) return NULL; } return he; } // -------------------------------------------------- void WSAClientSocket::open(Host &rh) { sockNum = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockNum == INVALID_SOCKET) throw SockException("Can`t open socket"); setBlocking(false); #ifdef DISABLE_NAGLE setNagle(false); #endif host = rh; memset(&remoteAddr,0,sizeof(remoteAddr)); remoteAddr.sin_family = AF_INET; remoteAddr.sin_port = htons(host.port); remoteAddr.sin_addr.S_un.S_addr = htonl(host.ip); } // -------------------------------------------------- void WSAClientSocket::checkTimeout(bool r, bool w) {     int err = WSAGetLastError();     if (err == WSAEWOULDBLOCK)     {
  24. timeval timeout; fd_set read_fds; fd_set write_fds;
  25. timeout.tv_sec = 0;
  26. timeout.tv_usec = 0;
  27.         FD_ZERO (&write_fds);
  28. if (w)
  29. {
  30. timeout.tv_sec = (int)this->writeTimeout/1000;
  31. FD_SET (sockNum, &write_fds);
  32. }
  33.         FD_ZERO (&read_fds);
  34. if (r)
  35. {
  36. timeout.tv_sec = (int)this->readTimeout/1000;
  37.         FD_SET (sockNum, &read_fds);
  38. }
  39. timeval *tp;
  40. if (timeout.tv_sec)
  41. tp = &timeout;
  42. else
  43. tp = NULL;
  44. int r=select (NULL, &read_fds, &write_fds, NULL, tp);         if (r == 0)
  45. throw TimeoutException();
  46. else if (r == SOCKET_ERROR) throw SockException("select failed."); }else{ char str[32]; sprintf(str,"%d",err); throw SockException(str); }
  47. }
  48. // --------------------------------------------------
  49. void WSAClientSocket::checkTimeout2(bool r, bool w)
  50. {
  51.     {
  52. timeval timeout;
  53. fd_set read_fds;
  54. fd_set write_fds;
  55. timeout.tv_sec = 0;
  56. timeout.tv_usec = 0;
  57.         FD_ZERO (&write_fds);
  58. if (w)
  59. {
  60. timeout.tv_sec = (int)this->writeTimeout/1000;
  61. FD_SET (sockNum, &write_fds);
  62. }
  63.         FD_ZERO (&read_fds);
  64. if (r)
  65. {
  66. timeout.tv_sec = (int)this->readTimeout/1000;
  67.         FD_SET (sockNum, &read_fds);
  68. }
  69. timeval *tp;
  70. if (timeout.tv_sec)
  71. tp = &timeout;
  72. else
  73. tp = NULL;
  74. int r=select (NULL, &read_fds, &write_fds, NULL, tp);
  75.         if (r == 0)
  76. throw TimeoutException();
  77. else if (r == SOCKET_ERROR)
  78. throw SockException("select failed.");
  79. }
  80. }
  81. // -------------------------------------------------- Host WSAClientSocket::getLocalHost() { struct sockaddr_in localAddr; int len = sizeof(localAddr);     if (getsockname(sockNum, (sockaddr *)&localAddr, &len) == 0) return Host(SWAP4(localAddr.sin_addr.s_addr),0); else return Host(0,0); } // -------------------------------------------------- void WSAClientSocket::connect() { if (::connect(sockNum,(struct sockaddr *)&remoteAddr,sizeof(remoteAddr)) == SOCKET_ERROR) checkTimeout(false,true); } // -------------------------------------------------- int WSAClientSocket::read(void *p, int l) {
  82. int bytesRead=0; while (l) { int r = recv(sockNum, (char *)p, l, 0); if (r == SOCKET_ERROR) {
  83. // non-blocking sockets always fall through to here
  84. checkTimeout(true,false);
  85. }else if (r == 0) {
  86. throw EOFException("Closed on read");
  87. }else { stats.add(Stats::BYTESIN,r); if (host.localIP()) stats.add(Stats::LOCALBYTESIN,r); updateTotals(r,0); bytesRead += r; l -= r; p = (char *)p+r; }
  88. } return bytesRead; } // --------------------------------------------------
  89. int WSAClientSocket::readUpto(void *p, int l)
  90. {
  91. int bytesRead=0;
  92. while (l)
  93. {
  94. int r = recv(sockNum, (char *)p, l, 0);
  95. if (r == SOCKET_ERROR)
  96. {
  97. // non-blocking sockets always fall through to here
  98. checkTimeout(true,false);
  99. }else if (r == 0)
  100. {
  101. break;
  102. }else
  103. {
  104. stats.add(Stats::BYTESIN,r);
  105. if (host.localIP())
  106. stats.add(Stats::LOCALBYTESIN,r);
  107. updateTotals(r,0);
  108. bytesRead += r;
  109. l -= r;
  110. p = (char *)p+r;
  111. }
  112. }
  113. return bytesRead;
  114. }
  115. // -------------------------------------------------- void WSAClientSocket::write(const void *p, int l) { while (l) { int r = send(sockNum, (char *)p, l, 0);
  116. if (r == SOCKET_ERROR) {
  117. checkTimeout(false,true);
  118. }
  119. else if (r == 0) { throw SockException("Closed on write"); }
  120. else
  121. if (r > 0) {
  122. stats.add(Stats::BYTESOUT,r); if (host.localIP()) stats.add(Stats::LOCALBYTESOUT,r); updateTotals(0,r); l -= r; p = (char *)p+r;
  123. } }
  124. } // -------------------------------------------------- void WSAClientSocket::bind(Host &h) { struct sockaddr_in localAddr; if ((sockNum = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) throw SockException("Can`t open socket"); setBlocking(false);
  125. setReuse(true); memset(&localAddr,0,sizeof(localAddr)); localAddr.sin_family = AF_INET; localAddr.sin_port = htons(h.port); localAddr.sin_addr.s_addr = INADDR_ANY; if( ::bind (sockNum, (sockaddr *)&localAddr, sizeof(localAddr)) == -1) throw SockException("Can`t bind socket"); if (::listen(sockNum,SOMAXCONN)) throw SockException("Can`t listen",WSAGetLastError()); host = h; } // -------------------------------------------------- ClientSocket *WSAClientSocket::accept() { int fromSize = sizeof(sockaddr_in); sockaddr_in from; int conSock = ::accept(sockNum,(sockaddr *)&from,&fromSize); if (conSock ==  INVALID_SOCKET) return NULL;     WSAClientSocket *cs = new WSAClientSocket(); cs->sockNum = conSock; cs->host.port = from.sin_port; cs->host.ip = from.sin_addr.S_un.S_un_b.s_b1<<24 |   from.sin_addr.S_un.S_un_b.s_b2<<16 |   from.sin_addr.S_un.S_un_b.s_b3<<8 |   from.sin_addr.S_un.S_un_b.s_b4; cs->setBlocking(false); #ifdef DISABLE_NAGLE cs->setNagle(false); #endif return cs; } // -------------------------------------------------- void WSAClientSocket::close() { if (sockNum) {
  126. shutdown(sockNum,SD_SEND);
  127. setReadTimeout(2000);
  128. try
  129. {
  130. //char c;
  131. //while (readUpto(&c,1)!=0);
  132. //readUpto(&c,1);
  133. }catch(StreamException &) {}
  134. if (closesocket(sockNum))
  135. LOG_ERROR("closesocket() error");
  136. sockNum=0; } }
  137. // --------------------------------------------------
  138. bool WSAClientSocket::readReady()
  139. {
  140. timeval timeout;
  141. fd_set read_fds;
  142. timeout.tv_sec = 0;
  143. timeout.tv_usec = 0;
  144.     FD_ZERO (&read_fds);
  145.     FD_SET (sockNum, &read_fds);
  146. return select (sockNum+1, &read_fds, NULL, NULL, &timeout) == 1;
  147. }