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

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

https://gitlab.com/garheade/linux_camp
C++ | 329 lines | 143 code | 92 blank | 94 comment | 25 complexity | 28947a7fdfb48e7162740eb525d906f1 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-February-4 Jason Rohrer
  8. * Fixed receive so that it waits for all requested bytes to arrive.
  9. *
  10. * 2001-March-4 Jason Rohrer
  11. * Replaced include of <winbase.h> and <windef.h> with <windows.h>
  12. * to fix compile bugs encountered with newer windows compilers.
  13. *
  14. * 2001-May-12 Jason Rohrer
  15. * Fixed a bug in socket receive error checking.
  16. *
  17. * 2001-November-13 Jason Rohrer
  18. * Changed timeout parameter to signed, since -1 is a possible argument.
  19. *
  20. * 2002-April-15 Jason Rohrer
  21. * Removed call to WSAGetLastError, since it seems to pick up errors from
  22. * non-socket calls. For example, if sys/stat.h stat() is called on a file
  23. * that does not exist, WSAGetLastError returns 2, which is not even a
  24. * winsock error code. We should probably report this bug, huh?
  25. *
  26. * 2002-August-2 Jason Rohrer
  27. * Added functon for getting remote host address, but no implementation.
  28. *
  29. * 2002-August-5 Jason Rohrer
  30. * Added implementation of getRemoteHostAddress().
  31. *
  32. * 2002-September-8 Jason Rohrer
  33. * Fixed a major looping bug with broken sockets.
  34. *
  35. * 2002-November-15 Jason Rohrer
  36. * Fixed a security hole when getting the remote host address.
  37. *
  38. * 2003-February-4 Jason Rohrer
  39. * Added a function for getting the local host address from a socket.
  40. * Still need to test the win32 version of this.
  41. *
  42. * 2003-February-5 Jason Rohrer
  43. * Fixed a bug in call to gethostname. Removed unused variable.
  44. *
  45. * 2004-January-4 Jason Rohrer
  46. * Added use of network function locks.
  47. *
  48. * 2004-January-11 Jason Rohrer
  49. * Fixed a bug in handling of timeout return value.
  50. *
  51. * 2004-March-23 Jason Rohrer
  52. * Removed timeout error message.
  53. *
  54. * 2004-December-13 Jason Rohrer
  55. * Added a breakConnection function.
  56. *
  57. * 2004-December-24 Jason Rohrer
  58. * Fixed bug in close call.
  59. *
  60. * 2005-July-5 Jason Rohrer
  61. * Added port number when getting address of remote host.
  62. */
  63. #include "minorGems/network/Socket.h"
  64. #include "minorGems/network/NetworkFunctionLocks.h"
  65. #include <winsock.h>
  66. #include <windows.h>
  67. #include <stdio.h>
  68. #include <time.h>
  69. #include <string.h>
  70. // prototypes
  71. int timed_read( int inSock, unsigned char *inBuf,
  72. int inLen, long inMilliseconds );
  73. /**
  74. * Windows-specific implementation of the Socket class member functions.
  75. *
  76. */
  77. // Win32 does not define socklen_t
  78. typedef int socklen_t;
  79. char Socket::sInitialized = false;
  80. int Socket::initSocketFramework() {
  81. WORD wVersionRequested;
  82. WSADATA wsaData;
  83. int err;
  84. wVersionRequested = MAKEWORD( 1, 0 );
  85. err = WSAStartup( wVersionRequested, &wsaData );
  86. if ( err != 0 ) {
  87. // no usable DLL found
  88. printf( "WinSock DLL version 1.0 or higher not found.\n" );
  89. return -1;
  90. }
  91. sInitialized = true;
  92. return 0;
  93. }
  94. Socket::~Socket() {
  95. int *socketIDptr = (int *)( mNativeObjectPointer );
  96. int socketID = socketIDptr[0];
  97. if( !mIsConnectionBroken ) {
  98. // 2 specifies shutting down both sends and receives
  99. shutdown( socketID, 2 );
  100. mIsConnectionBroken = true;
  101. }
  102. closesocket( socketID );
  103. delete [] socketIDptr;
  104. }
  105. int Socket::send( unsigned char *inBuffer, int inNumBytes ) {
  106. int *socketIDptr = (int *)( mNativeObjectPointer );
  107. int socketID = socketIDptr[0];
  108. return ::send( socketID, (char*)inBuffer, inNumBytes, 0 );
  109. }
  110. int Socket::receive( unsigned char *inBuffer, int inNumBytes,
  111. long inTimeout ) {
  112. int *socketIDptr = (int *)( mNativeObjectPointer );
  113. int socketID = socketIDptr[0];
  114. int numReceived = 0;
  115. char error = false;
  116. char errorReturnValue = -1;
  117. // for win32, we can't specify MSG_WAITALL
  118. // so we have too loop until the entire message is received,
  119. // as long as there is no error.
  120. while( numReceived < inNumBytes && !error ) {
  121. // the number of bytes left to receive
  122. int numRemaining = inNumBytes - numReceived;
  123. // pointer to the spot in the buffer where the
  124. // remaining bytes should be stored
  125. unsigned char *remainingBuffer = &( inBuffer[ numReceived ] );
  126. int numReceivedIn;
  127. if( inTimeout == -1 ) {
  128. numReceivedIn =
  129. recv( socketID, (char*)remainingBuffer, numRemaining, 0 );
  130. }
  131. else {
  132. numReceivedIn =
  133. timed_read( socketID, remainingBuffer,
  134. numRemaining, inTimeout );
  135. }
  136. if( numReceivedIn > 0 ) {
  137. numReceived += numReceivedIn;
  138. }
  139. else {
  140. error = true;
  141. if( numReceivedIn == 0 ) {
  142. // the socket was gracefully closed
  143. errorReturnValue = -1;
  144. }
  145. else if( numReceivedIn == SOCKET_ERROR ) {
  146. // socket error
  147. errorReturnValue = -1;
  148. }
  149. else if( numReceivedIn == -2 ) {
  150. // timeout
  151. errorReturnValue = -2;
  152. }
  153. else {
  154. printf( "Unexpected return value from socket receive: %d.\n",
  155. numReceivedIn );
  156. errorReturnValue = -1;
  157. }
  158. }
  159. }
  160. return numReceived;
  161. }
  162. void Socket::breakConnection() {
  163. int *socketIDptr = (int *)( mNativeObjectPointer );
  164. int socketID = socketIDptr[0];
  165. if( !mIsConnectionBroken ) {
  166. shutdown( socketID, 2 );
  167. mIsConnectionBroken = true;
  168. }
  169. closesocket( socketID );
  170. }
  171. HostAddress *Socket::getRemoteHostAddress() {
  172. int *socketIDptr = (int *)( mNativeObjectPointer );
  173. int socketID = socketIDptr[0];
  174. // adapted from Unix Socket FAQ
  175. socklen_t len;
  176. struct sockaddr_in sin;
  177. len = sizeof sin;
  178. int error = getpeername( socketID, (struct sockaddr *) &sin, &len );
  179. if( error ) {
  180. return NULL;
  181. }
  182. // this is potentially insecure, since a fake DNS name might be returned
  183. // we should use the IP address only
  184. //
  185. // struct hostent *host = gethostbyaddr( (char *) &sin.sin_addr,
  186. // sizeof sin.sin_addr,
  187. // AF_INET );
  188. NetworkFunctionLocks::mInet_ntoaLock.lock();
  189. // returned string is statically allocated, copy it
  190. char *ipAddress = stringDuplicate( inet_ntoa( sin.sin_addr ) );
  191. NetworkFunctionLocks::mInet_ntoaLock.unlock();
  192. int port = ntohs( sin.sin_port );
  193. return new HostAddress( ipAddress, port );
  194. }
  195. HostAddress *Socket::getLocalHostAddress() {
  196. int *socketIDptr = (int *)( mNativeObjectPointer );
  197. int socketID = socketIDptr[0];
  198. // adapted from GTK-gnutalla code, and elsewhere
  199. struct sockaddr_in addr;
  200. int len = sizeof( struct sockaddr_in );
  201. int result = getsockname( socketID, (struct sockaddr*)( &addr ), &len );
  202. if( result == -1 ) {
  203. return NULL;
  204. }
  205. else {
  206. char *stringAddress = inet_ntoa( addr.sin_addr );
  207. return new HostAddress( stringDuplicate( stringAddress ),
  208. 0 );
  209. }
  210. }
  211. /* timed_read adapted from gnut, by Josh Pieper */
  212. /* Josh Pieper, (c) 2000 */
  213. /* This file is distributed under the GPL, see file COPYING for details */
  214. // exactly like the real read, except that it returns -2
  215. // if no data was read before the timeout occurred...
  216. int timed_read( int inSock, unsigned char *inBuf,
  217. int inLen, long inMilliseconds ) {
  218. fd_set fsr;
  219. struct timeval tv;
  220. int ret;
  221. FD_ZERO( &fsr );
  222. FD_SET( inSock, &fsr );
  223. tv.tv_sec = inMilliseconds / 1000;
  224. int remainder = inMilliseconds % 1000;
  225. tv.tv_usec = remainder * 1000;
  226. ret = select( inSock + 1, &fsr, NULL, NULL, &tv );
  227. if( ret==0 ) {
  228. // printf( "Timed out waiting for data on socket receive.\n" );
  229. return -2;
  230. }
  231. if( ret<0 ) {
  232. printf( "Selecting socket during receive failed.\n" );
  233. return ret;
  234. }
  235. ret = recv( inSock, (char*)inBuf, inLen, 0 );
  236. return ret;
  237. }