libsocket 1.5
netsocket.cc
Go to the documentation of this file.
00001 /*
00002 ** netsocket.cc
00003 ** Login : Julien Lemoine <speedblue@happycoder.org>
00004 ** Started on  Mon May 12 22:23:27 2003 Julien Lemoine
00005 ** $Id: netsocket.cc,v 1.13 2004/11/24 21:25:36 speedblue Exp $
00006 **
00007 ** Copyright (C) 2003,2004 Julien Lemoine
00008 ** This program is free software; you can redistribute it and/or modify
00009 ** it under the terms of the GNU Lesser General Public License as published by
00010 ** the Free Software Foundation; either version 2 of the License, or
00011 ** (at your option) any later version.
00012 **
00013 ** This program is distributed in the hope that it will be useful,
00014 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 ** GNU Lesser General Public License for more details.
00017 **
00018 ** You should have received a copy of the GNU Lesser General Public License
00019 ** along with this program; if not, write to the Free Software
00020 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00021 */
00022 
00023 #include <iostream>
00024 #include "netsocket.hh"
00025 #include "socket.hxx"
00026 
00027 namespace Network
00028 {
00029 
00030   struct sockaddr_in    NetSocket::_get_addr(const std::string& host,
00031                                              int port) const
00032   {
00033     struct hostent      *he;
00034     struct sockaddr_in  addr;
00035 
00036     memset(&addr, 0, sizeof(struct sockaddr_in));
00037     he = gethostbyname(host.c_str());
00038     if (!he)
00039       throw HostnameError("Unknown Hostname", HERE);
00040     addr.sin_addr = *((struct in_addr *)he->h_addr);
00041     addr.sin_port = htons(port);
00042     addr.sin_family = AF_INET;
00043     return addr;
00044   }
00045 
00046 #ifdef IPV6_ENABLED
00047   struct sockaddr_in6   NetSocket::_get_addr6(const std::string& host,
00048                                               int port) const
00049   {
00050     struct sockaddr_in6 addr;
00051 
00052     memset(&addr, 0, sizeof(struct sockaddr_in6));
00053     if ( inet_pton(AF_INET6, host.c_str(), &addr.sin6_addr) == 0 )
00054       throw InetptonError("Unknown Hostname", HERE);
00055     addr.sin6_port = htons(port);
00056     addr.sin6_family = AF_INET6;
00057     return addr;
00058   }
00059 #endif
00060 
00061   struct sockaddr_in    NetSocket::_get_addr(int port) const
00062   {
00063     struct sockaddr_in  addr;
00064 
00065     memset(&addr, 0, sizeof(struct sockaddr_in));
00066     addr.sin_addr.s_addr = htonl(INADDR_ANY);
00067     addr.sin_port = htons(port);
00068     addr.sin_family = AF_INET;
00069     return addr;
00070   }
00071 
00072 #ifdef IPV6_ENABLED
00073   struct sockaddr_in6   NetSocket::_get_addr6(int port) const
00074   {
00075     struct sockaddr_in6 addr;
00076 
00077     memset(&addr, 0, sizeof(struct sockaddr_in6));
00078     if ( inet_pton(AF_INET6, "0::0", &addr.sin6_addr) == 0 )
00079       throw InetptonError("Not a valid address", HERE);
00080     addr.sin6_port = htons(port);
00081     addr.sin6_family = AF_INET6;
00082     return addr;
00083   }
00084 #endif
00085 
00086   int           NetSocket::_bind(int port, const std::string& host)
00087   {
00088     int                 s;
00089 
00090     if (_kind == UDP)
00091       {
00092 #ifdef IPV6_ENABLED
00093         if (_version == V4)
00094 #endif
00095           s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00096 #ifdef IPV6_ENABLED
00097         else
00098           s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
00099 #endif
00100       }
00101     else if (_kind == TCP)
00102       {
00103 #ifdef IPV6_ENABLED
00104         if (_version == V4)
00105 #endif
00106           s = socket(PF_INET, SOCK_STREAM, 0);
00107 #ifdef IPV6_ENABLED
00108         else
00109           s = socket(PF_INET6, SOCK_STREAM, 0);
00110 #endif
00111       }
00112     else
00113       throw Exception("Unknown Protocole", HERE);
00114 
00115     if (s < 0)
00116       throw SocketError("Socket error", HERE);
00117 #ifdef IPV6_ENABLED
00118     if (_version == V4)
00119 #endif
00120       _addr = _get_addr(host, port);
00121 #ifdef IPV6_ENABLED
00122     else
00123       _addr6 = _get_addr6(host, port);
00124 #endif
00125     return s;
00126   }
00127 
00128   int           NetSocket::_bind(int port)
00129   {
00130     int                 s, on;
00131 
00132     if (_kind == TCP)
00133       {
00134 #ifdef IPV6_ENABLED
00135         if (_version == V4)
00136 #endif
00137           s = socket(PF_INET, SOCK_STREAM, 0);
00138 #ifdef IPV6_ENABLED
00139         else
00140           s = socket(PF_INET6, SOCK_STREAM, 0);
00141 #endif
00142       }
00143     else if (_kind == UDP)
00144       {
00145 #ifdef IPV6_ENABLED
00146         if (_version == V4)
00147 #endif
00148           s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00149 #ifdef IPV6_ENABLED
00150         else
00151           s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
00152 #endif
00153       }
00154     else
00155       throw Exception("Unknown Protocole", HERE);
00156     if (s < 0)
00157       throw SocketError("Socket error", HERE);
00158     on = 1;
00159 
00160     if (_kind == TCP && setsockopt(s, SOL_SOCKET,
00161                                    SO_REUSEADDR, (void *)&on,
00162                                    sizeof (on)) == -1)
00163       throw SetsockoptError("setsockopt error", HERE);
00164 
00165 #ifdef IPV6_ENABLED
00166     if (_version == V4)
00167       {
00168 #endif
00169         struct sockaddr_in      addr;
00170         addr = _get_addr(port);
00171         if (bind(s,(struct sockaddr*)&addr, (int)sizeof(addr)) == -1)
00172           throw BindError("Bind error", HERE);
00173 #ifdef IPV6_ENABLED
00174       }
00175     else
00176       {
00177         struct sockaddr_in6     addr6;
00178         addr6 = _get_addr6(port);
00179         if (bind(s,(struct sockaddr*)&addr6, (int)sizeof(addr6)) == -1)
00180           throw BindError("Bind error", HERE);
00181       }
00182 #endif
00183     return s;
00184   }
00185 
00186   void  NetSocket::_connect(int socket, int port,
00187                             const std::string& host) const
00188   {
00189 #ifdef IPV6_ENABLED
00190     if (_version == V4)
00191       {
00192 #endif
00193         struct sockaddr_in      addr;
00194         addr = _get_addr(host, port);
00195         if (connect(socket, (struct sockaddr *)&addr,
00196                     sizeof (addr)) < 0)
00197           throw ConnectError("Unable to connect", HERE);
00198 #ifdef IPV6_ENABLED
00199       }
00200     else
00201       {
00202         struct sockaddr_in6     addr6;
00203         addr6 = _get_addr6(host, port);
00204         if (connect(socket, (struct sockaddr *)&addr6,
00205                     sizeof (addr6)) < 0)
00206           throw ConnectError("Unable to connect", HERE);
00207       }
00208 #endif
00209   }
00210 
00211   int           NetSocket::_accept(int port, int socket) const
00212   {
00213 #ifdef LIBSOCKET_WIN
00214     int                         size;
00215 #else
00216     socklen_t                   size;
00217 #endif
00218     int                 s;
00219     struct sockaddr_in  addr;
00220 #ifdef IPV6_ENABLED
00221     struct sockaddr_in6 addr6;
00222 
00223     if (_version == V4)
00224       {
00225 #endif
00226         addr = _get_addr(port);
00227         size = sizeof(addr);
00228         s = accept(socket, (struct sockaddr*)&addr, &size);
00229 #ifdef IPV6_ENABLED
00230       }
00231     else
00232       {
00233         addr6 = _get_addr6(port);
00234         size = sizeof(addr6);
00235         s = accept(socket, (struct sockaddr*)&addr6, &size);
00236       }
00237 #endif
00238     if (s < 0)
00239       throw AcceptError("Accept Error", HERE);
00240     return s;
00241   }
00242 
00243   std::string   NetSocket::_get_ip(int port, int socket) const
00244   {
00245     struct sockaddr_in        addr;
00246 #ifdef LIBSOCKET_WIN
00247     int                         size;
00248 #else
00249     socklen_t                   size;
00250 #endif
00251 
00252     memset(&addr, '\0', sizeof(addr));
00253     addr.sin_family = AF_INET;
00254     addr.sin_addr.s_addr = htonl(INADDR_ANY);
00255     addr.sin_port = htons(port);
00256     size = sizeof(addr);
00257     getpeername(socket, (struct sockaddr *)&addr, &size);
00258     return(std::string(inet_ntoa(addr.sin_addr)));
00259   }
00260 
00261   std::string   NetSocket::_read_line(int socket)
00262   {
00263     char                chr[MAXPKTSIZE];
00264     std::string         str = "";
00265     int                 res = 1, i;
00266     std::pair<int, int> delim;
00267     bool                end = false;
00268 
00269     if (socket < 0)
00270       throw NoConnection("No Socket", HERE);
00271     if (!_update_buffer(delim, i, str))
00272       while (!end)
00273         {
00274           memset(chr, 0, MAXPKTSIZE);
00275           if (_state_timeout)
00276             _set_timeout(true, _socket, _state_timeout);
00277           if (_kind == UDP)
00278 #ifdef LIBSOCKET_WIN
00279             res = recv(socket, chr, MAXPKTSIZE, 0);
00280 #else
00281             res = recv(socket, chr, MAXPKTSIZE, MSG_TRUNC);
00282 #endif
00283           else
00284 #ifdef TLS
00285             if (_tls)
00286               res = gnutls_record_recv(_session, chr, MAXPKTSIZE);
00287             else
00288 #endif
00289               res = recv(socket, chr, MAXPKTSIZE, 0);
00290           if (_check_answer(res, str))
00291             return str;
00292           _buffer += std::string(chr, res);
00293           if (_update_buffer(delim, i, str))
00294             end = true;
00295         }
00296     _state_timeout = 0;
00297     return str;
00298   }
00299 
00300   std::string   NetSocket::_read_line(int socket, int& port,
00301                                       std::string& host)
00302   {
00303     char                        chr[MAXPKTSIZE];
00304     std::string                 str = "";
00305     int                         res = 1, i;
00306     std::pair<int, int>         delim;
00307     struct sockaddr_in          addr;
00308 #ifdef IPV6_ENABLED
00309     struct sockaddr_in6         addr6;
00310 #endif
00311 #ifdef LIBSOCKET_WIN
00312     int                         size;
00313 #else
00314     socklen_t                   size;
00315 #endif
00316     bool                        end = false;
00317 
00318 #ifdef IPV6_ENABLED
00319     if (V4 == _version)
00320 #endif
00321       size = sizeof(addr);
00322 #ifdef IPV6_ENABLED
00323     else
00324       size = sizeof(addr6);
00325 #endif
00326     if (socket < 0)
00327       throw NoConnection("No Socket", HERE);
00328     if (!_update_buffer(delim, i, str))
00329       while (!end)
00330         {
00331           if (_state_timeout)
00332             _set_timeout(true, _socket, _state_timeout);
00333           if (_kind == UDP)
00334             {
00335 #ifdef LIBSOCKET_WIN
00336               int flags = 0;
00337 #else
00338               int flags = MSG_TRUNC;
00339 #endif
00340 
00341 #ifdef IPV6_ENABLED
00342               if (V4 == _version)
00343 #endif
00344                 res = recvfrom(socket, chr, MAXPKTSIZE, flags,
00345                                (struct sockaddr *) &addr, &size);
00346 #ifdef IPV6_ENABLED
00347               else
00348                 res = recvfrom(socket, chr, MAXPKTSIZE, flags,
00349                                (struct sockaddr *) &addr6, &size);
00350 #endif
00351             }
00352           else
00353             {
00354 #ifdef TLS
00355               if (_tls)
00356                 res = gnutls_record_recv(_session, chr, MAXPKTSIZE);
00357               else
00358 #endif
00359                 res = recvfrom(socket, chr, MAXPKTSIZE, 0, NULL, 0);
00360 #ifdef IPV6_ENABLED
00361               if (V4 == _version)
00362                 {
00363 #endif
00364                   if (getpeername(socket, (struct sockaddr *) &addr, &size) < 0)
00365                     throw GetpeernameError("getpeername error", HERE);
00366 #ifdef IPV6_ENABLED
00367                 }
00368               else
00369                 if (getpeername(socket, (struct sockaddr *) &addr6, &size) < 0)
00370                   throw GetpeernameError("getpeername error", HERE);
00371 #endif
00372             }
00373           if (_check_answer(res, str))
00374             return str;
00375           _buffer += std::string(chr, res);
00376           if (_update_buffer(delim, i, str))
00377             end = true;
00378         }
00379 #ifdef IPV6_ENABLED
00380     if (V4 == _version)
00381       {
00382 #endif
00383         host = std::string(inet_ntoa(addr.sin_addr));
00384         port = ntohs(addr.sin_port);
00385 #ifdef IPV6_ENABLED
00386       }
00387     else
00388       {
00389         char buf[INET6_ADDRSTRLEN];
00390         if (inet_ntop(AF_INET6, &addr6.sin6_addr, buf, INET6_ADDRSTRLEN) == 0)
00391           throw InetntopError("Not a valid address", HERE);
00392         host = std::string(buf);
00393         port = ntohs(addr6.sin6_port);
00394       }
00395 #endif
00396     _state_timeout = 0;
00397     return str;
00398   }
00399 
00400   void  NetSocket::_write_str(int socket, const std::string& str,
00401                               const std::string& host, int port) const
00402   {
00403     struct sockaddr_in          addr;
00404 #ifdef IPV6_ENABLED
00405     struct sockaddr_in6         addr6;
00406 #endif
00407     int                         res = 1;
00408     const char                  *buf = str.c_str();
00409     unsigned int                count = 0;
00410 
00411 #ifdef IPV6_ENABLED
00412     if (V4 == _version)
00413 #endif
00414       addr = _get_addr(host, port);
00415 #ifdef IPV6_ENABLED
00416     else
00417       addr6 = _get_addr6(host, port);
00418 #endif
00419     if (socket < 0)
00420       throw NoConnection("No Socket", HERE);
00421     while (res && count < str.size())
00422       {
00423 #ifdef IPV6_ENABLED
00424         if (V4 == _version)
00425 #endif
00426 #ifdef TLS
00427           if (_tls)
00428             res = gnutls_record_send(_session, buf + count, str.size() - count);
00429           else
00430 #endif
00431             res = sendto(socket, buf + count,
00432                          str.size() - count, SENDTO_FLAGS,
00433                          (const struct sockaddr*)&addr, sizeof(_addr));
00434 #ifdef IPV6_ENABLED
00435         else
00436           res = sendto(socket, buf + count,
00437                        str.size() - count, SENDTO_FLAGS,
00438                        (const struct sockaddr*)&addr6, sizeof(_addr6));
00439 #endif
00440         if (res <= 0)
00441           throw ConnectionClosed("Connection Closed", HERE);
00442         count += res;
00443       }
00444   }
00445 
00446   void  NetSocket::_write_str_bin(int socket, const std::string& str,
00447                                   const std::string& host, int port) const
00448   {
00449     struct sockaddr_in          addr;
00450 #ifdef IPV6_ENABLED
00451     struct sockaddr_in6         addr6;
00452 #endif
00453     int                         res = 1;
00454     unsigned int                count = 0;
00455 #ifdef LIBSOCKET_WIN
00456     char*                       buf = new char[str.size() + 2];
00457 #else
00458     char                        buf[str.size() + 2];
00459 #endif
00460 
00461     buf[0] = str.size() / 256;
00462     buf[1] = str.size() % 256;
00463     memcpy(buf + 2, str.c_str(), str.size());
00464 #ifdef IPV6_ENABLED
00465     if (V4 == _version)
00466 #endif
00467       addr = _get_addr(host, port);
00468 #ifdef IPV6_ENABLED
00469     else
00470       addr6 = _get_addr6(host, port);
00471 #endif
00472     if (socket < 0)
00473       throw NoConnection("No Socket", HERE);
00474     while (res && count < str.size() + 2)
00475       {
00476 #ifdef IPV6_ENABLED
00477         if (V4 == _version)
00478 #endif
00479 #ifdef TLS
00480           if (_tls)
00481             res = gnutls_record_send(_session, buf + count, str.size() + 2 - count);
00482           else
00483 #endif
00484             res = sendto(socket, buf + count, str.size() + 2 - count, 
00485                          SENDTO_FLAGS,
00486                          (const struct sockaddr*)&addr, sizeof(_addr));
00487 #ifdef IPV6_ENABLED
00488         else
00489           res = sendto(socket, buf + count, str.size() + 2 - count, 
00490                        SENDTO_FLAGS,
00491                        (const struct sockaddr*)&addr6, sizeof(_addr6));
00492 #endif
00493         if (res <= 0)
00494           throw ConnectionClosed("Connection Closed", HERE);
00495         count += res;
00496       }
00497 #ifdef LIBSOCKET_WIN
00498     delete[] buf;
00499 #endif
00500   }
00501 
00502   void  NetSocket::writeto(const std::string& str,
00503                            const std::string& host, int port)
00504   {
00505     if (_proto_kind == binary)
00506       _write_str_bin(_socket, str, host, port);
00507     else
00508       _write_str(_socket, str, host, port);
00509   }
00510 
00511   std::string   NetSocket::read(int& port, std::string& host)
00512   {
00513     if (_proto_kind == binary)
00514       return _read_line_bin(_socket, port, host, 0);
00515     else
00516       return _read_line(_socket, port, host);
00517   }
00518 
00519   std::string   NetSocket::read(int& port, std::string& host, int timeout)
00520   {
00521     if (_proto_kind == binary)
00522       {
00523         _set_timeout(true, _socket, timeout);
00524         return _read_line_bin(_socket, port, host, 0);
00525       }
00526     else
00527       {
00528         _state_timeout = timeout;
00529         return _read_line(_socket, port, host);
00530       }
00531   }
00532 
00533   std::string   NetSocket::read()
00534   {
00535     if (_proto_kind == binary)
00536       return _read_line_bin(_socket, 0);
00537     else
00538       return _read_line(_socket);
00539   }
00540 
00541   std::string   NetSocket::read(int timeout)
00542   {
00543     if (_proto_kind == binary)
00544       {
00545         _set_timeout(true, _socket, timeout);
00546         return _read_line_bin(_socket, 0);
00547       }
00548     else
00549       {
00550         _state_timeout = timeout;
00551         return _read_line(_socket);
00552       }
00553   }
00554 
00555   std::string   NetSocket::readn(int& port, std::string& host,
00556                                  unsigned int size)
00557   {
00558     // _read_line_bin is bufferised with the same buffer as textual
00559     // protocols, so this function can be used for binary and text
00560     // protocols.
00561     return _read_line_bin(_socket, port, host, size);
00562   }
00563 
00564   std::string   NetSocket::readn(int& port, std::string& host, int timeout,
00565                                  unsigned int size)
00566   {
00567     if (!size || size > _buffer.size())
00568       _set_timeout(true, _socket, timeout);
00569     // _read_line_bin is bufferised with the same buffer as textual
00570     // protocols, so this function can be used for binary and text
00571     // protocols.
00572     return _read_line_bin(_socket, port, host, size);
00573   }
00574 
00575   std::string   NetSocket::readn(unsigned int size)
00576   {
00577     // _read_line_bin is bufferised with the same buffer as textual
00578     // protocols, so this function can be used for binary and text
00579     // protocols.
00580     return _read_line_bin(_socket, size);
00581   }
00582 
00583   std::string   NetSocket::readn(int timeout, unsigned int size)
00584   {
00585     if (!size || size > _buffer.size())
00586       _set_timeout(true, _socket, timeout);
00587     // _read_line_bin is bufferised with the same buffer as textual
00588     // protocols, so this function can be used for binary and text
00589     // protocols.
00590     return _read_line_bin(_socket, size);
00591   }
00592 }