123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- // networking.inline.hpp
- // Copyright (C) 2006-2009 MicroNeil Research Corporation.
- //
- // This program is part of the MicroNeil Research Open Library Project. For
- // more information go to http://www.microneil.com/OpenLibrary/index.html
- //
- // This program is free software; you can redistribute it and/or modify it
- // under the terms of the GNU General Public License as published by the
- // Free Software Foundation; either version 2 of the License, or (at your
- // option) any later version.
- //
- // This program is distributed in the hope that it will be useful, but WITHOUT
- // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- // more details.
- //
- // You should have received a copy of the GNU General Public License along with
- // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- // Place, Suite 330, Boston, MA 02111-1307 USA
- //==============================================================================
-
- // Inlined methods for Networking module. See networking.hpp for notes.
-
- ////////////////////////////////////////////////////////////////////////////////
- // Platform Specific
-
- //// Windows platform
-
- #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
-
- inline int Networking::getLastError() { // In windows you get the last error
- return WSAGetLastError(); // from WSAGetLastError();
- }
-
- inline int Networking::setNonBlocking(hSocket socket) { // Set a winsock to non-blocking
- unsigned long nonblocking = 1; // Create a flag...
- int result = 0;
- if(0 != ioctlsocket(socket, FIONBIO, &nonblocking)) { // Set the state of the socket.
- result = -1; // If that fails then return -1.
- }
- return result; // Show 'em my motto!
- }
-
- inline int Networking::closeSocket(hSocket socket) { // Close a socket in winsock
- return closesocket(socket); // wraps closesocket().
- }
-
- inline bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK.
- return (WSAEWOULDBLOCK == ErrorCode);
- }
-
- inline bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS.
- return( // [WSA]EALREADY also returns true.
- WSAEINPROGRESS == ErrorCode || // In fact, on Win* platforms we could
- WSAEALREADY == ErrorCode || // get any of these when retesting
- WSAEWOULDBLOCK == ErrorCode || // open() for a connection.
- WSAEINVAL == ErrorCode
- );
- }
-
- inline bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN.
- return(WSAEISCONN == ErrorCode);
- }
-
- #else
-
- //// GNU platform
-
- inline int Networking::getLastError() { // In GNU you get the last error
- return errno; // from errno;
- }
-
- inline int Networking::setNonBlocking(hSocket socket) { // Set a socket to non-blocking
- int flags, result; // Grab a place to hold the flags.
- flags = fcntl(socket, F_GETFL, 0); // Get the current flags.
- result = fcntl(socket, F_SETFL, flags | O_NONBLOCK); // Set the NONBLOCK flag & return.
- return result; // Return the result.
- }
-
- inline int Networking::closeSocket(hSocket socket) { // Close a socket in GNU
- return close(socket); // wraps close().
- }
-
- inline bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK.
- return (EWOULDBLOCK == ErrorCode);
- }
-
- inline bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS.
- return( // [WSA]EALREADY also returns true.
- EINPROGRESS == ErrorCode ||
- EALREADY == ErrorCode
- );
- }
-
- inline bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN.
- return(EISCONN == ErrorCode);
- }
-
- #endif
-
- // End Platform Specific
- ////////////////////////////////////////////////////////////////////////////////
- // Begin Platform Agnostic
-
- //// class IP4Address //////////////////////////////////////////////////////////
-
- inline IP4Address::IP4Address():IP(0){} // Blank constructor IP = 0.0.0.0
- inline IP4Address::IP4Address(const unsigned long int newIP):IP(newIP){} // Constructor given unsigned long
- inline IP4Address::IP4Address(const IP4Address& newIP):IP(newIP.IP){} // Constructor given an IP4Address
-
- inline IP4Address::IP4Address(const char* newIP) { (*this) = newIP; } // Construcing with a cstring.
- inline IP4Address::IP4Address(const string& newIP) { (*this) = newIP; } // Constructing with a cppstring.
-
- inline IP4Address&
- IP4Address::operator=(const unsigned long int Right) { // Convert from unsigned long int.
- IP = Right;
- return *this;
- }
-
- inline IP4Address& IP4Address::operator=(const char* Right) { // Convert from c string.
- IP = ntohl(inet_addr(Right));
- return *this;
- }
-
- inline IP4Address& IP4Address::operator=(const string& Right) { // Convert from cpp string.
- IP = ntohl(inet_addr(Right.c_str()));
- return *this;
- }
-
- inline bool IP4Address::operator<(const IP4Address Right) const { // < Comparison.
- return (IP < Right.IP);
- }
-
- inline bool IP4Address::operator>(const IP4Address Right) const { // > Comparison.
- return (IP > Right.IP);
- }
-
- inline bool IP4Address::operator==(const IP4Address Right) const { // == Comparison.
- return (IP == Right.IP);
- }
-
- inline bool IP4Address::operator!=(const IP4Address Right) const { // != Comparison.
- return (IP != Right.IP);
- }
-
- inline bool IP4Address::operator<=(const IP4Address Right) const { // <= Comparison.
- return (IP <= Right.IP);
- }
-
- inline bool IP4Address::operator>=(const IP4Address Right) const { // >= Comparison.
- return (IP >= Right.IP);
- }
-
- //// class SocketAddress ///////////////////////////////////////////////////////
-
- inline void SocketAddress::clear() {
- memset(&Address, 0, sizeof(Address)); // Zero out the address strcuture
- Address.sin_family = AF_INET; // Internet Address Family ip4
- Address.sin_addr.s_addr = htonl(INADDR_ANY); // Any IP address
- Address.sin_port = 0; // Zero means any port.
- }
-
- inline SocketAddress::SocketAddress() { // Constructor sets up w/ wildcards
- clear(); // Conveniently, we can use clear() :-)
- }
-
- inline struct sockaddr_in* SocketAddress::getPtr_sockaddr_in() { // Returns a pointer to sockaddr_in.
- return &Address; // Simply return it's address.
- }
-
- inline struct sockaddr* SocketAddress::getPtr_sockaddr() { // Returns a pointer to sockaddr.
- return (struct sockaddr*) &Address;
- }
-
-
- inline socklen_t SocketAddress::getAddressSize() {
- return sizeof(Address); // Return the size of the structure.
- }
-
- inline void SocketAddress::setAddress(unsigned long ipAddress) { // Set the IP address from an unsigned int
- Address.sin_addr.s_addr = htonl(ipAddress); // Convert to network order and assign.
- }
-
- inline void SocketAddress::setAddress(char* ipString) { // Set the IP address from a cstring
- Address.sin_addr.s_addr = inet_addr(ipString); // Convert to number and assign.
- }
-
- inline unsigned long SocketAddress::getAddress() { // Get the IP address as an unsigned int
- return ntohl(Address.sin_addr.s_addr); // Convert to host order and return.
- }
-
- inline void SocketAddress::setPort(unsigned short port) { // Set the port address from an int
- Address.sin_port = htons(port); // Convert to network order and set.
- }
-
- inline void SocketAddress::setPort(char* port) { // Set the port address from a cstring
- setPort(atoi(port)); // Convert to int and set.
- }
-
- inline unsigned short SocketAddress::getPort() { // Get the port address as an unsigned int
- return ntohs(Address.sin_port); // Convert to host order and return.
- }
-
- inline const char* SocketAddress::getPort(char* str) { // Get the port address into a cstring.
- if(NULL == str) { // If the caller did not provide a
- str = PortStringBuffer; // buffer to use then we will use ours.
- }
- sprintf(str,"%d",getPort()); // Get the port and convert to cstring.
- return str; // Return the string we got.
- }
-
- //// class Socket //////////////////////////////////////////////////////////////
-
- inline Socket::Socket() : // When starting up we are
- Handle(INVALID_SOCKET), OpenSucceeded(false) { // not yet valid.
- }
-
- inline Socket::~Socket() { // When shutting down, be sure
- if(INVALID_SOCKET != Handle) { // any open socket is closed without
- Network.closeSocket(Handle); // throwing any exceptions.
- }
- }
-
- inline void Socket::close() { // When we close,
- if(INVALID_SOCKET != Handle) { // If the handle is open then
- if(Network.closeSocket(Handle)) { // close the handle and check for error.
- LastError = Network.getLastError(); // If there was an error record it.
- if(!Network.WouldBlock(LastError)) { // If the error was not WOULDBLOCK
- throw Networking::ControlError( // then throw a ControlError exception.
- Network.DescriptiveError(
- "Socket::close()", LastError));
- }
- } else { // If there was no error then
- LastError = 0; // reset the LastError value.
- }
- Handle = INVALID_SOCKET; // and reset the handle to INVALID.
- NonBlocking = false; // The default is Blocking.
- OpenSucceeded = false; // After close, forget we opened.
- }
- }
-
- inline hSocket Socket::getHandle() { // Returns the current Socket handle.
- return Handle;
- }
-
- inline bool Socket::isNonBlocking() { // Returns true if socket is NonBlocking
- return NonBlocking;
- }
-
- inline void Socket::makeNonBlocking() { // Sets the socket to NonBlocking mode.
- if(0 > Network.setNonBlocking(Handle)) { // Feed the call through Network.
- LastError = Network.getLastError(); // If it didn't work, go get the error.
- NonBlocking = false; // We are NOT NonBlocking.
- throw Networking::ControlError( // Throw a control error.
- Network.DescriptiveError(
- "Socket::makeNonBlocking()", LastError));
- } else {
- NonBlocking = true; // If we didn't throw, we're ON.
- }
- }
-
- inline bool Socket::isReuseAddress() { return ReuseAddress; } // True if socket is set SO_REUSEADDR.
- inline bool Socket::isReuseAddress(bool set) { return (ReuseAddress = set); } // Changes SO_REUSEADDR setting.
-
- inline bool Socket::isOpen() { // True if the socket is open.
- return(
- INVALID_SOCKET != Handle && // A valid handle and
- true == OpenSucceeded // a successful open operation
- ); // means we're open.
- }
-
- inline int Socket::getLastError() { // Returns the last error for this socket.
- return LastError;
- }
-
- //// class TCPClient ///////////////////////////////////////////////////////////
-
- inline TCPClient::TCPClient(TCPListener& L, hSocket H, SocketAddress& A) : // How to create a TCPClient.
- MyListener(L) { // Capture our listener.
- Handle = H; // Capture the new socket handle.
- RemoteAddress = A; // Capture the client address.
- ReadPointer = ReadBuffer; // Set the read position to zero.
- DataLength = 0; // There is no data yet.
- OpenSucceeded = true; // We're getting an open socket.
- }
-
- inline TCPClient::~TCPClient() { // When destroying a TCPClient
- try{ if(isOpen()) close(); } catch(...) {} // silently close any open connections.
- }
-
- inline void TCPClient::open() { // We provide open() as unsupported.
- throw Networking::NotSupportedError( // Throw an exception if this is called.
- Network.DescriptiveError(
- "TCPClient::open()", LastError));
- }
-
- inline bool TCPClient::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
- return (0 >= DataLength); // We can check that with DataLength.
- }
-
- inline void TCPClient::fillReadBuffer() { // Fills the buffer from the socket.
- LastError = 0; // Clear the LastError value.
- ReadPointer = ReadBuffer; // Reset the ReadPointer.
- DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data.
-
- if(0 >= DataLength) { // If there was an error then
- LastError = Network.getLastError(); // Grab the last error code.
- DataLength = 0; // Correct the DataLength.
- if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
- return; // simply return - it's ok.
- } else { // If it was a different error
- throw Networking::SocketReadError( // then throw a ReadError.
- Network.DescriptiveError(
- "TCPClient::fillReadBuffer()", LastError));
- }
- } // If we succeeded then our ReadBuffer
- } // assembly is in good shape.
-
- inline bool TCPClient::isNonBlocking() { // Provided for MessagePort.
- return Socket::isNonBlocking();
- }
-
- inline unsigned long TCPClient::getRemoteIP() { // Get remote IP as long.
- return RemoteAddress.getAddress();
- }
-
- inline const char* TCPClient::getRemoteIP(char* str) { // Get IP as string.
- return RemoteAddress.getAddress(str);
- }
-
- inline unsigned short TCPClient::getRemotePort() { // Get remote Port as unsigned short.
- return RemoteAddress.getPort();
- }
-
- inline const char* TCPClient::getRemotePort(char* str) { // Get Port as string.
- return RemoteAddress.getPort(str);
- }
-
- //// class TCPHost /////////////////////////////////////////////////////////////
-
- inline TCPHost::~TCPHost() { // When destroying a TCPHost
- try{ if(isOpen()) close(); } catch(...) {} // silently close any open connection.
- }
-
- inline bool TCPHost::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
- return (0 >= DataLength); // We can check that with DataLength.
- }
-
- inline void TCPHost::fillReadBuffer() { // Fills the buffer from the socket.
- LastError = 0; // Clear the LastError value.
- ReadPointer = ReadBuffer; // Reset the ReadPointer.
- DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data.
-
- if(0 >= DataLength) { // If there was an error then
- LastError = Network.getLastError(); // Grab the last error code.
- DataLength = 0; // Correct the DataLength.
- if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
- return; // simply return - it's ok.
- } else { // If it was a different error
- throw Networking::SocketReadError( // then throw a ReadError.
- Network.DescriptiveError(
- "TCPHost::fillReadBuffer()", LastError));
- }
- } // If we succeeded then our ReadBuffer
- } // assembly is in good shape.
-
- inline bool TCPHost::isNonBlocking() { // Provided for MessagePort.
- return Socket::isNonBlocking();
- }
-
- //// class TCPListener /////////////////////////////////////////////////////////
-
- inline TCPListener::~TCPListener() { // When destroying a TCPListener
- try{ close(); } catch(...) {} // silently close if not already done.
- }
|