return (false);
}
+ // Binding socket to unicast address and then joining multicast group
+ // works well on Mac OS (and possibly other BSDs), but does not work
+ // on Linux.
if ( !joinMulticast(sock, iface->getName(),
string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
close(sock);
count++;
#if defined(OS_LINUX)
- // this doesn't work too well on NetBSD
+ // To receive multicast traffic, Linux requires binding socket to
+ // a multicast group. That in turn doesn't work on NetBSD.
int sock2 = openSocket(iface->getName(),
IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
port);
m.msg_iov = &v;
m.msg_iovlen = 1;
-#if defined(OS_LINUX)
- // 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;
-#endif
+ // call OS-specific routines (like setting interface index)
+ os_send4(m, control_buf_, control_buf_len_, pkt);
cout << "Trying to send " << pkt->getBuffer().getLength() << " bytes to "
<< pkt->getRemoteAddr().toText() << ":" << pkt->getRemotePort()
// Now we have a socket, let's get some data from it!
struct sockaddr_in from_addr;
- struct in_addr to_addr;
const uint32_t RCVBUFSIZE = 1500;
static uint8_t buf[RCVBUFSIZE];
memset(&control_buf_[0], 0, control_buf_len_);
memset(&from_addr, 0, sizeof(from_addr));
- memset(&to_addr, 0, sizeof(to_addr));
// Initialize our message header structure.
struct msghdr m;
return (Pkt4Ptr()); // NULL
}
- unsigned int ifindex = iface->getIndex();
-
-#if defined(OS_LINUX)
- struct cmsghdr* cmsg;
- struct in_pktinfo* pktinfo;
-
- int found_pktinfo = 0;
- 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);
+ // We have all data let's create Pkt4 object.
+ Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(buf, result));
- ifindex = pktinfo->ipi_ifindex;
- to_addr = pktinfo->ipi_addr;
+ unsigned int ifindex = iface->getIndex();
- // 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.
+ IOAddress from(htonl(from_addr.sin_addr.s_addr));
+ uint16_t from_port = htons(from_addr.sin_port);
- // IOAddress tmp(htonl(pktinfo->ipi_spec_dst.s_addr));
- // cout << "The other addr is: " << tmp.toText() << endl;
+ // 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_);
- // Perhaps we should uncomment this:
- // to_addr = pktinfo->ipi_spec_dst;
- found_pktinfo = 1;
- }
- cmsg = CMSG_NXTHDR(&m, cmsg);
- }
- if (!found_pktinfo) {
+ if (!os_receive4(m, pkt)) {
cout << "Unable to find pktinfo" << endl;
return (boost::shared_ptr<Pkt4>()); // NULL
}
-#endif
-
- IOAddress to(htonl(to_addr.s_addr));
- IOAddress from(htonl(from_addr.sin_addr.s_addr));
- uint16_t from_port = htons(from_addr.sin_port);
cout << "Received " << result << " bytes from " << from.toText()
<< "/port=" << from_port
- << " sent to " << to.toText() << " over interface "
+ << " sent to " << pkt->getLocalAddr().toText() << " over interface "
<< iface->getFullName() << endl;
- // we have all data let's create Pkt4 object
- Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(buf, result));
-
- pkt->setIface(iface->getName());
- pkt->setIndex(ifindex);
- pkt->setLocalAddr(to);
- pkt->setRemoteAddr(from);
- pkt->setRemotePort(from_port);
- pkt->setLocalPort(candidate->port_);
-
return (pkt);
}
/// (e.g. remove expired leases)
///
/// @return Pkt6 object representing received packet (or NULL)
- boost::shared_ptr<Pkt6> receive6();
+ Pkt6Ptr receive6();
/// @brief Tries to receive IPv4 packet over open IPv4 sockets.
///
/// (e.g. remove expired leases)
///
/// @return Pkt4 object representing received packet (or NULL)
- boost::shared_ptr<Pkt4> receive4();
+ Pkt4Ptr receive4();
/// Opens UDP/IP socket and binds it to address, interface and port.
///
// to people who try to use multicast as source address.
/// length of the control_buf_ array
- int control_buf_len_;
+ size_t control_buf_len_;
/// control-buffer, used in transmission and reception
boost::scoped_array<char> control_buf_;
+
+ /// @brief A wrapper for OS-specific operations before sending IPv4 packet
+ ///
+ /// @param m message header (will be later used for sendmsg() call)
+ /// @param control_buf buffer to be used during transmission
+ /// @param control_buf_len buffer length
+ /// @param pkt packet to be sent
+ void os_send4(struct msghdr& m, boost::scoped_array<char>& control_buf,
+ size_t control_buf_len, const Pkt4Ptr& pkt);
+
+ /// @brief OS-specific operations during IPv4 packet reception
+ ///
+ /// @param m message header (was used during recvmsg() call)
+ /// @param pkt packet received (some fields will be set here)
+ ///
+ /// @return true if successful, false otherwise
+ bool os_receive4(struct msghdr& m, Pkt4Ptr& pkt);
+
private:
/// creates a single instance of this class (a singleton implementation)
flag_broadcast_ = flags & IFF_BROADCAST;
}
+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.
+
+ // IOAddress tmp(htonl(pktinfo->ipi_spec_dst.s_addr));
+ // cout << "The other addr is: " << tmp.toText() << endl;
+
+ // Perhaps we should uncomment this:
+ // to_addr = pktinfo->ipi_spec_dst;
+ }
+ cmsg = CMSG_NXTHDR(&m, cmsg);
+ }
+
+ return (false);
+}
+
}
#endif // if defined(LINUX)