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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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) { // 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 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* 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(isOpen()) close(); // any open socket is closed.
  171. }
  172. inline void Socket::close() { // When we close,
  173. if(INVALID_SOCKET != Handle) { // If the handle is open then
  174. if(Network.closeSocket(Handle)) { // close the handle and check for error.
  175. LastError = Network.getLastError(); // If there was an error record it.
  176. if(!Network.WouldBlock(LastError)) { // If the error was not WOULDBLOCK
  177. throw Networking::ControlError( // then throw a ControlError exception.
  178. Network.DescriptiveError(
  179. "Socket::close()", LastError));
  180. }
  181. } else { // If there was no error then
  182. LastError = 0; // reset the LastError value.
  183. }
  184. Handle = INVALID_SOCKET; // and reset the handle to INVALID.
  185. NonBlocking = false; // The default is Blocking.
  186. OpenSucceeded = false; // After close, forget we opened.
  187. }
  188. }
  189. inline hSocket Socket::getHandle() { // Returns the current Socket handle.
  190. return Handle;
  191. }
  192. inline bool Socket::isNonBlocking() { // Returns true if socket is NonBlocking
  193. return NonBlocking;
  194. }
  195. inline void Socket::makeNonBlocking() { // Sets the socket to NonBlocking mode.
  196. if(0 > Network.setNonBlocking(Handle)) { // Feed the call through Network.
  197. LastError = Network.getLastError(); // If it didn't work, go get the error.
  198. NonBlocking = false; // We are NOT NonBlocking.
  199. throw Networking::ControlError( // Throw a control error.
  200. Network.DescriptiveError(
  201. "Socket::makeNonBlocking()", LastError));
  202. } else {
  203. NonBlocking = true; // If we didn't throw, we're ON.
  204. }
  205. }
  206. inline bool Socket::isReuseAddress() { return ReuseAddress; } // True if socket is set SO_REUSEADDR.
  207. inline bool Socket::isReuseAddress(bool set) { return (ReuseAddress = set); } // Changes SO_REUSEADDR setting.
  208. inline bool Socket::isOpen() { // True if the socket is open.
  209. return(
  210. INVALID_SOCKET != Handle && // A valid handle and
  211. true == OpenSucceeded // a successful open operation
  212. ); // means we're open.
  213. }
  214. inline int Socket::getLastError() { // Returns the last error for this socket.
  215. return LastError;
  216. }
  217. //// class TCPClient ///////////////////////////////////////////////////////////
  218. inline TCPClient::TCPClient(TCPListener& L, hSocket H, SocketAddress& A) : // How to create a TCPClient.
  219. MyListener(L) { // Capture our listener.
  220. Handle = H; // Capture the new socket handle.
  221. RemoteAddress = A; // Capture the client address.
  222. ReadPointer = ReadBuffer; // Set the read position to zero.
  223. DataLength = 0; // There is no data yet.
  224. OpenSucceeded = true; // We're getting an open socket.
  225. }
  226. inline TCPClient::~TCPClient() { // When destroying a TCPClient
  227. if(isOpen()) close(); // Close when being destroyed.
  228. }
  229. inline void TCPClient::open() { // We provide open() as unsupported.
  230. throw Networking::NotSupportedError( // Throw an exception if this is called.
  231. Network.DescriptiveError(
  232. "TCPClient::open()", LastError));
  233. }
  234. inline bool TCPClient::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
  235. return (0 >= DataLength); // We can check that with DataLength.
  236. }
  237. inline void TCPClient::fillReadBuffer() { // Fills the buffer from the socket.
  238. LastError = 0; // Clear the LastError value.
  239. ReadPointer = ReadBuffer; // Reset the ReadPointer.
  240. DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), NOFLAGS); // Try to read some data.
  241. if(0 >= DataLength) { // If there was an error then
  242. LastError = Network.getLastError(); // Grab the last error code.
  243. DataLength = 0; // Correct the DataLength.
  244. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  245. return; // simply return - it's ok.
  246. } else { // If it was a different error
  247. throw Networking::SocketReadError( // then throw a ReadError.
  248. Network.DescriptiveError(
  249. "TCPClient::fillReadBuffer()", LastError));
  250. }
  251. } // If we succeeded then our ReadBuffer
  252. } // assembly is in good shape.
  253. inline bool TCPClient::isNonBlocking() { // Provided for MessagePort.
  254. return Socket::isNonBlocking();
  255. }
  256. inline unsigned long TCPClient::getRemoteIP() { // Get remote IP as long.
  257. return RemoteAddress.getAddress();
  258. }
  259. inline const char* TCPClient::getRemoteIP(char* str) { // Get IP as string.
  260. return RemoteAddress.getAddress(str);
  261. }
  262. inline unsigned short TCPClient::getRemotePort() { // Get remote Port as unsigned short.
  263. return RemoteAddress.getPort();
  264. }
  265. inline const char* TCPClient::getRemotePort(char* str) { // Get Port as string.
  266. return RemoteAddress.getPort(str);
  267. }
  268. //// class TCPHost /////////////////////////////////////////////////////////////
  269. inline TCPHost::~TCPHost() { // When destroying a TCPHost
  270. if(isOpen()) close(); // Close when being destroyed.
  271. }
  272. inline bool TCPHost::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
  273. return (0 >= DataLength); // We can check that with DataLength.
  274. }
  275. inline void TCPHost::fillReadBuffer() { // Fills the buffer from the socket.
  276. LastError = 0; // Clear the LastError value.
  277. ReadPointer = ReadBuffer; // Reset the ReadPointer.
  278. DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), NOFLAGS); // Try to read some data.
  279. if(0 >= DataLength) { // If there was an error then
  280. LastError = Network.getLastError(); // Grab the last error code.
  281. DataLength = 0; // Correct the DataLength.
  282. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  283. return; // simply return - it's ok.
  284. } else { // If it was a different error
  285. throw Networking::SocketReadError( // then throw a ReadError.
  286. Network.DescriptiveError(
  287. "TCPHost::fillReadBuffer()", LastError));
  288. }
  289. } // If we succeeded then our ReadBuffer
  290. } // assembly is in good shape.
  291. inline bool TCPHost::isNonBlocking() { // Provided for MessagePort.
  292. return Socket::isNonBlocking();
  293. }
  294. //// class TCPListener /////////////////////////////////////////////////////////
  295. inline TCPListener::~TCPListener() { // Close when deleting.
  296. close();
  297. }