Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
84076d91
Commit
84076d91
authored
Mar 28, 2013
by
Marcin Siodelski
Browse files
[991] Server responds with broadcast if direct response not supported.
parent
b59d780f
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/dhcp4_srv.cc
View file @
84076d91
...
...
@@ -317,7 +317,7 @@ Dhcpv4Srv::writeServerID(const std::string& file_name) {
return
(
true
);
}
string
string
Dhcpv4Srv
::
srvidToString
(
const
OptionPtr
&
srvid
)
{
if
(
!
srvid
)
{
isc_throw
(
BadValue
,
"NULL pointer passed to srvidToString()"
);
...
...
@@ -517,6 +517,22 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
answer
->
setYiaddr
(
lease
->
addr_
);
// If remote address is not set, we are dealing with a directly
// connected client requesting new lease. We scan end response to
// the address assigned in the lease, but first we have to make sure
// that IfaceMgr supports responding directly to the client when
// client doesn't have address assigned to its interface yet.
if
(
answer
->
getRemoteAddr
().
toText
()
==
"0.0.0.0"
)
{
if
(
IfaceMgr
::
instance
().
isDirectResponseSupported
())
{
answer
->
setRemoteAddr
(
lease
->
addr_
);
}
else
{
// Since IfaceMgr does not support direct responses to
// clients not having IP address, we have to send response
// to broadcast.
answer
->
setRemoteAddr
(
IOAddress
(
"255.255.255.255"
));
}
}
// IP Address Lease time (type 51)
opt
=
OptionPtr
(
new
Option
(
Option
::
V4
,
DHO_DHCP_LEASE_TIME
));
opt
->
setUint32
(
lease
->
valid_lft_
);
...
...
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
View file @
84076d91
...
...
@@ -17,6 +17,7 @@
#include <asiolink/io_address.h>
#include <dhcp/dhcp4.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/option.h>
#include <dhcp/option4_addrlst.h>
#include <dhcp/option_custom.h>
...
...
@@ -345,6 +346,113 @@ public:
EXPECT_TRUE
(
expected_clientid
->
getData
()
==
opt
->
getData
());
}
/// @brief Tests if Discover or Request message is processed correctly
///
/// @param msg_type DHCPDISCOVER or DHCPREQUEST
/// @param client_addr client address
/// @param relay_addr relay address
void
testDiscoverRequest
(
const
uint8_t
msg_type
,
const
IOAddress
&
client_addr
,
const
IOAddress
&
relay_addr
)
{
NakedDhcpv4Srv
*
srv
=
new
NakedDhcpv4Srv
(
0
);
vector
<
uint8_t
>
mac
(
6
);
for
(
int
i
=
0
;
i
<
6
;
i
++
)
{
mac
[
i
]
=
i
*
10
;
}
boost
::
shared_ptr
<
Pkt4
>
req
(
new
Pkt4
(
msg_type
,
1234
));
boost
::
shared_ptr
<
Pkt4
>
rsp
;
req
->
setIface
(
"eth0"
);
req
->
setIndex
(
17
);
req
->
setHWAddr
(
1
,
6
,
mac
);
req
->
setRemoteAddr
(
IOAddress
(
client_addr
));
req
->
setGiaddr
(
relay_addr
);
// We are going to test that certain options are returned
// in the response message when requested using 'Parameter
// Request List' option. Let's configure those options that
// are returned when requested.
configureRequestedOptions
();
if
(
msg_type
==
DHCPDISCOVER
)
{
ASSERT_NO_THROW
(
rsp
=
srv
->
processDiscover
(
req
);
);
// Should return OFFER
ASSERT_TRUE
(
rsp
);
EXPECT_EQ
(
DHCPOFFER
,
rsp
->
getType
());
}
else
{
ASSERT_NO_THROW
(
rsp
=
srv
->
processRequest
(
req
);
);
// Should return ACK
ASSERT_TRUE
(
rsp
);
EXPECT_EQ
(
DHCPACK
,
rsp
->
getType
());
}
if
(
relay_addr
.
toText
()
!=
"0.0.0.0"
)
{
// This is relayed message. It should be sent brsp to relay address.
EXPECT_EQ
(
req
->
getGiaddr
().
toText
(),
rsp
->
getRemoteAddr
().
toText
());
}
else
if
(
client_addr
.
toText
()
!=
"0.0.0.0"
)
{
// This is a message from a client having an IP address.
EXPECT_EQ
(
req
->
getRemoteAddr
().
toText
(),
rsp
->
getRemoteAddr
().
toText
());
}
else
{
// This is a message from a client having no IP address yet.
// If IfaceMgr supports direct traffic the response should
// be sent to the new address assigned to the client.
if
(
IfaceMgr
::
instance
().
isDirectResponseSupported
())
{
EXPECT_EQ
(
rsp
->
getYiaddr
(),
rsp
->
getRemoteAddr
().
toText
());
// If direct response to the client having no IP address is
// not supported, response should go to broadcast.
}
else
{
EXPECT_EQ
(
"255.255.255.255"
,
rsp
->
getRemoteAddr
().
toText
());
}
}
messageCheck
(
req
,
rsp
);
// There are some options that are always present in the
// message, even if not requested.
EXPECT_TRUE
(
rsp
->
getOption
(
DHO_DOMAIN_NAME
));
EXPECT_TRUE
(
rsp
->
getOption
(
DHO_DOMAIN_NAME_SERVERS
));
// We did not request any options so these should not be present
// in the RSP.
EXPECT_FALSE
(
rsp
->
getOption
(
DHO_LOG_SERVERS
));
EXPECT_FALSE
(
rsp
->
getOption
(
DHO_COOKIE_SERVERS
));
EXPECT_FALSE
(
rsp
->
getOption
(
DHO_LPR_SERVERS
));
// Add 'Parameter Request List' option.
addPrlOption
(
req
);
// Repeat the test but request some options.
ASSERT_NO_THROW
(
rsp
=
srv
->
processRequest
(
req
);
);
// Should return something
ASSERT_TRUE
(
rsp
);
EXPECT_EQ
(
DHCPACK
,
rsp
->
getType
());
// Check that the requested options are returned.
optionsCheck
(
rsp
);
}
~
Dhcpv4SrvTest
()
{
CfgMgr
::
instance
().
deleteSubnets4
();
...
...
@@ -389,7 +497,7 @@ TEST_F(Dhcpv4SrvTest, basic) {
delete
naked_srv
;
}
// Verifies that
received DISCOVER
can be processed correctly,
// Verifies that
DISCOVER received via relay
can be processed correctly,
// that the OFFER message generated in response is valid and
// contains necessary options.
//
...
...
@@ -397,203 +505,44 @@ TEST_F(Dhcpv4SrvTest, basic) {
// are other tests that verify correctness of the allocation
// engine. See DiscoverBasic, DiscoverHint, DiscoverNoClientId
// and DiscoverInvalidHint.
TEST_F
(
Dhcpv4SrvTest
,
processDiscover
)
{
NakedDhcpv4Srv
*
srv
=
new
NakedDhcpv4Srv
(
0
);
vector
<
uint8_t
>
mac
(
6
);
for
(
int
i
=
0
;
i
<
6
;
i
++
)
{
mac
[
i
]
=
255
-
i
;
}
boost
::
shared_ptr
<
Pkt4
>
pkt
(
new
Pkt4
(
DHCPDISCOVER
,
1234
));
boost
::
shared_ptr
<
Pkt4
>
offer
;
pkt
->
setIface
(
"eth0"
);
pkt
->
setIndex
(
17
);
pkt
->
setHWAddr
(
1
,
6
,
mac
);
pkt
->
setRemoteAddr
(
IOAddress
(
"192.0.2.56"
));
pkt
->
setGiaddr
(
IOAddress
(
"192.0.2.67"
));
// Let's make it a relayed message
pkt
->
setHops
(
3
);
pkt
->
setRemotePort
(
DHCP4_SERVER_PORT
);
// We are going to test that certain options are returned
// (or not returned) in the OFFER message when requested
// using 'Parameter Request List' option. Let's configure
// those options that are returned when requested.
configureRequestedOptions
();
// Should not throw
EXPECT_NO_THROW
(
offer
=
srv
->
processDiscover
(
pkt
);
);
// Should return something
ASSERT_TRUE
(
offer
);
EXPECT_EQ
(
DHCPOFFER
,
offer
->
getType
());
// This is relayed message. It should be sent back to relay address.
EXPECT_EQ
(
pkt
->
getGiaddr
(),
offer
->
getRemoteAddr
());
messageCheck
(
pkt
,
offer
);
// There are some options that are always present in the
// message, even if not requested.
EXPECT_TRUE
(
offer
->
getOption
(
DHO_DOMAIN_NAME
));
EXPECT_TRUE
(
offer
->
getOption
(
DHO_DOMAIN_NAME_SERVERS
));
// We did not request any options so they should not be present
// in the OFFER.
EXPECT_FALSE
(
offer
->
getOption
(
DHO_LOG_SERVERS
));
EXPECT_FALSE
(
offer
->
getOption
(
DHO_COOKIE_SERVERS
));
EXPECT_FALSE
(
offer
->
getOption
(
DHO_LPR_SERVERS
));
// Add 'Parameter Request List' option.
addPrlOption
(
pkt
);
// Now repeat the test but request some options.
EXPECT_NO_THROW
(
offer
=
srv
->
processDiscover
(
pkt
);
);
// Should return something
ASSERT_TRUE
(
offer
);
EXPECT_EQ
(
DHCPOFFER
,
offer
->
getType
());
// This is relayed message. It should be sent back to relay address.
EXPECT_EQ
(
pkt
->
getGiaddr
(),
offer
->
getRemoteAddr
());
messageCheck
(
pkt
,
offer
);
// Check that the requested options are returned.
optionsCheck
(
offer
);
// Now repeat the test for directly sent message
pkt
->
setHops
(
0
);
pkt
->
setGiaddr
(
IOAddress
(
"0.0.0.0"
));
pkt
->
setRemotePort
(
DHCP4_CLIENT_PORT
);
EXPECT_NO_THROW
(
offer
=
srv
->
processDiscover
(
pkt
);
);
// Should return something
ASSERT_TRUE
(
offer
);
EXPECT_EQ
(
DHCPOFFER
,
offer
->
getType
());
// This is direct message. It should be sent back to origin, not
// to relay.
EXPECT_EQ
(
pkt
->
getRemoteAddr
(),
offer
->
getRemoteAddr
());
messageCheck
(
pkt
,
offer
);
TEST_F
(
Dhcpv4SrvTest
,
processDiscoverRelay
)
{
testDiscoverRequest
(
DHCPDISCOVER
,
IOAddress
(
"192.0.2.56"
),
IOAddress
(
"192.0.2.67"
));
}
// Check that the requested options are returned.
optionsCheck
(
offer
);
// Verifies that the non-relayed DISCOVER is processed correctly when
// client source address is specified.
TEST_F
(
Dhcpv4SrvTest
,
processDiscoverNoRelay
)
{
testDiscoverRequest
(
DHCPDISCOVER
,
IOAddress
(
"0.0.0.0"
),
IOAddress
(
"192.0.2.67"
));
}
delete
srv
;
// Verified that the non-relayed DISCOVER is processed correctly when
// client source address is not specified.
TEST_F
(
Dhcpv4SrvTest
,
processDiscoverNoClientAddr
)
{
testDiscoverRequest
(
DHCPDISCOVER
,
IOAddress
(
"0.0.0.0"
),
IOAddress
(
"0.0.0.0"
));
}
// Verifies that received
REQUEST
can be processed correctly,
// that the
ACK
message generated in response is valid and
// Verifies that
REQUEST
received
via relay
can be processed correctly,
// that the
OFFER
message generated in response is valid and
// contains necessary options.
//
// Note: this test focuses on the packet correctness. There
// are other tests that verify correctness of the allocation
// engine. See RequestBasic.
TEST_F
(
Dhcpv4SrvTest
,
processRequest
)
{
NakedDhcpv4Srv
*
srv
=
new
NakedDhcpv4Srv
(
0
);
vector
<
uint8_t
>
mac
(
6
);
for
(
int
i
=
0
;
i
<
6
;
i
++
)
{
mac
[
i
]
=
i
*
10
;
}
boost
::
shared_ptr
<
Pkt4
>
req
(
new
Pkt4
(
DHCPREQUEST
,
1234
));
boost
::
shared_ptr
<
Pkt4
>
ack
;
req
->
setIface
(
"eth0"
);
req
->
setIndex
(
17
);
req
->
setHWAddr
(
1
,
6
,
mac
);
req
->
setRemoteAddr
(
IOAddress
(
"192.0.2.56"
));
req
->
setGiaddr
(
IOAddress
(
"192.0.2.67"
));
// We are going to test that certain options are returned
// in the ACK message when requested using 'Parameter
// Request List' option. Let's configure those options that
// are returned when requested.
configureRequestedOptions
();
// Should not throw
ASSERT_NO_THROW
(
ack
=
srv
->
processRequest
(
req
);
);
// Should return something
ASSERT_TRUE
(
ack
);
EXPECT_EQ
(
DHCPACK
,
ack
->
getType
());
// This is relayed message. It should be sent back to relay address.
EXPECT_EQ
(
req
->
getGiaddr
(),
ack
->
getRemoteAddr
());
messageCheck
(
req
,
ack
);
// There are some options that are always present in the
// message, even if not requested.
EXPECT_TRUE
(
ack
->
getOption
(
DHO_DOMAIN_NAME
));
EXPECT_TRUE
(
ack
->
getOption
(
DHO_DOMAIN_NAME_SERVERS
));
// We did not request any options so these should not be present
// in the ACK.
EXPECT_FALSE
(
ack
->
getOption
(
DHO_LOG_SERVERS
));
EXPECT_FALSE
(
ack
->
getOption
(
DHO_COOKIE_SERVERS
));
EXPECT_FALSE
(
ack
->
getOption
(
DHO_LPR_SERVERS
));
// Add 'Parameter Request List' option.
addPrlOption
(
req
);
// Repeat the test but request some options.
ASSERT_NO_THROW
(
ack
=
srv
->
processRequest
(
req
);
);
// Should return something
ASSERT_TRUE
(
ack
);
EXPECT_EQ
(
DHCPACK
,
ack
->
getType
());
// This is relayed message. It should be sent back to relay address.
EXPECT_EQ
(
req
->
getGiaddr
(),
ack
->
getRemoteAddr
());
// Check that the requested options are returned.
optionsCheck
(
ack
);
// Now repeat the test for directly sent message
req
->
setHops
(
0
);
req
->
setGiaddr
(
IOAddress
(
"0.0.0.0"
));
req
->
setRemotePort
(
DHCP4_CLIENT_PORT
);
EXPECT_NO_THROW
(
ack
=
srv
->
processDiscover
(
req
);
);
// Should return something
ASSERT_TRUE
(
ack
);
EXPECT_EQ
(
DHCPOFFER
,
ack
->
getType
());
// This is direct message. It should be sent back to origin, not
// to relay.
EXPECT_EQ
(
ack
->
getRemoteAddr
(),
req
->
getRemoteAddr
());
messageCheck
(
req
,
ack
);
// engine. See DiscoverBasic, DiscoverHint, DiscoverNoClientId
// and DiscoverInvalidHint.
TEST_F
(
Dhcpv4SrvTest
,
processRequestRelay
)
{
testDiscoverRequest
(
DHCPREQUEST
,
IOAddress
(
"192.0.2.56"
),
IOAddress
(
"192.0.2.67"
));
}
// Check that the requested options are returned.
optionsCheck
(
ack
);
// Verifies that the non-relayed REQUEST is processed correctly when
// client source address is specified.
TEST_F
(
Dhcpv4SrvTest
,
processRequestNoRelay
)
{
testDiscoverRequest
(
DHCPREQUEST
,
IOAddress
(
"0.0.0.0"
),
IOAddress
(
"192.0.2.67"
));
}
delete
srv
;
// Verified that the non-relayed REQUEST is processed correctly when
// client source address is not specified.
TEST_F
(
Dhcpv4SrvTest
,
processRequestNoClientAddr
)
{
testDiscoverRequest
(
DHCPREQUEST
,
IOAddress
(
"0.0.0.0"
),
IOAddress
(
"0.0.0.0"
));
}
TEST_F
(
Dhcpv4SrvTest
,
processRelease
)
{
...
...
src/lib/dhcp/iface_mgr.cc
View file @
84076d91
// Copyright (C) 2011-201
2
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-201
3
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -721,56 +721,6 @@ IfaceMgr::send(const Pkt6Ptr& pkt) {
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."
);
}
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
);
}
boost
::
shared_ptr
<
Pkt4
>
IfaceMgr
::
receive4
(
uint32_t
timeout_sec
,
uint32_t
timeout_usec
/* = 0 */
)
{
...
...
src/lib/dhcp/iface_mgr.h
View file @
84076d91
...
...
@@ -306,6 +306,16 @@ public:
/// @return the only existing instance of interface manager
static
IfaceMgr
&
instance
();
/// @brief Can be packet can be send directly to the client without address.
///
/// Checks if IfaceMgr can send DHCPv4 packet to the client
/// who hasn't got address assigned. If this is not supported
/// broadcast address should be used to send response to
/// the client.
///
/// @return true if direct response is supported.
bool
isDirectResponseSupported
();
/// @brief Returns interface with specified interface index
///
/// @param ifindex index of searched interface
...
...
src/lib/dhcp/iface_mgr_bsd.cc
View file @
84076d91
// Copyright (C) 2011
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011
, 2013
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -34,6 +34,60 @@ IfaceMgr::detectIfaces() {
stubDetectIfaces
();
}
bool
IfaceMgr
::
isDirectResponseSupported
()
{
return
(
false
);
}
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
&
/*m*/
,
boost
::
scoped_array
<
char
>&
/*control_buf*/
,
size_t
/*control_buf_len*/
,
...
...
src/lib/dhcp/iface_mgr_linux.cc
View file @
84076d91
// Copyright (C) 2011-201
2
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-201
3
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -494,6 +494,11 @@ void IfaceMgr::detectIfaces() {
nl
.
release_list
(
addr_info
);
}
bool
IfaceMgr
::
isDirectResponseSupported
()
{
return
(
false
);
}
/// @brief sets flag_*_ fields.
///
/// This implementation is OS-specific as bits have different meaning
...
...
@@ -510,6 +515,55 @@ void IfaceMgr::Iface::setFlags(uint32_t flags) {
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
&
m
,
boost
::
scoped_array
<
char
>&
control_buf
,
size_t
control_buf_len
,
const
Pkt4Ptr
&
pkt
)
{