summaryrefslogtreecommitdiff
path: root/forstio/io/io.h
blob: 4a87da5745e8a871004427c4306224294a63d5b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#pragma once

#include <forstio/async/async.h>
#include <forstio/core/common.h>
#include "io_helpers.h"

#include <string>
#include <variant>

namespace saw {
/*
 * Input stream
 */
class input_stream {
public:
	virtual ~input_stream() = default;

	virtual error_or<size_t> read(void *buffer, size_t length) = 0;

	virtual conveyor<void> read_ready() = 0;

	virtual conveyor<void> on_read_disconnected() = 0;
};

/*
 * Output stream
 */
class output_stream {
public:
	virtual ~output_stream() = default;

	virtual error_or<size_t> write(const void *buffer, size_t length) = 0;

	virtual conveyor<void> write_ready() = 0;
};

/*
 * Io stream
 */
class io_stream : public input_stream, public output_stream {
public:
	virtual ~io_stream() = default;
};

class async_input_stream {
public:
	virtual ~async_input_stream() = default;

	virtual void read(void *buffer, size_t min_length, size_t max_length) = 0;

	virtual conveyor<size_t> read_done() = 0;
	virtual conveyor<void> on_read_disconnected() = 0;
};

class async_output_stream {
public:
	virtual ~async_output_stream() = default;

	virtual void write(const void *buffer, size_t length) = 0;

	virtual conveyor<size_t> write_done() = 0;
};

class async_io_stream final : public async_input_stream,
							  public async_output_stream {
private:
	own<io_stream> stream_;

	conveyor_sink read_ready_;
	conveyor_sink write_ready_;
	conveyor_sink read_disconnected_;

	read_task_and_step_helper read_stepper_;
	write_task_and_step_helper write_stepper_;

public:
	async_io_stream(own<io_stream> str);

	SAW_FORBID_COPY(async_io_stream);
	SAW_FORBID_MOVE(async_io_stream);

	void read(void *buffer, size_t length, size_t max_length) override;

	conveyor<size_t> read_done() override;

	conveyor<void> on_read_disconnected() override;

	void write(const void *buffer, size_t length) override;

	conveyor<size_t> write_done() override;
};

class server {
public:
	virtual ~server() = default;

	virtual conveyor<own<io_stream>> accept() = 0;
};

class network_address;
/**
 * Datagram class. Bound to a local address it is able to receive inbound
 * datagram messages and send them as well as long as an address is provided as
 * well
 */
class datagram {
public:
	virtual ~datagram() = default;

	virtual error_or<size_t> read(void *buffer, size_t length) = 0;
	virtual conveyor<void> read_ready() = 0;

	virtual error_or<size_t> write(const void *buffer, size_t length,
								   network_address &dest) = 0;
	virtual conveyor<void> write_ready() = 0;
};

class os_network_address;
class string_network_address;

class network_address {
public:
	using child_variant =
		std::variant<os_network_address *, string_network_address *>;

	virtual ~network_address() = default;

	virtual network_address::child_variant representation() = 0;

	virtual const std::string &address() const = 0;
	virtual uint16_t port() const = 0;
};

class os_network_address : public network_address {
public:
	virtual ~os_network_address() = default;

	network_address::child_variant representation() override { return this; }
};

class string_network_address final : public network_address {
private:
	std::string address_value_;
	uint16_t port_value_;

public:
	string_network_address(const std::string &address, uint16_t port);

	const std::string &address() const override;
	uint16_t port() const override;

	network_address::child_variant representation() override { return this; }
};

class network {
public:
	virtual ~network() = default;

	/**
	 * Resolve the provided string and uint16 to the preferred storage method
	 */
	virtual conveyor<own<network_address>>
	resolve_address(const std::string &addr, uint16_t port_hint = 0) = 0;

	/**
	 * Parse the provided string and uint16 to the preferred storage method
	 * Since no dns request is made here, no async conveyors have to be used.
	 */
	/// @todo implement
	// virtual Own<NetworkAddress> parseAddress(const std::string& addr,
	// uint16_t port_hint = 0) = 0;

	/**
	 * Set up a listener on this address
	 */
	virtual own<server> listen(network_address &bind_addr) = 0;

	/**
	 * Connect to a remote address
	 */
	virtual conveyor<own<io_stream>> connect(network_address &address) = 0;

	/**
	 * Bind a datagram socket at this address.
	 */
	virtual own<datagram> datagram(network_address &address) = 0;
};

class io_provider {
public:
	virtual ~io_provider() = default;

	virtual own<input_stream> wrap_input_fd(int fd) = 0;

	virtual network &network() = 0;
};

struct async_io_context {
	own<io_provider> io;
	event_loop &event_loop;
	event_port &event_port;
};

error_or<async_io_context> setup_async_io();
} // namespace saw