}
}
- Iface::SocketInfo info(sock, addr, port);
+ SocketInfo info(sock, addr, port);
+ iface.addSocket(info);
+
+ return (sock);
+}
+
+int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port,
+ bool receive_bcast, bool send_bcast) {
+
+ int sock = packet_filter_->openSocket(iface, addr, port,
+ receive_bcast, send_bcast);
+
+ SocketInfo info(sock, addr, port);
iface.addSocket(info);
return (sock);
return (result);
}
+bool
+IfaceMgr::send(const Pkt4Ptr& pkt) {
+
+ Iface* iface = getIface(pkt->getIface());
+ if (!iface) {
+ isc_throw(BadValue, "Unable to send Pkt4. Invalid interface ("
+ << pkt->getIface() << ") specified.");
+ }
+
+ return (packet_filter_->send(getSocket(*pkt), pkt));
+}
+
boost::shared_ptr<Pkt4>
IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
isc_throw(BadValue, "fractional timeout must be shorter than"
" one million microseconds");
}
- const Iface::SocketInfo* candidate = 0;
+ const SocketInfo* candidate = 0;
IfaceCollection::const_iterator iface;
fd_set sockets;
int maxfd = 0;
}
// Now we have a socket, let's get some data from it!
- struct sockaddr_in from_addr;
- uint8_t buf[RCVBUFSIZE];
-
- memset(&control_buf_[0], 0, control_buf_len_);
- memset(&from_addr, 0, sizeof(from_addr));
-
- // Initialize our message header structure.
- struct msghdr m;
- memset(&m, 0, sizeof(m));
-
- // Point so we can get the from address.
- m.msg_name = &from_addr;
- m.msg_namelen = sizeof(from_addr);
-
- struct iovec v;
- v.iov_base = static_cast<void*>(buf);
- v.iov_len = RCVBUFSIZE;
- m.msg_iov = &v;
- m.msg_iovlen = 1;
-
- // Getting the interface is a bit more involved.
- //
- // We set up some space for a "control message". We have
- // previously asked the kernel to give us packet
- // information (when we initialized the interface), so we
- // should get the destination address from that.
- m.msg_control = &control_buf_[0];
- m.msg_controllen = control_buf_len_;
-
- result = recvmsg(candidate->sockfd_, &m, 0);
- if (result < 0) {
- isc_throw(SocketReadError, "failed to receive UDP4 data");
- }
-
- // We have all data let's create Pkt4 object.
- Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(buf, result));
-
- pkt->updateTimestamp();
-
- unsigned int ifindex = iface->getIndex();
-
- IOAddress from(htonl(from_addr.sin_addr.s_addr));
- uint16_t from_port = htons(from_addr.sin_port);
-
- // Set receiving interface based on information, which socket was used to
- // receive data. OS-specific info (see os_receive4()) may be more reliable,
- // so this value may be overwritten.
- pkt->setIndex(ifindex);
- pkt->setIface(iface->getName());
- pkt->setRemoteAddr(from);
- pkt->setRemotePort(from_port);
- pkt->setLocalPort(candidate->port_);
-
- if (!os_receive4(m, pkt)) {
- isc_throw(SocketReadError, "unable to find pktinfo");
- }
-
- return (pkt);
+ return (packet_filter_->receive(*iface, *candidate));
}
Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
" one million microseconds");
}
- const Iface::SocketInfo* candidate = 0;
+ const SocketInfo* candidate = 0;
fd_set sockets;
int maxfd = 0;
stringstream names;
isc::Exception(file, line, what) { };
};
+/// Holds information about socket.
+struct SocketInfo {
+ uint16_t sockfd_; /// socket descriptor
+ isc::asiolink::IOAddress addr_; /// bound address
+ uint16_t port_; /// socket port
+ uint16_t family_; /// IPv4 or IPv6
+
+ /// @brief SocketInfo constructor.
+ ///
+ /// @param sockfd socket descriptor
+ /// @param addr an address the socket is bound to
+ /// @param port a port the socket is bound to
+ SocketInfo(uint16_t sockfd, const isc::asiolink::IOAddress& addr,
+ uint16_t port)
+ :sockfd_(sockfd), addr_(addr), port_(port), family_(addr.getFamily()) { }
+};
+
+
/// @brief represents a single network interface
///
/// Iface structure represents network interface with all useful
/// type that defines list of addresses
typedef std::vector<isc::asiolink::IOAddress> AddressCollection;
- /// Holds information about socket.
- struct SocketInfo {
- uint16_t sockfd_; /// socket descriptor
- isc::asiolink::IOAddress addr_; /// bound address
- uint16_t port_; /// socket port
- uint16_t family_; /// IPv4 or IPv6
-
- /// @brief SocketInfo constructor.
- ///
- /// @param sockfd socket descriptor
- /// @param addr an address the socket is bound to
- /// @param port a port the socket is bound to
- SocketInfo(uint16_t sockfd, const isc::asiolink::IOAddress& addr,
- uint16_t port)
- :sockfd_(sockfd), addr_(addr), port_(port), family_(addr.getFamily()) { }
- };
-
/// type that holds a list of socket informations
/// @todo: Add SocketCollectionConstIter type
typedef std::list<SocketInfo> SocketCollection;
return (false);
}
-int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port,
- bool receive_bcast, bool send_bcast) {
-
- int sock = packet_filter_->openSocket(iface, addr, port,
- receive_bcast, send_bcast);
-
- Iface::SocketInfo info(sock, addr, port);
- iface.addSocket(info);
-
- return (sock);
-}
-
/// @brief sets flag_*_ fields.
///
/// This implementation is OS-specific as bits have different meaning
flag_broadcast_ = flags & IFF_BROADCAST;
}
-bool
-IfaceMgr::send(const Pkt4Ptr& pkt)
-{
- Iface* iface = getIface(pkt->getIface());
- if (!iface) {
- isc_throw(BadValue, "Unable to send Pkt4. Invalid interface ("
- << pkt->getIface() << ") specified.");
- }
-
- memset(&control_buf_[0], 0, control_buf_len_);
-
- // Set the target address we're sending to.
- sockaddr_in to;
- memset(&to, 0, sizeof(to));
- to.sin_family = AF_INET;
- to.sin_port = htons(pkt->getRemotePort());
- to.sin_addr.s_addr = htonl(pkt->getRemoteAddr());
-
- struct msghdr m;
- // Initialize our message header structure.
- memset(&m, 0, sizeof(m));
- m.msg_name = &to;
- m.msg_namelen = sizeof(to);
-
- // Set the data buffer we're sending. (Using this wacky
- // "scatter-gather" stuff... we only have a single chunk
- // of data to send, so we declare a single vector entry.)
- struct iovec v;
- memset(&v, 0, sizeof(v));
- // iov_base field is of void * type. We use it for packet
- // transmission, so this buffer will not be modified.
- v.iov_base = const_cast<void *>(pkt->getBuffer().getData());
- v.iov_len = pkt->getBuffer().getLength();
- m.msg_iov = &v;
- m.msg_iovlen = 1;
-
- // call OS-specific routines (like setting interface index)
- os_send4(m, control_buf_, control_buf_len_, pkt);
-
- pkt->updateTimestamp();
-
- int result = sendmsg(getSocket(*pkt), &m, 0);
- if (result < 0) {
- isc_throw(SocketWriteError, "pkt4 send failed");
- }
- return (result);
-}
+void IfaceMgr::os_send4(struct msghdr&, boost::scoped_array<char>&,
+ size_t, const Pkt4Ptr&) {
+ return;
-void IfaceMgr::os_send4(struct msghdr& m, boost::scoped_array<char>& control_buf,
- size_t control_buf_len, const Pkt4Ptr& pkt) {
-
- // Setting the interface is a bit more involved.
- //
- // We have to create a "control message", and set that to
- // define the IPv4 packet information. We could set the
- // source address if we wanted, but we can safely let the
- // kernel decide what that should be.
- m.msg_control = &control_buf[0];
- m.msg_controllen = control_buf_len;
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
- cmsg->cmsg_level = IPPROTO_IP;
- cmsg->cmsg_type = IP_PKTINFO;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
- struct in_pktinfo* pktinfo =(struct in_pktinfo *)CMSG_DATA(cmsg);
- memset(pktinfo, 0, sizeof(struct in_pktinfo));
- pktinfo->ipi_ifindex = pkt->getIndex();
- m.msg_controllen = cmsg->cmsg_len;
}
-bool IfaceMgr::os_receive4(struct msghdr& m, Pkt4Ptr& pkt) {
- struct cmsghdr* cmsg;
- struct in_pktinfo* pktinfo;
- struct in_addr to_addr;
-
- memset(&to_addr, 0, sizeof(to_addr));
-
- cmsg = CMSG_FIRSTHDR(&m);
- while (cmsg != NULL) {
- if ((cmsg->cmsg_level == IPPROTO_IP) &&
- (cmsg->cmsg_type == IP_PKTINFO)) {
- pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
-
- pkt->setIndex(pktinfo->ipi_ifindex);
- pkt->setLocalAddr(IOAddress(htonl(pktinfo->ipi_addr.s_addr)));
- return (true);
-
- // This field is useful, when we are bound to unicast
- // address e.g. 192.0.2.1 and the packet was sent to
- // broadcast. This will return broadcast address, not
- // the address we are bound to.
-
- // XXX: Perhaps we should uncomment this:
- // to_addr = pktinfo->ipi_spec_dst;
- }
- cmsg = CMSG_NXTHDR(&m, cmsg);
- }
-
- return (false);
+bool IfaceMgr::os_receive4(struct msghdr&, Pkt4Ptr&) {
+ return (true);
}
} // end of isc::dhcp namespace
namespace isc {
namespace dhcp {
+struct SocketInfo;
+
/// Forward declaration to the class representing interface
class Iface;
/// @brief Receive packet over specified socket.
///
- /// @param sockfd descriptor of a socket to be used for packet reception
- /// @param timeout_sec integral part of a timeout.
- /// @param timeout_usec fractional part of a timeout (in microseconds).
+ /// @param iface interface
+ /// @param socket_info structure holding socket information
///
/// @return Received packet
- Pkt4Ptr receive(uint16_t sockfd, uint32_t timeout_sec,
- uint32_t timeout_usec = 0);
+ virtual Pkt4Ptr receive(const Iface& iface,
+ const SocketInfo& socket_info) = 0;
- // bool send(const Pkt4Ptr& pkt) = 0;
+ /// @brief Send packet over specified socket.
+ ///
+ /// @param sockfd socket descriptor
+ /// @param pkt packet to be sent
+ ///
+ /// @return result of sending the packet. It is 0 if successful.
+ virtual int send(uint16_t sockfd, const Pkt4Ptr& pkt) = 0;
};
} // namespace isc::dhcp
#include <dhcp/pkt4.h>
#include <dhcp/pkt_filter_inet.h>
+using namespace isc::asiolink;
+
namespace isc {
namespace dhcp {
+PktFilterInet::PktFilterInet()
+ : control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
+ control_buf_(new char[control_buf_len_])
+{
+}
+
int
PktFilterInet::openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
}
#endif
- return sock;
+ return (sock);
}
+Pkt4Ptr
+PktFilterInet::receive(const Iface& iface, const SocketInfo& socket_info) {
+ struct sockaddr_in from_addr;
+ uint8_t buf[IfaceMgr::RCVBUFSIZE];
+
+ memset(&control_buf_[0], 0, control_buf_len_);
+ memset(&from_addr, 0, sizeof(from_addr));
+
+ // Initialize our message header structure.
+ struct msghdr m;
+ memset(&m, 0, sizeof(m));
+
+ // Point so we can get the from address.
+ m.msg_name = &from_addr;
+ m.msg_namelen = sizeof(from_addr);
+
+ struct iovec v;
+ v.iov_base = static_cast<void*>(buf);
+ v.iov_len = IfaceMgr::RCVBUFSIZE;
+ m.msg_iov = &v;
+ m.msg_iovlen = 1;
+
+ // Getting the interface is a bit more involved.
+ //
+ // We set up some space for a "control message". We have
+ // previously asked the kernel to give us packet
+ // information (when we initialized the interface), so we
+ // should get the destination address from that.
+ m.msg_control = &control_buf_[0];
+ m.msg_controllen = control_buf_len_;
+
+ int result = recvmsg(socket_info.sockfd_, &m, 0);
+ if (result < 0) {
+ isc_throw(SocketReadError, "failed to receive UDP4 data");
+ }
+
+ // We have all data let's create Pkt4 object.
+ Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(buf, result));
+
+ pkt->updateTimestamp();
+
+ unsigned int ifindex = iface.getIndex();
+
+ IOAddress from(htonl(from_addr.sin_addr.s_addr));
+ uint16_t from_port = htons(from_addr.sin_port);
+
+ // Set receiving interface based on information, which socket was used to
+ // receive data. OS-specific info (see os_receive4()) may be more reliable,
+ // so this value may be overwritten.
+ pkt->setIndex(ifindex);
+ pkt->setIface(iface.getName());
+ pkt->setRemoteAddr(from);
+ pkt->setRemotePort(from_port);
+ pkt->setLocalPort(socket_info.port_);
+
+ struct cmsghdr* cmsg;
+ struct in_pktinfo* pktinfo;
+ struct in_addr to_addr;
+
+ memset(&to_addr, 0, sizeof(to_addr));
+
+ cmsg = CMSG_FIRSTHDR(&m);
+ while (cmsg != NULL) {
+ if ((cmsg->cmsg_level == IPPROTO_IP) &&
+ (cmsg->cmsg_type == IP_PKTINFO)) {
+ pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+
+ pkt->setIndex(pktinfo->ipi_ifindex);
+ pkt->setLocalAddr(IOAddress(htonl(pktinfo->ipi_addr.s_addr)));
+ break;
+
+ // This field is useful, when we are bound to unicast
+ // address e.g. 192.0.2.1 and the packet was sent to
+ // broadcast. This will return broadcast address, not
+ // the address we are bound to.
+
+ // XXX: Perhaps we should uncomment this:
+ // to_addr = pktinfo->ipi_spec_dst;
+ }
+ cmsg = CMSG_NXTHDR(&m, cmsg);
+ }
+
+ return (pkt);
+}
+
+int
+PktFilterInet::send(uint16_t sockfd, const Pkt4Ptr& pkt) {
+ memset(&control_buf_[0], 0, control_buf_len_);
+
+ // Set the target address we're sending to.
+ sockaddr_in to;
+ memset(&to, 0, sizeof(to));
+ to.sin_family = AF_INET;
+ to.sin_port = htons(pkt->getRemotePort());
+ to.sin_addr.s_addr = htonl(pkt->getRemoteAddr());
+
+ struct msghdr m;
+ // Initialize our message header structure.
+ memset(&m, 0, sizeof(m));
+ m.msg_name = &to;
+ m.msg_namelen = sizeof(to);
+
+ // Set the data buffer we're sending. (Using this wacky
+ // "scatter-gather" stuff... we only have a single chunk
+ // of data to send, so we declare a single vector entry.)
+ struct iovec v;
+ memset(&v, 0, sizeof(v));
+ // iov_base field is of void * type. We use it for packet
+ // transmission, so this buffer will not be modified.
+ v.iov_base = const_cast<void *>(pkt->getBuffer().getData());
+ v.iov_len = pkt->getBuffer().getLength();
+ m.msg_iov = &v;
+ m.msg_iovlen = 1;
+
+ // Setting the interface is a bit more involved.
+ //
+ // We have to create a "control message", and set that to
+ // define the IPv4 packet information. We could set the
+ // source address if we wanted, but we can safely let the
+ // kernel decide what that should be.
+ m.msg_control = &control_buf_[0];
+ m.msg_controllen = control_buf_len_;
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ struct in_pktinfo* pktinfo =(struct in_pktinfo *)CMSG_DATA(cmsg);
+ memset(pktinfo, 0, sizeof(struct in_pktinfo));
+ pktinfo->ipi_ifindex = pkt->getIndex();
+ m.msg_controllen = cmsg->cmsg_len;
+
+ pkt->updateTimestamp();
+
+ int result = sendmsg(sockfd, &m, 0);
+ if (result < 0) {
+ isc_throw(SocketWriteError, "pkt4 send failed");
+ }
+
+ return (result);
+}
+
+
} // end of isc::dhcp namespace
} // end of isc namespace
class PktFilterInet : public PktFilter {
public:
+ /// @brief Constructor
+ ///
+ /// Allocates control buffer.
+ PktFilterInet();
+
/// @brief Open socket.
///
/// @param iface interface descriptor
/// @brief Receive packet over specified socket.
///
- /// @param sockfd descriptor of a socket to be used for packet reception
- /// @param timeout_sec integral part of a timeout.
- /// @param timeout_usec fractional part of a timeout (in microseconds).
+ /// @param iface interface
+ /// @param socket_info structure holding socket information
///
/// @return Received packet
- Pkt4Ptr receive(uint16_t sockfd, uint32_t timeout_sec,
- uint32_t timeout_usec = 0);
+ virtual Pkt4Ptr receive(const Iface& iface, const SocketInfo& socket_info);
+
+ /// @brief Send packet over specified socket.
+ ///
+ /// @param sockfd socket descriptor
+ /// @param pkt packet to be sent
+ ///
+ /// @return result of sending a packet. It is 0 if successful.
+ virtual int send(uint16_t sockfd, const Pkt4Ptr& pkt);
- // bool send(const Pkt4Ptr& pkt) = 0;
+private:
+ /// Length of the control_buf_ array.
+ size_t control_buf_len_;
+ /// Control buffer, used in transmission and reception.
+ boost::scoped_array<char> control_buf_;
};
} // namespace isc::dhcp
TEST_F(IfaceMgrTest, socketInfo) {
// check that socketinfo for IPv4 socket is functional
- Iface::SocketInfo sock1(7, IOAddress("192.0.2.56"), DHCP4_SERVER_PORT + 7);
+ SocketInfo sock1(7, IOAddress("192.0.2.56"), DHCP4_SERVER_PORT + 7);
EXPECT_EQ(7, sock1.sockfd_);
EXPECT_EQ("192.0.2.56", sock1.addr_.toText());
EXPECT_EQ(AF_INET, sock1.family_);
EXPECT_EQ(DHCP4_SERVER_PORT + 7, sock1.port_);
// check that socketinfo for IPv6 socket is functional
- Iface::SocketInfo sock2(9, IOAddress("2001:db8:1::56"), DHCP4_SERVER_PORT + 9);
+ SocketInfo sock2(9, IOAddress("2001:db8:1::56"), DHCP4_SERVER_PORT + 9);
EXPECT_EQ(9, sock2.sockfd_);
EXPECT_EQ("2001:db8:1::56", sock2.addr_.toText());
EXPECT_EQ(AF_INET6, sock2.family_);