Commit d5e189cf authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[1238] Socket binding for IPv4 implemented.

parent 0b6937d0
......@@ -250,17 +250,75 @@ IfaceMgr::openSocket(const std::string& ifname,
uint16_t
IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
isc_throw(NotImplemented, "Sorry. Try again in 2 weeks");
cout << iface.getFullName() << addr.toText() << port; // just to disable unused warning
cout << "Creating UDP4 socket on " << iface.getFullName()
<< " " << addr.toText() << "/port=" << port << endl;
struct sockaddr_in addr4;
memset(&addr4, 0, sizeof(sockaddr));
addr4.sin_family = AF_INET;
addr4.sin_port = htons(port);
memcpy(&addr4.sin_addr, addr.getAddress().to_v4().to_bytes().data(),
sizeof(addr4.sin_addr));
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
isc_throw(Unexpected, "Failed to create UDP6 socket.");
}
if (bind(sock, (struct sockaddr *)&addr4, sizeof(addr4)) < 0) {
close(sock);
isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
<< "/port=" << port);
}
#if defined(SO_BINDTODEVICE)
#if 0
/// For some reason that doesn't work. It's not a big deal as this is
/// Linux only feature. We can use IP_PKTINFO to check that we received
/// packet over proper interface.
// Bind this socket to this interface.
const char* ifname = iface.getName().c_str();
int len = strlen(ifname);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
ifname, len) < 0) {
isc_throw(Unexpected, "setsockopt: SO_BINDTODEVICE failed.");
}
#endif
#endif
int flag = 1;
#ifdef IP_RECVPKTINFO
if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO,
&flag, sizeof(flag)) != 0) {
close(sock);
isc_throw(Unexpected, "setsockopt: IP_RECVPKTINFO failed.")
}
#else
/* RFC2292 - an old way */
if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO,
&flag, sizeof(flag)) != 0) {
close(sock);
isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
}
#endif
cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
addr.toText() << "/port=" << port << endl;
// TODO: Add socket to iface interface
return (sock);
}
uint16_t
IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
struct sockaddr_in6 addr6;
cout << "Creating socket on " << iface.getFullName()
<< "/port=" << port << endl;
cout << "Creating UDP6 socket on " << iface.getFullName()
<< " " << addr.toText() << "/port=" << port << endl;
struct sockaddr_in6 addr6;
memset(&addr6, 0, sizeof(addr6));
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
......@@ -278,8 +336,7 @@ IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
// make a socket
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock < 0) {
cout << "Failed to create UDP6 socket." << endl;
return (-1);
isc_throw(Unexpected, "Failed to create UDP6 socket.");
}
/* Set the REUSEADDR option so that we don't fail to start if
......@@ -287,32 +344,28 @@ IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
int flag = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&flag, sizeof(flag)) < 0) {
cout << "Can't set SO_REUSEADDR option on dhcpv6 socket." << endl;
close(sock);
return (-1);
isc_throw(Unexpected, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
}
if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
cout << "Failed to bind socket " << sock << " to " << addr.toText()
<< "/port=" << port << endl;
close(sock);
return (-1);
isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
<< "/port=" << port);
}
#ifdef IPV6_RECVPKTINFO
/* RFC3542 - a new way */
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
&flag, sizeof(flag)) != 0) {
cout << "setsockopt: IPV6_RECVPKTINFO failed." << endl;
close(sock);
return (-1);
isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
}
#else
/* RFC2292 - an old way */
if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
&flag, sizeof(flag)) != 0) {
cout << "setsockopt: IPV6_PKTINFO: failed." << endl;
close(sock);
return (-1);
isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
}
#endif
......@@ -326,7 +379,8 @@ IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
if ( !joinMcast( sock, iface.getName(),
string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
close(sock);
return (-1);
isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
<< " multicast group.");
}
}
......
......@@ -25,8 +25,6 @@ check-local:
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
AM_CPPFLAGS += -I$(top_srcdir)/src/bin
AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/bin/dhcp6/tests\"
......@@ -58,7 +56,6 @@ dhcp6_unittests_LDADD += $(SQLITE_LIBS)
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
endif
noinst_PROGRAMS = $(TESTS)
......@@ -20,9 +20,10 @@
#include <arpa/inet.h>
#include <gtest/gtest.h>
#include "io_address.h"
#include "dhcp/pkt6.h"
#include "dhcp6/iface_mgr.h"
#include <asiolink/io_address.h>
#include <dhcp/pkt6.h>
#include <dhcp6/iface_mgr.h>
#include <dhcp/dhcp4.h>
using namespace std;
using namespace isc;
......@@ -242,10 +243,6 @@ TEST_F(IfaceMgrTest, detectIfaces) {
delete ifacemgr;
}
// TODO: disabled due to other naming on various systems
// (lo in Linux, lo0 in BSD systems)
// Fix for this is available on 1186 branch, will reenable
// this test once 1186 is merged
TEST_F(IfaceMgrTest, sockets6) {
// testing socket operation in a portable way is tricky
// without interface detection implemented
......@@ -285,7 +282,7 @@ TEST_F(IfaceMgrTest, sockets6) {
// TODO: disabled due to other naming on various systems
// (lo in Linux, lo0 in BSD systems)
TEST_F(IfaceMgrTest, sockets6Mcast) {
TEST_F(IfaceMgrTest, DISABLED_sockets6Mcast) {
// testing socket operation in a portable way is tricky
// without interface detection implemented
......@@ -326,12 +323,15 @@ TEST_F(IfaceMgrTest, sendReceive6) {
fakeifaces << LOOPBACK << " ::1";
fakeifaces.close();
NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
// let's assume that every supported OS have lo interface
IOAddress loAddr("::1");
int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
int socket1 = 0, socket2 = 0;
EXPECT_NO_THROW(
socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
);
ifacemgr->setSendSock(socket2);
ifacemgr->setRecvSock(socket1);
......@@ -367,4 +367,25 @@ TEST_F(IfaceMgrTest, sendReceive6) {
delete ifacemgr;
}
TEST_F(IfaceMgrTest, socket4) {
createLoInterfacesTxt();
NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
// let's assume that every supported OS have lo interface
IOAddress loAddr("127.0.0.1");
// use unprivileged port (it's convenient for running tests as non-root)
int socket1 = 0;
EXPECT_NO_THROW(
socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000);
);
EXPECT_GT(socket1, 0);
close(socket1);
delete ifacemgr;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment