Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Sebastian Schrader
Kea
Commits
682436e8
Commit
682436e8
authored
Feb 28, 2011
by
Stephen Morris
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[trac499] Completed TCPSocket and unit tests
parent
b13c2fd0
Changes
10
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
546 additions
and
265 deletions
+546
-265
src/lib/asiolink/Makefile.am
src/lib/asiolink/Makefile.am
+1
-0
src/lib/asiolink/asiolink_utilities.h
src/lib/asiolink/asiolink_utilities.h
+61
-0
src/lib/asiolink/io_asio_socket.h
src/lib/asiolink/io_asio_socket.h
+37
-44
src/lib/asiolink/io_fetch.cc
src/lib/asiolink/io_fetch.cc
+2
-1
src/lib/asiolink/tcp_socket.h
src/lib/asiolink/tcp_socket.h
+71
-40
src/lib/asiolink/tests/Makefile.am
src/lib/asiolink/tests/Makefile.am
+1
-0
src/lib/asiolink/tests/asiolink_utilities_unittest.cc
src/lib/asiolink/tests/asiolink_utilities_unittest.cc
+74
-0
src/lib/asiolink/tests/tcp_socket_unittest.cc
src/lib/asiolink/tests/tcp_socket_unittest.cc
+267
-145
src/lib/asiolink/tests/udp_socket_unittest.cc
src/lib/asiolink/tests/udp_socket_unittest.cc
+2
-2
src/lib/asiolink/udp_socket.h
src/lib/asiolink/udp_socket.h
+30
-33
No files found.
src/lib/asiolink/Makefile.am
View file @
682436e8
...
...
@@ -13,6 +13,7 @@ CLEANFILES = *.gcno *.gcda
# which would make the build fail with -Werror (our default setting).
lib_LTLIBRARIES
=
libasiolink.la
libasiolink_la_SOURCES
=
asiolink.h
libasiolink_la_SOURCES
+=
asiolink_utilities.h
libasiolink_la_SOURCES
+=
asiodef.cc asiodef.h
libasiolink_la_SOURCES
+=
dns_answer.h
libasiolink_la_SOURCES
+=
dns_lookup.h
...
...
src/lib/asiolink/asiolink_utilities.h
0 → 100644
View file @
682436e8
// Copyright (C) 2011 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef __ASIOLINK_UTILITIES_H
#define __ASIOLINK_UTILITIES_H
#include <cstddef>
namespace
asiolink
{
/// \brief Read Unsigned 16-Bit Integer from Buffer
///
/// This is essentially a copy of the isc::dns::InputBuffer::readUint16. It
/// should really be moved into a separate library.
///
/// \param buffer Data buffer at least two bytes long of which the first two
/// bytes are assumed to represent a 16-bit integer in network-byte
/// order.
///
/// \return Value of 16-bit integer
inline
uint16_t
readUint16
(
const
void
*
buffer
)
{
const
uint8_t
*
byte_buffer
=
static_cast
<
const
uint8_t
*>
(
buffer
);
uint16_t
result
=
(
static_cast
<
uint16_t
>
(
byte_buffer
[
0
]))
<<
8
;
result
|=
static_cast
<
uint16_t
>
(
byte_buffer
[
1
]);
return
(
result
);
}
/// \brief Write Unisgned 16-Bit Integer to Buffer
///
/// This is essentially a copy of isc::dns::OutputBuffer::writeUint16. It
/// should really be moved into a separate library.
///
/// \param value 16-bit value to convert
/// \param buffer Data buffer at least two bytes long into which the 16-bit
/// value is written in network-byte order.
inline
void
writeUint16
(
uint16_t
value
,
void
*
buffer
)
{
uint8_t
*
byte_buffer
=
static_cast
<
uint8_t
*>
(
buffer
);
byte_buffer
[
0
]
=
static_cast
<
uint8_t
>
((
value
&
0xff00U
)
>>
8
);
byte_buffer
[
1
]
=
static_cast
<
uint8_t
>
(
value
&
0x00ffU
);
}
}
// namespace asiolink
#endif // __ASIOLINK_UTILITIES_H
src/lib/asiolink/io_asio_socket.h
View file @
682436e8
...
...
@@ -41,7 +41,7 @@ public:
IOError
(
file
,
line
,
what
)
{}
};
/// \brief
Socket not open
/// \brief
Error setting socket options
///
/// Thrown if attempt to change socket options fails.
class
SocketSetError
:
public
IOError
{
...
...
@@ -50,7 +50,7 @@ public:
IOError
(
file
,
line
,
what
)
{}
};
/// \brief Buffer
O
verflow
/// \brief Buffer
o
verflow
///
/// Thrown if an attempt is made to receive into an area beyond the end of
/// the receive data buffer.
...
...
@@ -108,19 +108,18 @@ public:
/// \brief Return the "native" representation of the socket.
///
/// In practice, this is the file descriptor of the socket for
/// UNIX-like systems so the current implementation simply uses
/// \c int as the type of the return value.
/// We may have to need revisit this decision later.
/// In practice, this is the file descriptor of the socket for UNIX-like
/// systems so the current implementation simply uses \c int as the type of
/// the return value. We may have to need revisit this decision later.
///
/// In general, the application should avoid using this method;
///
it
essentially discloses an implementation specific "handle" that
///
can
change the internal state of the socket (consider
the
/// application closes it, for example).
///
But we sometimes need to
perform very low-level operations that
///
requires the native
representation. Passing the file descriptor
///
to a different process is one example.
///
This method is provided as a necessary evil for such
limited purposes.
/// In general, the application should avoid using this method;
it
/// essentially discloses an implementation specific "handle" that
can
/// change the internal state of the socket (consider
what would happen if
///
the
application closes it, for example).
But we sometimes need to
/// perform very low-level operations that
requires the native
/// representation. Passing the file descriptor
to a different process is
///
one example. This method is provided as a necessary evil for such
///
/
limited purposes.
///
/// This method never throws an exception.
///
...
...
@@ -135,16 +134,15 @@ public:
///
/// This method never throws an exception.
///
/// \return IPPROTO_UDP for UDP sockets
/// \return IPPROTO_TCP for TCP sockets
/// \return \c IPPROTO_UDP for UDP sockets, \c IPPROTO_TCP for TCP sockets
virtual
int
getProtocol
()
const
=
0
;
/// \brief Is Open() synchronous?
///
/// On a
UD
P socket, an "open" operation is
merely
a call to "open()"
on
///
the underlying socket (so completes immediately), but on a TCP socket it
/// a
lso includings connecting to the remote end (which is done as an
/// a
synchronous operation)
.
/// On a
TC
P socket, an "open" operation is a call to
the socket's
"open()"
///
method followed by a connection to the remote system: it is an
/// a
synchronous operation. On a UDP socket, it is just a call to "open()"
/// a
nd completes synchronously
.
///
/// For TCP, signalling of the completion of the operation is done by
/// by calling the callback function in the normal way. This could be done
...
...
@@ -154,31 +152,31 @@ public:
/// asynchronously.
///
/// Owing to the way that the stackless coroutines are implemented, we need
/// to know _before_ executing the ope
ra
tion whether or not t
he open
is
/// asynchronous. So this method
simply
provide
s
that information.
/// to know _before_ executing the
"
ope
n" func
tion whether or not
i
t is
/// asynchronous. So this method
is called to
provide that information.
///
/// (The reason there is a need to know is because the call to open() passes
/// in the state of the coroutine at the time the call is made. On an
/// asynchronous I/O, we need to set the state to point to the statement
/// after the call to open() before we pass the coro
t
uine to the open()
/// call. Unfortunately, the macros that
do this also yield control - which
/// we don't want to do if the open is
synchronous. Hence we need to know
/// before we make the call to open()
whether that call will complete
/// asynchronously.)
/// after the call to open()
_
before
_
we pass the corouine to the open()
/// call. Unfortunately, the macros that
set the state of the coroutine
///
also yield control - which
we don't want to do if the open is
///
synchronous. Hence we need to know
before we make the call to open()
///
whether that call will complete
asynchronously.)
virtual
bool
isOpenSynchronous
()
const
=
0
;
/// \brief Open AsioSocket
///
/// Opens the socket for asynchronous I/O. The open will complete
/// synchronously on UCP or asynchronously on TCP (in which case a callback
/// will be queued): what will happen can be found by calling the method
/// isOpenSynchronous().
/// will be queued).
///
/// \param endpoint Pointer to the endpoint object. This is ignored for
/// a UDP socket (the target is specified in the send call), but
should
/// be of type TCPEndpoint for a TCP connection.
///
a UDP socket (the target is specified in the send call), but
///
should
be of type TCPEndpoint for a TCP connection.
/// \param callback I/O Completion callback, called when the operation has
/// completed, but only if the operation was asynchronous.
/// completed, but only if the operation was asynchronous. (It is
/// ignored on a UDP socket.)
virtual
void
open
(
const
IOEndpoint
*
endpoint
,
C
&
callback
)
=
0
;
/// \brief Send Asynchronously
...
...
@@ -196,7 +194,7 @@ public:
/// \brief Receive Asynchronously
///
/// This corres
t
ponds to async_receive_from() for UDP sockets and
/// This corresponds to async_receive_from() for UDP sockets and
/// async_receive() for TCP. In both cases, an endpoint argument is
/// supplied to receive the source of the communication. For TCP it will
/// be filled in with details of the connection.
...
...
@@ -214,22 +212,17 @@ public:
/// This applies to TCP receives, where the data is a byte stream and a
/// receive is not guaranteed to receive the entire message. DNS messages
/// over TCP are prefixed by a two-byte count field. This method takes the
/// amount received so far and the amount received in this I/O and checks
/// if the message is complete, returning the appropriate indication. As
/// a side-effect, it also updates the amount received.
/// amount received so far and checks if the message is complete.
///
/// For a UDP receive, all the data is received in one I/O, so this is
/// effectively a no-op
(although it does update the amount received
).
/// effectively a no-op).
///
/// \param data Data buffer containing data to date
/// \param length Amount of data received in last asynchronous I/O
/// \param cumulative On input, amount of data received before the last
/// I/O. On output, the total amount of data received to date.
/// \param length Total amount of data in the buffer.
///
/// \return true if the receive is complete, false if another receive is
/// needed.
virtual
bool
receiveComplete
(
void
*
data
,
size_t
length
,
size_t
&
cumulative
)
=
0
;
virtual
bool
receiveComplete
(
const
void
*
data
,
size_t
length
)
=
0
;
/// \brief Cancel I/O On AsioSocket
virtual
void
cancel
()
=
0
;
...
...
src/lib/asiolink/io_fetch.cc
View file @
682436e8
...
...
@@ -222,8 +222,9 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
CORO_YIELD
data_
->
socket
->
asyncReceive
(
data_
->
data
.
get
(),
static_cast
<
size_t
>
(
MIN_LENGTH
),
data_
->
cumulative
,
data_
->
remote
.
get
(),
*
this
);
data_
->
cumulative
+=
length
;
std
::
cerr
<<
"IOFetch: resuming after asynchronous receive
\n
"
;
}
while
(
!
data_
->
socket
->
receiveComplete
(
data_
->
data
.
get
(),
length
,
}
while
(
!
data_
->
socket
->
receiveComplete
(
data_
->
data
.
get
(),
data_
->
cumulative
));
// The message is not rendered yet, so we can't print it easily
...
...
src/lib/asiolink/tcp_socket.h
View file @
682436e8
...
...
@@ -24,7 +24,6 @@
#include <sys/socket.h>
#include <unistd.h> // for some IPC/network system calls
#include <iostream>
#include <cstddef>
#include <boost/bind.hpp>
...
...
@@ -34,6 +33,7 @@
#include <dns/buffer.h>
#include <asiolink/asiolink_utilities.h>
#include <asiolink/io_asio_socket.h>
#include <asiolink/io_endpoint.h>
#include <asiolink/io_service.h>
...
...
@@ -65,15 +65,15 @@ public:
/// \brief Constructor from an ASIO TCP socket.
///
/// \param socket The ASIO representation of the TCP socket. It
///
is assumed
that the caller will open and close the socket, so
///
these
operations are a no-op for that socket.
/// \param socket The ASIO representation of the TCP socket. It
is assumed
///
that the caller will open and close the socket, so
these
///
operations are a no-op for that socket.
TCPSocket
(
asio
::
ip
::
tcp
::
socket
&
socket
);
/// \brief Constructor
///
/// Used when the TCPSocket is being asked to manage its own internal
/// socket. I
t
is as
sumed
th
at
open() and close()
will not b
e used.
/// socket. I
n th
is
c
as
e,
th
e
open() and close()
methods ar
e used.
///
/// \param service I/O Service object used to manage the socket.
TCPSocket
(
IOService
&
service
);
...
...
@@ -100,10 +100,10 @@ public:
/// \brief Open Socket
///
/// Opens the
UD
P socket. This is an asynchronous operation, completion of
/// Opens the
TC
P socket. This is an asynchronous operation, completion of
/// which will be signalled via a call to the callback function.
///
/// \param endpoint Endpoint to which the socket will connect
to
.
/// \param endpoint Endpoint to which the socket will connect.
/// \param callback Callback object.
virtual
void
open
(
const
IOEndpoint
*
endpoint
,
C
&
callback
);
...
...
@@ -115,7 +115,8 @@ public:
///
/// \param data Data to send
/// \param length Length of data to send
/// \param endpoint Target of the send
/// \param endpoint Target of the send. (Unused for a TCP socket because
/// that was determined when the connection was opened.)
/// \param callback Callback object.
virtual
void
asyncSend
(
const
void
*
data
,
size_t
length
,
const
IOEndpoint
*
endpoint
,
C
&
callback
);
...
...
@@ -136,21 +137,15 @@ public:
/// \brief Checks if the data received is complete.
///
/// As all the data is received in one I/O, so this is, this is effectively
/// a no-op (although it does update the amount of data received).
/// Checks if all the data has been received by checking that the amount
/// of data received is equal to the number in the first two bytes of the
/// message plus two (for the count field itself).
///
/// \param data Data buffer containing data to date. (This is ignored
/// for TCP receives.)
/// \param length Amount of data received in last asynchronous I/O
/// \param cumulative On input, amount of data received before the last
/// I/O. On output, the total amount of data received to date.
/// \param data Data buffer containing data to date (ignored)
/// \param length Amount of data in the buffer.
///
/// \return true if the receive is complete, false if another receive is
/// needed.
virtual
bool
receiveComplete
(
void
*
,
size_t
length
,
size_t
&
cumulative
)
{
cumulative
=
length
;
return
(
true
);
}
/// \return true if the receive is complete, false if not.
virtual
bool
receiveComplete
(
const
void
*
data
,
size_t
length
);
/// \brief Cancel I/O On Socket
virtual
void
cancel
();
...
...
@@ -176,6 +171,10 @@ private:
// achieved by altering isc::dns::buffer to have pairs of methods:
// getLength()/getTCPLength(), getData()/getTCPData(), with the getTCPXxx()
// methods taking into account a two-byte count field.)
//
// The option of sending the data in two operations, the count followed by
// the data was discounted as that would lead to two callbacks which would
// cause problems with the stackless coroutine code.
isc
::
dns
::
OutputBufferPtr
send_buffer_
;
///< Send buffer
};
...
...
@@ -212,8 +211,6 @@ TCPSocket<C>::open(const IOEndpoint* endpoint, C& callback) {
// Ignore opens on already-open socket. Don't throw a failure because
// of uncertainties as to what precedes whan when using asynchronous I/O.
// At also allows us a treat a passed-in socket as a self-managed socket.
std
::
cerr
<<
"TCPSocket::open(): open_ flags is "
<<
isopen_
<<
"
\n
"
;
if
(
!
isopen_
)
{
if
(
endpoint
->
getFamily
()
==
AF_INET
)
{
socket_
.
open
(
asio
::
ip
::
tcp
::
v4
());
...
...
@@ -266,8 +263,6 @@ TCPSocket<C>::asyncSend(const void* data, size_t length, const IOEndpoint*,
send_buffer_
->
writeData
(
data
,
length
);
// ... and send it
std
::
cerr
<<
"TCPSocket::asyncSend(): sending "
<<
count
<<
" data bytes
\n
"
;
socket_
.
async_send
(
asio
::
buffer
(
send_buffer_
->
getData
(),
send_buffer_
->
getLength
()),
callback
);
}
catch
(
boost
::
numeric
::
bad_numeric_cast
&
e
)
{
...
...
@@ -281,26 +276,40 @@ TCPSocket<C>::asyncSend(const void* data, size_t length, const IOEndpoint*,
}
}
// Receive a message. Note that the "cumulative" argument is ignored - every TCP
// receive is put into the buffer beginning at the start - there is no concept
// receiving a subsequent part of a message. Same critera as before concerning
// the need for the socket to be open.
// Receive a message. Note that the "offset" argument is used as an index
// into the buffer in order to decide where to put the data. It is up to the
// caller to initialize the data to zero
template
<
typename
C
>
void
TCPSocket
<
C
>::
asyncReceive
(
void
*
data
,
size_t
length
,
size_t
,
TCPSocket
<
C
>::
asyncReceive
(
void
*
data
,
size_t
length
,
size_t
offset
,
IOEndpoint
*
endpoint
,
C
&
callback
)
{
if
(
isopen_
)
{
// Upconvert the endpoint again.
// Upconvert to a TCPEndpoint. We need to do this because although
// IOEndpoint is the base class of UDPEndpoint and TCPEndpoint, it
// does not contain a method for getting at the underlying endpoint
// type - that is in the derived class and the two classes differ on
// return type.
assert
(
endpoint
->
getProtocol
()
==
IPPROTO_TCP
);
const
TCPEndpoint
*
tcp_endpoint
=
static_cast
<
const
TCPEndpoint
*>
(
endpoint
);
std
::
cerr
<<
"TCPSocket::asyncReceive(): receiving from "
<<
tcp_endpoint
->
getAddress
().
toText
()
<<
", port "
<<
tcp_endpoint
->
getPort
()
<<
"
\n
"
;
TCPEndpoint
*
tcp_endpoint
=
static_cast
<
TCPEndpoint
*>
(
endpoint
);
// Write the endpoint details from the comminications link. Ideally
// we should make IOEndpoint assignable, but this runs in to all sorts
// of problems concerning the management of the underlying Boost
// endpoint (e.g. if it is not self-managed, is the copied one
// self-managed?) The most pragmatic solution is to let Boost take care
// of everything and copy details of the underlying endpoint.
tcp_endpoint
->
getASIOEndpoint
()
=
socket_
.
remote_endpoint
();
// Ensure we can write into the buffer and if so, set the pointer to
// where the data will be written.
if
(
offset
>=
length
)
{
isc_throw
(
BufferOverflow
,
"attempt to read into area beyond end of "
"TCP receive buffer"
);
}
void
*
buffer_start
=
static_cast
<
void
*>
(
static_cast
<
uint8_t
*>
(
data
)
+
offset
);
// TODO: Complete TCPSocket::asyncReceive()
// ... and kick off the read.
socket_
.
async_receive
(
asio
::
buffer
(
buffer_start
,
length
-
offset
),
callback
);
}
else
{
isc_throw
(
SocketNotOpen
,
...
...
@@ -308,7 +317,29 @@ TCPSocket<C>::asyncReceive(void* data, size_t length, size_t,
}
}
// Is the receive complete?
template
<
typename
C
>
bool
TCPSocket
<
C
>::
receiveComplete
(
const
void
*
data
,
size_t
length
)
{
bool
complete
=
false
;
// If we have read at least two bytes, we can work out how much we should be
// reading.
if
(
length
>=
2
)
{
// Convert first two bytes to a count and check that the following data
// is that length.
// TODO: Should we check to see if we have received too much data?
uint16_t
expected
=
readUint16
(
data
);
complete
=
((
expected
+
2
)
==
length
);
}
return
(
complete
);
}
// Cancel I/O on the socket. No-op if the socket is not open.
template
<
typename
C
>
void
TCPSocket
<
C
>::
cancel
()
{
if
(
isopen_
)
{
...
...
src/lib/asiolink/tests/Makefile.am
View file @
682436e8
...
...
@@ -18,6 +18,7 @@ TESTS += run_unittests
run_unittests_SOURCES
=
run_unittests.cc
run_unittests_SOURCES
+=
$(top_srcdir)
/src/lib/dns/tests/unittest_util.h
run_unittests_SOURCES
+=
$(top_srcdir)
/src/lib/dns/tests/unittest_util.cc
run_unittests_SOURCES
+=
asiolink_utilities_unittest.cc
run_unittests_SOURCES
+=
io_address_unittest.cc
run_unittests_SOURCES
+=
io_endpoint_unittest.cc
run_unittests_SOURCES
+=
io_fetch_unittest.cc
...
...
src/lib/asiolink/tests/asiolink_utilities_unittest.cc
0 → 100644
View file @
682436e8
// Copyright (C) 2011 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
/// \brief Test of asiolink utilties
///
/// Tests the fuctionality of the asiolink utilities code by comparing them
/// with the equivalent methods in isc::dns::[Input/Output]Buffer.
#include <cstddef>
#include <gtest/gtest.h>
#include <dns/buffer.h>
#include <asiolink/asiolink_utilities.h>
using
namespace
asiolink
;
using
namespace
isc
::
dns
;
TEST
(
asioutil
,
readUint16
)
{
// Reference buffer
uint8_t
data
[
2
];
isc
::
dns
::
InputBuffer
buffer
(
data
,
sizeof
(
data
));
// Avoid possible compiler warnings by only setting uint8_t variables to
// uint8_t values.
uint8_t
i8
=
0
;
uint8_t
j8
=
0
;
for
(
int
i
=
0
;
i
<
(
2
<<
8
);
++
i
,
++
i8
)
{
for
(
int
j
=
0
;
j
<
(
2
<<
8
);
++
j
,
++
j8
)
{
data
[
0
]
=
i8
;
data
[
1
]
=
j8
;
buffer
.
setPosition
(
0
);
EXPECT_EQ
(
buffer
.
readUint16
(),
readUint16
(
data
));
}
}
}
TEST
(
asioutil
,
writeUint16
)
{
// Reference buffer
isc
::
dns
::
OutputBuffer
buffer
(
2
);
uint8_t
test
[
2
];
// Avoid possible compiler warnings by only setting uint16_t variables to
// uint16_t values.
uint16_t
i16
=
0
;
for
(
uint32_t
i
=
0
;
i
<
(
2
<<
16
);
++
i
,
++
i16
)
{
// Write the reference data
buffer
.
clear
();
buffer
.
writeUint16
(
i16
);
// ... and the test data
writeUint16
(
i16
,
test
);
// ... and compare
const
uint8_t
*
ref
=
static_cast
<
const
uint8_t
*>
(
buffer
.
getData
());
EXPECT_EQ
(
ref
[
0
],
test
[
0
]);
EXPECT_EQ
(
ref
[
1
],
test
[
1
]);
}
}
src/lib/asiolink/tests/tcp_socket_unittest.cc
View file @
682436e8
This diff is collapsed.
Click to expand it.
src/lib/asiolink/tests/udp_socket_unittest.cc
View file @
682436e8
...
...
@@ -263,8 +263,8 @@ TEST(UDPSocket, SequenceTest) {
EXPECT_EQ
(
SERVER_PORT
,
client_remote_endpoint
.
getPort
());
// Finally, check that the receive received a complete buffer's worth of data.
EXPECT_TRUE
(
client
.
receiveComplete
(
&
data
[
0
],
client_cb
.
getLength
()
,
client_cumulative
));
client_cumulative
+=
client_cb
.
getLength
()
;
EXPECT_TRUE
(
client
.
receiveComplete
(
&
data
[
0
],
client_cumulative
));
EXPECT_EQ
(
client_cb
.
getLength
(),
client_cumulative
);
// Close client and server.
...
...
src/lib/asiolink/udp_socket.h
View file @
682436e8
...
...
@@ -53,15 +53,15 @@ public:
/// \brief Constructor from an ASIO UDP socket.
///
/// \param socket The ASIO representation of the UDP socket. It
///
is assumed
that the caller will open and close the socket, so
///
these
operations are a no-op for that socket.
/// \param socket The ASIO representation of the UDP socket. It
is assumed
///
that the caller will open and close the socket, so
these
///
operations are a no-op for that socket.
UDPSocket
(
asio
::
ip
::
udp
::
socket
&
socket
);
/// \brief Constructor
///
/// Used when the UDPSocket is being asked to manage its own internal
/// socket. I
t
is as
sumed
th
at
open() and close()
will not b
e used.
/// socket. I
n th
is
c
as
e,
th
e
open() and close()
methods ar
e used.
///
/// \param service I/O Service object used to manage the socket.
UDPSocket
(
IOService
&
service
);
...
...
@@ -90,9 +90,11 @@ public:
///
/// Opens the UDP socket. This is a synchronous operation.
///
/// \param endpoint Endpoint to which the socket will connect to.
/// \param callback Unused.
virtual
void
open
(
const
IOEndpoint
*
endpoint
,
C
&
);
/// \param endpoint Endpoint to which the socket will send data. This is
/// used to determine the address family trhat should be used for the
/// underlying socket.
/// \param callback Unused as the operation is synchronous.
virtual
void
open
(
const
IOEndpoint
*
endpoint
,
C
&
callback
);
/// \brief Send Asynchronously
///
...
...
@@ -110,8 +112,8 @@ public:
/// \brief Receive Asynchronously
///
/// Calls the underlying socket's async_receive_from() method to read a
/// packet of data from a remote endpoint. Arrival of the data is
///
signalled
via a call to the callback function.
/// packet of data from a remote endpoint. Arrival of the data is
signalled
/// via a call to the callback function.
///
/// \param data Buffer to receive incoming message
/// \param length Length of the data buffer
...
...
@@ -123,19 +125,15 @@ public:
/// \brief Checks if the data received is complete.
///
/// As all the data is received in one I/O, so this is, this is effectively
/// a no-op (although it does update the amount of data received).
/// For a UDP socket all the data is received in one I/O, so this is
/// effectively a no-op (although it does update the amount of data
/// received).
///
/// \param data Data buffer containing data to date. (This is ignored
/// for UDP receives.)
/// \param length Amount of data received in last asynchronous I/O
/// \param cumulative On input, amount of data received before the last
/// I/O. On output, the total amount of data received to date.
/// \param data Data buffer containing data to date (ignored)
/// \param length Amount of data in the buffer.
///
/// \return true if the receive is complete, false if another receive is
/// needed. Always true for a UDP socket.
virtual
bool
receiveComplete
(
void
*
,
size_t
length
,
size_t
&
cumulative
)
{
cumulative
=
length
;
/// \return Always true
virtual
bool
receiveComplete
(
const
void
*
,
size_t
)
{
return
(
true
);
}
...
...
@@ -185,10 +183,11 @@ UDPSocket<C>::~UDPSocket()
template
<
typename
C
>
void
UDPSocket
<
C
>::
open
(
const
IOEndpoint
*
endpoint
,
C
&
)
{
// Ignore opens on already-open socket. Don't throw a failure because
// of uncertainties as to what precedes whan when using asynchronous I/O.
// At also allows us a treat a passed-in socket as a self-managed socket.
// Ignore opens on already-open socket. (Don't throw a failure because
// of uncertainties as to what precedes whan when using asynchronous I/O.)
// It also allows us a treat a passed-in socket in exactly the same way as
// a self-managed socket (in that we can call the open() and close() methods
// of this class).
if
(
!
isopen_
)
{
if
(
endpoint
->
getFamily
()
==
AF_INET
)
{
socket_
.
open
(
asio
::
ip
::
udp
::
v4
());
...
...
@@ -198,8 +197,7 @@ UDPSocket<C>::open(const IOEndpoint* endpoint, C&) {
}
isopen_
=
true
;
// Ensure it can send and receive 4K buffers.
// Ensure it can send and receive at least 4K buffers.
asio
::
ip
::
udp
::
socket
::
send_buffer_size
snd_size
;
socket_
.
get_option
(
snd_size
);
if
(
snd_size
.
value
()
<
MIN_SIZE
)
{
...
...
@@ -227,13 +225,14 @@ UDPSocket<C>::asyncSend(const void* data, size_t length,