blocksock.cpp
上传用户:shengde
上传日期:2007-02-26
资源大小:117k
文件大小:9k
源码类别:

Ftp服务器

开发平台:

Visual C++

  1. #include "stdafx.h"
  2. #include "blocksock.h"
  3. IMPLEMENT_DYNAMIC(CBlockingSocketException, CException)
  4. CBlockingSocketException::CBlockingSocketException(char* pchMessage)
  5. {
  6. m_strMessage = pchMessage;
  7. m_nError = WSAGetLastError();
  8. }
  9. BOOL CBlockingSocketException::GetErrorMessage(LPTSTR lpstrError, UINT nMaxError,
  10. PUINT pnHelpContext /*= NULL*/)
  11. {
  12. char text[200];
  13. if(m_nError == 0) {
  14. wsprintf(text, "%s error", (const char*) m_strMessage);
  15. }
  16. else {
  17. wsprintf(text, "%s error #%d", (const char*) m_strMessage, m_nError);
  18. }
  19. strncpy(lpstrError, text, nMaxError - 1);
  20. return TRUE;
  21. }
  22. IMPLEMENT_DYNAMIC(CBlockingSocket, CObject)
  23. void CBlockingSocket::Cleanup()
  24. {
  25. // doesn't throw an exception because it's called in a catch block
  26. if(m_hSocket == NULL) return;
  27. VERIFY(closesocket(m_hSocket) != SOCKET_ERROR);
  28. m_hSocket = NULL;
  29. }
  30. bool CBlockingSocket::Create(int nType /* = SOCK_STREAM */)
  31. {
  32. ASSERT(m_hSocket == NULL);
  33. if((m_hSocket = socket(AF_INET, nType, 0)) == INVALID_SOCKET)
  34. return false;
  35. else
  36. return true;
  37. }
  38. bool CBlockingSocket::Bind(LPCSOCKADDR psa)
  39. {
  40. ASSERT(m_hSocket != NULL);
  41. if(bind(m_hSocket, psa, sizeof(SOCKADDR)) == SOCKET_ERROR)
  42. return false;
  43. else
  44. return true;
  45. }
  46. bool CBlockingSocket::Listen()
  47. {
  48. ASSERT(m_hSocket != NULL);
  49. if(listen(m_hSocket, 5) == SOCKET_ERROR)
  50. return false;
  51. else
  52. return true;
  53. }
  54. BOOL CBlockingSocket::Accept(CBlockingSocket& sConnect, LPSOCKADDR psa)
  55. {
  56. ASSERT(m_hSocket != NULL);
  57. ASSERT(sConnect.m_hSocket == NULL);
  58. int nLengthAddr = sizeof(SOCKADDR);
  59. sConnect.m_hSocket = accept(m_hSocket, psa, &nLengthAddr);
  60. if(sConnect == INVALID_SOCKET) {
  61. // no exception if the listen was canceled
  62. if(WSAGetLastError() != WSAEINTR) {
  63. throw new CBlockingSocketException("Accept");
  64. }
  65. return FALSE;
  66. }
  67. return TRUE;
  68. }
  69. void CBlockingSocket::Close()
  70. {
  71. if (NULL == m_hSocket)
  72. return;
  73. if(closesocket(m_hSocket) == SOCKET_ERROR) {
  74. // should be OK to close if closed already
  75. throw new CBlockingSocketException("Close");
  76. }
  77. m_hSocket = NULL;
  78. }
  79. bool CBlockingSocket::Connect(LPCSOCKADDR psa)
  80. {
  81. ASSERT(m_hSocket != NULL);
  82. // should timeout by itself
  83. if(connect(m_hSocket, psa, sizeof(SOCKADDR)) == SOCKET_ERROR)
  84. return false;
  85. else
  86. return true;
  87. }
  88. int CBlockingSocket::Write(const char* pch, const int nSize, const int nSecs)
  89. {
  90. int nBytesSent = 0;
  91. int nBytesThisTime;
  92. const char* pch1 = pch;
  93. do {
  94. nBytesThisTime = Send(pch1, nSize - nBytesSent, nSecs);
  95. nBytesSent += nBytesThisTime;
  96. pch1 += nBytesThisTime;
  97. } while(nBytesSent < nSize);
  98. return nBytesSent;
  99. }
  100. int CBlockingSocket::Send(const char* pch, const int nSize, const int nSecs)
  101. {
  102. ASSERT(m_hSocket != NULL);
  103. // returned value will be less than nSize if client cancels the reading
  104. FD_SET fd = {1, m_hSocket};
  105. TIMEVAL tv = {nSecs, 0};
  106. if(select(0, NULL, &fd, NULL, &tv) == 0) {
  107. throw new CBlockingSocketException("Send timeout");
  108. }
  109. int nBytesSent;
  110. if((nBytesSent = send(m_hSocket, pch, nSize, 0)) == SOCKET_ERROR) {
  111. throw new CBlockingSocketException("Send");
  112. }
  113. return nBytesSent;
  114. }
  115. int CBlockingSocket::Receive(char* pch, const int nSize, const int nSecs)
  116. {
  117. ASSERT(m_hSocket != NULL);
  118. FD_SET fd = {1, m_hSocket};
  119. TIMEVAL tv = {nSecs, 0};
  120. if(select(0, &fd, NULL, NULL, &tv) == 0) {
  121. throw new CBlockingSocketException("Receive timeout");
  122. }
  123. int nBytesReceived;
  124. if((nBytesReceived = recv(m_hSocket, pch, nSize, 0)) == SOCKET_ERROR) {
  125. throw new CBlockingSocketException("Receive");
  126. }
  127. return nBytesReceived;
  128. }
  129. int CBlockingSocket::ReceiveDatagram(char* pch, const int nSize, LPSOCKADDR psa, const int nSecs)
  130. {
  131. ASSERT(m_hSocket != NULL);
  132. FD_SET fd = {1, m_hSocket};
  133. TIMEVAL tv = {nSecs, 0};
  134. if(select(0, &fd, NULL, NULL, &tv) == 0) {
  135. throw new CBlockingSocketException("Receive timeout");
  136. }
  137. // input buffer should be big enough for the entire datagram
  138. int nFromSize = sizeof(SOCKADDR);
  139. int nBytesReceived = recvfrom(m_hSocket, pch, nSize, 0, psa, &nFromSize);
  140. if(nBytesReceived == SOCKET_ERROR) {
  141. throw new CBlockingSocketException("ReceiveDatagram");
  142. }
  143. return nBytesReceived;
  144. }
  145. int CBlockingSocket::SendDatagram(const char* pch, const int nSize, LPCSOCKADDR psa, const int nSecs)
  146. {
  147. ASSERT(m_hSocket != NULL);
  148. FD_SET fd = {1, m_hSocket};
  149. TIMEVAL tv = {nSecs, 0};
  150. if(select(0, NULL, &fd, NULL, &tv) == 0) {
  151. throw new CBlockingSocketException("Send timeout");
  152. }
  153. int nBytesSent = sendto(m_hSocket, pch, nSize, 0, psa, sizeof(SOCKADDR));
  154. if(nBytesSent == SOCKET_ERROR) {
  155. throw new CBlockingSocketException("SendDatagram");
  156. }
  157. return nBytesSent;
  158. }
  159. void CBlockingSocket::GetPeerAddr(LPSOCKADDR psa)
  160. {
  161. ASSERT(m_hSocket != NULL);
  162. // gets the address of the socket at the other end
  163. int nLengthAddr = sizeof(SOCKADDR);
  164. if(getpeername(m_hSocket, psa, &nLengthAddr) == SOCKET_ERROR) {
  165. throw new CBlockingSocketException("GetPeerName");
  166. }
  167. }
  168. void CBlockingSocket::GetSockAddr(LPSOCKADDR psa)
  169. {
  170. ASSERT(m_hSocket != NULL);
  171. // gets the address of the socket at this end
  172. int nLengthAddr = sizeof(SOCKADDR);
  173. if(getsockname(m_hSocket, psa, &nLengthAddr) == SOCKET_ERROR) {
  174. throw new CBlockingSocketException("GetSockName");
  175. }
  176. }
  177. //static
  178. CSockAddr CBlockingSocket::GetHostByName(const char* pchName, const USHORT ushPort /* = 0 */)
  179. {
  180. hostent* pHostEnt = gethostbyname(pchName);
  181. if(pHostEnt == NULL) {
  182. throw new CBlockingSocketException("GetHostByName");
  183. }
  184. ULONG* pulAddr = (ULONG*) pHostEnt->h_addr_list[0];
  185. SOCKADDR_IN sockTemp;
  186. sockTemp.sin_family = AF_INET;
  187. sockTemp.sin_port = htons(ushPort);
  188. sockTemp.sin_addr.s_addr = *pulAddr; // address is already in network byte order
  189. return sockTemp;
  190. }
  191. //static
  192. const char* CBlockingSocket::GetHostByAddr(LPCSOCKADDR psa)
  193. {
  194. hostent* pHostEnt = gethostbyaddr((char*) &((LPSOCKADDR_IN) psa)
  195. ->sin_addr.s_addr, 4, PF_INET);
  196. if(pHostEnt == NULL) {
  197. throw new CBlockingSocketException("GetHostByAddr");
  198. }
  199. return pHostEnt->h_name; // caller shouldn't delete this memory
  200. }
  201. // Class CHttpBlockingSocket
  202. IMPLEMENT_DYNAMIC(CHttpBlockingSocket, CBlockingSocket)
  203. CHttpBlockingSocket::CHttpBlockingSocket()
  204. {
  205. m_pReadBuf = new char[nSizeRecv];
  206. m_nReadBuf = 0;
  207. }
  208. CHttpBlockingSocket::~CHttpBlockingSocket()
  209. {
  210. delete [] m_pReadBuf;
  211. }
  212. int CHttpBlockingSocket::ReadHttpHeaderLine(char* pch, const int nSize, const int nSecs)
  213. // reads an entire header line through CRLF (or socket close)
  214. // inserts zero string terminator, object maintains a buffer
  215. {
  216. int nBytesThisTime = m_nReadBuf;
  217. int nLineLength = 0;
  218. char* pch1 = m_pReadBuf;
  219. char* pch2;
  220. do {
  221. // look for lf (assume preceded by cr)
  222. if((pch2 = (char*) memchr(pch1 , 'n', nBytesThisTime)) != NULL) {
  223. ASSERT((pch2) > m_pReadBuf);
  224. ASSERT(*(pch2 - 1) == 'r');
  225. nLineLength = (pch2 - m_pReadBuf) + 1;
  226. if(nLineLength >= nSize) nLineLength = nSize - 1;
  227. memcpy(pch, m_pReadBuf, nLineLength); // copy the line to caller
  228. m_nReadBuf -= nLineLength;
  229. memmove(m_pReadBuf, pch2 + 1, m_nReadBuf); // shift remaining characters left
  230. break;
  231. }
  232. pch1 += nBytesThisTime;
  233. nBytesThisTime = Receive(m_pReadBuf + m_nReadBuf, nSizeRecv - m_nReadBuf, nSecs);
  234. if(nBytesThisTime <= 0) { // sender closed socket or line longer than buffer
  235. throw new CBlockingSocketException("ReadHeaderLine");
  236. }
  237. m_nReadBuf += nBytesThisTime;
  238. }
  239. while(TRUE);
  240. *(pch + nLineLength) = '';
  241. return nLineLength;
  242. }
  243. int CHttpBlockingSocket::ReadHttpResponse(char* pch, const int nSize, const int nSecs)
  244. // reads remainder of a transmission through buffer full or socket close
  245. // (assume headers have been read already)
  246. {
  247. int nBytesToRead, nBytesThisTime, nBytesRead = 0;
  248. if(m_nReadBuf > 0) { // copy anything already in the recv buffer
  249. memcpy(pch, m_pReadBuf, m_nReadBuf);
  250. pch += m_nReadBuf;
  251. nBytesRead = m_nReadBuf;
  252. m_nReadBuf = 0;
  253. }
  254. do { // now pass the rest of the data directly to the caller
  255. nBytesToRead = min(nSizeRecv, nSize - nBytesRead);
  256. nBytesThisTime = Receive(pch, nBytesToRead, nSecs);
  257. if(nBytesThisTime <= 0) break; // sender closed the socket
  258. pch += nBytesThisTime;
  259. nBytesRead += nBytesThisTime;
  260. }
  261. while(nBytesRead <= nSize);
  262. return nBytesRead;
  263. }
  264. void LogBlockingSocketException(LPVOID pParam, char* pch, CBlockingSocketException* pe)
  265. { // pParam holds the HWND for the destination window (in another thread)
  266. CString strGmt = CTime::GetCurrentTime().FormatGmt("%m/%d/%y %H:%M:%S GMT");
  267. char text1[200], text2[50];
  268. pe->GetErrorMessage(text2, 49);
  269. wsprintf(text1, "WINSOCK ERROR--%s %s -- %srn", pch, text2, (const char*) strGmt);
  270. ::SendMessage((HWND) pParam, EM_SETSEL, (WPARAM) 65534, 65535);
  271. ::SendMessage((HWND) pParam, EM_REPLACESEL, (WPARAM) 0, (LPARAM) text1);
  272. }