wavesock.h

Go to the documentation of this file.
00001 /*
00002  * wavesock.h
00003  *
00004  * Copyright (C) 2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Quick and dirty abstraction layer (very low-level).
00032  */
00033 
00034 #ifndef WAVEPACKET_WAVESOCK_H__
00035 #define WAVEPACKET_WAVESOCK_H__
00036 
00037 
00038 // includes --------------------------------------------------------------------
00039 #include "common/common.h"
00040 
00041 
00042 namespace netlib {
00043 
00044 
00045 // networking typedefs ---------------------------------------------------------
00046 
00047 ////////////////////////////////////////////////////////////////////////////////
00048 ///
00049 /// \ingroup networking
00050 /// \defgroup wavesock Wavepacket Sockets API
00051 ///
00052 /// This is a quick and dirty sockets-like API to abstract the netlib
00053 /// implementation from operating-system-specific issues.
00054 ///
00055 /// Basically this abstracts the BSD Sockets and Winsock APIs.
00056 ///
00057 /// This is not completely general, it is tailored for netlib.  For instance,
00058 /// it assumes (and enforces) nonblocking sockets.  It quiets all signals.
00059 ///
00060 /// This follows BSD socket-style error handling.  If something goes wrong,
00061 /// call wsGetError() for the error code.
00062 ///
00063 /// \b WARNING: the select() behavior is a bit funky.  In particular, I took a
00064 /// shortcut and relied on global state for some of the fd sets.  This means
00065 /// this library is NOT threadsafe.  That's fine for now, but may be cleaned
00066 /// up someday.
00067 ///
00068 ////////////////////////////////////////////////////////////////////////////////
00069 /*@{*/
00070 
00071 
00072 /// these are error codes.  They also are abstracted!  as a result, they don't
00073 ///     cover the full spectrum of possible errors.  They only cover what I've
00074 ///     needed so far.  Most errors will therefore be mapped to eWS_Unknown.
00075 enum eWSError {
00076         eWS_Okay                = 0,    ///< no error
00077         eWS_Again               = 1,    ///< read/write failed, just try again
00078         eWS_Denied              = 2,    ///< permission denied (bad port#?)
00079         eWS_InUse               = 3,    ///< address is already in use
00080         eWS_ConnectionRefused   = 4,    ///< no one listening at other end
00081 
00082         eWS_Unknown             = 0x100,///< unmapped error
00083 
00084         // must be last!
00085         eWS_Invalid             = 0x7ff
00086 };
00087 
00088 
00089 
00090 /// representation of IP address (abstracts IPv4 and IPv6)
00091 struct ip_addr_t {
00092         enum eType {
00093                 eType_IPv4              = 1,    ///< IPv4 address
00094                 eType_IPv6              = 2,    ///< IPv6 address
00095 
00096                 eType_Invalid           = 0     // keep this last!
00097         };
00098 
00099         // constructor, manipulators
00100         ip_addr_t(void) throw() { this->clear(); }
00101         void clear(void) throw() {
00102                         memset(addr, 0, 6 * sizeof(byte_t));
00103                         flags = 0;
00104                         unused = 0;
00105                 }
00106 
00107         eType getType(void) const throw() { return (eType) flags; }
00108 
00109         bool isValid(void) const throw() {
00110                         // only support IPv4 for now
00111                         return (eType_IPv4 == flags);
00112                 }
00113 
00114         bool operator != (IN const ip_addr_t& rhs) const throw() {
00115                         return !(*this == rhs);
00116                 }
00117 
00118         bool operator == (IN const ip_addr_t& rhs) const throw() {
00119                         return !memcmp(this, &rhs, 7);
00120                 }
00121 
00122         void dump(IN const char * title) const throw() {
00123                         if (!flags) {
00124                                 DPRINTF("%s: (invalid IP address)", title);
00125                         } else if (eType_IPv4 == flags) {
00126                                 DPRINTF("%s:  IPv4  %d.%d.%d.%d", title,
00127                                     addr[0], addr[1], addr[2], addr[3]);
00128                         } else if (eType_IPv6 == flags) {
00129                                 DPRINTF("%s:  IPv6  address (?)", title);
00130                         } else {
00131                                 DPRINTF("%s: corrupt!", title);
00132                         }
00133                 }
00134 
00135         /// attempts to look up the IP of the remote host.  Returns false on
00136         ///     failure (and the value of the ip address object is unchanged).
00137         bool lookupHostname(IN const char * hostname);
00138 
00139         /// is this just a loopback IP address?  (127.0.0.1 for IPv4)
00140         bool isLoopback(void) const throw();
00141 
00142         /// sets to loopback (127.0.0.1 for IPv4)
00143         void setLoopback(void) throw();
00144 
00145         /// sets to broadcast.  \b WARNING: this isn't a very clever method.
00146         ///     It just sets the last byte to 255.  If you want more control
00147         ///     over the broadcast mask, set it explicitly.
00148         /// Only works when applied to an already-valid IP address.  Returns
00149         ///     false on failure.
00150         bool setBroadcast(void) throw();
00151 
00152         void setIPv4(IN const byte_t * ip) throw() {
00153                         ASSERT(ip, "null");
00154                         this->clear();
00155                         flags = eType_IPv4;
00156                         addr[0] = ip[0];
00157                         addr[1] = ip[1];
00158                         addr[2] = ip[2];
00159                         addr[3] = ip[3];
00160                 }
00161 
00162         void setIPv6(IN const byte_t * ip) throw() {
00163                         ASSERT(ip, "null");
00164                         this->clear();
00165                         ASSERT(false, "setIPv6() is not yet supported");
00166                 }
00167 
00168         // data fields
00169         byte_t          addr[6];
00170         byte_t          flags;  // actually the type
00171         byte_t          unused; // keep dword-aligned
00172 };
00173 
00174 
00175 
00176 /// holds the IP address and port of a remote host
00177 struct address_t {
00178         // constructor, manipulators
00179         address_t(IN const char * server, IN int remotePort) throw() {
00180                         this->clear();
00181                         this->set(server, remotePort);
00182                 }
00183         address_t(void) throw() { this->clear(); }
00184         void clear(void) throw() {
00185                         ip.clear();
00186                         port = -1;
00187                 }
00188 
00189         bool isValid(void) const throw() {
00190                         return (port > 0 && ip.isValid());
00191                 }
00192 
00193         bool operator == (IN const address_t& rhs) const throw() {
00194                         return (port == rhs.port &&
00195                                 ip == rhs.ip);
00196                 }
00197 
00198         bool operator != (IN const address_t& rhs) const throw() {
00199                         return !(*this == rhs);
00200                 }
00201 
00202         /// set the IP and port.  Returns false if server name doesn't resolve
00203         bool set(IN const char * server, IN int remotePort);
00204 
00205         /// set to local host (picks first non-loopback address)
00206         bool setlocal(IN int remotePort);
00207 
00208         void dump(IN const char * msg) const throw() {
00209                         DPRINTF("%s: internet address ================", msg);
00210                         ip.dump("  ip");
00211                         DPRINTF("  port= %d", port);
00212                         DPRINTF("%s: end of address ==================", msg);
00213                 }
00214 
00215         // data fields
00216         ip_addr_t       ip;
00217         int             port;
00218 };
00219 
00220 
00221 
00222 /// a map of IP addresses (typically interface name --> IP address)
00223 typedef std::map<std::string, ip_addr_t> map_ip_addr_t;
00224 
00225 
00226 /// get set of local interfaces
00227 bool getLocalInterfaces(OUT map_ip_addr_t& interfaces);
00228 
00229 
00230 /// is the given socket identifier valid?
00231 bool wsIsValidSocket(IN int s) throw();
00232 
00233 
00234 /// gets the current error (0 means no error).  This is mapped to the
00235 ///     known (small) set of wavesocket errors, and therefore is only
00236 ///     useful in a few cases.  See the eWSError enum.
00237 /// If you need richer information, call wsGetErrorMessage().
00238 eWSError wsGetError(void) throw();
00239 
00240 
00241 /// returns the most recent error message
00242 void wsGetErrorMessage(IN char * buffer,
00243                         IN int bufferSize) throw();
00244 
00245 
00246 /// creates a socket that can be used for TCP
00247 int wsCreateTcpSocket(void) throw();
00248 
00249 
00250 /// creates a socket that can be used for UDP
00251 int wsCreateUdpSocket(IN bool broadcast) throw();
00252 
00253 
00254 /// binds the given socket to a specific local port for UDP or TCP
00255 /// returns 0 on success, -1 for error.  See BSD bind() for details.
00256 int wsBindToPort(IN int s,
00257                         IN int port) throw();
00258 
00259 
00260 /// usually used for TCP listening sockets.  See BSD listen() for details.
00261 /// Returns 0 on success, -1 for error.
00262 int wsListen(IN int s,
00263                         IN int maxBacklog) throw();
00264 
00265 
00266 
00267 /// makes a connection to the specified server
00268 int wsConnect(IN int s,
00269                         IN const address_t& server) throw();
00270 
00271 
00272 /// receives data (typically from TCP).  Look at BSD recv() for details.
00273 /// Returns the number of bytes read, -1 for error, 0 for disconnect
00274 int wsReceive(IN int s,
00275                         IN char * buffer,
00276                         IN int bufferSize) throw();
00277 
00278 
00279 /// receives data (typically from UPD).  This also tells you where the
00280 ///   data came from (where the sender is).  Look at BSD recvfrom() for
00281 ///   details.
00282 /// Returns the number of bytes read, -1 for error, 0 for disconnect
00283 int wsReceiveFrom(IN int s,
00284                         IN char * buffer,
00285                         IN int bufferSize,
00286                         OUT address_t& from) throw();
00287 
00288 
00289 /// sends data (typically for TCP).  Look at BSD send() for details.
00290 /// Returns the number of bytes sent, -1 for error
00291 int wsSend(IN int s,
00292                         IN const char * buffer,
00293                         IN int bufferSize) throw();
00294 
00295 
00296 /// sends data (typically for UDP).  Look at BSD sendto() for details.
00297 /// Returns the number of bytes sent, -1 for error
00298 int wsSendTo(IN int s,
00299                         IN const char * buffer,
00300                         IN int bufferSize,
00301                         IN const address_t& to) throw();
00302 
00303 
00304 /// accepts an incoming request.  See BSD accept() for details.
00305 /// Returns the socket for the accepted connection.
00306 int wsAccept(IN int s,
00307                         OUT address_t& address) throw();
00308 
00309 
00310 typedef void * ws_set_t;
00311 
00312 
00313 /// creates an object that you can clear, and then populate with sockets.
00314 /// This involves memory allocation, so you should cache any sets you create.
00315 ws_set_t wsCreateSet(void);
00316 
00317 
00318 /// clears the given set
00319 void wsClearSet(IN ws_set_t set) throw();
00320 
00321 
00322 /// adds the given socket to the given set
00323 void wsAddSocketToSet(IN ws_set_t set,
00324                         IN int s) throw();
00325 
00326 
00327 /// is the given socket in the set?
00328 bool wsIsSocketInSet(IN ws_set_t set,
00329                         IN int s) throw();
00330 
00331 
00332 /// destroys the given set
00333 void wsDestroySet(IN ws_set_t set) throw();
00334 
00335 
00336 /// waits until a socket is ready for read/write.  See BSD select() for details.
00337 /// To call this, you must first clear and then populate the reader and writer
00338 ///   sets.
00339 /// Returns -1 on error
00340 int wsSelect(IN int maxSocket, ///< needs to be max+1 of any socket in any set
00341                         IN ws_set_t readers,
00342                         IN ws_set_t writers,
00343                         IN long wait_microseconds) throw();
00344 
00345 
00346 /// closes a socket
00347 void wsCloseSocket(IN int s) throw();
00348 
00349 
00350 
00351 };      // netlib namespace
00352 
00353 
00354 
00355 #endif  // WAVEPACKET_WAVESOCK_H__