wavesock.cpp

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