ActiveSocket.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*---------------------------------------------------------------------------*/
  2. /* */
  3. /* CActiveSocket.cpp - Active Socket Implementation */
  4. /* */
  5. /* Author : Mark Carrier (mark@carrierlabs.com) */
  6. /* */
  7. /*---------------------------------------------------------------------------*/
  8. /* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. *
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in
  19. * the documentation and/or other materials provided with the
  20. * distribution.
  21. *
  22. * 3. The name of the author may not be used to endorse or promote products
  23. * derived from this software without specific prior written permission.
  24. *
  25. * 4. The name "CarrierLabs" must not be used to
  26. * endorse or promote products derived from this software without
  27. * prior written permission. For written permission, please contact
  28. * mark@carrierlabs.com.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
  31. * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  33. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
  34. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  41. * OF THE POSSIBILITY OF SUCH DAMAGE.
  42. *----------------------------------------------------------------------------*/
  43. #include "ActiveSocket.h"
  44. CActiveSocket::CActiveSocket(CSocketType nType) : CSimpleSocket(nType)
  45. {
  46. }
  47. //------------------------------------------------------------------------------
  48. //
  49. // ConnectTCP() -
  50. //
  51. //------------------------------------------------------------------------------
  52. bool CActiveSocket::ConnectTCP(const char *pAddr, uint16 nPort)
  53. {
  54. bool bRetVal = false;
  55. struct in_addr stIpAddress;
  56. //------------------------------------------------------------------
  57. // Preconnection setup that must be preformed
  58. //------------------------------------------------------------------
  59. memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr));
  60. m_stServerSockaddr.sin_family = AF_INET;
  61. if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL)
  62. {
  63. #ifdef WIN32
  64. TranslateSocketError();
  65. #else
  66. if (h_errno == HOST_NOT_FOUND)
  67. {
  68. SetSocketError(SocketInvalidAddress);
  69. }
  70. #endif
  71. return bRetVal;
  72. }
  73. memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length);
  74. m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr;
  75. if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError)
  76. {
  77. TranslateSocketError();
  78. return bRetVal;
  79. }
  80. m_stServerSockaddr.sin_port = htons(nPort);
  81. //------------------------------------------------------------------
  82. // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only.
  83. //
  84. //------------------------------------------------------------------
  85. m_timer.Initialize();
  86. m_timer.SetStartTime();
  87. if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) ==
  88. CSimpleSocket::SocketError)
  89. {
  90. //--------------------------------------------------------------
  91. // Get error value this might be a non-blocking socket so we
  92. // must first check.
  93. //--------------------------------------------------------------
  94. TranslateSocketError();
  95. //--------------------------------------------------------------
  96. // If the socket is non-blocking and the current socket error
  97. // is SocketEinprogress or SocketEwouldblock then poll connection
  98. // with select for designated timeout period.
  99. // Linux returns EINPROGRESS and Windows returns WSAEWOULDBLOCK.
  100. //--------------------------------------------------------------
  101. if ((IsNonblocking()) &&
  102. ((GetSocketError() == CSimpleSocket::SocketEwouldblock) ||
  103. (GetSocketError() == CSimpleSocket::SocketEinprogress)))
  104. {
  105. bRetVal = Select(GetConnectTimeoutSec(), GetConnectTimeoutUSec());
  106. }
  107. }
  108. else
  109. {
  110. TranslateSocketError();
  111. bRetVal = true;
  112. }
  113. m_timer.SetEndTime();
  114. return bRetVal;
  115. }
  116. //------------------------------------------------------------------------------
  117. //
  118. // ConnectUDP() -
  119. //
  120. //------------------------------------------------------------------------------
  121. bool CActiveSocket::ConnectUDP(const char *pAddr, uint16 nPort)
  122. {
  123. bool bRetVal = false;
  124. struct in_addr stIpAddress;
  125. //------------------------------------------------------------------
  126. // Pre-connection setup that must be preformed
  127. //------------------------------------------------------------------
  128. memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr));
  129. m_stServerSockaddr.sin_family = AF_INET;
  130. if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL)
  131. {
  132. #ifdef WIN32
  133. TranslateSocketError();
  134. #else
  135. if (h_errno == HOST_NOT_FOUND)
  136. {
  137. SetSocketError(SocketInvalidAddress);
  138. }
  139. #endif
  140. return bRetVal;
  141. }
  142. memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length);
  143. m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr;
  144. if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError)
  145. {
  146. TranslateSocketError();
  147. return bRetVal;
  148. }
  149. m_stServerSockaddr.sin_port = htons(nPort);
  150. //------------------------------------------------------------------
  151. // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only.
  152. //
  153. //------------------------------------------------------------------
  154. m_timer.Initialize();
  155. m_timer.SetStartTime();
  156. if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError)
  157. {
  158. bRetVal = true;
  159. }
  160. TranslateSocketError();
  161. m_timer.SetEndTime();
  162. return bRetVal;
  163. }
  164. //------------------------------------------------------------------------------
  165. //
  166. // ConnectRAW() -
  167. //
  168. //------------------------------------------------------------------------------
  169. bool CActiveSocket::ConnectRAW(const char *pAddr, uint16 nPort)
  170. {
  171. bool bRetVal = false;
  172. struct in_addr stIpAddress;
  173. //------------------------------------------------------------------
  174. // Pre-connection setup that must be preformed
  175. //------------------------------------------------------------------
  176. memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr));
  177. m_stServerSockaddr.sin_family = AF_INET;
  178. if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL)
  179. {
  180. #ifdef WIN32
  181. TranslateSocketError();
  182. #else
  183. if (h_errno == HOST_NOT_FOUND)
  184. {
  185. SetSocketError(SocketInvalidAddress);
  186. }
  187. #endif
  188. return bRetVal;
  189. }
  190. memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length);
  191. m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr;
  192. if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError)
  193. {
  194. TranslateSocketError();
  195. return bRetVal;
  196. }
  197. m_stServerSockaddr.sin_port = htons(nPort);
  198. //------------------------------------------------------------------
  199. // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only.
  200. //
  201. //------------------------------------------------------------------
  202. m_timer.Initialize();
  203. m_timer.SetStartTime();
  204. if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError)
  205. {
  206. bRetVal = true;
  207. }
  208. TranslateSocketError();
  209. m_timer.SetEndTime();
  210. return bRetVal;
  211. }
  212. //------------------------------------------------------------------------------
  213. //
  214. // Open() - Create a connection to a specified address on a specified port
  215. //
  216. //------------------------------------------------------------------------------
  217. bool CActiveSocket::Open(const char *pAddr, uint16 nPort)
  218. {
  219. bool bRetVal = false;
  220. if (IsSocketValid() == false)
  221. {
  222. SetSocketError(CSimpleSocket::SocketInvalidSocket);
  223. return bRetVal;
  224. }
  225. if (pAddr == NULL)
  226. {
  227. SetSocketError(CSimpleSocket::SocketInvalidAddress);
  228. return bRetVal;
  229. }
  230. if (nPort == 0)
  231. {
  232. SetSocketError(CSimpleSocket::SocketInvalidPort);
  233. return bRetVal;
  234. }
  235. switch (m_nSocketType)
  236. {
  237. case CSimpleSocket::SocketTypeTcp :
  238. {
  239. bRetVal = ConnectTCP(pAddr, nPort);
  240. break;
  241. }
  242. case CSimpleSocket::SocketTypeUdp :
  243. {
  244. bRetVal = ConnectUDP(pAddr, nPort);
  245. break;
  246. }
  247. case CSimpleSocket::SocketTypeRaw :
  248. break;
  249. default:
  250. break;
  251. }
  252. //--------------------------------------------------------------------------
  253. // If successful then create a local copy of the address and port
  254. //--------------------------------------------------------------------------
  255. if (bRetVal)
  256. {
  257. socklen_t nSockLen = sizeof(struct sockaddr);
  258. memset(&m_stServerSockaddr, 0, nSockLen);
  259. getpeername(m_socket, (struct sockaddr *)&m_stServerSockaddr, &nSockLen);
  260. nSockLen = sizeof(struct sockaddr);
  261. memset(&m_stClientSockaddr, 0, nSockLen);
  262. getsockname(m_socket, (struct sockaddr *)&m_stClientSockaddr, &nSockLen);
  263. SetSocketError(SocketSuccess);
  264. }
  265. return bRetVal;
  266. }