PageRenderTime 34ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/ClassMaster2014/barahon/Cultivation_9_UnixSource/minorGems/network/linux/SocketClientLinux.cpp

https://gitlab.com/garheade/linux_camp
C++ | 362 lines | 161 code | 91 blank | 110 comment | 34 complexity | d3aa395619ec6d7f31bd93cb7d76cb93 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. * Modification History
  3. *
  4. * 2001-January-10 Jason Rohrer
  5. * Created.
  6. *
  7. * 2001-January-15 Jason Rohrer
  8. * Commented out a redundant print statement (it's better if these kinds
  9. * of messages are handled at a higher level).
  10. *
  11. * 2001-January-28 Jason Rohrer
  12. * Changed to comply with new initSocketFramework Socket interface.
  13. *
  14. * 2001-January-29 Jason Rohrer
  15. * Fixed an endian bug with the port number.
  16. *
  17. * 2001-November-13 Jason Rohrer
  18. * Added a missing include.
  19. *
  20. * 2001-December-12 Jason Rohrer
  21. * Changed the include order to make BSD compatible.
  22. *
  23. * 2002-August-5 Jason Rohrer
  24. * Removed use of obsolete call.
  25. *
  26. * 2002-October-13 Jason Rohrer
  27. * Added support for timeout on connect.
  28. *
  29. * 2002-October-17 Jason Rohrer
  30. * Added missing include.
  31. * Added support for BSD's version of getsockopt.
  32. *
  33. * 2002-Novenber-27 Jason Rohrer
  34. * Changed to print error number. There's a bug that needs to be fixed.
  35. *
  36. * 2002-December-2 Jason Rohrer
  37. * Fixed resource leak when connection fails.
  38. *
  39. * 2003-March-18 Jason Rohrer
  40. * Fixed a thread safety issue with gethostbyname.
  41. *
  42. * 2004-January-2 Jason Rohrer
  43. * Fixed a memory leak when host name lookup fails.
  44. *
  45. * 2004-January-4 Jason Rohrer
  46. * Added use of network function locks.
  47. *
  48. * 2006-April-25 Jason Rohrer
  49. * Added missing check for a NULL outTimedOut parameter.
  50. *
  51. * 2008-September-30 Jason Rohrer
  52. * Added support for non-blocking connect.
  53. *
  54. * 2009-April-3 Jason Rohrer
  55. * OpenBSD support.
  56. *
  57. * 2009-June-15 Jason Rohrer
  58. * Fixed bug when connect timeout not used.
  59. *
  60. * 2010-January-26 Jason Rohrer
  61. * Fixed socklen_t on later versions of MacOSX.
  62. */
  63. #include "minorGems/network/SocketClient.h"
  64. #include "minorGems/network/NetworkFunctionLocks.h"
  65. #include "minorGems/system/MutexLock.h"
  66. #include <stdlib.h>
  67. #include <sys/types.h>
  68. #include <netdb.h>
  69. #include <netinet/in.h>
  70. #include <arpa/inet.h>
  71. #include <sys/socket.h>
  72. #include <fcntl.h>
  73. #include <time.h>
  74. #include <sys/time.h>
  75. #include <unistd.h>
  76. #include <errno.h>
  77. // BSD does not define socklen_t
  78. #ifdef BSD
  79. #ifndef IPHONE
  80. #ifndef __OpenBSD__
  81. #ifndef _SOCKLEN_T // later versions of MacOS define it and mark it
  82. typedef int socklen_t;
  83. #endif
  84. #endif
  85. #endif
  86. #endif
  87. // prototypes
  88. struct in_addr *nameToAddress( char *inAddress );
  89. int timed_connect( int inSocketID,
  90. struct sockaddr *inSocketAddress,
  91. int inAddressLength,
  92. int inTimeoutInMilliseconds );
  93. Socket *SocketClient::connectToServer( HostAddress *inAddress,
  94. long inTimeoutInMilliseconds,
  95. char *outTimedOut ) {
  96. if( !Socket::isFrameworkInitialized() ) {
  97. // try to init the framework
  98. int error = Socket::initSocketFramework();
  99. if( error == -1 ) {
  100. printf( "initializing network socket framework failed\n" );
  101. return NULL;
  102. }
  103. }
  104. int socketID = socket( AF_INET, SOCK_STREAM, 0 );
  105. if( socketID == -1 ) {
  106. printf( "Creating socket failed, error %d.\n", errno );
  107. return NULL;
  108. }
  109. union sock {
  110. struct sockaddr s;
  111. struct sockaddr_in i;
  112. } sock;
  113. struct in_addr *internet_address =
  114. nameToAddress( inAddress->mAddressString );
  115. if( internet_address == NULL ) {
  116. printf( "Host name lookup failed: " );
  117. inAddress->print();
  118. printf( "\n" );
  119. close( socketID );
  120. return NULL;
  121. }
  122. sock.i.sin_family = AF_INET;
  123. sock.i.sin_port = htons( inAddress->mPort );
  124. sock.i.sin_addr = *internet_address;
  125. int error;
  126. if( inTimeoutInMilliseconds != -1 ) {
  127. // use timeout
  128. error = timed_connect( socketID, &sock.s, sizeof( struct sockaddr ),
  129. inTimeoutInMilliseconds );
  130. if( outTimedOut != NULL ) {
  131. if( error == -2 ) {
  132. *outTimedOut = true;
  133. if( inTimeoutInMilliseconds == 0 ) {
  134. // caller didn't want to wait at all
  135. error = 0;
  136. }
  137. else {
  138. // treat timeout as error
  139. error = -1;
  140. }
  141. }
  142. else {
  143. *outTimedOut = false;
  144. }
  145. }
  146. }
  147. else {
  148. // don't use timeout
  149. error = connect( socketID, &sock.s, sizeof( struct sockaddr ) );
  150. }
  151. delete internet_address;
  152. if( error == -1 ) {
  153. //printf( "Connecting to host failed: " );
  154. //inAddress->print();
  155. //printf( "\n" );
  156. close( socketID );
  157. return NULL;
  158. }
  159. // package into a Socket and return it
  160. Socket *returnSocket = new Socket();
  161. int *idSpace = new int[1];
  162. idSpace[0] = socketID;
  163. returnSocket->mNativeObjectPointer = (void *)idSpace;
  164. if( outTimedOut != NULL &&
  165. *outTimedOut ) {
  166. // not connected yet
  167. returnSocket->setConnected( false );
  168. }
  169. return returnSocket;
  170. }
  171. /* Converts ascii text to in_addr struct. NULL is returned if the
  172. address can not be found.
  173. Result must be destroyed by caller.
  174. Adapted from the Unix Socket FAQ */
  175. struct in_addr *nameToAddress( char *inAddress ) {
  176. struct hostent *host;
  177. static struct in_addr saddr;
  178. struct in_addr *copiedSaddr = new struct in_addr;
  179. /* First try it as aaa.bbb.ccc.ddd. */
  180. // this is obsolete on linux
  181. // saddr.s_addr = inet_addr( inAddress );
  182. int error = inet_aton( inAddress, &saddr );
  183. if( error != 0 ) {
  184. // copy to avoid returning pointer to stack
  185. memcpy( copiedSaddr, &saddr, sizeof( struct in_addr ) );
  186. return copiedSaddr;
  187. }
  188. // must keep this locked until we are done copying the in_addr out
  189. // of the returned hostent
  190. NetworkFunctionLocks::mGetHostByNameLock.lock();
  191. char hostFound = false;
  192. host = gethostbyname( inAddress );
  193. if( host != NULL ) {
  194. memcpy( copiedSaddr,
  195. *host->h_addr_list,
  196. sizeof( struct in_addr ) );
  197. hostFound = true;
  198. }
  199. NetworkFunctionLocks::mGetHostByNameLock.unlock();
  200. if( hostFound ) {
  201. return copiedSaddr;
  202. }
  203. else {
  204. delete copiedSaddr;
  205. }
  206. return NULL;
  207. }
  208. /* timed_connect adapted from gnut, by Josh Pieper */
  209. /* Josh Pieper, (c) 2000 */
  210. /* This file is distributed under the GPL, see file COPYING for details */
  211. // just like connect except that it times out after time secs
  212. // returns -2 on timeout, otherwise same as connect
  213. int timed_connect( int inSocketID,
  214. struct sockaddr *inSocketAddress,
  215. int inAddressLength,
  216. int inTimeoutInMilliseconds ) {
  217. int ret;
  218. fd_set fsr;
  219. struct timeval tv;
  220. int val;
  221. socklen_t len;
  222. //g_debug(1,"entering sock=%i secs=%i\n",inSocketID,inTimeoutInSeconds);
  223. ret = fcntl( inSocketID, F_SETFL, O_NONBLOCK );
  224. //g_debug(5,"fcntl returned %i\n",ret);
  225. if( ret < 0 ) {
  226. return ret;
  227. }
  228. ret = connect( inSocketID, inSocketAddress, inAddressLength );
  229. //g_debug(5,"connect returned %i\n",ret);
  230. if( ret == 0 ) {
  231. //g_debug(0,"immediate connection!\n");
  232. // wooah! immediate connection
  233. // return -2;
  234. // changed from what Josh originally returned (-2)
  235. // immediate connection *can* happen sometimes, right?
  236. // for example, when connecting to localhost...
  237. return 0;
  238. }
  239. // if (errno != EINPROGRESS) {
  240. // perror("timed_connect, connect");
  241. // return ret;
  242. // }
  243. FD_ZERO( &fsr );
  244. FD_SET( inSocketID, &fsr );
  245. tv.tv_sec = inTimeoutInMilliseconds / 1000;
  246. int remainder = inTimeoutInMilliseconds % 1000;
  247. tv.tv_usec = remainder * 1000;
  248. ret = select( inSocketID+1, NULL, &fsr, NULL, &tv );
  249. //g_debug(5,"select returned %i\n",ret);
  250. if( ret==0 ) {
  251. // timeout
  252. //g_debug(1,"timeout\n");
  253. fcntl( inSocketID, F_SETFL, 0 );
  254. return -2;
  255. }
  256. len = 4;
  257. ret = getsockopt( inSocketID, SOL_SOCKET, SO_ERROR, &val, &len );
  258. //g_debug(5,"getsockopt returned %i val=%i\n",ret,val);
  259. if( ret < 0 ) {
  260. //g_debug(1,"getsockopt returned: %i\n",ret);
  261. return ret;
  262. }
  263. if (val!=0) {
  264. //g_debug(3,"returning failure!\n");
  265. return -1;
  266. }
  267. ret = fcntl( inSocketID, F_SETFL, 0 );
  268. //g_debug(1,"fcntl: %i\n",ret);
  269. //g_debug(3,"returning success val=%i\n",val);
  270. return 0;
  271. }