wavesock.cpp

Go to the documentation of this file.
00001 /*
00002  * wavesock.cpp
00003  *
00004  * Copyright (C) 2007-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.  See wavesock.h, and netlib.cpp
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "wavesock.h"           // always include our own header first!
00036 
00037 // socket-related headers common to Windows and BSD/*nix
00038 #include <fcntl.h>
00039 
00040 #ifdef WIN32
00041 
00042 // Compiling under windows: use these headers
00043 #ifndef WIN32_LEAN_AND_MEAN
00044 #define WIN32_LEAN_AND_MEAN
00045 #endif  // lean and mean
00046 #include <winsock2.h>
00047 //#include <ws2tcpip.h>
00048 
00049 #else   // WIN32
00050 
00051 // Compiling under *nix: use these headers
00052 #include <netdb.h>
00053 #include <linux/if.h>
00054 #include <sys/errno.h>
00055 #include <sys/ioctl.h>
00056 #include <sys/select.h>
00057 #include <sys/time.h>
00058 
00059 #endif  // WIN32
00060 
00061 
00062 // common headers
00063 #include "common/wave_ex.h"
00064 #include "perf/perf.h"
00065 #include "util/parsing.h"
00066 
00067 
00068 namespace netlib {
00069 
00070 
00071 #define ASSERT_SOCK(s) ASSERT( wsIsValidSocket(s) , "Bad socket: %d", s)
00072 
00073 
00074 // typedefs that depend on the socket API
00075 #ifdef WIN32
00076 typedef int socket_length_t;
00077 #else   // WIN32
00078 typedef socklen_t socket_length_t;
00079 #endif  // WIN32
00080 
00081 
00082 
00083 ////////////////////////////////////////////////////////////////////////////////
00084 //
00085 //      static helper methods
00086 //
00087 ////////////////////////////////////////////////////////////////////////////////
00088 
00089 class smart_socket {
00090 public:
00091         smart_socket(void) throw() : m_s(-1) { }
00092         ~smart_socket(void) throw() {
00093                         this->clear();
00094                 }
00095 
00096         void set(IN int s) throw() {
00097                         this->clear();
00098                         m_s = s;
00099                 }
00100 
00101         int get(void) throw() { return m_s; }
00102 
00103         operator bool (void) const throw() { return (m_s >= 0); }
00104 
00105 private:
00106         void clear(void) throw() {
00107                         if (m_s >= 0) {
00108                                 wsCloseSocket(m_s);
00109                         }
00110                         m_s = -1;
00111                 }
00112 
00113         int     m_s;
00114 };
00115 
00116 
00117 #ifndef WIN32
00118 // these functions only used in *nix
00119 
00120 static void
00121 dumpErrorInfo
00122 (
00123 IN const char * msg
00124 )
00125 {
00126         const int s_bufsize = 256;
00127         char buffer[s_bufsize];
00128         int error = wsGetError();
00129         wsGetErrorMessage(buffer, s_bufsize);
00130 
00131         DPRINTF("%s", msg);
00132         DPRINTF("Error: %d", error);
00133         DPRINTF("%s", buffer);
00134 }
00135 
00136 
00137 
00138 static void
00139 verify
00140 (
00141 IN bool isOK,
00142 IN const char * msg
00143 )
00144 {
00145         if (isOK)
00146                 return;         // no problem!
00147 
00148         // if we're here, there is a big problem!
00149         dumpErrorInfo(msg);
00150         ASSERT(false, "halting");
00151 }
00152 #endif  // WIN32
00153 
00154 
00155 
00156 static void
00157 setNonBlocking
00158 (
00159 IN int s
00160 )
00161 {
00162         ASSERT_SOCK(s);
00163 
00164 #ifdef WIN32
00165         // do nothing
00166 #else   // WIN32
00167         int flags = fcntl(s, F_GETFL, 0);
00168         verify(flags >= 0, "Failed to get socket descriptor flags");
00169         verify(fcntl(s, F_SETFL, flags | O_NONBLOCK) >= 0,
00170             "Failed to set nonblocking flag on socket");
00171 #endif  // WIN32
00172 }
00173 
00174 
00175 
00176 static void
00177 getAddressFromSockaddr
00178 (
00179 IN const struct sockaddr_storage * psa,
00180 OUT address_t& address
00181 )
00182 throw()
00183 {
00184         ASSERT(psa, "null");
00185 
00186         const struct sockaddr_in * psi = (const struct sockaddr_in *) psa;
00187 
00188         address.port = ntohs(psi->sin_port);
00189         address.ip.setIPv4((byte_t *) &psi->sin_addr);
00190 //      memcpy(address.ip.bytes, &psi->sin_addr, 4 * sizeof(byte_t)); 
00191 }
00192 
00193 
00194 
00195 static void
00196 getSockaddrFromAddress
00197 (
00198 IN const address_t& address,
00199 OUT struct sockaddr_in& sa
00200 )
00201 throw()
00202 {
00203         ASSERT(address.ip.isValid(), "invalid");
00204         memset(&sa, 0, sizeof(sa));
00205         sa.sin_family = AF_INET;
00206         sa.sin_port = htons(address.port);
00207         memcpy(&sa.sin_addr, address.ip.addr, 4 * sizeof(byte_t));
00208 }
00209 
00210 
00211 
00212 ////////////////////////////////////////////////////////////////////////////////
00213 //
00214 //      public API
00215 //
00216 ////////////////////////////////////////////////////////////////////////////////
00217 
00218 bool
00219 getLocalInterfaces
00220 (
00221 OUT map_ip_addr_t& map
00222 )
00223 {
00224         map.clear();            // reset
00225 
00226         // TODO: find what works under win32
00227         // I believe gethostbyname() may work there?
00228 
00229         // linux (freebsd sockets): use ioctl
00230         // see: http://stackoverflow.com/questions/212528/linux-c-get-the-ip-address-of-local-computer
00231 
00232         // create a UDP socket
00233         smart_socket s;
00234         s.set(socket(AF_INET, SOCK_DGRAM, 0));
00235         if (!s) {
00236                 DPRINTF("Failed to create UDP socket?");
00237                 return false;
00238         }
00239 
00240         // call ioctl() to retrieve local interfaces
00241         // weird loop here: we have to keep calling until we're
00242         //      sure that adding more buffer space won't result in
00243         //      more interfaces being returned.
00244         struct ifconf ifconf;
00245         std::vector<char> vecbytes;
00246         int bufSize = sizeof(struct ifreq);
00247         int lastIfcReturned = -1;
00248         while (true) {
00249                 vecbytes.reserve(bufSize);
00250                 ifconf.ifc_len = bufSize;
00251                 ifconf.ifc_buf = vecbytes.data();
00252                 int retval = ioctl(s.get(), SIOCGIFCONF, &ifconf);
00253 
00254                 if (retval < 0) {
00255                         DPRINTF("Error calling ioctl(SIOCGIFCONF)");
00256                         return false;
00257                 }
00258 
00259                 //DPRINTF("retval: %d", retval);
00260                 //DPRINTF("ifc_len: %d", ifconf.ifc_len);
00261 
00262                 if (ifconf.ifc_len == lastIfcReturned) {
00263                         // no change in interfaces returned!  all done
00264                         break;
00265                 }
00266 
00267                 //DPRINTF("Need more buffer for ioctl(SIOCGIFCONF)");
00268                 bufSize *= 4;
00269                 //DPRINTF("  expanding to %d bytes", bufSize);
00270                 lastIfcReturned = ifconf.ifc_len;
00271         }
00272 
00273         // odd iteration method, but this is apparently how to do it...
00274         for (int n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) {
00275                 struct ifreq * ifreq = (struct ifreq *) (vecbytes.data() + n);
00276 //              DPRINTF("Found interface: %s", ifreq->ifr_ifrn.ifrn_name);
00277                 address_t address;
00278                 getAddressFromSockaddr(
00279                     (const struct sockaddr_storage *) &ifreq->ifr_ifru.ifru_addr,
00280                     address);
00281 //              address.dump("  Address");
00282 
00283                 map[ifreq->ifr_ifrn.ifrn_name] = address.ip;
00284         }
00285 
00286         // all done!
00287         return true;
00288 }
00289 
00290 
00291 
00292 bool
00293 ip_addr_t::lookupHostname
00294 (
00295 IN const char * hostname
00296 )
00297 {
00298         ASSERT(hostname, "null");
00299 
00300         // use a re-entrant version of gethostbyname()
00301         // TODO: supposedly, gethostbyname() is deprecated in favor of
00302         //      getaddrinfo().  Should update at some point.
00303 
00304         int workspaceSize = 256;        // bump this down for testing
00305         std::vector<char> vecbytes;
00306         struct hostent hent;
00307         struct hostent * h = NULL;
00308         while (!h) {
00309                 DPRINTF("Trying workspace size = %d bytes", workspaceSize);
00310                 int error = 0;
00311                 vecbytes.reserve(workspaceSize);
00312                 int retval = gethostbyname_r(hostname, &hent,
00313                                 vecbytes.data(), workspaceSize, &h, &error);
00314                 if (retval) {
00315                         DPRINTF("Error getting host name: %d", retval);
00316                         if (ERANGE == retval) {
00317                                 DPRINTF("Need more space!");
00318                                 workspaceSize *= 4;
00319                         } else {
00320                                 DPRINTF("Unrecoverable error!");
00321                                 DPRINTF("  retval: %d", retval);
00322                                 DPRINTF("  error: %d", error);
00323                                 return false;
00324                         }
00325                 }
00326         }
00327 
00328         // debug only
00329         {
00330                 DPRINTF("Asked to look up server: '%s'", hostname);
00331                 DPRINTF("  official name: '%s'", h->h_name);
00332                 DPRINTF("  Aliases:");
00333                 for (char ** p = h->h_aliases; *p; ++p) {
00334                         DPRINTF("    '%s'", *p);
00335                 }
00336                 DPRINTF("  address type: %s", (AF_INET == h->h_addrtype) ?
00337                     "AF_INET" : "unknown?");
00338                 DPRINTF("  address length: %d", h->h_length);
00339                 DPRINTF("  addresses:");
00340                 for (char ** p = h->h_addr_list; *p; ++p) {
00341                         const byte_t * ip = (const byte_t *) *p;
00342                         if (4 == h->h_length) {
00343                                 DPRINTF("    %d.%d.%d.%d",
00344                                     ip[0], ip[1], ip[2], ip[3]);
00345                         } else {
00346                                 DPRINTF("    (don't know how to print)");
00347                         }
00348                 }
00349         }
00350 
00351         // only understand IPv4 for now
00352         if (4 != h->h_length) {
00353                 DPRINTF("  Unknown address length: %d", h->h_length);
00354                 DPRINTF("  Failing address lookup for host: %s", hostname);
00355                 return false;
00356         }
00357 
00358         // succeeded, so set!
00359         ASSERT(4 == h->h_length, "Only allow IPv4 for now");
00360 
00361         // set the first non-localhost value
00362         for (char ** p = h->h_addr_list; *p; ++p) {
00363                 const byte_t * ip = (const byte_t *) *p;
00364                 if (127 == ip[0] &&
00365                     0 == ip[1] &&
00366                     0 == ip[2] &&
00367                     1 == ip[3]) {
00368                         DPRINTF("skipping localhost!");
00369                         continue;
00370                 }
00371 
00372                 // found a non-localhost IPv4 address!
00373                 DPRINTF("    Using: %d.%d.%d.%d",
00374                     ip[0], ip[1], ip[2], ip[3]);
00375                 this->setIPv4(ip);
00376                 return true;
00377         }
00378 
00379         // got here?  Then we've only got a localhost address...
00380         DPRINTF("Only have a local host address for host: %s", hostname);
00381         this->setIPv4((byte_t *) h->h_addr_list[0]);
00382         return true;
00383 }
00384 
00385 
00386 
00387 bool
00388 ip_addr_t::isLoopback
00389 (
00390 void
00391 )
00392 const
00393 throw()
00394 {
00395         if (eType_IPv4 == flags) {
00396                 return (127 == addr[0] &&
00397                         0 == addr[1] &&
00398                         0 == addr[2] &&
00399                         1 == addr[3]);
00400         }
00401 
00402         DPRINTF("Invalid ip address--not loopback!");
00403         return false;
00404 }
00405 
00406 
00407 
00408 void
00409 ip_addr_t::setLoopback
00410 (
00411 void
00412 )
00413 throw()
00414 {
00415         byte_t ip[4] = { 127, 0, 0, 1 };
00416         this->setIPv4(ip);
00417 }
00418 
00419 
00420 
00421 bool
00422 ip_addr_t::setBroadcast
00423 (
00424 void
00425 )
00426 throw()
00427 {
00428         if (eType_IPv4 != flags) {
00429                 DPRINTF("Attempting setBroadcast() on invalid IP address");
00430                 return false;
00431         }
00432 
00433         // not very clever...
00434         addr[3] = 255;
00435         return true;
00436 }
00437 
00438 
00439 
00440 bool
00441 address_t::set
00442 (
00443 IN const char * servername,
00444 IN int remotePort
00445 )
00446 {
00447         ASSERT(servername, "null");
00448         ASSERT(remotePort > 0, "Bad port: %d", remotePort);
00449 
00450         if (!this->ip.lookupHostname(servername)) {
00451                 DPRINTF("Failed to look up host: %s", servername);
00452                 return false;
00453         }
00454         port = remotePort;
00455         return true;
00456 }
00457 
00458 
00459 
00460 static bool
00461 tryInterface
00462 (
00463 IN const map_ip_addr_t& map,
00464 IN const char * name,
00465 OUT ip_addr_t& ip
00466 )
00467 throw()
00468 {
00469         ASSERT(name, "null");
00470 
00471         DPRINTF("Looking for interface '%s'...", name);
00472         map_ip_addr_t::const_iterator i = map.find(name);
00473         if (i == map.end()) {
00474                 return false;           // not found
00475         }
00476 
00477         DPRINTF("Found interface '%s'", name);
00478         ip = i->second;
00479         ip.dump(name);
00480         return true;
00481 }
00482 
00483 
00484 
00485 bool
00486 address_t::setlocal
00487 (
00488 IN int remotePort
00489 )
00490 {
00491         ASSERT(remotePort > 0, "Bad port: %d", remotePort);
00492 
00493         map_ip_addr_t map;
00494         getLocalInterfaces(map);
00495 
00496         // debugging
00497         {
00498                 DPRINTF("Found local interfaces:");
00499                 for (map_ip_addr_t::const_iterator i = map.begin();
00500                      i != map.end(); ++i) {
00501                         const char * name = i->first.c_str();
00502                         const ip_addr_t& ip = i->second;
00503                         ip.dump(name);
00504                 }
00505         }
00506 
00507         // set our port
00508         port = remotePort;
00509 
00510         // now try to figure out correct interface
00511         if (tryInterface(map, "eth0", ip)) {
00512                 return true;
00513         }
00514         if (tryInterface(map, "wlan0", ip)) {
00515                 return true;
00516         }
00517 
00518         DPRINTF("Couldn't find a preconfigured interface, guessing...");
00519         for (map_ip_addr_t::const_iterator i = map.begin();
00520              i != map.end(); ++i) {
00521                 const char * name = i->first.c_str();
00522 
00523                 if (!strcmp("lo", name))
00524                         continue;       // skip loopback
00525 
00526                 DPRINTF("  Using interface '%s'", name);
00527                 ip = i->second;
00528                 ip.dump(name);
00529                 return true;
00530         }
00531 
00532         return tryInterface(map, "lo", ip);
00533 }
00534 
00535 
00536 
00537 bool
00538 wsIsValidSocket
00539 (
00540 IN int s
00541 )
00542 throw()
00543 {
00544         return (s >= 0);
00545 }
00546 
00547 
00548 
00549 eWSError
00550 wsGetError
00551 (
00552 void
00553 )
00554 throw()
00555 {
00556         switch (errno) {
00557         case 0:                 return eWS_Okay;
00558 
00559         // these errors seem to be supported in Winsock and BSD
00560         case EAGAIN:            return eWS_Again;
00561         case EACCES:            return eWS_Denied;
00562 
00563 #ifdef WIN32
00564         // Winsock-specific errors
00565         case WSAEACCES:         return eWS_Denied;
00566         case WSAEWOULDBLOCK:    return eWS_Again;
00567         case WSAEADDRINUSE:     return eWS_InUse;
00568         case WSAECONNREFUSED:   return eWS_ConnectionRefused;
00569 
00570 #else   // WIN32
00571         // BSD-specific errors
00572         case EADDRINUSE:        return eWS_InUse;
00573         case ECONNREFUSED:      return eWS_ConnectionRefused;
00574 #endif  // WIN32
00575 
00576         default:
00577                 return eWS_Unknown;
00578         }
00579 }
00580 
00581 
00582 
00583 void
00584 wsGetErrorMessage
00585 (
00586 IO char * buffer,
00587 IN int bufferSize
00588 )
00589 throw()
00590 {
00591         ASSERT(buffer, "null");
00592         ASSERT(bufferSize > 0, "Bad buffer size: %d", bufferSize);
00593 
00594         const int localBufSize = 256;
00595         char local[localBufSize];
00596 
00597         int error = errno;
00598         strncpy(local, strerror(error), localBufSize);
00599         local[localBufSize - 1] = 0;    // null-terminate
00600 
00601         eWSError wserr  = wsGetError();
00602         snprintf(buffer, bufferSize, "%d(%d): %s", wserr, error, local);
00603         buffer[bufferSize - 1] = 0;     // null-terminate
00604 }
00605 
00606 
00607 
00608 int
00609 wsCreateTcpSocket
00610 (
00611 void
00612 )
00613 throw()
00614 {
00615         return socket(PF_INET, SOCK_STREAM, 0);
00616 }
00617 
00618 
00619 
00620 int
00621 wsCreateUdpSocket
00622 (
00623 IN bool broadcast
00624 )
00625 throw()
00626 {
00627         int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00628         if (s >= 0 && broadcast) {
00629                 int b = 1;
00630                 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &b, sizeof(b)) < 0)
00631                 {
00632                         wsCloseSocket(s);
00633                         s = -1;
00634                 }
00635         }
00636         return s;
00637 }
00638 
00639 
00640 
00641 int
00642 wsBindToPort
00643 (
00644 IN int s,
00645 IN int port
00646 )
00647 throw()
00648 {
00649         ASSERT_SOCK(s);
00650         ASSERT(port > 0, "Bad port: %d", port);
00651 
00652         struct sockaddr_in sa;
00653         memset(&sa, 0, sizeof(sa));
00654         sa.sin_family = AF_INET;
00655         sa.sin_port = htons(port);
00656         sa.sin_addr.s_addr = htonl(INADDR_ANY);
00657 
00658         int retval = bind(s, (struct sockaddr *) &sa, sizeof(sa));
00659         if (!retval) {
00660                 setNonBlocking(s);
00661         }
00662         return retval;
00663 }
00664 
00665 
00666 
00667 int
00668 wsListen
00669 (
00670 IN int s,
00671 IN int maxBacklog
00672 )
00673 throw()
00674 {
00675         ASSERT_SOCK(s);
00676         ASSERT(maxBacklog >= 0, "Bad max backlog: %d", maxBacklog);
00677 
00678         return listen(s, maxBacklog);
00679 }
00680 
00681 
00682 
00683 int
00684 wsConnect
00685 (
00686 IN int s,
00687 IN const address_t& address
00688 )
00689 throw()
00690 {
00691         ASSERT_SOCK(s);
00692         ASSERT(address.port > 0, "bad port: %d", address.port);
00693 
00694         struct sockaddr_in sa;
00695         getSockaddrFromAddress(address, sa);
00696         int retval = connect(s, (struct sockaddr *) &sa, sizeof(sa));
00697         if (!retval) {
00698                 setNonBlocking(s);
00699         }
00700         return retval;
00701 }
00702 
00703 
00704 
00705 int
00706 wsReceive
00707 (
00708 IN int s,
00709 IN char * buffer,
00710 IN int bufferSize
00711 )
00712 throw()
00713 {
00714         ASSERT_SOCK(s);
00715         ASSERT(buffer, "null");
00716         ASSERT(bufferSize > 0, "Bad buffer size: %d", bufferSize);
00717 
00718         int flags = 0;
00719         return recv(s, buffer, bufferSize, flags);
00720 }
00721 
00722 
00723 
00724 int
00725 wsReceiveFrom
00726 (
00727 IN int s,
00728 IN char * buffer,
00729 IN int bufferSize,
00730 OUT address_t& from
00731 )
00732 throw()
00733 {
00734         ASSERT_SOCK(s);
00735         ASSERT(buffer, "null");
00736         ASSERT(bufferSize > 0, "Bad buffer size: %d", bufferSize);
00737         from.clear();
00738 
00739         struct sockaddr_storage sa;
00740         socket_length_t bytes = sizeof(sa);
00741         int flags = 0;
00742         int retval = recvfrom(s, buffer, bufferSize, flags,
00743             (struct sockaddr *) &sa, &bytes);
00744 
00745         // copy address
00746         if (retval > 0) {
00747                 getAddressFromSockaddr(&sa, from);
00748                 // from.dump("Received UDP packet");
00749         }
00750 
00751         // all done
00752         return retval;
00753 }
00754 
00755 
00756 
00757 int
00758 wsSend
00759 (
00760 IN int s,
00761 IN const char * buffer,
00762 IN int bufferSize
00763 )
00764 throw()
00765 {
00766         ASSERT_SOCK(s);
00767         ASSERT(buffer, "null");
00768         ASSERT(bufferSize >= 0, "bad buffer size: %d", bufferSize);
00769 
00770         int flags = 0;
00771 
00772 #ifdef WIN32
00773 #else   // WIN32
00774         flags |= MSG_NOSIGNAL;  // in *nix, don't wan't signals
00775 #endif  // WIN32
00776 
00777         return send(s, buffer, bufferSize, flags);
00778 }
00779 
00780 
00781 
00782 int
00783 wsSendTo
00784 (
00785 IN int s,
00786 IN const char * buffer,
00787 IN int bufferSize,
00788 IN const address_t& address
00789 )
00790 throw()
00791 {
00792         ASSERT_SOCK(s);
00793         ASSERT(buffer, "null");
00794         ASSERT(bufferSize > 0, "Bad buffer size: %d", bufferSize);
00795 
00796         struct sockaddr_in sa;
00797         getSockaddrFromAddress(address, sa);
00798 
00799         int flags = 0;
00800 #ifdef WIN32
00801 #else   // WIN32
00802         flags |= MSG_NOSIGNAL;  // in *nix, don't want signals
00803 #endif  // WIN32
00804 
00805         return sendto(s, buffer, bufferSize, flags,
00806             (struct sockaddr *) &sa, sizeof(sa));
00807 }
00808 
00809 
00810 
00811 int
00812 wsAccept
00813 (
00814 IN int s,
00815 OUT address_t& address
00816 )
00817 throw()
00818 {
00819         ASSERT_SOCK(s);
00820 
00821         struct sockaddr_storage sa;
00822         socket_length_t bytes = sizeof(sa);
00823         int c = accept(s, (struct sockaddr *) &sa, &bytes);
00824         if (wsIsValidSocket(c)) {
00825                 getAddressFromSockaddr(&sa, address);
00826                 setNonBlocking(c);
00827         }
00828 
00829         return c;
00830 }
00831 
00832 
00833 
00834 ws_set_t
00835 wsCreateSet
00836 (
00837 void
00838 )
00839 {
00840         fd_set * pf = new fd_set;
00841         ASSERT_THROW(pf, "out of memory");
00842 
00843         return (ws_set_t) pf;
00844 }
00845 
00846 
00847 
00848 void
00849 wsClearSet
00850 (
00851 IN ws_set_t set
00852 )
00853 throw()
00854 {
00855         fd_set * pf = (fd_set *) set;
00856         ASSERT(pf, "null");
00857 
00858         FD_ZERO(pf);
00859 }
00860 
00861 
00862 
00863 void
00864 wsAddSocketToSet
00865 (
00866 IN ws_set_t set,
00867 IN int s
00868 )
00869 throw()
00870 {
00871         ASSERT_SOCK(s);
00872         fd_set * pf = (fd_set *) set;
00873         ASSERT(pf, "null");
00874 
00875         // cast to unsigned is necessary to avoid warnings in WIN32
00876         FD_SET((word_t) s, pf);
00877 }
00878 
00879 
00880 
00881 bool
00882 wsIsSocketInSet
00883 (
00884 IN ws_set_t set,
00885 IN int s
00886 )
00887 throw()
00888 {
00889         ASSERT_SOCK(s);
00890         fd_set * pf = (fd_set *) set;
00891         ASSERT(pf, "null");
00892 
00893         return (FD_ISSET(s, pf) != 0);
00894 }
00895 
00896 
00897 
00898 void
00899 wsDestroySet
00900 (
00901 IN ws_set_t set
00902 )
00903 throw()
00904 {
00905         fd_set * pf = (fd_set *) set;
00906         // ASSERT(pf) -- can be null!
00907 
00908         delete pf;
00909 }
00910 
00911 
00912 
00913 int
00914 wsSelect
00915 (
00916 IN int maxSockets,
00917 IN ws_set_t readers,
00918 IN ws_set_t writers,
00919 IN long wait_microseconds
00920 )
00921 throw()
00922 {
00923         ASSERT_SOCK(maxSockets);
00924         ASSERT(readers, "null");
00925         ASSERT(writers, "null");
00926         ASSERT(wait_microseconds >= 0, "Bad wait time: %ld", wait_microseconds);
00927 
00928         struct timeval timeout;
00929         timeout.tv_sec = 0;
00930         timeout.tv_usec = wait_microseconds;
00931 
00932         return select(maxSockets, (fd_set *) readers, (fd_set *) writers,
00933             NULL, &timeout);
00934 }
00935 
00936 
00937 
00938 void
00939 wsCloseSocket
00940 (
00941 IN int s
00942 )
00943 throw()
00944 {
00945         int ops = 0;
00946 
00947 #ifdef WIN32
00948         ops = SD_BOTH;
00949 #else   // WIN32
00950         ops = SHUT_RDWR;
00951 #endif  // WIN32
00952 
00953         shutdown(s, ops);
00954         close(s);
00955 }
00956 
00957 
00958 
00959 };      // netlib namespace
00960