You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

networking.inline.hpp 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // networking.inline.hpp
  2. // Copyright (C) 2006-2009 MicroNeil Research Corporation.
  3. //
  4. // This program is part of the MicroNeil Research Open Library Project. For
  5. // more information go to http://www.microneil.com/OpenLibrary/index.html
  6. //
  7. // This program is free software; you can redistribute it and/or modify it
  8. // under the terms of the GNU General Public License as published by the
  9. // Free Software Foundation; either version 2 of the License, or (at your
  10. // option) any later version.
  11. //
  12. // This program is distributed in the hope that it will be useful, but WITHOUT
  13. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  15. // more details.
  16. //
  17. // You should have received a copy of the GNU General Public License along with
  18. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  19. // Place, Suite 330, Boston, MA 02111-1307 USA
  20. //==============================================================================
  21. // Inlined methods for Networking module. See networking.hpp for notes.
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // Platform Specific
  24. //// Windows platform
  25. #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
  26. inline int Networking::getLastError() { // In windows you get the last error
  27. return WSAGetLastError(); // from WSAGetLastError();
  28. }
  29. inline int Networking::setNonBlocking(hSocket socket) { // Set a winsock to non-blocking
  30. unsigned long nonblocking = 1; // Create a flag...
  31. int result = 0;
  32. if(0 != ioctlsocket(socket, FIONBIO, &nonblocking)) { // Set the state of the socket.
  33. result = -1; // If that fails then return -1.
  34. }
  35. return result; // Show 'em my motto!
  36. }
  37. inline int Networking::closeSocket(hSocket socket) { // Close a socket in winsock
  38. return closesocket(socket); // wraps closesocket().
  39. }
  40. inline bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK.
  41. return (WSAEWOULDBLOCK == ErrorCode);
  42. }
  43. inline bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS.
  44. return( // [WSA]EALREADY also returns true.
  45. WSAEINPROGRESS == ErrorCode || // In fact, on Win* platforms we could
  46. WSAEALREADY == ErrorCode || // get any of these when retesting
  47. WSAEWOULDBLOCK == ErrorCode || // open() for a connection.
  48. WSAEINVAL == ErrorCode
  49. );
  50. }
  51. inline bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN.
  52. return(WSAEISCONN == ErrorCode);
  53. }
  54. #else
  55. //// GNU platform
  56. inline int Networking::getLastError() { // In GNU you get the last error
  57. return errno; // from errno;
  58. }
  59. inline int Networking::setNonBlocking(hSocket socket) { // Set a socket to non-blocking
  60. int flags, result; // Grab a place to hold the flags.
  61. flags = fcntl(socket, F_GETFL, 0); // Get the current flags.
  62. result = fcntl(socket, F_SETFL, flags | O_NONBLOCK); // Set the NONBLOCK flag & return.
  63. return result; // Return the result.
  64. }
  65. inline int Networking::closeSocket(hSocket socket) { // Close a socket in GNU
  66. return close(socket); // wraps close().
  67. }
  68. inline bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK.
  69. return (EWOULDBLOCK == ErrorCode);
  70. }
  71. inline bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS.
  72. return( // [WSA]EALREADY also returns true.
  73. EINPROGRESS == ErrorCode ||
  74. EALREADY == ErrorCode
  75. );
  76. }
  77. inline bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN.
  78. return(EISCONN == ErrorCode);
  79. }
  80. #endif
  81. // End Platform Specific
  82. ////////////////////////////////////////////////////////////////////////////////
  83. // Begin Platform Agnostic
  84. //// class IP4Address //////////////////////////////////////////////////////////
  85. inline IP4Address::IP4Address():IP(0){} // Blank constructor IP = 0.0.0.0
  86. inline IP4Address::IP4Address(const unsigned long int newIP):IP(newIP){} // Constructor given unsigned long
  87. inline IP4Address::IP4Address(const IP4Address& newIP):IP(newIP.IP){} // Constructor given an IP4Address
  88. inline IP4Address::IP4Address(const char* newIP) { (*this) = newIP; } // Construcing with a cstring.
  89. inline IP4Address::IP4Address(const std::string& newIP) { (*this) = newIP; } // Constructing with a cppstring.
  90. inline IP4Address&
  91. IP4Address::operator=(const unsigned long int Right) { // Convert from unsigned long int.
  92. IP = Right;
  93. return *this;
  94. }
  95. inline IP4Address& IP4Address::operator=(const char* Right) { // Convert from c string.
  96. IP = ntohl(inet_addr(Right));
  97. return *this;
  98. }
  99. inline IP4Address& IP4Address::operator=(const std::string& Right) { // Convert from cpp string.
  100. IP = ntohl(inet_addr(Right.c_str()));
  101. return *this;
  102. }
  103. inline bool IP4Address::operator<(const IP4Address Right) const { // < Comparison.
  104. return (IP < Right.IP);
  105. }
  106. inline bool IP4Address::operator>(const IP4Address Right) const { // > Comparison.
  107. return (IP > Right.IP);
  108. }
  109. inline bool IP4Address::operator==(const IP4Address Right) const { // == Comparison.
  110. return (IP == Right.IP);
  111. }
  112. inline bool IP4Address::operator!=(const IP4Address Right) const { // != Comparison.
  113. return (IP != Right.IP);
  114. }
  115. inline bool IP4Address::operator<=(const IP4Address Right) const { // <= Comparison.
  116. return (IP <= Right.IP);
  117. }
  118. inline bool IP4Address::operator>=(const IP4Address Right) const { // >= Comparison.
  119. return (IP >= Right.IP);
  120. }
  121. //// class SocketAddress ///////////////////////////////////////////////////////
  122. inline void SocketAddress::clear() {
  123. memset(&Address, 0, sizeof(Address)); // Zero out the address strcuture
  124. Address.sin_family = AF_INET; // Internet Address Family ip4
  125. Address.sin_addr.s_addr = htonl(INADDR_ANY); // Any IP address
  126. Address.sin_port = 0; // Zero means any port.
  127. }
  128. inline SocketAddress::SocketAddress() { // Constructor sets up w/ wildcards
  129. clear(); // Conveniently, we can use clear() :-)
  130. }
  131. inline struct sockaddr_in* SocketAddress::getPtr_sockaddr_in() { // Returns a pointer to sockaddr_in.
  132. return &Address; // Simply return it's address.
  133. }
  134. inline struct sockaddr* SocketAddress::getPtr_sockaddr() { // Returns a pointer to sockaddr.
  135. return (struct sockaddr*) &Address;
  136. }
  137. inline socklen_t SocketAddress::getAddressSize() {
  138. return sizeof(Address); // Return the size of the structure.
  139. }
  140. inline void SocketAddress::setAddress(unsigned long ipAddress) { // Set the IP address from an unsigned int
  141. Address.sin_addr.s_addr = htonl(ipAddress); // Convert to network order and assign.
  142. }
  143. inline void SocketAddress::setAddress(char const * ipString) { // Set the IP address from a cstring
  144. Address.sin_addr.s_addr = inet_addr(ipString); // Convert to number and assign.
  145. }
  146. inline unsigned long SocketAddress::getAddress() { // Get the IP address as an unsigned int
  147. return ntohl(Address.sin_addr.s_addr); // Convert to host order and return.
  148. }
  149. inline void SocketAddress::setPort(unsigned short port) { // Set the port address from an int
  150. Address.sin_port = htons(port); // Convert to network order and set.
  151. }
  152. inline void SocketAddress::setPort(char* port) { // Set the port address from a cstring
  153. setPort(atoi(port)); // Convert to int and set.
  154. }
  155. inline unsigned short SocketAddress::getPort() { // Get the port address as an unsigned int
  156. return ntohs(Address.sin_port); // Convert to host order and return.
  157. }
  158. inline const char* SocketAddress::getPort(char* str) { // Get the port address into a cstring.
  159. if(NULL == str) { // If the caller did not provide a
  160. str = PortStringBuffer; // buffer to use then we will use ours.
  161. }
  162. sprintf(str,"%d",getPort()); // Get the port and convert to cstring.
  163. return str; // Return the string we got.
  164. }
  165. //// class Socket //////////////////////////////////////////////////////////////
  166. inline Socket::Socket() : // When starting up we are
  167. Handle(INVALID_SOCKET), OpenSucceeded(false) { // not yet valid.
  168. }
  169. inline Socket::~Socket() { // When shutting down, be sure
  170. if(INVALID_SOCKET != Handle) { // any open socket is closed without
  171. Network.closeSocket(Handle); // throwing any exceptions.
  172. }
  173. }
  174. inline void Socket::close() { // When we close,
  175. if(INVALID_SOCKET != Handle) { // If the handle is open then
  176. if(Network.closeSocket(Handle)) { // close the handle and check for error.
  177. LastError = Network.getLastError(); // If there was an error record it.
  178. if(!Network.WouldBlock(LastError)) { // If the error was not WOULDBLOCK
  179. throw Networking::ControlError( // then throw a ControlError exception.
  180. Network.DescriptiveError(
  181. "Socket::close()", LastError));
  182. }
  183. } else { // If there was no error then
  184. LastError = 0; // reset the LastError value.
  185. }
  186. Handle = INVALID_SOCKET; // and reset the handle to INVALID.
  187. NonBlocking = false; // The default is Blocking.
  188. OpenSucceeded = false; // After close, forget we opened.
  189. }
  190. }
  191. inline hSocket Socket::getHandle() { // Returns the current Socket handle.
  192. return Handle;
  193. }
  194. inline bool Socket::isNonBlocking() { // Returns true if socket is NonBlocking
  195. return NonBlocking;
  196. }
  197. inline void Socket::makeNonBlocking() { // Sets the socket to NonBlocking mode.
  198. if(0 > Network.setNonBlocking(Handle)) { // Feed the call through Network.
  199. LastError = Network.getLastError(); // If it didn't work, go get the error.
  200. NonBlocking = false; // We are NOT NonBlocking.
  201. throw Networking::ControlError( // Throw a control error.
  202. Network.DescriptiveError(
  203. "Socket::makeNonBlocking()", LastError));
  204. } else {
  205. NonBlocking = true; // If we didn't throw, we're ON.
  206. }
  207. }
  208. inline bool Socket::isReuseAddress() { return ReuseAddress; } // True if socket is set SO_REUSEADDR.
  209. inline bool Socket::isReuseAddress(bool set) { return (ReuseAddress = set); } // Changes SO_REUSEADDR setting.
  210. inline bool Socket::isOpen() { // True if the socket is open.
  211. return(
  212. INVALID_SOCKET != Handle && // A valid handle and
  213. true == OpenSucceeded // a successful open operation
  214. ); // means we're open.
  215. }
  216. inline int Socket::getLastError() { // Returns the last error for this socket.
  217. return LastError;
  218. }
  219. //// class TCPClient ///////////////////////////////////////////////////////////
  220. inline TCPClient::TCPClient(TCPListener& L, hSocket H, SocketAddress& A) : // How to create a TCPClient.
  221. MyListener(L) { // Capture our listener.
  222. Handle = H; // Capture the new socket handle.
  223. RemoteAddress = A; // Capture the client address.
  224. ReadPointer = ReadBuffer; // Set the read position to zero.
  225. DataLength = 0; // There is no data yet.
  226. OpenSucceeded = true; // We're getting an open socket.
  227. }
  228. inline TCPClient::~TCPClient() { // When destroying a TCPClient
  229. try{ if(isOpen()) close(); } catch(...) {} // silently close any open connections.
  230. }
  231. inline void TCPClient::open() { // We provide open() as unsupported.
  232. throw Networking::NotSupportedError( // Throw an exception if this is called.
  233. Network.DescriptiveError(
  234. "TCPClient::open()", LastError));
  235. }
  236. inline bool TCPClient::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
  237. return (0 >= DataLength); // We can check that with DataLength.
  238. }
  239. inline void TCPClient::fillReadBuffer() { // Fills the buffer from the socket.
  240. LastError = 0; // Clear the LastError value.
  241. ReadPointer = ReadBuffer; // Reset the ReadPointer.
  242. DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data.
  243. if(0 >= DataLength) { // If there was an error then
  244. LastError = Network.getLastError(); // Grab the last error code.
  245. DataLength = 0; // Correct the DataLength.
  246. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  247. return; // simply return - it's ok.
  248. } else { // If it was a different error
  249. throw Networking::SocketReadError( // then throw a ReadError.
  250. Network.DescriptiveError(
  251. "TCPClient::fillReadBuffer()", LastError));
  252. }
  253. } // If we succeeded then our ReadBuffer
  254. } // assembly is in good shape.
  255. inline bool TCPClient::isNonBlocking() { // Provided for MessagePort.
  256. return Socket::isNonBlocking();
  257. }
  258. inline unsigned long TCPClient::getRemoteIP() { // Get remote IP as long.
  259. return RemoteAddress.getAddress();
  260. }
  261. inline const char* TCPClient::getRemoteIP(char* str) { // Get IP as string.
  262. return RemoteAddress.getAddress(str);
  263. }
  264. inline unsigned short TCPClient::getRemotePort() { // Get remote Port as unsigned short.
  265. return RemoteAddress.getPort();
  266. }
  267. inline const char* TCPClient::getRemotePort(char* str) { // Get Port as string.
  268. return RemoteAddress.getPort(str);
  269. }
  270. //// class TCPHost /////////////////////////////////////////////////////////////
  271. inline TCPHost::~TCPHost() { // When destroying a TCPHost
  272. try{ if(isOpen()) close(); } catch(...) {} // silently close any open connection.
  273. }
  274. inline bool TCPHost::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
  275. return (0 >= DataLength); // We can check that with DataLength.
  276. }
  277. inline void TCPHost::fillReadBuffer() { // Fills the buffer from the socket.
  278. LastError = 0; // Clear the LastError value.
  279. ReadPointer = ReadBuffer; // Reset the ReadPointer.
  280. DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data.
  281. if(0 >= DataLength) { // If there was an error then
  282. LastError = Network.getLastError(); // Grab the last error code.
  283. DataLength = 0; // Correct the DataLength.
  284. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  285. return; // simply return - it's ok.
  286. } else { // If it was a different error
  287. throw Networking::SocketReadError( // then throw a ReadError.
  288. Network.DescriptiveError(
  289. "TCPHost::fillReadBuffer()", LastError));
  290. }
  291. } // If we succeeded then our ReadBuffer
  292. } // assembly is in good shape.
  293. inline bool TCPHost::isNonBlocking() { // Provided for MessagePort.
  294. return Socket::isNonBlocking();
  295. }
  296. //// class TCPListener /////////////////////////////////////////////////////////
  297. inline TCPListener::~TCPListener() { // When destroying a TCPListener
  298. try{ close(); } catch(...) {} // silently close if not already done.
  299. }