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