Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

socket.hxx

Go to the documentation of this file.
00001 // Copyright (C) 2003, 2004, 2005 Laboratoire de Recherche en Informatique
00002 
00003 // This file is part of Qolyester.
00004 
00005 // Qolyester is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 // Qolyester is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018 
00019 #include "config.hh"
00020 
00021 #ifndef QOLYESTER_ENABLE_VIRTUAL
00022 
00023 # ifndef QOLYESTER_DAEMON_SYS_SOCKET_HXX
00024 #  define QOLYESTER_DAEMON_SYS_SOCKET_HXX 1
00025 
00026 #  include <sys/socket.h>
00027 #  include <fcntl.h>
00028 #  include <sys/ioctl.h>
00029 #  include <net/if.h>
00030 #  include <sstream>
00031 
00032 #  include "cst/constants.hh"
00033 #  include "utl/exception.hh"
00034 
00035 #  include "sys/realinterfaceinfo.hh"
00036 
00037 #  include "socket.hh"
00038 
00039 namespace olsr {
00040 
00041 #  if QOLYESTER_FAMILY_INET == 6
00042   extern bool   dirty_promisc_hack;
00043 #  endif
00044 
00045   namespace sys {
00046 
00047     Socket::Socket(_dummy_values)
00048       : _fd(-1),
00049         _mtu(0),
00050         _baddr(),
00051         _index(0)
00052     {}
00053 
00054     Socket::Socket()
00055       : _mtu(0),
00056         _baddr(),
00057         _index(0) {
00058       init();
00059     }
00060 
00061     Socket::Socket(unsigned mtu)
00062       : _mtu(mtu),
00063         _baddr(),
00064         _index(0) {
00065       init();
00066     }
00067 
00068     Socket::Socket(unsigned mtu, const addr_t& addr, port_t port)
00069       : _mtu(mtu),
00070         _baddr(),
00071         _index(0) {
00072       init();
00073       bind(addr, port);
00074     }
00075 
00076     Socket::Socket(unsigned mtu, const std::string& host, port_t port)
00077       : _mtu(mtu),
00078         _baddr(),
00079         _index(0) {
00080       init();
00081       bind(addr_t(host), port);
00082     }
00083 
00084     Socket::Socket(unsigned mtu, const char* host, port_t port)
00085       : _mtu(mtu),
00086         _baddr(),
00087         _index(0) {
00088       init();
00089       bind(addr_t(std::string(host)), port);
00090     }
00091 
00092     void
00093     Socket::close() {
00094       if (_fd >= 0)
00095         ::close(_fd);
00096       _fd = -1;
00097     }
00098 
00099     void
00100     Socket::bind_to_device(const std::string& name) {
00101       if (::setsockopt(_fd, SOL_SOCKET, SO_BINDTODEVICE,
00102                        name.c_str(), name.length() + 1) < 0)
00103         throw errnoexcept_t(std::string("setsockopt(SO_BINDTODEVICE): ") +
00104                             strerror(errno), errno);
00105     }
00106 
00107     void
00108 #  if QOLYESTER_FAMILY_INET != 6
00109     Socket::set_multicast(const RealInterfaceInfo&) {
00110       int val = 1;
00111       if (setsockopt(_fd, SOL_SOCKET, SO_BROADCAST, &val, sizeof val) < 0)
00112         throw errnoexcept_t(std::string("setsockopt(SO_BROADCAST): ") +
00113                                         strerror(errno), errno);
00114 #  else // QOLYESTER_FAMILY_INET == 6
00115     Socket::set_multicast(const RealInterfaceInfo& info) {
00116       unsigned  index = info.index();
00117 
00118       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
00119                      &index, sizeof index) < 0)
00120         throw errnoexcept_t(std::string("setsockopt(IPV6_MULTICAST_IF): ") +
00121                             strerror(errno), errno);
00122       int       val = 0;
00123 
00124       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
00125                      &val, sizeof val) < 0)
00126         throw errnoexcept_t(std::string("setsockopt(IPV6_MULTICAST_LOOP): ") +
00127                                         strerror(errno), errno);
00128 
00129       if (dirty_promisc_hack) {
00130         ifreq   ifr;
00131         strncpy(ifr.ifr_name, info.name().c_str(), IFNAMSIZ);
00132         ifr.ifr_name[IFNAMSIZ - 1] = 0;
00133         if (ioctl(_fd, SIOCGIFFLAGS, &ifr) < 0)
00134           throw errnoexcept_t(std::string("ioctl(SIOCGIFFLAGS): ") +
00135                               strerror(errno), errno);
00136         if ((ifr.ifr_flags & IFF_PROMISC) == 0) {
00137           ifr.ifr_flags |= IFF_PROMISC;
00138           if (ioctl(_fd, SIOCSIFFLAGS, &ifr) < 0)
00139             throw errnoexcept_t(std::string("ioctl(SIOCSIFFLAGS): ") +
00140                                 strerror(errno), errno);
00141           ifr.ifr_flags &= ~IFF_PROMISC;
00142           if (ioctl(_fd, SIOCSIFFLAGS, &ifr) < 0)
00143             throw errnoexcept_t(std::string("ioctl(SIOCSIFFLAGS): ") +
00144                                 strerror(errno), errno);
00145         }
00146       }
00147 #  endif
00148     }
00149 
00150     void
00151     Socket::bind(const sockaddr_t& sin) {
00152       if (::bind(_fd, (::sockaddr*) &sin, sizeof sin) < 0) {
00153         std::stringstream       msg;
00154         msg << "bind("
00155             << address_t(sin) << ":" <<
00156 #  if QOLYESTER_FAMILY_INET == 6
00157           ntohs(sin.sin6_port)
00158 #  else // QOLYESTER_FAMILY_INET != 6
00159           ntohs(sin.sin_port)
00160 #  endif
00161             << "): "
00162             << strerror(errno);
00163         throw errnoexcept_t(msg.str(), errno);
00164       }
00165     }
00166 
00167     void
00168     Socket::bind_multicast(const RealInterfaceInfo& info,
00169                            const address_t& a, port_t port) {
00170 #  if QOLYESTER_FAMILY_INET == 6
00171       bind_to_device(info.name());
00172       _index = info.index();
00173 
00174       bind(a, port);
00175 
00176       set_multicast(info);
00177 
00178       int       hops = 1;
00179 
00180       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
00181                      &hops, sizeof hops) < 0)
00182         throw errnoexcept_t(std::string("setsockopt(IPV6_MULTICAST_HOPS): ") +
00183                             strerror(errno), errno);
00184 
00185       ipv6_mreq mreq;
00186       a.dump(reinterpret_cast<u_int8_t*>(&mreq.ipv6mr_multiaddr));
00187       mreq.ipv6mr_interface = info.index();
00188 
00189       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
00190                      &mreq, sizeof mreq) < 0) {
00191         std::stringstream       msg;
00192         msg << "setsockopt(IPV6_ADD_MEMBERSHIP, "
00193             << a << ", " << info.index() << "): " << strerror(errno);
00194         throw errnoexcept_t(msg.str(), errno);
00195       }
00196 
00197       int       val = 0;
00198 
00199       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
00200                      &val, sizeof val) < 0)
00201         throw errnoexcept_t(std::string("setsockopt(IPV6_MULTICAST_LOOP): ") +
00202                                         strerror(errno), errno);
00203 
00204 #  else // QOLYESTER_FAMILY_INET != 6
00205 
00206       bind(a, port);
00207       bind_to_device(info.name());
00208       set_multicast(info);
00209 
00210 #  endif
00211     }
00212 
00213 #  if QOLYESTER_FAMILY_INET == 6
00214     void
00215     Socket::bind(const addr_t& addr, port_t port, unsigned index) {
00216       sockaddr_t        sin = addr.make_sockaddr(port);
00217       sin.sin6_scope_id = index;
00218       bind(sin);
00219 #  else // QOLYESTER_FAMILY_INET != 6
00220     void
00221     Socket::bind(const addr_t& addr, port_t port) {
00222       bind(addr.make_sockaddr(port));
00223 #  endif
00224     }
00225 
00226     void
00227     Socket::connect(const sockaddr_t& sin) {
00228       if (::connect(_fd, (::sockaddr*) &sin, sizeof sin) < 0) {
00229         std::stringstream       msg;
00230         msg << "connect("
00231             << address_t(sin) << ":" <<
00232 #  if QOLYESTER_FAMILY_INET == 6
00233           ntohs(sin.sin6_port)
00234 #  else // QOLYESTER_FAMILY_INET != 6
00235           ntohs(sin.sin_port)
00236 #  endif
00237             << "): "
00238             << strerror(errno);
00239         throw errnoexcept_t(msg.str(), errno);
00240       }
00241     }
00242 
00243     void
00244     Socket::connect(const addr_t& addr, port_t port) {
00245       connect(addr.make_sockaddr(port));
00246     }
00247 
00248     utl::Data
00249     Socket::receive(address_t& sender) const {
00250       sockaddr_t        sin_from;
00251       socklen_t         sin_len = sizeof sin_from;
00252       utl::Data         data(_mtu);
00253       int               len;
00254       while ((len = ::recvfrom(_fd, data.raw(), data.size(), 0,
00255                                (sockaddr*) &sin_from, &sin_len)) < 0 &&
00256              errno == EINTR);
00257       if (len < 0)
00258         throw errnoexcept_t(std::string("recvfrom(): ") + strerror(errno),
00259                             errno);
00260 
00261       sender = address_t(sin_from);
00262 
00263       return data.shrink_to(len);
00264     }
00265 
00266     void
00267     Socket::send(const utl::ConstData& d) const {
00268       int       len;
00269       while ((len = ::send(_fd, d.raw(), d.size(), 0)) < 0 &&
00270              errno == EINTR);
00271       if (len < 0)
00272         throw errnoexcept_t(std::string("send(): ") + strerror(errno), errno);
00273     }
00274 
00275     void
00276     Socket::sendto(const utl::ConstData& d,
00277                    const address_t::sockaddr_t& s) const {
00278       int       len;
00279       while ((len = ::sendto(_fd, d.raw(), d.size(), 0,
00280                              reinterpret_cast<const sockaddr*>(&s),
00281                              sizeof s)) < 0 && errno == EINTR);
00282       if (len < 0) {
00283         std::stringstream       msg;
00284         msg << "sendto("
00285             << address_t(s) << ":" <<
00286 #  if QOLYESTER_FAMILY_INET == 6
00287           ntohs(s.sin6_port)
00288 #  else // QOLYESTER_FAMILY_INET != 6
00289           ntohs(s.sin_port)
00290 #  endif
00291             << "): "
00292             << strerror(errno);
00293         throw errnoexcept_t(msg.str(), errno);
00294       }
00295     }
00296 
00297     void
00298     Socket::sendto_bcast(const utl::ConstData& d) const {
00299       address_t::sockaddr_t     sin = _baddr.make_sockaddr(OLSR_PORT_NUMBER);
00300 #  if QOLYESTER_FAMILY_INET == 6
00301       sin.sin6_scope_id = _index;
00302 #  endif // QOLYESTER_FAMILY_INET != 6
00303       int       len;
00304       while ((len = ::sendto(_fd, d.raw(), d.size(), 0,
00305                              reinterpret_cast<sockaddr*>(&sin),
00306                              sizeof (address_t::sockaddr_t))) < 0 &&
00307              errno == EINTR);
00308       if (len < 0) {
00309         std::stringstream       msg;
00310         msg << "sendto("
00311             << address_t(sin) << ":" <<
00312 #  if QOLYESTER_FAMILY_INET == 6
00313           ntohs(sin.sin6_port)
00314 #  else // QOLYESTER_FAMILY_INET != 6
00315           ntohs(sin.sin_port)
00316 #  endif
00317             << "): "
00318             << strerror(errno);
00319         throw errnoexcept_t(msg.str(), errno);
00320       }
00321     }
00322 
00323     bool
00324     Socket::operator<(const This& rhs) const { return _fd < rhs._fd; }
00325 
00326     sch::IOEvent::p_t
00327     Socket::read_p() const {
00328       return sch::IOEvent::p_t(_fd, POLLIN);
00329     }
00330 
00331     sch::IOEvent::p_t
00332     Socket::write_p() const {
00333       return sch::IOEvent::p_t(_fd, POLLOUT);
00334     }
00335 
00336     void
00337     Socket::init() {
00338       if ((_fd = ::socket(addr_t::proto, SOCK_DGRAM, IPPROTO_UDP)) < 0)
00339         throw errnoexcept_t(std::string("socket(SOCK_DGRAM, IPPROTO_UDP): ") +
00340                             strerror(errno), errno);
00341       if (::fcntl(_fd, F_SETFL, O_RDWR | O_NONBLOCK) < 0)
00342         throw errnoexcept_t(std::string("fcntl(F_SETFL, O_NONBLOCK): ") +
00343                             strerror(errno), errno);
00344     }
00345 
00346   } // namespace sys
00347 
00348 } // namespace olsr
00349 
00350 # endif // ! QOLYESTER_DAEMON_SYS_SOCKET_HXX
00351 
00352 #endif // ! QOLYESTER_ENABLE_VIRTUAL

Generated on Thu Jul 28 21:21:48 2005 for Qolyester daemon by  doxygen 1.4.1