Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
actor-incubator
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
actor-incubator
Commits
cdea6c3b
Unverified
Commit
cdea6c3b
authored
Nov 11, 2019
by
Dominik Charousset
Committed by
GitHub
Nov 11, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #34
Add `datagram-transport`
parents
71254c55
17def710
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
784 additions
and
86 deletions
+784
-86
libcaf_net/caf/detail/socket_sys_includes.hpp
libcaf_net/caf/detail/socket_sys_includes.hpp
+1
-0
libcaf_net/caf/net/datagram_transport.hpp
libcaf_net/caf/net/datagram_transport.hpp
+293
-0
libcaf_net/caf/net/endpoint_manager_impl.hpp
libcaf_net/caf/net/endpoint_manager_impl.hpp
+0
-4
libcaf_net/caf/net/fwd.hpp
libcaf_net/caf/net/fwd.hpp
+1
-1
libcaf_net/caf/net/stream_transport.hpp
libcaf_net/caf/net/stream_transport.hpp
+2
-4
libcaf_net/caf/net/transport_worker_dispatcher.hpp
libcaf_net/caf/net/transport_worker_dispatcher.hpp
+71
-41
libcaf_net/caf/net/udp_datagram_socket.hpp
libcaf_net/caf/net/udp_datagram_socket.hpp
+13
-0
libcaf_net/src/udp_datagram_socket.cpp
libcaf_net/src/udp_datagram_socket.cpp
+59
-5
libcaf_net/test/datagram_transport.cpp
libcaf_net/test/datagram_transport.cpp
+262
-0
libcaf_net/test/stream_application.cpp
libcaf_net/test/stream_application.cpp
+1
-1
libcaf_net/test/transport_worker_dispatcher.cpp
libcaf_net/test/transport_worker_dispatcher.cpp
+17
-14
libcaf_net/test/udp_datagram_socket.cpp
libcaf_net/test/udp_datagram_socket.cpp
+64
-16
No files found.
libcaf_net/caf/detail/socket_sys_includes.hpp
View file @
cdea6c3b
...
...
@@ -52,5 +52,6 @@
# include <netinet/tcp.h>
# include <sys/socket.h>
# include <unistd.h>
# include <sys/uio.h>
#endif
// clang-format on
libcaf_net/caf/net/datagram_transport.hpp
0 → 100644
View file @
cdea6c3b
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <deque>
#include <unordered_map>
#include "caf/byte.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp"
#include "caf/ip_endpoint.hpp"
#include "caf/logger.hpp"
#include "caf/net/defaults.hpp"
#include "caf/net/endpoint_manager.hpp"
#include "caf/net/fwd.hpp"
#include "caf/net/receive_policy.hpp"
#include "caf/net/transport_worker_dispatcher.hpp"
#include "caf/net/udp_datagram_socket.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
#include "caf/variant.hpp"
namespace
caf
{
namespace
net
{
/// Implements a udp_transport policy that manages a datagram socket.
template
<
class
Factory
>
class
datagram_transport
{
public:
// Maximal UDP-packet size
static
constexpr
size_t
max_datagram_size
=
std
::
numeric_limits
<
uint16_t
>::
max
();
// -- member types -----------------------------------------------------------
using
id_type
=
ip_endpoint
;
using
buffer_type
=
std
::
vector
<
byte
>
;
using
buffer_cache_type
=
std
::
vector
<
buffer_type
>
;
using
factory_type
=
Factory
;
using
transport_type
=
datagram_transport
<
Factory
>
;
using
dispatcher_type
=
transport_worker_dispatcher
<
transport_type
,
id_type
>
;
using
application_type
=
typename
Factory
::
application_type
;
// -- constructors, destructors, and assignment operators --------------------
datagram_transport
(
udp_datagram_socket
handle
,
factory_type
factory
)
:
dispatcher_
(
*
this
,
std
::
move
(
factory
)),
handle_
(
handle
),
read_buf_
(
max_datagram_size
),
manager_
(
nullptr
)
{
// nop
}
// -- properties -------------------------------------------------------------
udp_datagram_socket
handle
()
const
noexcept
{
return
handle_
;
}
actor_system
&
system
()
{
return
manager
().
system
();
}
transport_type
&
transport
()
{
return
*
this
;
}
endpoint_manager
&
manager
()
{
return
*
manager_
;
}
// -- public member functions ------------------------------------------------
template
<
class
Parent
>
error
init
(
Parent
&
parent
)
{
manager_
=
&
parent
;
auto
&
cfg
=
system
().
config
();
auto
max_header_bufs
=
get_or
(
cfg
,
"middleman.max-header-buffers"
,
defaults
::
middleman
::
max_header_buffers
);
header_bufs_
.
reserve
(
max_header_bufs
);
auto
max_payload_bufs
=
get_or
(
cfg
,
"middleman.max-payload-buffers"
,
defaults
::
middleman
::
max_payload_buffers
);
payload_bufs_
.
reserve
(
max_payload_bufs
);
if
(
auto
err
=
dispatcher_
.
init
(
*
this
))
return
err
;
return
none
;
}
template
<
class
Parent
>
bool
handle_read_event
(
Parent
&
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
handle_
.
id
));
auto
ret
=
read
(
handle_
,
make_span
(
read_buf_
));
if
(
auto
res
=
get_if
<
std
::
pair
<
size_t
,
ip_endpoint
>>
(
&
ret
))
{
auto
num_bytes
=
res
->
first
;
auto
ep
=
res
->
second
;
read_buf_
.
resize
(
num_bytes
);
dispatcher_
.
handle_data
(
*
this
,
make_span
(
read_buf_
),
std
::
move
(
ep
));
prepare_next_read
();
}
else
{
auto
err
=
get
<
sec
>
(
ret
);
CAF_LOG_DEBUG
(
"send failed"
<<
CAF_ARG
(
err
));
dispatcher_
.
handle_error
(
err
);
return
false
;
}
return
true
;
}
template
<
class
Parent
>
bool
handle_write_event
(
Parent
&
parent
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
handle_
.
id
)
<<
CAF_ARG2
(
"queue-size"
,
packet_queue_
.
size
()));
// Try to write leftover data.
write_some
();
// Get new data from parent.
for
(
auto
msg
=
parent
.
next_message
();
msg
!=
nullptr
;
msg
=
parent
.
next_message
())
{
dispatcher_
.
write_message
(
*
this
,
std
::
move
(
msg
));
}
// Write prepared data.
return
write_some
();
}
template
<
class
Parent
>
void
resolve
(
Parent
&
,
const
uri
&
locator
,
const
actor
&
listener
)
{
dispatcher_
.
resolve
(
*
this
,
locator
,
listener
);
}
template
<
class
Parent
>
void
new_proxy
(
Parent
&
,
const
node_id
&
peer
,
actor_id
id
)
{
dispatcher_
.
new_proxy
(
*
this
,
peer
,
id
);
}
template
<
class
Parent
>
void
local_actor_down
(
Parent
&
,
const
node_id
&
peer
,
actor_id
id
,
error
reason
)
{
dispatcher_
.
local_actor_down
(
*
this
,
peer
,
id
,
std
::
move
(
reason
));
}
template
<
class
Parent
>
void
timeout
(
Parent
&
,
atom_value
value
,
uint64_t
id
)
{
dispatcher_
.
timeout
(
*
this
,
value
,
id
);
}
void
set_timeout
(
uint64_t
timeout_id
,
id_type
id
)
{
dispatcher_
.
set_timeout
(
timeout_id
,
id
);
}
void
handle_error
(
sec
code
)
{
dispatcher_
.
handle_error
(
code
);
}
error
add_new_worker
(
node_id
node
,
id_type
id
)
{
auto
worker
=
dispatcher_
.
add_new_worker
(
*
this
,
node
,
id
);
if
(
!
worker
)
return
worker
.
error
();
return
none
;
}
void
prepare_next_read
()
{
read_buf_
.
clear
();
read_buf_
.
resize
(
max_datagram_size
);
}
void
configure_read
(
receive_policy
::
config
)
{
// nop
}
void
write_packet
(
id_type
id
,
span
<
buffer_type
*>
buffers
)
{
CAF_ASSERT
(
!
buffers
.
empty
());
if
(
packet_queue_
.
empty
())
manager
().
register_writing
();
// By convention, the first buffer is a header buffer. Every other buffer is
// a payload buffer.
packet_queue_
.
emplace_back
(
id
,
buffers
);
}
// -- buffer management ------------------------------------------------------
buffer_type
next_header_buffer
()
{
return
next_buffer_impl
(
header_bufs_
);
}
buffer_type
next_payload_buffer
()
{
return
next_buffer_impl
(
payload_bufs_
);
}
/// Helper struct for managing outgoing packets
struct
packet
{
id_type
id
;
buffer_cache_type
bytes
;
size_t
size
;
packet
(
id_type
id
,
span
<
buffer_type
*>
bufs
)
:
id
(
id
)
{
size
=
0
;
for
(
auto
buf
:
bufs
)
{
size
+=
buf
->
size
();
bytes
.
emplace_back
(
std
::
move
(
*
buf
));
}
}
};
private:
// -- utility functions ------------------------------------------------------
static
buffer_type
next_buffer_impl
(
buffer_cache_type
cache
)
{
if
(
cache
.
empty
())
{
return
{};
}
auto
buf
=
std
::
move
(
cache
.
back
());
cache
.
pop_back
();
return
buf
;
}
bool
write_some
()
{
CAF_LOG_TRACE
(
CAF_ARG
(
handle_
.
id
));
// Helper function to sort empty buffers back into the right caches.
auto
recycle
=
[
&
]()
{
auto
&
front
=
packet_queue_
.
front
();
auto
&
bufs
=
front
.
bytes
;
auto
it
=
bufs
.
begin
();
if
(
header_bufs_
.
size
()
<
header_bufs_
.
capacity
())
{
it
->
clear
();
header_bufs_
.
emplace_back
(
std
::
move
(
*
it
++
));
}
for
(;
it
!=
bufs
.
end
()
&&
payload_bufs_
.
size
()
<
payload_bufs_
.
capacity
();
++
it
)
{
it
->
clear
();
payload_bufs_
.
emplace_back
(
std
::
move
(
*
it
));
}
packet_queue_
.
pop_front
();
};
// Write as many bytes as possible.
while
(
!
packet_queue_
.
empty
())
{
auto
&
packet
=
packet_queue_
.
front
();
std
::
vector
<
std
::
vector
<
byte
>*>
ptrs
;
for
(
auto
&
buf
:
packet
.
bytes
)
ptrs
.
emplace_back
(
&
buf
);
auto
write_ret
=
write
(
handle_
,
make_span
(
ptrs
),
packet
.
id
);
if
(
auto
num_bytes
=
get_if
<
size_t
>
(
&
write_ret
))
{
CAF_LOG_DEBUG
(
CAF_ARG
(
handle_
.
id
)
<<
CAF_ARG
(
*
num_bytes
));
CAF_LOG_WARNING_IF
(
*
num_bytes
<
packet
.
size
,
"packet was not sent completely"
);
recycle
();
}
else
{
auto
err
=
get
<
sec
>
(
write_ret
);
if
(
err
!=
sec
::
unavailable_or_would_block
)
{
CAF_LOG_DEBUG
(
"send failed"
<<
CAF_ARG
(
err
));
dispatcher_
.
handle_error
(
err
);
return
false
;
}
return
true
;
}
}
return
false
;
}
dispatcher_type
dispatcher_
;
udp_datagram_socket
handle_
;
buffer_cache_type
header_bufs_
;
buffer_cache_type
payload_bufs_
;
std
::
vector
<
byte
>
read_buf_
;
std
::
deque
<
packet
>
packet_queue_
;
endpoint_manager
*
manager_
;
};
}
// namespace net
}
// namespace caf
libcaf_net/caf/net/endpoint_manager_impl.hpp
View file @
cdea6c3b
...
...
@@ -53,10 +53,6 @@ public:
// -- properties -------------------------------------------------------------
application_type
&
application
()
{
return
transport_
.
application
();
}
transport_type
&
transport
()
{
return
transport_
;
}
...
...
libcaf_net/caf/net/fwd.hpp
View file @
cdea6c3b
...
...
@@ -30,7 +30,7 @@ namespace net {
template
<
class
Application
,
class
IdType
=
unit_t
>
class
transport_worker
;
template
<
class
Application
,
class
IdType
=
unit_t
>
template
<
class
Transport
,
class
IdType
=
unit_t
>
class
transport_worker_dispatcher
;
// -- classes ------------------------------------------------------------------
...
...
libcaf_net/caf/net/stream_transport.hpp
View file @
cdea6c3b
...
...
@@ -248,8 +248,6 @@ private:
bool
write_some
()
{
CAF_LOG_TRACE
(
CAF_ARG
(
handle_
.
id
));
if
(
write_queue_
.
empty
())
return
false
;
// Helper function to sort empty buffers back into the right caches.
auto
recycle
=
[
&
]()
{
auto
&
front
=
write_queue_
.
front
();
...
...
@@ -266,7 +264,7 @@ private:
write_queue_
.
pop_front
();
};
// Write buffers from the write_queue_ for as long as possible.
do
{
while
(
!
write_queue_
.
empty
())
{
auto
&
buf
=
write_queue_
.
front
().
second
;
CAF_ASSERT
(
!
buf
.
empty
());
auto
data
=
buf
.
data
()
+
written_
;
...
...
@@ -290,7 +288,7 @@ private:
}
return
true
;
}
}
while
(
!
write_queue_
.
empty
());
}
return
false
;
}
...
...
libcaf_net/caf/net/transport_worker_dispatcher.hpp
View file @
cdea6c3b
...
...
@@ -18,6 +18,8 @@
#pragma once
#include <caf/logger.hpp>
#include <caf/sec.hpp>
#include <unordered_map>
#include "caf/byte.hpp"
...
...
@@ -26,23 +28,26 @@
#include "caf/net/fwd.hpp"
#include "caf/net/packet_writer_decorator.hpp"
#include "caf/net/transport_worker.hpp"
#include "caf/send.hpp"
#include "caf/span.hpp"
#include "caf/unit.hpp"
namespace
caf
{
namespace
net
{
///
i
mplements a dispatcher that dispatches between transport and workers.
template
<
class
ApplicationFactory
,
class
IdType
>
///
I
mplements a dispatcher that dispatches between transport and workers.
template
<
class
Transport
,
class
IdType
>
class
transport_worker_dispatcher
{
public:
// -- member types -----------------------------------------------------------
using
id_type
=
IdType
;
using
factory_type
=
ApplicationFactory
;
using
transport_type
=
Transport
;
using
application_type
=
typename
ApplicationFactory
::
application_type
;
using
factory_type
=
typename
transport_type
::
factory_type
;
using
application_type
=
typename
factory_type
::
application_type
;
using
worker_type
=
transport_worker
<
application_type
,
id_type
>
;
...
...
@@ -50,8 +55,8 @@ public:
// -- constructors, destructors, and assignment operators --------------------
transport_worker_dispatcher
(
factory_type
factory
)
:
factory_
(
std
::
move
(
factory
))
{
transport_worker_dispatcher
(
transport_type
&
transport
,
factory_type
factory
)
:
factory_
(
std
::
move
(
factory
))
,
transport_
(
&
transport
)
{
// nop
}
...
...
@@ -65,48 +70,52 @@ public:
template
<
class
Parent
>
error
handle_data
(
Parent
&
parent
,
span
<
byte
>
data
,
id_type
id
)
{
auto
it
=
workers_by_id_
.
find
(
id
);
if
(
it
==
workers_by_id_
.
end
())
{
// TODO: w
here to get node_id from here?
add_new_worker
(
parent
,
node_id
{},
id
);
it
=
workers_by_id_
.
find
(
id
);
}
auto
worker
=
it
->
second
;
return
worker
->
handle_data
(
parent
,
data
);
if
(
auto
worker
=
find_worker
(
id
))
return
worker
->
handle_data
(
parent
,
data
);
// TODO: W
here to get node_id from here?
auto
worker
=
add_new_worker
(
parent
,
node_id
{},
id
);
if
(
worker
)
return
(
*
worker
)
->
handle_data
(
parent
,
data
);
else
return
std
::
move
(
worker
.
error
()
);
}
template
<
class
Parent
>
void
write_message
(
Parent
&
parent
,
std
::
unique_ptr
<
endpoint_manager_queue
::
message
>
msg
)
{
auto
sender
=
msg
->
msg
->
sender
;
if
(
!
sender
)
auto
receiver
=
msg
->
receiver
;
if
(
!
receiver
)
return
;
auto
nid
=
receiver
->
node
();
if
(
auto
worker
=
find_worker
(
nid
))
{
worker
->
write_message
(
parent
,
std
::
move
(
msg
));
return
;
auto
nid
=
sender
->
node
();
auto
it
=
workers_by_node_
.
find
(
nid
);
if
(
it
==
workers_by_node_
.
end
())
{
// TODO: where to get id_type from here?
add_new_worker
(
parent
,
nid
,
id_type
{});
it
=
workers_by_node_
.
find
(
nid
);
}
auto
worker
=
it
->
second
;
worker
->
write_message
(
parent
,
std
::
move
(
msg
));
// TODO: where to get id_type from here?
if
(
auto
worker
=
add_new_worker
(
parent
,
nid
,
id_type
{}))
(
*
worker
)
->
write_message
(
parent
,
std
::
move
(
msg
));
}
template
<
class
Parent
>
void
write_packet
(
Parent
&
parent
,
span
<
const
byte
>
header
,
span
<
const
byte
>
payload
,
id_type
id
)
{
parent
.
write_packet
(
header
,
payload
,
id
);
void
resolve
(
Parent
&
parent
,
const
uri
&
locator
,
const
actor
&
listener
)
{
if
(
auto
worker
=
find_worker
(
make_node_id
(
locator
)))
worker
->
resolve
(
parent
,
locator
.
path
(),
listener
);
else
anon_send
(
listener
,
make_error
(
sec
::
runtime_error
,
"could not resolve node"
));
}
template
<
class
Parent
>
void
resolve
(
Parent
&
parent
,
const
std
::
string
&
path
,
actor
listener
)
{
// TODO path should be uri to lookup the corresponding worker
// if enpoint is known -> resolve actor through worker
// if not connect to endpoint?!
if
(
workers_by_id_
.
empty
())
return
;
auto
worker
=
workers_by_id_
.
begin
()
->
second
;
worker
->
resolve
(
parent
,
path
,
listener
);
void
new_proxy
(
Parent
&
parent
,
const
node_id
&
nid
,
actor_id
id
)
{
if
(
auto
worker
=
find_worker
(
nid
))
worker
->
new_proxy
(
parent
,
nid
,
id
);
}
template
<
class
Parent
>
void
local_actor_down
(
Parent
&
parent
,
const
node_id
&
nid
,
actor_id
id
,
error
reason
)
{
if
(
auto
worker
=
find_worker
(
nid
))
worker
->
local_actor_down
(
parent
,
nid
,
id
,
std
::
move
(
reason
));
}
template
<
class
...
Ts
>
...
...
@@ -116,9 +125,10 @@ public:
template
<
class
Parent
>
void
timeout
(
Parent
&
parent
,
atom_value
value
,
uint64_t
id
)
{
auto
worker
=
workers_by_timeout_id_
.
at
(
id
);
worker
->
timeout
(
parent
,
value
,
id
);
workers_by_timeout_id_
.
erase
(
id
);
if
(
auto
worker
=
workers_by_timeout_id_
.
at
(
id
))
{
worker
->
timeout
(
parent
,
value
,
id
);
workers_by_timeout_id_
.
erase
(
id
);
}
}
void
handle_error
(
sec
error
)
{
...
...
@@ -129,17 +139,36 @@ public:
}
template
<
class
Parent
>
error
add_new_worker
(
Parent
&
parent
,
node_id
node
,
id_type
id
)
{
expected
<
worker_ptr
>
add_new_worker
(
Parent
&
parent
,
node_id
node
,
id_type
id
)
{
auto
application
=
factory_
.
make
();
auto
worker
=
std
::
make_shared
<
worker_type
>
(
std
::
move
(
application
),
id
);
if
(
auto
err
=
worker
->
init
(
parent
))
return
err
;
workers_by_id_
.
emplace
(
std
::
move
(
id
),
worker
);
workers_by_node_
.
emplace
(
std
::
move
(
node
),
std
::
move
(
worker
)
);
return
none
;
workers_by_node_
.
emplace
(
std
::
move
(
node
),
worker
);
return
worker
;
}
private:
worker_ptr
find_worker
(
const
node_id
&
nid
)
{
return
find_worker_impl
(
workers_by_node_
,
nid
);
}
worker_ptr
find_worker
(
const
id_type
&
id
)
{
return
find_worker_impl
(
workers_by_id_
,
id
);
}
template
<
class
Key
>
worker_ptr
find_worker_impl
(
const
std
::
unordered_map
<
Key
,
worker_ptr
>&
map
,
const
Key
&
key
)
{
if
(
map
.
count
(
key
)
==
0
)
{
CAF_LOG_DEBUG
(
"could not find worker: "
<<
CAF_ARG
(
key
));
return
nullptr
;
}
return
map
.
at
(
key
);
}
// -- worker lookups ---------------------------------------------------------
std
::
unordered_map
<
id_type
,
worker_ptr
>
workers_by_id_
;
...
...
@@ -147,6 +176,7 @@ private:
std
::
unordered_map
<
uint64_t
,
worker_ptr
>
workers_by_timeout_id_
;
factory_type
factory_
;
transport_type
*
transport_
;
};
}
// namespace net
...
...
libcaf_net/caf/net/udp_datagram_socket.hpp
View file @
cdea6c3b
...
...
@@ -56,9 +56,22 @@ error allow_connreset(udp_datagram_socket x, bool new_value);
variant
<
std
::
pair
<
size_t
,
ip_endpoint
>
,
sec
>
read
(
udp_datagram_socket
x
,
span
<
byte
>
buf
);
/// Sends the content of `bufs` as a datagram to the endpoint `ep` on socket
/// `x`.
/// @param x The UDP socket for sending datagrams.
/// @param bufs Points to the datagram to send, scattered across up to 10
/// buffers.
/// @param ep The enpoint to send the datagram to.
/// @returns The number of written bytes on success, otherwise an error code.
/// @relates udp_datagram_socket
/// @pre `bufs.size() < 10`
variant
<
size_t
,
sec
>
write
(
udp_datagram_socket
x
,
span
<
std
::
vector
<
byte
>*>
bufs
,
ip_endpoint
ep
);
/// Sends the content of `buf` as a datagram to the endpoint `ep` on socket `x`.
/// @param x The UDP socket for sending datagrams.
/// @param buf The buffer to send.
/// @param ep The enpoint to send the datagram to.
/// @returns The number of written bytes on success, otherwise an error code.
/// @relates udp_datagram_socket
variant
<
size_t
,
sec
>
write
(
udp_datagram_socket
x
,
span
<
const
byte
>
buf
,
...
...
libcaf_net/src/udp_datagram_socket.cpp
View file @
cdea6c3b
...
...
@@ -58,7 +58,7 @@ error allow_connreset(udp_datagram_socket x, bool) {
expected
<
std
::
pair
<
udp_datagram_socket
,
uint16_t
>>
make_udp_datagram_socket
(
ip_endpoint
ep
,
bool
reuse_addr
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
ep
));
sockaddr_storage
addr
;
sockaddr_storage
addr
=
{}
;
detail
::
convert
(
ep
,
addr
);
CAF_NET_SYSCALL
(
"socket"
,
fd
,
==
,
invalid_socket_id
,
::
socket
(
addr
.
ss_family
,
SOCK_DGRAM
,
0
));
...
...
@@ -112,12 +112,12 @@ variant<std::pair<size_t, ip_endpoint>, sec> read(udp_datagram_socket x,
variant
<
size_t
,
sec
>
write
(
udp_datagram_socket
x
,
span
<
const
byte
>
buf
,
ip_endpoint
ep
)
{
sockaddr_storage
addr
;
sockaddr_storage
addr
=
{}
;
detail
::
convert
(
ep
,
addr
);
auto
len
=
ep
.
address
().
embeds_v4
()
?
sizeof
(
sockaddr_in
)
:
sizeof
(
sockaddr_in6
);
auto
res
=
::
sendto
(
x
.
id
,
reinterpret_cast
<
socket_send_ptr
>
(
buf
.
data
()),
buf
.
size
(),
0
,
reinterpret_cast
<
sockaddr
*>
(
&
addr
),
ep
.
address
().
embeds_v4
()
?
sizeof
(
sockaddr_in
)
:
sizeof
(
sockaddr_in6
));
buf
.
size
(),
0
,
reinterpret_cast
<
sockaddr
*>
(
&
addr
),
len
);
auto
ret
=
check_udp_datagram_socket_io_res
(
res
);
if
(
auto
num_bytes
=
get_if
<
size_t
>
(
&
ret
))
return
*
num_bytes
;
...
...
@@ -125,6 +125,60 @@ variant<size_t, sec> write(udp_datagram_socket x, span<const byte> buf,
return
get
<
sec
>
(
ret
);
}
#ifdef CAF_WINDOWS
variant
<
size_t
,
sec
>
write
(
udp_datagram_socket
x
,
span
<
std
::
vector
<
byte
>*>
bufs
,
ip_endpoint
ep
)
{
CAF_ASSERT
(
bufs
.
size
()
<
10
);
WSABUF
buf_array
[
10
];
auto
convert
=
[](
std
::
vector
<
byte
>*
buf
)
{
return
WSABUF
{
static_cast
<
ULONG
>
(
buf
->
size
()),
reinterpret_cast
<
CHAR
*>
(
buf
->
data
())};
};
std
::
transform
(
bufs
.
begin
(),
bufs
.
end
(),
std
::
begin
(
buf_array
),
convert
);
sockaddr_storage
addr
=
{};
detail
::
convert
(
ep
,
addr
);
auto
len
=
ep
.
address
().
embeds_v4
()
?
sizeof
(
sockaddr_in
)
:
sizeof
(
sockaddr_in6
);
DWORD
bytes_sent
=
0
;
auto
res
=
WSASendTo
(
x
.
id
,
buf_array
,
static_cast
<
DWORD
>
(
bufs
.
size
()),
&
bytes_sent
,
0
,
reinterpret_cast
<
sockaddr
*>
(
&
addr
),
len
,
nullptr
,
nullptr
);
if
(
res
!=
0
)
{
auto
code
=
last_socket_error
();
if
(
code
==
std
::
errc
::
operation_would_block
||
code
==
std
::
errc
::
resource_unavailable_try_again
)
return
sec
::
unavailable_or_would_block
;
return
sec
::
socket_operation_failed
;
}
return
static_cast
<
size_t
>
(
bytes_sent
);
}
#else // CAF_WINDOWS
variant
<
size_t
,
sec
>
write
(
udp_datagram_socket
x
,
span
<
std
::
vector
<
byte
>*>
bufs
,
ip_endpoint
ep
)
{
CAF_ASSERT
(
bufs
.
size
()
<
10
);
auto
convert
=
[](
std
::
vector
<
byte
>*
buf
)
{
return
iovec
{
buf
->
data
(),
buf
->
size
()};
};
sockaddr_storage
addr
=
{};
detail
::
convert
(
ep
,
addr
);
iovec
buf_array
[
10
];
std
::
transform
(
bufs
.
begin
(),
bufs
.
end
(),
std
::
begin
(
buf_array
),
convert
);
msghdr
message
=
{};
memset
(
&
message
,
0
,
sizeof
(
msghdr
));
message
.
msg_name
=
&
addr
;
message
.
msg_namelen
=
ep
.
address
().
embeds_v4
()
?
sizeof
(
sockaddr_in
)
:
sizeof
(
sockaddr_in6
);
message
.
msg_iov
=
buf_array
;
message
.
msg_iovlen
=
bufs
.
size
();
auto
res
=
sendmsg
(
x
.
id
,
&
message
,
0
);
return
check_udp_datagram_socket_io_res
(
res
);
}
#endif // CAF_WINDOWS
variant
<
size_t
,
sec
>
check_udp_datagram_socket_io_res
(
std
::
make_signed
<
size_t
>::
type
res
)
{
if
(
res
<
0
)
{
...
...
libcaf_net/test/datagram_transport.cpp
0 → 100644
View file @
cdea6c3b
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE datagram_transport
#include "caf/net/datagram_transport.hpp"
#include "caf/net/test/host_fixture.hpp"
#include "caf/test/dsl.hpp"
#include "caf/byte.hpp"
#include "caf/detail/socket_sys_includes.hpp"
#include "caf/make_actor.hpp"
#include "caf/net/actor_proxy_impl.hpp"
#include "caf/net/endpoint_manager.hpp"
#include "caf/net/endpoint_manager_impl.hpp"
#include "caf/net/ip.hpp"
#include "caf/net/make_endpoint_manager.hpp"
#include "caf/net/multiplexer.hpp"
#include "caf/net/udp_datagram_socket.hpp"
#include "caf/serializer_impl.hpp"
#include "caf/span.hpp"
using
namespace
caf
;
using
namespace
caf
::
net
;
using
namespace
caf
::
net
::
ip
;
namespace
{
constexpr
string_view
hello_manager
=
"hello manager!"
;
class
dummy_application_factory
;
struct
fixture
:
test_coordinator_fixture
<>
,
host_fixture
{
using
buffer_type
=
std
::
vector
<
byte
>
;
using
buffer_ptr
=
std
::
shared_ptr
<
buffer_type
>
;
fixture
()
:
shared_buf
(
std
::
make_shared
<
buffer_type
>
(
1024
))
{
mpx
=
std
::
make_shared
<
multiplexer
>
();
if
(
auto
err
=
mpx
->
init
())
CAF_FAIL
(
"mpx->init failed: "
<<
sys
.
render
(
err
));
mpx
->
set_thread_id
();
CAF_CHECK_EQUAL
(
mpx
->
num_socket_managers
(),
1u
);
auto
addresses
=
local_addresses
(
"localhost"
);
CAF_CHECK
(
!
addresses
.
empty
());
ep
=
ip_endpoint
(
*
addresses
.
begin
(),
0
);
auto
send_pair
=
unbox
(
make_udp_datagram_socket
(
ep
));
send_socket
=
send_pair
.
first
;
auto
receive_pair
=
unbox
(
make_udp_datagram_socket
(
ep
));
recv_socket
=
receive_pair
.
first
;
ep
.
port
(
htons
(
receive_pair
.
second
));
CAF_MESSAGE
(
"sending message to "
<<
CAF_ARG
(
ep
));
if
(
auto
err
=
nonblocking
(
recv_socket
,
true
))
CAF_FAIL
(
"nonblocking() returned an error: "
<<
err
);
}
~
fixture
()
{
close
(
send_socket
);
close
(
recv_socket
);
}
bool
handle_io_event
()
override
{
return
mpx
->
poll_once
(
false
);
}
error
read_from_socket
(
udp_datagram_socket
sock
,
buffer_type
&
buf
)
{
uint8_t
receive_attempts
=
0
;
variant
<
std
::
pair
<
size_t
,
ip_endpoint
>
,
sec
>
read_ret
;
do
{
read_ret
=
read
(
sock
,
make_span
(
buf
));
if
(
auto
read_res
=
get_if
<
std
::
pair
<
size_t
,
ip_endpoint
>>
(
&
read_ret
))
{
buf
.
resize
(
read_res
->
first
);
}
else
if
(
get
<
sec
>
(
read_ret
)
!=
sec
::
unavailable_or_would_block
)
{
return
make_error
(
get
<
sec
>
(
read_ret
),
"read failed"
);
}
if
(
++
receive_attempts
>
100
)
return
make_error
(
sec
::
runtime_error
,
"too many unavailable_or_would_blocks"
);
}
while
(
read_ret
.
index
()
!=
0
);
return
none
;
}
multiplexer_ptr
mpx
;
buffer_ptr
shared_buf
;
ip_endpoint
ep
;
udp_datagram_socket
send_socket
;
udp_datagram_socket
recv_socket
;
};
class
dummy_application
{
using
buffer_type
=
std
::
vector
<
byte
>
;
using
buffer_ptr
=
std
::
shared_ptr
<
buffer_type
>
;
public:
explicit
dummy_application
(
buffer_ptr
rec_buf
)
:
rec_buf_
(
std
::
move
(
rec_buf
)){
// nop
};
template
<
class
Parent
>
error
init
(
Parent
&
)
{
return
none
;
}
template
<
class
Transport
>
void
write_message
(
Transport
&
transport
,
std
::
unique_ptr
<
endpoint_manager_queue
::
message
>
msg
)
{
transport
.
write_packet
(
msg
->
payload
);
}
template
<
class
Parent
>
error
handle_data
(
Parent
&
,
span
<
const
byte
>
data
)
{
rec_buf_
->
clear
();
rec_buf_
->
insert
(
rec_buf_
->
begin
(),
data
.
begin
(),
data
.
end
());
return
none
;
}
template
<
class
Parent
>
void
resolve
(
Parent
&
parent
,
string_view
path
,
const
actor
&
listener
)
{
actor_id
aid
=
42
;
auto
uri
=
unbox
(
make_uri
(
"test:/id/42"
));
auto
nid
=
make_node_id
(
uri
);
actor_config
cfg
;
endpoint_manager_ptr
ptr
{
&
parent
.
manager
()};
auto
p
=
make_actor
<
actor_proxy_impl
,
strong_actor_ptr
>
(
aid
,
nid
,
&
parent
.
system
(),
cfg
,
std
::
move
(
ptr
));
anon_send
(
listener
,
resolve_atom
::
value
,
std
::
string
{
path
.
begin
(),
path
.
end
()},
p
);
}
template
<
class
Parent
>
void
new_proxy
(
Parent
&
,
actor_id
)
{
// nop
}
template
<
class
Parent
>
void
local_actor_down
(
Parent
&
,
actor_id
,
error
)
{
// nop
}
template
<
class
Parent
>
void
timeout
(
Parent
&
,
atom_value
,
uint64_t
)
{
// nop
}
void
handle_error
(
sec
sec
)
{
CAF_FAIL
(
"handle_error called: "
<<
to_string
(
sec
));
}
static
expected
<
buffer_type
>
serialize
(
actor_system
&
sys
,
const
type_erased_tuple
&
x
)
{
buffer_type
result
;
serializer_impl
<
buffer_type
>
sink
{
sys
,
result
};
if
(
auto
err
=
message
::
save
(
sink
,
x
))
return
err
;
return
result
;
}
private:
buffer_ptr
rec_buf_
;
};
class
dummy_application_factory
{
using
buffer_ptr
=
std
::
shared_ptr
<
std
::
vector
<
byte
>>
;
public:
using
application_type
=
dummy_application
;
explicit
dummy_application_factory
(
buffer_ptr
buf
)
:
buf_
(
std
::
move
(
buf
))
{
// nop
}
dummy_application
make
()
{
return
dummy_application
{
buf_
};
}
private:
buffer_ptr
buf_
;
};
}
// namespace
CAF_TEST_FIXTURE_SCOPE
(
datagram_transport_tests
,
fixture
)
CAF_TEST
(
receive
)
{
using
transport_type
=
datagram_transport
<
dummy_application_factory
>
;
if
(
auto
err
=
nonblocking
(
recv_socket
,
true
))
CAF_FAIL
(
"nonblocking() returned an error: "
<<
sys
.
render
(
err
));
auto
mgr
=
make_endpoint_manager
(
mpx
,
sys
,
transport_type
{
recv_socket
,
dummy_application_factory
{
shared_buf
}});
CAF_CHECK_EQUAL
(
mgr
->
init
(),
none
);
auto
mgr_impl
=
mgr
.
downcast
<
endpoint_manager_impl
<
transport_type
>>
();
CAF_CHECK
(
mgr_impl
!=
nullptr
);
auto
&
transport
=
mgr_impl
->
transport
();
transport
.
configure_read
(
net
::
receive_policy
::
exactly
(
hello_manager
.
size
()));
CAF_CHECK_EQUAL
(
mpx
->
num_socket_managers
(),
2u
);
CAF_CHECK_EQUAL
(
write
(
send_socket
,
as_bytes
(
make_span
(
hello_manager
)),
ep
),
hello_manager
.
size
());
CAF_MESSAGE
(
"wrote "
<<
hello_manager
.
size
()
<<
" bytes."
);
run
();
CAF_CHECK_EQUAL
(
string_view
(
reinterpret_cast
<
char
*>
(
shared_buf
->
data
()),
shared_buf
->
size
()),
hello_manager
);
}
CAF_TEST
(
resolve
and
proxy
communication
)
{
using
transport_type
=
datagram_transport
<
dummy_application_factory
>
;
buffer_type
recv_buf
(
1024
);
auto
uri
=
unbox
(
make_uri
(
"test:/id/42"
));
auto
mgr
=
make_endpoint_manager
(
mpx
,
sys
,
transport_type
{
send_socket
,
dummy_application_factory
{
shared_buf
}});
CAF_CHECK_EQUAL
(
mgr
->
init
(),
none
);
auto
mgr_impl
=
mgr
.
downcast
<
endpoint_manager_impl
<
transport_type
>>
();
CAF_CHECK
(
mgr_impl
!=
nullptr
);
auto
&
transport
=
mgr_impl
->
transport
();
transport
.
add_new_worker
(
make_node_id
(
uri
),
ep
);
run
();
mgr
->
resolve
(
uri
,
self
);
run
();
self
->
receive
(
[
&
](
resolve_atom
,
const
std
::
string
&
,
const
strong_actor_ptr
&
p
)
{
CAF_MESSAGE
(
"got a proxy, send a message to it"
);
self
->
send
(
actor_cast
<
actor
>
(
p
),
"hello proxy!"
);
},
after
(
std
::
chrono
::
seconds
(
0
))
>>
[
&
]
{
CAF_FAIL
(
"manager did not respond with a proxy."
);
});
run
();
CAF_CHECK_EQUAL
(
read_from_socket
(
recv_socket
,
recv_buf
),
none
);
CAF_MESSAGE
(
"receive buffer contains "
<<
recv_buf
.
size
()
<<
" bytes"
);
message
msg
;
binary_deserializer
source
{
sys
,
recv_buf
};
CAF_CHECK_EQUAL
(
source
(
msg
),
none
);
if
(
msg
.
match_elements
<
std
::
string
>
())
CAF_CHECK_EQUAL
(
msg
.
get_as
<
std
::
string
>
(
0
),
"hello proxy!"
);
else
CAF_ERROR
(
"expected a string, got: "
<<
to_string
(
msg
));
}
CAF_TEST_FIXTURE_SCOPE_END
()
libcaf_net/test/stream_application.cpp
View file @
cdea6c3b
...
...
@@ -70,7 +70,7 @@ struct fixture : host_fixture, test_coordinator_fixture<config> {
auto
backend
=
dynamic_cast
<
backend
::
test
*>
(
mm
.
backend
(
"test"
));
auto
mgr
=
backend
->
peer
(
mars
);
auto
&
dref
=
dynamic_cast
<
endpoint_manager_impl
<
transport_type
>&>
(
*
mgr
);
app
=
&
dref
.
application
();
app
=
&
dref
.
transport
().
application
();
sock
=
backend
->
socket
(
mars
);
}
...
...
libcaf_net/test/transport_worker_dispatcher.cpp
View file @
cdea6c3b
...
...
@@ -122,6 +122,8 @@ private:
struct
dummy_transport
{
using
transport_type
=
dummy_transport
;
using
factory_type
=
dummy_application_factory
;
using
application_type
=
dummy_application
;
dummy_transport
(
std
::
shared_ptr
<
buffer_type
>
buf
)
:
buf_
(
std
::
move
(
buf
))
{
...
...
@@ -180,12 +182,12 @@ uri operator"" _u(const char* cstr, size_t cstr_len) {
}
struct
fixture
:
host_fixture
{
using
dispatcher_type
=
transport_worker_dispatcher
<
dummy_
application_factory
,
using
dispatcher_type
=
transport_worker_dispatcher
<
dummy_
transport
,
ip_endpoint
>
;
fixture
()
:
buf
{
std
::
make_shared
<
buffer_type
>
()},
dispatcher
{
dummy_application_factory
{
buf
}},
dispatcher
{
dummy
,
dummy
_application_factory
{
buf
}},
dummy
{
buf
}
{
add_new_workers
();
}
...
...
@@ -197,13 +199,14 @@ struct fixture : host_fixture {
auto
p
=
make_actor
<
dummy_actor
,
strong_actor_ptr
>
(
aid
,
nid
,
&
sys
,
cfg
);
auto
test_span
=
as_bytes
(
make_span
(
hello_test
));
buffer_type
payload
(
test_span
.
begin
(),
test_span
.
end
());
auto
strong_actor
=
actor_cast
<
strong_actor_ptr
>
(
p
);
auto
receiver
=
actor_cast
<
strong_actor_ptr
>
(
p
);
if
(
!
receiver
)
CAF_FAIL
(
"failed to cast receiver to a strong_actor_ptr"
);
mailbox_element
::
forwarding_stack
stack
;
auto
elem
=
make_mailbox_element
(
std
::
move
(
strong_actor
),
make_message_id
(
12345
),
std
::
move
(
stack
),
make_message
());
auto
elem
=
make_mailbox_element
(
nullptr
,
make_message_id
(
12345
),
std
::
move
(
stack
),
make_message
());
return
detail
::
make_unique
<
endpoint_manager_queue
::
message
>
(
std
::
move
(
elem
),
strong_acto
r
,
receive
r
,
payload
);
}
...
...
@@ -213,16 +216,17 @@ struct fixture : host_fixture {
void
add_new_workers
()
{
for
(
auto
&
data
:
test_data
)
{
if
(
auto
err
=
dispatcher
.
add_new_worker
(
dummy
,
data
.
nid
,
data
.
ep
))
CAF_FAIL
(
"add_new_worker returned an error: "
<<
err
);
auto
worker
=
dispatcher
.
add_new_worker
(
dummy
,
data
.
nid
,
data
.
ep
);
if
(
!
worker
)
CAF_FAIL
(
"add_new_worker returned an error: "
<<
worker
.
error
());
}
buf
->
clear
();
}
void
test_write_message
(
testdata
&
testcase
)
{
auto
msg
=
make_dummy_message
(
testcase
.
nid
);
if
(
!
msg
->
msg
->
send
er
)
CAF_FAIL
(
"
send
er is null"
);
if
(
!
msg
->
receiv
er
)
CAF_FAIL
(
"
receiv
er is null"
);
dispatcher
.
write_message
(
dummy
,
std
::
move
(
msg
));
}
...
...
@@ -268,9 +272,8 @@ struct fixture : host_fixture {
CAF_TEST_FIXTURE_SCOPE
(
transport_worker_dispatcher_test
,
fixture
)
CAF_TEST
(
init
)
{
dispatcher_type
dispatcher
{
dummy_application_factory
{
buf
}};
if
(
auto
err
=
dispatcher
.
init
(
dummy
))
CAF_FAIL
(
"init failed with error: "
<<
err
);
dispatcher_type
dispatcher
{
dummy
,
dummy_application_factory
{
buf
}};
CAF_CHECK_EQUAL
(
dispatcher
.
init
(
dummy
),
none
);
}
CAF_TEST
(
handle_data
)
{
...
...
libcaf_net/test/udp_datagram_socket.cpp
View file @
cdea6c3b
...
...
@@ -39,7 +39,7 @@ namespace {
constexpr
string_view
hello_test
=
"Hello test!"
;
struct
fixture
:
host_fixture
{
fixture
()
:
host_fixture
()
{
fixture
()
:
host_fixture
()
,
buf
(
1024
)
{
addresses
=
local_addresses
(
"localhost"
);
CAF_CHECK
(
!
addresses
.
empty
());
ep
=
ip_endpoint
(
*
addresses
.
begin
(),
0
);
...
...
@@ -61,14 +61,48 @@ struct fixture : host_fixture {
ip_endpoint
ep
;
udp_datagram_socket
send_socket
;
udp_datagram_socket
receive_socket
;
std
::
vector
<
byte
>
buf
;
};
error
read_from_socket
(
udp_datagram_socket
sock
,
std
::
vector
<
byte
>&
buf
)
{
uint8_t
receive_attempts
=
0
;
variant
<
std
::
pair
<
size_t
,
ip_endpoint
>
,
sec
>
read_ret
;
do
{
read_ret
=
read
(
sock
,
make_span
(
buf
));
if
(
auto
read_res
=
get_if
<
std
::
pair
<
size_t
,
ip_endpoint
>>
(
&
read_ret
))
{
buf
.
resize
(
read_res
->
first
);
}
else
if
(
get
<
sec
>
(
read_ret
)
!=
sec
::
unavailable_or_would_block
)
{
return
make_error
(
get
<
sec
>
(
read_ret
),
"read failed"
);
}
if
(
++
receive_attempts
>
100
)
return
make_error
(
sec
::
runtime_error
,
"too many unavailable_or_would_blocks"
);
}
while
(
read_ret
.
index
()
!=
0
);
return
none
;
}
struct
header
{
header
(
size_t
payload_size
)
:
payload_size
(
payload_size
)
{
// nop
}
header
()
:
header
(
0
)
{
// nop
}
template
<
class
Inspector
>
friend
typename
Inspector
::
result_type
inspect
(
Inspector
&
f
,
header
&
x
)
{
return
f
(
meta
::
type_name
(
"header"
),
x
.
payload_size
);
}
size_t
payload_size
;
};
}
// namespace
CAF_TEST_FIXTURE_SCOPE
(
udp_datagram_socket_test
,
fixture
)
CAF_TEST
(
send
and
receive
)
{
std
::
vector
<
byte
>
buf
(
1024
);
CAF_TEST
(
read
/
write
using
span
<
byte
>
)
{
if
(
auto
err
=
nonblocking
(
socket_cast
<
net
::
socket
>
(
receive_socket
),
true
))
CAF_FAIL
(
"setting socket to nonblocking failed: "
<<
err
);
CAF_CHECK_EQUAL
(
read
(
receive_socket
,
make_span
(
buf
)),
...
...
@@ -76,21 +110,35 @@ CAF_TEST(send and receive) {
CAF_MESSAGE
(
"sending data to "
<<
to_string
(
ep
));
CAF_CHECK_EQUAL
(
write
(
send_socket
,
as_bytes
(
make_span
(
hello_test
)),
ep
),
hello_test
.
size
());
int
receive_attempts
=
0
;
variant
<
std
::
pair
<
size_t
,
ip_endpoint
>
,
sec
>
read_ret
;
do
{
read_ret
=
read
(
receive_socket
,
make_span
(
buf
));
if
(
auto
read_res
=
get_if
<
std
::
pair
<
size_t
,
ip_endpoint
>>
(
&
read_ret
))
{
CAF_CHECK_EQUAL
(
read_res
->
first
,
hello_test
.
size
());
buf
.
resize
(
read_res
->
first
);
}
else
if
(
get
<
sec
>
(
read_ret
)
!=
sec
::
unavailable_or_would_block
)
{
CAF_FAIL
(
"read returned an error: "
<<
sys
.
render
(
get
<
sec
>
(
read_ret
)));
}
if
(
++
receive_attempts
>
100
)
CAF_FAIL
(
"unable to receive data from the UDP socket"
);
}
while
(
read_ret
.
index
()
!=
0
);
CAF_CHECK_EQUAL
(
read_from_socket
(
receive_socket
,
buf
),
none
);
string_view
received
{
reinterpret_cast
<
const
char
*>
(
buf
.
data
()),
buf
.
size
()};
CAF_CHECK_EQUAL
(
received
,
hello_test
);
}
CAF_TEST
(
read
/
write
using
span
<
std
::
vector
<
byte
>*>
)
{
// generate header and payload in separate buffers
header
hdr
{
hello_test
.
size
()};
std
::
vector
<
byte
>
hdr_buf
;
serializer_impl
<
std
::
vector
<
byte
>>
sink
(
sys
,
hdr_buf
);
if
(
auto
err
=
sink
(
hdr
))
CAF_FAIL
(
"serializing payload failed"
<<
sys
.
render
(
err
));
auto
bytes
=
as_bytes
(
make_span
(
hello_test
));
std
::
vector
<
byte
>
payload_buf
(
bytes
.
begin
(),
bytes
.
end
());
auto
packet_size
=
hdr_buf
.
size
()
+
payload_buf
.
size
();
std
::
vector
<
std
::
vector
<
byte
>*>
bufs
{
&
hdr_buf
,
&
payload_buf
};
CAF_CHECK_EQUAL
(
write
(
send_socket
,
make_span
(
bufs
),
ep
),
packet_size
);
// receive both as one single packet.
buf
.
resize
(
packet_size
);
CAF_CHECK_EQUAL
(
read_from_socket
(
receive_socket
,
buf
),
none
);
CAF_CHECK_EQUAL
(
buf
.
size
(),
packet_size
);
binary_deserializer
source
(
nullptr
,
buf
);
header
recv_hdr
;
source
(
recv_hdr
);
CAF_CHECK_EQUAL
(
hdr
.
payload_size
,
recv_hdr
.
payload_size
);
string_view
received
{
reinterpret_cast
<
const
char
*>
(
buf
.
data
())
+
sizeof
(
header
),
buf
.
size
()
-
sizeof
(
header
)};
CAF_CHECK_EQUAL
(
received
,
hello_test
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment