PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/ClassMaster2014/barahon/Transcend_0.3_UnixSource/minorGems/network/linux/SocketClientLinux.cpp

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