Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
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
Operations
Operations
Metrics
Environments
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 Framework
Commits
f1a3b267
Commit
f1a3b267
authored
Feb 19, 2022
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow socket managers to transfer socket ownership
parent
085a1045
Changes
18
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
916 additions
and
477 deletions
+916
-477
libcaf_net/caf/net/connection_acceptor.hpp
libcaf_net/caf/net/connection_acceptor.hpp
+12
-8
libcaf_net/caf/net/endpoint_manager_impl.hpp
libcaf_net/caf/net/endpoint_manager_impl.hpp
+12
-5
libcaf_net/caf/net/hypertext_oriented_layer_ptr.hpp
libcaf_net/caf/net/hypertext_oriented_layer_ptr.hpp
+1
-1
libcaf_net/caf/net/message_flow_bridge.hpp
libcaf_net/caf/net/message_flow_bridge.hpp
+1
-1
libcaf_net/caf/net/multiplexer.hpp
libcaf_net/caf/net/multiplexer.hpp
+52
-7
libcaf_net/caf/net/pollset_updater.hpp
libcaf_net/caf/net/pollset_updater.hpp
+2
-2
libcaf_net/caf/net/socket_manager.hpp
libcaf_net/caf/net/socket_manager.hpp
+83
-55
libcaf_net/caf/net/stream_transport.hpp
libcaf_net/caf/net/stream_transport.hpp
+243
-107
libcaf_net/src/multiplexer.cpp
libcaf_net/src/multiplexer.cpp
+225
-115
libcaf_net/src/pollset_updater.cpp
libcaf_net/src/pollset_updater.cpp
+15
-13
libcaf_net/src/socket_manager.cpp
libcaf_net/src/socket_manager.cpp
+33
-43
libcaf_net/test/multiplexer.cpp
libcaf_net/test/multiplexer.cpp
+166
-70
libcaf_net/test/net-test.hpp
libcaf_net/test/net-test.hpp
+28
-0
libcaf_net/test/net/actor_shell.cpp
libcaf_net/test/net/actor_shell.cpp
+1
-0
libcaf_net/test/net/length_prefix_framing.cpp
libcaf_net/test/net/length_prefix_framing.cpp
+7
-4
libcaf_net/test/net/producer_adapter.cpp
libcaf_net/test/net/producer_adapter.cpp
+1
-2
libcaf_net/test/net/typed_actor_shell.cpp
libcaf_net/test/net/typed_actor_shell.cpp
+1
-0
libcaf_net/test/stream_transport.cpp
libcaf_net/test/stream_transport.cpp
+33
-44
No files found.
libcaf_net/caf/net/connection_acceptor.hpp
View file @
f1a3b267
...
...
@@ -28,6 +28,10 @@ public:
using
factory_type
=
Factory
;
using
read_result
=
typename
socket_manager
::
read_result
;
using
write_result
=
typename
socket_manager
::
write_result
;
// -- constructors, destructors, and assignment operators --------------------
template
<
class
...
Ts
>
...
...
@@ -51,28 +55,28 @@ public:
}
template
<
class
LowerLayerPtr
>
bool
handle_read_event
(
LowerLayerPtr
parent
)
{
read_result
handle_read_event
(
LowerLayerPtr
parent
)
{
CAF_LOG_TRACE
(
""
);
if
(
auto
x
=
accept
(
parent
->
handle
()))
{
socket_manager_ptr
child
=
factory_
.
make
(
*
x
,
owner_
->
mpx_ptr
());
if
(
!
child
)
{
CAF_LOG_ERROR
(
"factory failed to create a new child"
);
parent
->
abort_reason
(
sec
::
runtime_error
);
return
false
;
return
read_result
::
stop
;
}
if
(
auto
err
=
child
->
init
(
cfg_
))
{
CAF_LOG_ERROR
(
"failed to initialize new child:"
<<
err
);
parent
->
abort_reason
(
std
::
move
(
err
));
return
false
;
return
read_result
::
stop
;
}
if
(
limit_
==
0
)
{
return
true
;
return
read_result
::
again
;
}
else
{
return
++
accepted_
<
limit_
;
return
++
accepted_
<
limit_
?
read_result
::
again
:
read_result
::
stop
;
}
}
else
{
CAF_LOG_ERROR
(
"accept failed:"
<<
x
.
error
());
return
false
;
return
read_result
::
stop
;
}
}
...
...
@@ -82,9 +86,9 @@ public:
}
template
<
class
LowerLayerPtr
>
bool
handle_write_event
(
LowerLayerPtr
)
{
write_result
handle_write_event
(
LowerLayerPtr
)
{
CAF_LOG_ERROR
(
"connection_acceptor received write event"
);
return
false
;
return
write_result
::
stop
;
}
template
<
class
LowerLayerPtr
>
...
...
libcaf_net/caf/net/endpoint_manager_impl.hpp
View file @
f1a3b267
...
...
@@ -23,6 +23,10 @@ public:
using
application_type
=
typename
transport_type
::
application_type
;
using
read_result
=
typename
super
::
read_result
;
using
write_result
=
typename
super
::
write_result
;
// -- constructors, destructors, and assignment operators --------------------
endpoint_manager_impl
(
const
multiplexer_ptr
&
parent
,
actor_system
&
sys
,
...
...
@@ -52,11 +56,11 @@ public:
return
transport_
.
init
(
*
this
);
}
bool
handle_read_event
()
override
{
read_result
handle_read_event
()
override
{
return
transport_
.
handle_read_event
(
*
this
);
}
bool
handle_write_event
()
override
{
write_result
handle_write_event
()
override
{
if
(
!
this
->
queue_
.
blocked
())
{
this
->
queue_
.
fetch_more
();
auto
&
q
=
std
::
get
<
0
>
(
this
->
queue_
.
queue
().
queues
());
...
...
@@ -83,10 +87,13 @@ public:
}
if
(
!
transport_
.
handle_write_event
(
*
this
))
{
if
(
this
->
queue_
.
blocked
())
return
false
;
return
!
(
this
->
queue_
.
empty
()
&&
this
->
queue_
.
try_block
());
return
write_result
::
stop
;
else
if
(
!
(
this
->
queue_
.
empty
()
&&
this
->
queue_
.
try_block
()))
return
write_result
::
again
;
else
return
write_result
::
stop
;
}
return
true
;
return
write_result
::
again
;
}
void
handle_error
(
sec
code
)
override
{
...
...
libcaf_net/caf/net/hypertext_oriented_layer_ptr.hpp
View file @
f1a3b267
...
...
@@ -117,7 +117,7 @@ public:
std
::
string
len
;
header_fields_type
fields
;
if
(
!
content
.
empty
())
{
auto
len
=
std
::
to_string
(
content
.
size
());
len
=
std
::
to_string
(
content
.
size
());
fields
.
emplace
(
"Content-Type"
,
content_type
);
fields
.
emplace
(
"Content-Length"
,
len
);
}
...
...
libcaf_net/caf/net/message_flow_bridge.hpp
View file @
f1a3b267
...
...
@@ -160,7 +160,7 @@ public:
void
abort
(
LowerLayerPtr
,
const
error
&
reason
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
reason
));
if
(
out_
)
{
if
(
reason
==
sec
::
socket_disconnected
||
reason
==
sec
::
dis
card
ed
)
if
(
reason
==
sec
::
socket_disconnected
||
reason
==
sec
::
dis
pos
ed
)
out_
->
close
();
else
out_
->
abort
(
reason
);
...
...
libcaf_net/caf/net/multiplexer.hpp
View file @
f1a3b267
...
...
@@ -10,6 +10,7 @@
#include "caf/action.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/detail/unordered_flat_map.hpp"
#include "caf/net/fwd.hpp"
#include "caf/net/operation.hpp"
#include "caf/net/pipe_socket.hpp"
...
...
@@ -24,15 +25,28 @@ struct pollfd;
namespace
caf
::
net
{
class
pollset_updater
;
/// Multiplexes any number of ::socket_manager objects with a ::socket.
class
CAF_NET_EXPORT
multiplexer
{
public:
// -- member types -----------------------------------------------------------
struct
poll_update
{
short
events
=
0
;
socket_manager_ptr
mgr
;
};
using
poll_update_map
=
detail
::
unordered_flat_map
<
socket
,
poll_update
>
;
using
pollfd_list
=
std
::
vector
<
pollfd
>
;
using
manager_list
=
std
::
vector
<
socket_manager_ptr
>
;
// -- friends ----------------------------------------------------------------
friend
class
pollset_updater
;
// Needs access to the `do_*` functions.
// -- constructors, destructors, and assignment operators --------------------
/// @param parent Points to the owning middleman instance. May be `nullptr`
...
...
@@ -55,12 +69,18 @@ public:
/// Returns the index of `mgr` in the pollset or `-1`.
ptrdiff_t
index_of
(
const
socket_manager_ptr
&
mgr
);
/// Returns the index of `fd` in the pollset or `-1`.
ptrdiff_t
index_of
(
socket
fd
);
/// Returns the owning @ref middleman instance.
middleman
&
owner
();
/// Returns the enclosing @ref actor_system.
actor_system
&
system
();
/// Computes the current mask for the manager. Mostly useful for testing.
operation
mask_of
(
const
socket_manager_ptr
&
mgr
);
// -- thread-safe signaling --------------------------------------------------
/// Registers `mgr` for read events.
...
...
@@ -109,6 +129,9 @@ public:
/// ready as a result.
bool
poll_once
(
bool
blocking
);
/// Applies all pending updates.
void
apply_updates
();
/// Sets the thread ID to `std::this_thread::id()`.
void
set_thread_id
();
...
...
@@ -123,13 +146,7 @@ protected:
// -- utility functions ------------------------------------------------------
/// Handles an I/O event on given manager.
short
handle
(
const
socket_manager_ptr
&
mgr
,
short
events
,
short
revents
);
/// Adds a new socket manager to the pollset.
void
add
(
socket_manager_ptr
mgr
);
/// Deletes a known socket manager from the pollset.
void
del
(
ptrdiff_t
index
);
void
handle
(
const
socket_manager_ptr
&
mgr
,
short
events
,
short
revents
);
// -- member variables -------------------------------------------------------
...
...
@@ -140,6 +157,10 @@ protected:
/// order as their sockets appear in `pollset_`.
manager_list
managers_
;
/// Caches changes to the events mask of managed sockets until they can safely
/// take place.
poll_update_map
updates_
;
/// Stores the ID of the thread this multiplexer is running in. Set when
/// calling `init()`.
std
::
thread
::
id
tid_
;
...
...
@@ -157,15 +178,39 @@ protected:
bool
shutting_down_
=
false
;
private:
/// Returns a change entry for the socket at given index. Lazily creates a new
/// entry before returning if necessary.
poll_update
&
update_for
(
ptrdiff_t
index
);
/// Returns a change entry for the socket of the manager.
poll_update
&
update_for
(
const
socket_manager_ptr
&
mgr
);
/// Writes `opcode` and pointer to `mgr` the the pipe for handling an event
/// later via the pollset updater.
template
<
class
T
>
void
write_to_pipe
(
uint8_t
opcode
,
T
*
ptr
);
/// @copydoc write_to_pipe
template
<
class
Enum
,
class
T
>
std
::
enable_if_t
<
std
::
is_enum_v
<
Enum
>>
write_to_pipe
(
Enum
opcode
,
T
*
ptr
)
{
write_to_pipe
(
static_cast
<
uint8_t
>
(
opcode
),
ptr
);
}
// -- internal callback the pollset updater ----------------------------------
void
do_shutdown
();
void
do_register_reading
(
const
socket_manager_ptr
&
mgr
);
void
do_register_writing
(
const
socket_manager_ptr
&
mgr
);
void
do_discard
(
const
socket_manager_ptr
&
mgr
);
void
do_shutdown_reading
(
const
socket_manager_ptr
&
mgr
);
void
do_shutdown_writing
(
const
socket_manager_ptr
&
mgr
);
void
do_init
(
const
socket_manager_ptr
&
mgr
);
};
}
// namespace caf::net
libcaf_net/caf/net/pollset_updater.hpp
View file @
f1a3b267
...
...
@@ -51,9 +51,9 @@ public:
error
init
(
const
settings
&
config
)
override
;
bool
handle_read_event
()
override
;
read_result
handle_read_event
()
override
;
bool
handle_write_event
()
override
;
write_result
handle_write_event
()
override
;
void
handle_error
(
sec
code
)
override
;
...
...
libcaf_net/caf/net/socket_manager.hpp
View file @
f1a3b267
...
...
@@ -14,7 +14,6 @@
#include "caf/make_counted.hpp"
#include "caf/net/actor_shell.hpp"
#include "caf/net/fwd.hpp"
#include "caf/net/operation.hpp"
#include "caf/net/socket.hpp"
#include "caf/net/typed_actor_shell.hpp"
#include "caf/ref_counted.hpp"
...
...
@@ -28,13 +27,48 @@ class CAF_NET_EXPORT socket_manager : public ref_counted {
public:
// -- member types -----------------------------------------------------------
/// A callback for unprocessed messages.
using
fallback_handler
=
unique_callback_ptr
<
result
<
message
>
(
message
&
)
>
;
/// Encodes how a manager wishes to proceed after a read operation.
enum
class
read_result
{
/// Indicates that a manager wants to read again later.
again
,
/// Indicates that a manager wants to stop reading until explicitly resumed.
stop
,
/// Indicates that a manager wants to write to the socket instead of reading
/// from the socket.
want_write
,
/// Indicates that a manager is done with the socket and hands ownership to
/// another manager.
handover
,
};
/// Encodes how a manager wishes to proceed after a write operation.
enum
class
write_result
{
/// Indicates that a manager wants to read again later.
again
,
/// Indicates that a manager wants to stop reading until explicitly resumed.
stop
,
/// Indicates that a manager wants to read from the socket instead of
/// writing to the socket.
want_read
,
/// Indicates that a manager is done with the socket and hands ownership to
/// another manager.
handover
,
};
/// Stores manager-related flags in a single block.
struct
flags_t
{
bool
read_closed
:
1
;
bool
write_closed
:
1
;
};
// -- constructors, destructors, and assignment operators --------------------
/// @pre `handle != invalid_socket`
/// @pre `
parent
!= nullptr`
socket_manager
(
socket
handle
,
multiplexer
*
parent
);
/// @pre `
mpx
!= nullptr`
socket_manager
(
socket
handle
,
multiplexer
*
mpx
);
~
socket_manager
()
override
;
...
...
@@ -59,69 +93,45 @@ public:
/// Returns the owning @ref multiplexer instance.
multiplexer
&
mpx
()
noexcept
{
return
*
parent
_
;
return
*
mpx
_
;
}
/// Returns the owning @ref multiplexer instance.
const
multiplexer
&
mpx
()
const
noexcept
{
return
*
parent
_
;
return
*
mpx
_
;
}
/// Returns a pointer to the owning @ref multiplexer instance.
multiplexer
*
mpx_ptr
()
noexcept
{
return
parent
_
;
return
mpx
_
;
}
/// Returns a pointer to the owning @ref multiplexer instance.
const
multiplexer
*
mpx_ptr
()
const
noexcept
{
return
parent
_
;
return
mpx
_
;
}
/// Returns registered operations (read, write, or both).
operation
mask
()
const
noexcept
{
return
mask_
;
}
/// Closes the read channel of the socket.
void
close_read
()
noexcept
;
/// Convenience function for checking whether `mask()` contains the read bit.
bool
is_reading
()
const
noexcept
{
return
net
::
is_reading
(
mask_
);
}
/// Closes the write channel of the socket.
void
close_write
()
noexcept
;
///
Convenience function for checking whether `mask()` contains the write bi
t.
bool
is_writing
()
const
noexcept
{
return
net
::
is_writing
(
mask_
)
;
///
Returns whether the manager closed read operations on the socke
t.
[[
nodiscard
]]
bool
read_closed
()
const
noexcept
{
return
flags_
.
read_closed
;
}
/// Tries to add the read flag to the event mask.
/// @returns `true` if the flag was added, `false` if this call had no effect.
bool
set_read_flag
()
noexcept
;
/// Tries to add the write flag to the event mask.
/// @returns `true` if the flag was added, `false` if this call had no effect.
bool
set_write_flag
()
noexcept
;
/// Removes the read flag from the event mask if present.
bool
unset_read_flag
()
noexcept
;
/// Removes the write flag from the event mask if present.
bool
unset_write_flag
()
noexcept
;
/// Adds the `block_read` flag to the event mask.
void
block_reads
()
noexcept
;
/// Adds the `block_write` flag to the event mask.
void
block_writes
()
noexcept
;
/// Blocks reading and writing in the event mask.
void
block_reads_and_writes
()
noexcept
;
/// Returns whether the manager closed write operations on the socket.
[[
nodiscard
]]
bool
write_closed
()
const
noexcept
{
return
flags_
.
write_closed
;
}
const
error
&
abort_reason
()
const
noexcept
{
return
abort_reason_
;
}
void
abort_reason
(
error
reason
)
noexcept
{
abort_reason_
=
std
::
move
(
reason
);
}
void
abort_reason
(
error
reason
)
noexcept
;
template
<
class
...
Ts
>
const
error
&
abort_reason_or
(
Ts
&&
...
xs
)
{
...
...
@@ -153,23 +163,26 @@ public:
// -- event loop management --------------------------------------------------
/// Registers the manager for read operations on the @ref multiplexer.
void
register_reading
();
/// Registers the manager for write operations on the @ref multiplexer.
void
register_writing
();
void
shutdown_reading
();
void
shutdown_writing
();
/// Performs a handover to another manager after `handle_read_event` or
/// `handle_read_event` returned `handover`.
socket_manager_ptr
do_handover
();
// -- pure virtual member functions ------------------------------------------
/// Initializes the manager and its all of its sub-components.
virtual
error
init
(
const
settings
&
config
)
=
0
;
/// Called whenever the socket received new data.
virtual
bool
handle_read_event
()
=
0
;
virtual
read_result
handle_read_event
()
=
0
;
/// Called whenever the socket is allowed to send data.
virtual
bool
handle_write_event
()
=
0
;
virtual
write_result
handle_write_event
()
=
0
;
/// Called when the remote side becomes unreachable due to an error.
/// @param code The error code as reported by the operating system.
...
...
@@ -179,16 +192,25 @@ public:
/// function on active managers is a no-op.
virtual
void
continue_reading
()
=
0
;
/// Returns the new manager for the socket after `handle_read_event` or
/// `handle_read_event` returned `handover`.
/// @note When returning a non-null pointer, the new manager *must* also be
/// initialized.
virtual
socket_manager_ptr
make_next_manager
(
socket
handle
);
protected:
// --
member variables ----------
---------------------------------------------
// --
protected member variables
---------------------------------------------
socket
handle_
;
operation
mask
_
;
multiplexer
*
mpx
_
;
multiplexer
*
parent_
;
private:
// -- private member variables -----------------------------------------------
error
abort_reason_
;
flags_t
flags_
;
};
template
<
class
Protocol
>
...
...
@@ -196,10 +218,16 @@ class socket_manager_impl : public socket_manager {
public:
// -- member types -----------------------------------------------------------
using
super
=
socket_manager
;
using
output_tag
=
tag
::
io_event_oriented
;
using
socket_type
=
typename
Protocol
::
socket_type
;
using
read_result
=
typename
super
::
read_result
;
using
write_result
=
typename
super
::
write_result
;
// -- constructors, destructors, and assignment operators --------------------
template
<
class
...
Ts
>
...
...
@@ -228,20 +256,20 @@ public:
// -- event callbacks --------------------------------------------------------
bool
handle_read_event
()
override
{
read_result
handle_read_event
()
override
{
CAF_LOG_TRACE
(
""
);
return
protocol_
.
handle_read_event
(
this
);
}
bool
handle_write_event
()
override
{
write_result
handle_write_event
()
override
{
CAF_LOG_TRACE
(
""
);
return
protocol_
.
handle_write_event
(
this
);
}
void
handle_error
(
sec
code
)
override
{
CAF_LOG_TRACE
(
CAF_ARG
(
code
));
abort_reason_
=
code
;
return
protocol_
.
abort
(
this
,
abort_reason_
);
this
->
abort_reason
(
make_error
(
code
))
;
return
protocol_
.
abort
(
this
,
this
->
abort_reason
()
);
}
void
continue_reading
()
override
{
...
...
libcaf_net/caf/net/stream_transport.hpp
View file @
f1a3b267
This diff is collapsed.
Click to expand it.
libcaf_net/src/multiplexer.cpp
View file @
f1a3b267
This diff is collapsed.
Click to expand it.
libcaf_net/src/pollset_updater.cpp
View file @
f1a3b267
...
...
@@ -18,7 +18,7 @@ namespace caf::net {
pollset_updater
::
pollset_updater
(
pipe_socket
read_handle
,
multiplexer
*
parent
)
:
super
(
read_handle
,
parent
)
{
mask_
=
operation
::
read
;
// nop
}
pollset_updater
::~
pollset_updater
()
{
...
...
@@ -45,7 +45,7 @@ void run_action(intptr_t ptr) {
}
// namespace
bool
pollset_updater
::
handle_read_event
()
{
pollset_updater
::
read_result
pollset_updater
::
handle_read_event
()
{
CAF_LOG_TRACE
(
""
);
for
(;;)
{
CAF_ASSERT
((
buf_
.
size
()
-
buf_size_
)
>
0
);
...
...
@@ -60,29 +60,29 @@ bool pollset_updater::handle_read_event() {
memcpy
(
&
ptr
,
buf_
.
data
()
+
1
,
sizeof
(
intptr_t
));
switch
(
static_cast
<
code
>
(
opcode
))
{
case
code
:
:
register_reading
:
parent_
->
register_reading
(
as_mgr
(
ptr
));
mpx_
->
do_
register_reading
(
as_mgr
(
ptr
));
break
;
case
code
:
:
register_writing
:
parent_
->
register_writing
(
as_mgr
(
ptr
));
mpx_
->
do_
register_writing
(
as_mgr
(
ptr
));
break
;
case
code
:
:
init_manager
:
parent_
->
init
(
as_mgr
(
ptr
));
mpx_
->
do_
init
(
as_mgr
(
ptr
));
break
;
case
code
:
:
discard_manager
:
parent_
->
discard
(
as_mgr
(
ptr
));
mpx_
->
do_
discard
(
as_mgr
(
ptr
));
break
;
case
code
:
:
shutdown_reading
:
parent_
->
shutdown_reading
(
as_mgr
(
ptr
));
mpx_
->
do_
shutdown_reading
(
as_mgr
(
ptr
));
break
;
case
code
:
:
shutdown_writing
:
parent_
->
shutdown_writing
(
as_mgr
(
ptr
));
mpx_
->
do_
shutdown_writing
(
as_mgr
(
ptr
));
break
;
case
code
:
:
run_action
:
run_action
(
ptr
);
break
;
case
code
:
:
shutdown
:
CAF_ASSERT
(
ptr
==
0
);
parent_
->
shutdown
();
mpx_
->
do_
shutdown
();
break
;
default:
CAF_LOG_ERROR
(
"opcode not recognized: "
<<
CAF_ARG
(
opcode
));
...
...
@@ -91,15 +91,17 @@ bool pollset_updater::handle_read_event() {
}
}
else
if
(
num_bytes
==
0
)
{
CAF_LOG_DEBUG
(
"pipe closed, assume shutdown"
);
return
false
;
return
read_result
::
stop
;
}
else
if
(
last_socket_error_is_temporary
())
{
return
read_result
::
again
;
}
else
{
return
last_socket_error_is_temporary
()
;
return
read_result
::
stop
;
}
}
}
bool
pollset_updater
::
handle_write_event
()
{
return
false
;
pollset_updater
::
write_result
pollset_updater
::
handle_write_event
()
{
return
write_result
::
stop
;
}
void
pollset_updater
::
handle_error
(
sec
)
{
...
...
libcaf_net/src/socket_manager.cpp
View file @
f1a3b267
...
...
@@ -10,10 +10,11 @@
namespace
caf
::
net
{
socket_manager
::
socket_manager
(
socket
handle
,
multiplexer
*
parent
)
:
handle_
(
handle
),
m
ask_
(
operation
::
none
),
parent_
(
parent
)
{
socket_manager
::
socket_manager
(
socket
handle
,
multiplexer
*
mpx
)
:
handle_
(
handle
),
m
px_
(
mpx
)
{
CAF_ASSERT
(
handle_
!=
invalid_socket
);
CAF_ASSERT
(
parent
!=
nullptr
);
CAF_ASSERT
(
mpx_
!=
nullptr
);
memset
(
&
flags_
,
0
,
sizeof
(
flags_t
));
}
socket_manager
::~
socket_manager
()
{
...
...
@@ -21,62 +22,51 @@ socket_manager::~socket_manager() {
}
actor_system
&
socket_manager
::
system
()
noexcept
{
CAF_ASSERT
(
parent
_
!=
nullptr
);
return
parent
_
->
system
();
CAF_ASSERT
(
mpx
_
!=
nullptr
);
return
mpx
_
->
system
();
}
bool
socket_manager
::
set_read_flag
()
noexcept
{
auto
old
=
mask_
;
mask_
=
add_read_flag
(
mask_
);
return
old
!=
mask_
;
void
socket_manager
::
close_read
()
noexcept
{
// TODO: extend transport API for closing read operations.
flags_
.
read_closed
=
true
;
}
bool
socket_manager
::
set_write_flag
()
noexcept
{
auto
old
=
mask_
;
mask_
=
add_write_flag
(
mask_
);
return
old
!=
mask_
;
void
socket_manager
::
close_write
()
noexcept
{
// TODO: extend transport API for closing write operations.
flags_
.
write_closed
=
true
;
}
bool
socket_manager
::
unset_read_flag
()
noexcept
{
auto
old
=
mask_
;
mask_
=
remove_read_flag
(
mask_
);
return
old
!=
mask_
;
}
bool
socket_manager
::
unset_write_flag
()
noexcept
{
auto
old
=
mask_
;
mask_
=
remove_write_flag
(
mask_
);
return
old
!=
mask_
;
}
void
socket_manager
::
block_reads
()
noexcept
{
mask_
=
net
::
block_reads
(
mask_
);
}
void
socket_manager
::
block_writes
()
noexcept
{
mask_
=
net
::
block_writes
(
mask_
);
}
void
socket_manager
::
block_reads_and_writes
()
noexcept
{
mask_
=
operation
::
shutdown
;
void
socket_manager
::
abort_reason
(
error
reason
)
noexcept
{
abort_reason_
=
std
::
move
(
reason
);
flags_
.
read_closed
=
true
;
flags_
.
write_closed
=
true
;
}
void
socket_manager
::
register_reading
()
{
if
(
!
net
::
is_reading
(
mask_
)
&&
!
is_read_blocked
(
mask_
))
parent
_
->
register_reading
(
this
);
if
(
!
read_closed
(
))
mpx
_
->
register_reading
(
this
);
}
void
socket_manager
::
register_writing
()
{
if
(
!
net
::
is_writing
(
mask_
)
&&
!
is_write_blocked
(
mask_
))
parent
_
->
register_writing
(
this
);
if
(
!
write_closed
(
))
mpx
_
->
register_writing
(
this
);
}
void
socket_manager
::
shutdown_reading
()
{
parent_
->
shutdown_reading
(
this
);
socket_manager_ptr
socket_manager
::
do_handover
()
{
flags_
.
read_closed
=
true
;
flags_
.
write_closed
=
true
;
auto
hdl
=
handle_
;
handle_
=
invalid_socket
;
if
(
auto
ptr
=
make_next_manager
(
hdl
))
{
return
ptr
;
}
else
{
close
(
hdl
);
return
nullptr
;
}
}
void
socket_manager
::
shutdown_writing
(
)
{
parent_
->
shutdown_writing
(
this
)
;
socket_manager_ptr
socket_manager
::
make_next_manager
(
socket
)
{
return
{}
;
}
}
// namespace caf::net
libcaf_net/test/multiplexer.cpp
View file @
f1a3b267
...
...
@@ -6,8 +6,7 @@
#include "caf/net/multiplexer.hpp"
#include "caf/net/test/host_fixture.hpp"
#include "caf/test/dsl.hpp"
#include "net-test.hpp"
#include <new>
#include <tuple>
...
...
@@ -23,19 +22,21 @@ using namespace caf::net;
namespace
{
using
shared_atomic_count
=
std
::
shared_ptr
<
std
::
atomic
<
size_t
>>
;
class
dummy_manager
:
public
socket_manager
{
public:
dummy_manager
(
s
ize_t
&
manager_count
,
stream_socket
handl
e
,
multiplexer
*
pare
nt
)
:
socket_manager
(
handle
,
parent
),
count_
(
manager_
count
)
{
CAF_
MESSAGE
(
"created new dummy manager"
);
++
count_
;
dummy_manager
(
s
tream_socket
handle
,
multiplexer
*
parent
,
std
::
string
nam
e
,
shared_atomic_count
cou
nt
)
:
socket_manager
(
handle
,
parent
),
name
(
std
::
move
(
name
)),
count_
(
count
)
{
MESSAGE
(
"created new dummy manager"
);
++
*
count_
;
rd_buf_
.
resize
(
1024
);
}
~
dummy_manager
()
{
CAF_
MESSAGE
(
"destroyed dummy manager"
);
--
count_
;
MESSAGE
(
"destroyed dummy manager"
);
--
*
count_
;
}
error
init
(
const
settings
&
)
override
{
...
...
@@ -46,7 +47,11 @@ public:
return
socket_cast
<
stream_socket
>
(
handle_
);
}
bool
handle_read_event
()
override
{
read_result
handle_read_event
()
override
{
if
(
trigger_handover
)
{
MESSAGE
(
name
<<
" triggered a handover"
);
return
read_result
::
handover
;
}
if
(
read_capacity
()
<
1024
)
rd_buf_
.
resize
(
rd_buf_
.
size
()
+
2048
);
auto
num_bytes
=
read
(
handle
(),
...
...
@@ -54,28 +59,47 @@ public:
if
(
num_bytes
>
0
)
{
CAF_ASSERT
(
num_bytes
>
0
);
rd_buf_pos_
+=
num_bytes
;
return
true
;
return
read_result
::
again
;
}
else
if
(
num_bytes
<
0
&&
last_socket_error_is_temporary
())
{
return
read_result
::
again
;
}
else
{
return
read_result
::
stop
;
}
return
num_bytes
<
0
&&
last_socket_error_is_temporary
();
}
bool
handle_write_event
()
override
{
write_result
handle_write_event
()
override
{
if
(
trigger_handover
)
{
MESSAGE
(
name
<<
" triggered a handover"
);
return
write_result
::
handover
;
}
if
(
wr_buf_
.
size
()
==
0
)
return
false
;
return
write_result
::
stop
;
auto
num_bytes
=
write
(
handle
(),
wr_buf_
);
if
(
num_bytes
>
0
)
{
wr_buf_
.
erase
(
wr_buf_
.
begin
(),
wr_buf_
.
begin
()
+
num_bytes
);
return
wr_buf_
.
size
()
>
0
;
return
wr_buf_
.
size
()
>
0
?
write_result
::
again
:
write_result
::
stop
;
}
return
num_bytes
<
0
&&
last_socket_error_is_temporary
();
return
num_bytes
<
0
&&
last_socket_error_is_temporary
()
?
write_result
::
again
:
write_result
::
stop
;
}
void
handle_error
(
sec
code
)
override
{
CAF_
FAIL
(
"handle_error called with code "
<<
code
);
FAIL
(
"handle_error called with code "
<<
code
);
}
void
continue_reading
()
override
{
CAF_FAIL
(
"continue_reading called"
);
FAIL
(
"continue_reading called"
);
}
socket_manager_ptr
make_next_manager
(
socket
handle
)
override
{
if
(
next
!=
nullptr
)
FAIL
(
"asked to do handover twice!"
);
next
=
make_counted
<
dummy_manager
>
(
socket_cast
<
stream_socket
>
(
handle
),
mpx_
,
"Carl"
,
count_
);
if
(
auto
err
=
next
->
init
(
settings
{}))
FAIL
(
"next->init failed: "
<<
err
);
return
next
;
}
void
send
(
string_view
x
)
{
...
...
@@ -89,6 +113,12 @@ public:
return
result
;
}
bool
trigger_handover
=
false
;
intrusive_ptr
<
dummy_manager
>
next
;
std
::
string
name
;
private:
byte
*
read_position_begin
()
{
return
rd_buf_
.
data
()
+
rd_buf_pos_
;
...
...
@@ -102,7 +132,7 @@ private:
return
rd_buf_
.
size
()
-
rd_buf_pos_
;
}
s
ize_t
&
count_
;
s
hared_atomic_count
count_
;
size_t
rd_buf_pos_
=
0
;
...
...
@@ -115,84 +145,150 @@ using dummy_manager_ptr = intrusive_ptr<dummy_manager>;
struct
fixture
:
host_fixture
{
fixture
()
:
mpx
(
nullptr
)
{
manager_count
=
std
::
make_shared
<
std
::
atomic
<
size_t
>>
(
0
);
mpx
.
set_thread_id
();
}
~
fixture
()
{
CAF_REQUIRE_EQUAL
(
manager_count
,
0u
);
mpx
.
shutdown
();
exhaust
();
REQUIRE_EQ
(
*
manager_count
,
0u
);
}
void
exhaust
()
{
mpx
.
apply_updates
();
while
(
mpx
.
poll_once
(
false
))
;
// Repeat.
}
size_t
manager_count
=
0
;
void
apply_updates
()
{
mpx
.
apply_updates
();
}
auto
make_manager
(
stream_socket
fd
,
std
::
string
name
)
{
return
make_counted
<
dummy_manager
>
(
fd
,
&
mpx
,
std
::
move
(
name
),
manager_count
);
}
void
init
()
{
if
(
auto
err
=
mpx
.
init
())
FAIL
(
"mpx.init failed: "
<<
err
);
exhaust
();
}
shared_atomic_count
manager_count
;
multiplexer
mpx
;
};
}
// namespace
CAF_TEST_FIXTURE_SCOPE
(
multiplexer_tests
,
fixture
)
BEGIN_FIXTURE_SCOPE
(
fixture
)
CAF_TEST
(
default
construction
)
{
CAF_CHECK_EQUAL
(
mpx
.
num_socket_managers
(),
0u
);
SCENARIO
(
"the multiplexer has no socket managers after default construction"
)
{
GIVEN
(
"a default constructed multiplexer"
)
{
WHEN
(
"querying the number of socket managers"
)
{
THEN
(
"the result is 0"
)
{
CHECK_EQ
(
mpx
.
num_socket_managers
(),
0u
);
}
}
}
}
SCENARIO
(
"the multiplexer constructs the pollset updater while initializing"
)
{
GIVEN
(
"an initialized multiplexer"
)
{
WHEN
(
"querying the number of socket managers"
)
{
THEN
(
"the result is 1"
)
{
CHECK_EQ
(
mpx
.
num_socket_managers
(),
0u
);
CHECK_EQ
(
mpx
.
init
(),
none
);
exhaust
();
CHECK_EQ
(
mpx
.
num_socket_managers
(),
1u
);
}
}
}
}
CAF_TEST
(
init
)
{
CAF_CHECK_EQUAL
(
mpx
.
num_socket_managers
(),
0u
);
CAF_REQUIRE_EQUAL
(
mpx
.
init
(),
none
);
CAF_CHECK_EQUAL
(
mpx
.
num_socket_managers
(),
1u
);
mpx
.
shutdown
();
exhaust
();
// Calling run must have no effect now.
mpx
.
run
();
SCENARIO
(
"socket managers can register for read and write operations"
)
{
GIVEN
(
"an initialized multiplexer"
)
{
init
();
WHEN
(
"socket managers register for read and write operations"
)
{
auto
[
alice_fd
,
bob_fd
]
=
unbox
(
make_stream_socket_pair
());
auto
alice
=
make_manager
(
alice_fd
,
"Alice"
);
auto
bob
=
make_manager
(
bob_fd
,
"Bob"
);
alice
->
register_reading
();
bob
->
register_reading
();
apply_updates
();
CHECK_EQ
(
mpx
.
num_socket_managers
(),
3u
);
THEN
(
"the multiplexer runs callbacks on socket activity"
)
{
alice
->
send
(
"Hello Bob!"
);
alice
->
register_writing
();
exhaust
();
CHECK_EQ
(
bob
->
receive
(),
"Hello Bob!"
);
}
}
}
}
CAF_TEST
(
send
and
receive
)
{
CAF_REQUIRE_EQUAL
(
mpx
.
init
(),
none
);
auto
sockets
=
unbox
(
make_stream_socket_pair
());
{
// Lifetime scope of alice and bob.
auto
alice
=
make_counted
<
dummy_manager
>
(
manager_count
,
sockets
.
first
,
&
mpx
);
auto
bob
=
make_counted
<
dummy_manager
>
(
manager_count
,
sockets
.
second
,
&
mpx
);
SCENARIO
(
"a multiplexer terminates its thread after shutting down"
)
{
GIVEN
(
"a multiplexer running in its own thread and some socket managers"
)
{
init
();
auto
go_time
=
std
::
make_shared
<
barrier
>
(
2
);
auto
mpx_thread
=
std
::
thread
{[
this
,
go_time
]
{
mpx
.
set_thread_id
();
go_time
->
arrive_and_wait
();
mpx
.
run
();
}};
go_time
->
arrive_and_wait
();
auto
[
alice_fd
,
bob_fd
]
=
unbox
(
make_stream_socket_pair
());
auto
alice
=
make_manager
(
alice_fd
,
"Alice"
);
auto
bob
=
make_manager
(
bob_fd
,
"Bob"
);
alice
->
register_reading
();
bob
->
register_reading
();
CAF_CHECK_EQUAL
(
mpx
.
num_socket_managers
(),
3u
);
alice
->
send
(
"hello bob"
);
alice
->
register_writing
();
exhaust
();
CAF_CHECK_EQUAL
(
bob
->
receive
(),
"hello bob"
);
WHEN
(
"calling shutdown on the multiplexer"
)
{
mpx
.
shutdown
();
THEN
(
"the thread terminates and all socket managers get shut down"
)
{
mpx_thread
.
join
();
CHECK
(
alice
->
read_closed
());
CHECK
(
bob
->
read_closed
());
}
}
}
mpx
.
shutdown
();
}
CAF_TEST
(
shutdown
)
{
std
::
mutex
m
;
std
::
condition_variable
cv
;
bool
thread_id_set
=
false
;
auto
run_mpx
=
[
&
]
{
{
std
::
unique_lock
<
std
::
mutex
>
guard
(
m
);
mpx
.
set_thread_id
();
thread_id_set
=
true
;
cv
.
notify_one
();
SCENARIO
(
"a multiplexer allows managers to perform socket handovers"
)
{
GIVEN
(
"an initialized multiplexer"
)
{
init
();
WHEN
(
"socket manager triggers a handover"
)
{
auto
[
alice_fd
,
bob_fd
]
=
unbox
(
make_stream_socket_pair
());
auto
alice
=
make_manager
(
alice_fd
,
"Alice"
);
auto
bob
=
make_manager
(
bob_fd
,
"Bob"
);
alice
->
register_reading
();
bob
->
register_reading
();
apply_updates
();
CHECK_EQ
(
mpx
.
num_socket_managers
(),
3u
);
THEN
(
"the multiplexer swaps out the socket managers for the socket"
)
{
alice
->
send
(
"Hello Bob!"
);
alice
->
register_writing
();
exhaust
();
CHECK_EQ
(
bob
->
receive
(),
"Hello Bob!"
);
bob
->
trigger_handover
=
true
;
alice
->
send
(
"Hello Carl!"
);
alice
->
register_writing
();
bob
->
register_reading
();
exhaust
();
CHECK_EQ
(
bob
->
receive
(),
""
);
CHECK_EQ
(
bob
->
handle
(),
invalid_socket
);
if
(
CHECK_NE
(
bob
->
next
,
nullptr
))
{
auto
carl
=
bob
->
next
;
CHECK_EQ
(
carl
->
handle
(),
socket
{
bob_fd
});
carl
->
register_reading
();
exhaust
();
CHECK_EQ
(
carl
->
name
,
"Carl"
);
CHECK_EQ
(
carl
->
receive
(),
"Hello Carl!"
);
}
}
}
mpx
.
run
();
};
CAF_REQUIRE_EQUAL
(
mpx
.
init
(),
none
);
auto
sockets
=
unbox
(
make_stream_socket_pair
());
auto
alice
=
make_counted
<
dummy_manager
>
(
manager_count
,
sockets
.
first
,
&
mpx
);
auto
bob
=
make_counted
<
dummy_manager
>
(
manager_count
,
sockets
.
second
,
&
mpx
);
alice
->
register_reading
();
bob
->
register_reading
();
CAF_REQUIRE_EQUAL
(
mpx
.
num_socket_managers
(),
3u
);
std
::
thread
mpx_thread
{
run_mpx
};
std
::
unique_lock
<
std
::
mutex
>
lk
(
m
);
cv
.
wait
(
lk
,
[
&
]
{
return
thread_id_set
;
});
mpx
.
shutdown
();
mpx_thread
.
join
();
}
}
CAF_TEST_FIXTURE_SCOPE_END
()
END_FIXTURE_SCOPE
()
libcaf_net/test/net-test.hpp
View file @
f1a3b267
...
...
@@ -148,3 +148,31 @@ private:
caf
::
error
abort_reason_
;
};
// Drop-in replacement for std::barrier (based on the TS API as of 2020).
class
barrier
{
public:
explicit
barrier
(
ptrdiff_t
num_threads
)
:
num_threads_
(
num_threads
),
count_
(
0
)
{
// nop
}
void
arrive_and_wait
()
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mx_
};
auto
new_count
=
++
count_
;
if
(
new_count
==
num_threads_
)
{
cv_
.
notify_all
();
}
else
if
(
new_count
>
num_threads_
)
{
count_
=
1
;
cv_
.
wait
(
guard
,
[
this
]
{
return
count_
.
load
()
==
num_threads_
;
});
}
else
{
cv_
.
wait
(
guard
,
[
this
]
{
return
count_
.
load
()
==
num_threads_
;
});
}
}
private:
ptrdiff_t
num_threads_
;
std
::
mutex
mx_
;
std
::
atomic
<
ptrdiff_t
>
count_
;
std
::
condition_variable
cv_
;
};
libcaf_net/test/net/actor_shell.cpp
View file @
f1a3b267
...
...
@@ -163,6 +163,7 @@ struct fixture : host_fixture, test_coordinator_fixture<> {
if
(
!
predicate
())
return
;
for
(
size_t
i
=
0
;
i
<
1000
;
++
i
)
{
mpx
.
apply_updates
();
mpx
.
poll_once
(
false
);
byte
tmp
[
1024
];
auto
bytes
=
read
(
self_socket_guard
.
socket
(),
make_span
(
tmp
,
1024
));
...
...
libcaf_net/test/net/length_prefix_framing.cpp
View file @
f1a3b267
...
...
@@ -153,22 +153,24 @@ SCENARIO("calling suspend_reading removes message apps temporarily") {
}
}};
net
::
multiplexer
mpx
{
nullptr
};
mpx
.
set_thread_id
();
if
(
auto
err
=
mpx
.
init
())
FAIL
(
"mpx.init failed: "
<<
err
);
mpx
.
set_thread_id
();
mpx
.
apply_updates
();
REQUIRE_EQ
(
mpx
.
num_socket_managers
(),
1u
);
if
(
auto
err
=
net
::
nonblocking
(
fd2
,
true
))
CAF_FAIL
(
"nonblocking returned an error: "
<<
err
);
auto
mgr
=
net
::
make_socket_manager
<
app
<
true
>
,
net
::
length_prefix_framing
,
net
::
stream_transport
>
(
fd2
,
&
mpx
);
CHECK_EQ
(
mgr
->
init
(
settings
{}),
none
);
mpx
.
apply_updates
();
REQUIRE_EQ
(
mpx
.
num_socket_managers
(),
2u
);
CHECK_EQ
(
m
gr
->
mask
(
),
net
::
operation
::
read
);
CHECK_EQ
(
m
px
.
mask_of
(
mgr
),
net
::
operation
::
read
);
auto
&
state
=
mgr
->
top_layer
();
WHEN
(
"the app calls suspend_reading"
)
{
while
(
mpx
.
num_socket_managers
()
>
1u
)
mpx
.
poll_once
(
true
);
CHECK_EQ
(
m
gr
->
mask
(
),
net
::
operation
::
none
);
CHECK_EQ
(
m
px
.
mask_of
(
mgr
),
net
::
operation
::
none
);
if
(
CHECK_EQ
(
state
.
inputs
.
size
(),
3u
))
{
CHECK_EQ
(
state
.
inputs
[
0
],
"first"
);
CHECK_EQ
(
state
.
inputs
[
1
],
"second"
);
...
...
@@ -176,7 +178,8 @@ SCENARIO("calling suspend_reading removes message apps temporarily") {
}
THEN
(
"users can resume it via continue_reading "
)
{
mgr
->
continue_reading
();
CHECK_EQ
(
mgr
->
mask
(),
net
::
operation
::
read
);
mpx
.
apply_updates
();
CHECK_EQ
(
mpx
.
mask_of
(
mgr
),
net
::
operation
::
read
);
while
(
mpx
.
num_socket_managers
()
>
1u
)
mpx
.
poll_once
(
true
);
if
(
CHECK_EQ
(
state
.
inputs
.
size
(),
5u
))
{
...
...
libcaf_net/test/net/producer_adapter.cpp
View file @
f1a3b267
...
...
@@ -89,8 +89,7 @@ public:
template
<
class
LowerLayerPtr
>
void
abort
(
LowerLayerPtr
,
const
error
&
reason
)
{
if
(
reason
==
caf
::
sec
::
socket_disconnected
||
reason
==
caf
::
sec
::
discarded
)
if
(
reason
==
caf
::
sec
::
socket_disconnected
||
reason
==
caf
::
sec
::
disposed
)
adapter_
->
close
();
else
adapter_
->
abort
(
reason
);
...
...
libcaf_net/test/net/typed_actor_shell.cpp
View file @
f1a3b267
...
...
@@ -166,6 +166,7 @@ struct fixture : host_fixture, test_coordinator_fixture<> {
if
(
!
predicate
())
return
;
for
(
size_t
i
=
0
;
i
<
1000
;
++
i
)
{
mpx
.
apply_updates
();
mpx
.
poll_once
(
false
);
byte
tmp
[
1024
];
auto
bytes
=
read
(
self_socket_guard
.
socket
(),
make_span
(
tmp
,
1024
));
...
...
libcaf_net/test/stream_transport.cpp
View file @
f1a3b267
...
...
@@ -6,8 +6,7 @@
#include "caf/net/stream_transport.hpp"
#include "caf/net/test/host_fixture.hpp"
#include "caf/test/dsl.hpp"
#include "net-test.hpp"
#include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
...
...
@@ -26,6 +25,7 @@ using namespace caf;
using
namespace
caf
::
net
;
namespace
{
constexpr
string_view
hello_manager
=
"hello manager!"
;
struct
fixture
:
test_coordinator_fixture
<>
,
host_fixture
{
...
...
@@ -36,15 +36,16 @@ struct fixture : test_coordinator_fixture<>, host_fixture {
recv_buf
(
1024
),
shared_recv_buf
{
std
::
make_shared
<
byte_buffer
>
()},
shared_send_buf
{
std
::
make_shared
<
byte_buffer
>
()}
{
if
(
auto
err
=
mpx
.
init
())
CAF_FAIL
(
"mpx.init failed: "
<<
err
);
mpx
.
set_thread_id
();
CAF_CHECK_EQUAL
(
mpx
.
num_socket_managers
(),
1u
);
mpx
.
apply_updates
();
if
(
auto
err
=
mpx
.
init
())
FAIL
(
"mpx.init failed: "
<<
err
);
REQUIRE_EQ
(
mpx
.
num_socket_managers
(),
1u
);
auto
sockets
=
unbox
(
make_stream_socket_pair
());
send_socket_guard
.
reset
(
sockets
.
first
);
recv_socket_guard
.
reset
(
sockets
.
second
);
if
(
auto
err
=
nonblocking
(
recv_socket_guard
.
socket
(),
true
))
CAF_
FAIL
(
"nonblocking returned an error: "
<<
err
);
FAIL
(
"nonblocking returned an error: "
<<
err
);
}
bool
handle_io_event
()
override
{
...
...
@@ -82,7 +83,7 @@ public:
template
<
class
ParentPtr
>
bool
prepare_send
(
ParentPtr
parent
)
{
CAF_
MESSAGE
(
"prepare_send called"
);
MESSAGE
(
"prepare_send called"
);
auto
&
buf
=
parent
->
output_buffer
();
auto
data
=
as_bytes
(
make_span
(
hello_manager
));
buf
.
insert
(
buf
.
end
(),
data
.
begin
(),
data
.
end
());
...
...
@@ -91,44 +92,30 @@ public:
template
<
class
ParentPtr
>
bool
done_sending
(
ParentPtr
)
{
CAF_
MESSAGE
(
"done_sending called"
);
MESSAGE
(
"done_sending called"
);
return
true
;
}
template
<
class
ParentPtr
>
void
continue_reading
(
ParentPtr
)
{
CAF_
FAIL
(
"continue_reading called"
);
FAIL
(
"continue_reading called"
);
}
template
<
class
ParentPtr
>
size_t
consume
(
ParentPtr
,
span
<
const
byte
>
data
,
span
<
const
byte
>
)
{
recv_buf_
->
clear
();
recv_buf_
->
insert
(
recv_buf_
->
begin
(),
data
.
begin
(),
data
.
end
());
CAF_MESSAGE
(
"Received "
<<
recv_buf_
->
size
()
<<
" bytes in dummy_application"
);
MESSAGE
(
"Received "
<<
recv_buf_
->
size
()
<<
" bytes in dummy_application"
);
return
recv_buf_
->
size
();
}
template
<
class
ParentPtr
>
void
resolve
(
ParentPtr
parent
,
string_view
path
,
const
actor
&
listener
)
{
actor_id
aid
=
42
;
auto
hid
=
string_view
(
"0011223344556677889900112233445566778899"
);
auto
nid
=
unbox
(
make_node_id
(
42
,
hid
));
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_v
,
std
::
string
{
path
.
begin
(),
path
.
end
()},
p
);
}
static
void
handle_error
(
sec
code
)
{
CAF_
FAIL
(
"handle_error called with "
<<
CAF_ARG
(
code
));
FAIL
(
"handle_error called with "
<<
CAF_ARG
(
code
));
}
template
<
class
ParentPtr
>
static
void
abort
(
ParentPtr
,
const
error
&
reason
)
{
CAF_
FAIL
(
"abort called with "
<<
CAF_ARG
(
reason
));
FAIL
(
"abort called with "
<<
CAF_ARG
(
reason
));
}
private:
...
...
@@ -138,39 +125,41 @@ private:
}
// namespace
CAF_TEST_FIXTURE_SCOPE
(
endpoint_manager_tests
,
fixture
)
BEGIN_FIXTURE_SCOPE
(
fixture
)
CAF_TEST
(
receive
)
{
auto
mgr
=
make_socket_manager
<
dummy_application
,
stream_transport
>
(
recv_socket_guard
.
release
(),
&
mpx
,
shared_recv_buf
,
shared_send_buf
);
C
AF_CHECK_EQUAL
(
mgr
->
init
(
config
),
none
);
CAF_CHECK_EQUAL
(
mpx
.
num_socket_managers
(),
2u
);
C
AF_CHECK_EQUAL
(
static_cast
<
size_t
>
(
write
(
send_socket_guard
.
socket
(),
as_bytes
(
make_span
(
hello_manager
)))),
hello_manager
.
size
());
CAF_
MESSAGE
(
"wrote "
<<
hello_manager
.
size
()
<<
" bytes."
);
C
HECK_EQ
(
mgr
->
init
(
config
),
none
);
mpx
.
apply_updates
(
);
C
HECK_EQ
(
mpx
.
num_socket_managers
(),
2u
);
CHECK_EQ
(
static_cast
<
size_t
>
(
write
(
send_socket_guard
.
socket
(),
as_bytes
(
make_span
(
hello_manager
)))),
hello_manager
.
size
());
MESSAGE
(
"wrote "
<<
hello_manager
.
size
()
<<
" bytes."
);
run
();
C
AF_CHECK_EQUAL
(
string_view
(
reinterpret_cast
<
char
*>
(
shared_recv_buf
->
data
()),
shared_recv_buf
->
size
()),
hello_manager
);
C
HECK_EQ
(
string_view
(
reinterpret_cast
<
char
*>
(
shared_recv_buf
->
data
()),
shared_recv_buf
->
size
()),
hello_manager
);
}
CAF_TEST
(
send
)
{
auto
mgr
=
make_socket_manager
<
dummy_application
,
stream_transport
>
(
recv_socket_guard
.
release
(),
&
mpx
,
shared_recv_buf
,
shared_send_buf
);
CAF_CHECK_EQUAL
(
mgr
->
init
(
config
),
none
);
CAF_CHECK_EQUAL
(
mpx
.
num_socket_managers
(),
2u
);
CHECK_EQ
(
mgr
->
init
(
config
),
none
);
mpx
.
apply_updates
();
CHECK_EQ
(
mpx
.
num_socket_managers
(),
2u
);
mgr
->
register_writing
();
mpx
.
apply_updates
();
while
(
handle_io_event
())
;
recv_buf
.
resize
(
hello_manager
.
size
());
auto
res
=
read
(
send_socket_guard
.
socket
(),
make_span
(
recv_buf
));
CAF_
MESSAGE
(
"received "
<<
res
<<
" bytes"
);
MESSAGE
(
"received "
<<
res
<<
" bytes"
);
recv_buf
.
resize
(
res
);
C
AF_CHECK_EQUAL
(
string_view
(
reinterpret_cast
<
char
*>
(
recv_buf
.
data
()),
recv_buf
.
size
()),
hello_manager
);
C
HECK_EQ
(
string_view
(
reinterpret_cast
<
char
*>
(
recv_buf
.
data
()),
recv_buf
.
size
()),
hello_manager
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
END_FIXTURE_SCOPE
()
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