PageRenderTime 50ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/ClassMaster2014/barahon/Transcend_0.3_UnixSource/minorGems/network/win32/SocketClientWin32.cpp

https://gitlab.com/garheade/linux_camp
C++ | 298 lines | 139 code | 83 blank | 76 comment | 27 complexity | c15acb1d2b3bfaf03cb86e78153b5659 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. * Modification History
  3. *
  4. * 2001-January-28 Jason Rohrer
  5. * Created.
  6. *
  7. * 2001-January-29 Jason Rohrer
  8. * Fixed an endian bug that was messing up the port numbers.
  9. *
  10. * 2002-October-13 Jason Rohrer
  11. * Added support for timeout on connect.
  12. * Fixed several windows compile bugs.
  13. *
  14. * 2002-December-2 Jason Rohrer
  15. * Fixed resource leak when connection fails.
  16. * Changed close calls to win32 closesocket calls.
  17. *
  18. * 2004-January-2 Jason Rohrer
  19. * Fixed a thread safety issue with gethostbyname.
  20. *
  21. * 2004-January-4 Jason Rohrer
  22. * Added use of network function locks.
  23. */
  24. #include "minorGems/network/SocketClient.h"
  25. #include "minorGems/network/NetworkFunctionLocks.h"
  26. #include "minorGems/system/MutexLock.h"
  27. #include <Winsock.h>
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <fcntl.h>
  31. #include <time.h>
  32. // prototypes
  33. struct in_addr *nameToAddress( char *inAddress );
  34. int timed_connect( int inSocketID,
  35. struct sockaddr *inSocketAddress,
  36. int inAddressLength,
  37. int inTimeoutInMilliseconds );
  38. Socket *SocketClient::connectToServer( HostAddress *inAddress,
  39. long inTimeoutInMilliseconds,
  40. char *outTimedOut ) {
  41. if( !Socket::isFrameworkInitialized() ) {
  42. // try to init the framework
  43. int error = Socket::initSocketFramework();
  44. if( error == -1 ) {
  45. printf( "initializing network socket framework failed\n" );
  46. return NULL;
  47. }
  48. }
  49. int socketID = socket( AF_INET, SOCK_STREAM, 0 );
  50. if( socketID == INVALID_SOCKET ) {
  51. printf( "Creating socket failed.\n" );
  52. return NULL;
  53. }
  54. union sock {
  55. struct sockaddr s;
  56. struct sockaddr_in i;
  57. } sock;
  58. //struct in_addr internet_address;
  59. //struct hostent *hp;
  60. struct in_addr *internet_address =
  61. nameToAddress( inAddress->mAddressString );
  62. if( internet_address == NULL ) {
  63. printf( "Host name lookup failed: " );
  64. inAddress->print();
  65. printf( "\n" );
  66. closesocket( socketID );
  67. return NULL;
  68. }
  69. //hp = gethostbyname( inAddress->mAddressString );
  70. //memcpy( &internet_address, *( hp->h_addr_list ), sizeof( struct in_addr ) );
  71. sock.i.sin_family = AF_INET;
  72. sock.i.sin_port = htons( inAddress->mPort );
  73. sock.i.sin_addr = *internet_address;
  74. int error;
  75. if( inTimeoutInMilliseconds != -1 ) {
  76. // use timeout
  77. error = timed_connect( socketID, &sock.s, sizeof( struct sockaddr ),
  78. inTimeoutInMilliseconds );
  79. if( error == -2 ) {
  80. *outTimedOut = true;
  81. error = -1;
  82. }
  83. else {
  84. *outTimedOut = false;
  85. }
  86. }
  87. else {
  88. // don't use timeout
  89. error = connect( socketID, &sock.s, sizeof( struct sockaddr ) );
  90. }
  91. delete internet_address;
  92. if( error == -1 ) {
  93. //printf( "Connecting to host failed: " );
  94. //inAddress->print();
  95. //printf( "\n" );
  96. closesocket( socketID );
  97. return NULL;
  98. }
  99. // packate into a Socket and return it
  100. Socket *returnSocket = new Socket();
  101. int *idSpace = new int[1];
  102. idSpace[0] = socketID;
  103. returnSocket->mNativeObjectPointer = (void *)idSpace;
  104. return returnSocket;
  105. }
  106. /* Converts ascii text to in_addr struct. NULL is returned if the
  107. address can not be found.
  108. Result must be destroyed by caller.
  109. Adapted from the Unix Socket FAQ */
  110. struct in_addr *nameToAddress( char *inAddress ) {
  111. struct hostent *host;
  112. struct hostent *copiedHost;
  113. static struct in_addr saddr;
  114. struct in_addr *copiedSaddr = new struct in_addr;
  115. /* First try it as aaa.bbb.ccc.ddd. */
  116. saddr.s_addr = inet_addr( inAddress );
  117. if( saddr.s_addr != -1 ) {
  118. // copy to avoid returning pointer to stack
  119. memcpy( copiedSaddr, &saddr, sizeof( struct in_addr ) );
  120. return copiedSaddr;
  121. }
  122. // must keep this locked until we are done copying the in_addr out
  123. // of the returned hostent
  124. NetworkFunctionLocks::mGetHostByNameLock.lock();
  125. char hostFound = false;
  126. host = gethostbyname( inAddress );
  127. if( host != NULL ) {
  128. memcpy( copiedSaddr,
  129. *host->h_addr_list,
  130. sizeof( struct in_addr ) );
  131. hostFound = true;
  132. }
  133. NetworkFunctionLocks::mGetHostByNameLock.unlock();
  134. if( hostFound ) {
  135. return copiedSaddr;
  136. }
  137. else {
  138. delete copiedSaddr;
  139. }
  140. return NULL;
  141. }
  142. /* timed_read adapted from gnut, by Josh Pieper */
  143. /* Josh Pieper, (c) 2000 */
  144. /* This file is distributed under the GPL, see file COPYING for details */
  145. // just like connect except that it times out after time secs
  146. // returns -2 on timeout, otherwise same as connect
  147. int timed_connect( int inSocketID,
  148. struct sockaddr *inSocketAddress,
  149. int inAddressLength,
  150. int inTimeoutInMilliseconds ) {
  151. int ret;
  152. fd_set fsr;
  153. struct timeval tv;
  154. int val;
  155. int len;
  156. //g_debug(1,"entering sock=%i secs=%i\n",inSocketID,inTimeoutInSeconds);
  157. //ret = fcntl( inSocketID, F_SETFL, O_NONBLOCK );
  158. // use ioctlsocket on win32 instead of fcntl
  159. // set to non-blocking mode
  160. unsigned long onFlag = 1;
  161. ret = ioctlsocket( inSocketID, FIONBIO, &onFlag );
  162. //g_debug(5,"fcntl returned %i\n",ret);
  163. if( ret < 0 ) {
  164. return ret;
  165. }
  166. ret = connect( inSocketID, inSocketAddress, inAddressLength );
  167. //g_debug(5,"connect returned %i\n",ret);
  168. if( ret == 0 ) {
  169. //g_debug(0,"immediate connection!\n");
  170. // wooah! immediate connection
  171. // return -2;
  172. // changed from what Josh originally returned (-2)
  173. // immediate connection *can* happen sometimes, right?
  174. // for example, when connecting to localhost...
  175. return 0;
  176. }
  177. // if (errno != EINPROGRESS) {
  178. // perror("timed_connect, connect");
  179. // return ret;
  180. // }
  181. FD_ZERO( &fsr );
  182. FD_SET( inSocketID, &fsr );
  183. tv.tv_sec = inTimeoutInMilliseconds / 1000;
  184. int remainder = inTimeoutInMilliseconds % 1000;
  185. tv.tv_usec = remainder * 1000;
  186. ret = select( inSocketID+1, NULL, &fsr, NULL, &tv );
  187. //g_debug(5,"select returned %i\n",ret);
  188. if( ret==0 ) {
  189. // timeout
  190. //g_debug(1,"timeout\n");
  191. //fcntl( inSocketID, F_SETFL, 0 );
  192. unsigned long offFlag = 0;
  193. ret = ioctlsocket( inSocketID, FIONBIO, &offFlag );
  194. return -2;
  195. }
  196. len = 4;
  197. ret = getsockopt( inSocketID, SOL_SOCKET, SO_ERROR, (char*)( &val ), &len );
  198. //g_debug(5,"getsockopt returned %i val=%i\n",ret,val);
  199. if( ret < 0 ) {
  200. //g_debug(1,"getsockopt returned: %i\n",ret);
  201. return ret;
  202. }
  203. if (val!=0) {
  204. //g_debug(3,"returning failure!\n");
  205. return -1;
  206. }
  207. //ret = fcntl( inSocketID, F_SETFL, 0 );
  208. // use ioctlsocket on win32 instead of fcntl
  209. // set back to blocking mode
  210. unsigned long offFlag = 0;
  211. ret = ioctlsocket( inSocketID, FIONBIO, &offFlag );
  212. //g_debug(1,"fcntl: %i\n",ret);
  213. //g_debug(3,"returning success val=%i\n",val);
  214. return 0;
  215. }