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

/ClassMaster2014/barahon/Cultivation_9_UnixSource/minorGems/network/win32/SocketClientWin32.cpp

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