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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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) || (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 string& newIP) { (*this) = newIP; } // Constructing with a cppstring.
  90. inline IP4Address&
  91. IP4Address::operator=(const unsigned long int Right) { IP = Right; } // Convert from unsigned long int.
  92. inline IP4Address& IP4Address::operator=(const char* Right) { // Convert from c string.
  93. IP = ntohl(inet_addr(Right));
  94. }
  95. inline IP4Address& IP4Address::operator=(const string& Right) { // Convert from cpp string.
  96. IP = ntohl(inet_addr(Right.c_str()));
  97. }
  98. inline bool IP4Address::operator<(const IP4Address Right) const { // < Comparison.
  99. return (IP < Right.IP);
  100. }
  101. inline bool IP4Address::operator>(const IP4Address Right) const { // > Comparison.
  102. return (IP > Right.IP);
  103. }
  104. inline bool IP4Address::operator==(const IP4Address Right) const { // == Comparison.
  105. return (IP == Right.IP);
  106. }
  107. inline bool IP4Address::operator!=(const IP4Address Right) const { // != Comparison.
  108. return (IP != Right.IP);
  109. }
  110. inline bool IP4Address::operator<=(const IP4Address Right) const { // <= Comparison.
  111. return (IP <= Right.IP);
  112. }
  113. inline bool IP4Address::operator>=(const IP4Address Right) const { // >= Comparison.
  114. return (IP >= Right.IP);
  115. }
  116. //// class SocketAddress ///////////////////////////////////////////////////////
  117. inline void SocketAddress::clear() {
  118. memset(&Address, 0, sizeof(Address)); // Zero out the address strcuture
  119. Address.sin_family = AF_INET; // Internet Address Family ip4
  120. Address.sin_addr.s_addr = htonl(INADDR_ANY); // Any IP address
  121. Address.sin_port = 0; // Zero means any port.
  122. }
  123. inline SocketAddress::SocketAddress() { // Constructor sets up w/ wildcards
  124. clear(); // Conveniently, we can use clear() :-)
  125. }
  126. inline struct sockaddr_in* SocketAddress::getPtr_sockaddr_in() { // Returns a pointer to sockaddr_in.
  127. return &Address; // Simply return it's address.
  128. }
  129. inline struct sockaddr* SocketAddress::getPtr_sockaddr() { // Returns a pointer to sockaddr.
  130. return (struct sockaddr*) &Address;
  131. }
  132. inline socklen_t SocketAddress::getAddressSize() {
  133. return sizeof(Address); // Return the size of the structure.
  134. }
  135. inline void SocketAddress::setAddress(unsigned long ipAddress) { // Set the IP address from an unsigned int
  136. Address.sin_addr.s_addr = htonl(ipAddress); // Convert to network order and assign.
  137. }
  138. inline void SocketAddress::setAddress(char* ipString) { // Set the IP address from a cstring
  139. Address.sin_addr.s_addr = inet_addr(ipString); // Convert to number and assign.
  140. }
  141. inline unsigned long SocketAddress::getAddress() { // Get the IP address as an unsigned int
  142. return ntohl(Address.sin_addr.s_addr); // Convert to host order and return.
  143. }
  144. inline void SocketAddress::setPort(unsigned short port) { // Set the port address from an int
  145. Address.sin_port = htons(port); // Convert to network order and set.
  146. }
  147. inline void SocketAddress::setPort(char* port) { // Set the port address from a cstring
  148. setPort(atoi(port)); // Convert to int and set.
  149. }
  150. inline unsigned short SocketAddress::getPort() { // Get the port address as an unsigned int
  151. return ntohs(Address.sin_port); // Convert to host order and return.
  152. }
  153. inline const char* SocketAddress::getPort(char* str) { // Get the port address into a cstring.
  154. if(NULL == str) { // If the caller did not provide a
  155. str = PortStringBuffer; // buffer to use then we will use ours.
  156. }
  157. sprintf(str,"%d",getPort()); // Get the port and convert to cstring.
  158. return str; // Return the string we got.
  159. }
  160. //// class Socket //////////////////////////////////////////////////////////////
  161. inline Socket::Socket() : // When starting up we are
  162. Handle(INVALID_SOCKET), OpenSucceeded(false) { // not yet valid.
  163. }
  164. inline Socket::~Socket() { // When shutting down, be sure
  165. close(); // any open socket is closed.
  166. }
  167. inline void Socket::close() { // When we close,
  168. if(INVALID_SOCKET != Handle) { // If the handle is open then
  169. if(Network.closeSocket(Handle)) { // close the handle and check for error.
  170. LastError = Network.getLastError(); // If there was an error record it.
  171. if(!Network.WouldBlock(LastError)) { // If the error was not WOULDBLOCK
  172. throw Networking::ControlError( // then throw a ControlError exception.
  173. Network.DescriptiveError(
  174. "Socket::close()", LastError));
  175. }
  176. } else { // If there was no error then
  177. LastError = 0; // reset the LastError value.
  178. }
  179. Handle = INVALID_SOCKET; // and reset the handle to INVALID.
  180. NonBlocking = false; // The default is Blocking.
  181. OpenSucceeded = false; // After close, forget we opened.
  182. }
  183. }
  184. inline hSocket Socket::getHandle() { // Returns the current Socket handle.
  185. return Handle;
  186. }
  187. inline bool Socket::isNonBlocking() { // Returns true if socket is NonBlocking
  188. return NonBlocking;
  189. }
  190. inline void Socket::makeNonBlocking() { // Sets the socket to NonBlocking mode.
  191. if(0 > Network.setNonBlocking(Handle)) { // Feed the call through Network.
  192. LastError = Network.getLastError(); // If it didn't work, go get the error.
  193. NonBlocking = false; // We are NOT NonBlocking.
  194. throw Networking::ControlError( // Throw a control error.
  195. Network.DescriptiveError(
  196. "Socket::makeNonBlocking()", LastError));
  197. } else {
  198. NonBlocking = true; // If we didn't throw, we're ON.
  199. }
  200. }
  201. inline bool Socket::isReuseAddress() { return ReuseAddress; } // True if socket is set SO_REUSEADDR.
  202. inline bool Socket::isReuseAddress(bool set) { return (ReuseAddress = set); } // Changes SO_REUSEADDR setting.
  203. inline bool Socket::isOpen() { // True if the socket is open.
  204. return(
  205. INVALID_SOCKET != Handle && // A valid handle and
  206. true == OpenSucceeded // a successful open operation
  207. ); // means we're open.
  208. }
  209. inline int Socket::getLastError() { // Returns the last error for this socket.
  210. return LastError;
  211. }
  212. //// class TCPClient ///////////////////////////////////////////////////////////
  213. inline TCPClient::TCPClient(TCPListener& L, hSocket H, SocketAddress& A) : // How to create a TCPClient.
  214. MyListener(L) { // Capture our listener.
  215. Handle = H; // Capture the new socket handle.
  216. RemoteAddress = A; // Capture the client address.
  217. ReadPointer = ReadBuffer; // Set the read position to zero.
  218. DataLength = 0; // There is no data yet.
  219. OpenSucceeded = true; // We're getting an open socket.
  220. }
  221. inline TCPClient::~TCPClient() { // When destroying a TCPClient
  222. if(isOpen()) close(); // Close when being destroyed.
  223. }
  224. inline void TCPClient::open() { // We provide open() as unsupported.
  225. throw Networking::NotSupportedError( // Throw an exception if this is called.
  226. Network.DescriptiveError(
  227. "TCPClient::open()", LastError));
  228. }
  229. inline bool TCPClient::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
  230. return (0 >= DataLength); // We can check that with DataLength.
  231. }
  232. inline void TCPClient::fillReadBuffer() { // Fills the buffer from the socket.
  233. LastError = 0; // Clear the LastError value.
  234. ReadPointer = ReadBuffer; // Reset the ReadPointer.
  235. DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), NOFLAGS); // Try to read some data.
  236. if(0 >= DataLength) { // If there was an error then
  237. LastError = Network.getLastError(); // Grab the last error code.
  238. DataLength = 0; // Correct the DataLength.
  239. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  240. return; // simply return - it's ok.
  241. } else { // If it was a different error
  242. throw Networking::SocketReadError( // then throw a ReadError.
  243. Network.DescriptiveError(
  244. "TCPClient::fillReadBuffer()", LastError));
  245. }
  246. } // If we succeeded then our ReadBuffer
  247. } // assembly is in good shape.
  248. inline bool TCPClient::isNonBlocking() { // Provided for MessagePort.
  249. return Socket::isNonBlocking();
  250. }
  251. inline unsigned long TCPClient::getRemoteIP() { // Get remote IP as long.
  252. return RemoteAddress.getAddress();
  253. }
  254. inline const char* TCPClient::getRemoteIP(char* str) { // Get IP as string.
  255. return RemoteAddress.getAddress(str);
  256. }
  257. inline unsigned short TCPClient::getRemotePort() { // Get remote Port as unsigned short.
  258. return RemoteAddress.getPort();
  259. }
  260. inline const char* TCPClient::getRemotePort(char* str) { // Get Port as string.
  261. return RemoteAddress.getPort(str);
  262. }
  263. //// class TCPHost /////////////////////////////////////////////////////////////
  264. inline TCPHost::~TCPHost() { // When destroying a TCPHost
  265. if(isOpen()) close(); // Close when being destroyed.
  266. }
  267. inline bool TCPHost::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
  268. return (0 >= DataLength); // We can check that with DataLength.
  269. }
  270. inline void TCPHost::fillReadBuffer() { // Fills the buffer from the socket.
  271. LastError = 0; // Clear the LastError value.
  272. ReadPointer = ReadBuffer; // Reset the ReadPointer.
  273. DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), NOFLAGS); // Try to read some data.
  274. if(0 >= DataLength) { // If there was an error then
  275. LastError = Network.getLastError(); // Grab the last error code.
  276. DataLength = 0; // Correct the DataLength.
  277. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  278. return; // simply return - it's ok.
  279. } else { // If it was a different error
  280. throw Networking::SocketReadError( // then throw a ReadError.
  281. Network.DescriptiveError(
  282. "TCPHost::fillReadBuffer()", LastError));
  283. }
  284. } // If we succeeded then our ReadBuffer
  285. } // assembly is in good shape.
  286. inline bool TCPHost::isNonBlocking() { // Provided for MessagePort.
  287. return Socket::isNonBlocking();
  288. }
  289. //// class TCPListener /////////////////////////////////////////////////////////
  290. inline TCPListener::~TCPListener() { // Close when deleting.
  291. close();
  292. }