summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>2016-11-25 17:18:34 -0200
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>2016-11-25 17:27:32 -0200
commit167ff29ea004f6d2d22e5f94a3b0b64fb19da44b (patch)
tree945137250f08304d48434262a92874ed57c0af05 /src
parent46341b329d72736c1f1c47478f760ab8db76bbc8 (diff)
efl_net_{socket,dialer,server}_simple: easy to use, buffered network sockets.
The low level I/O primitives are powerful but adds some complexity to use, for bi-directional streaming communication one ends creating two Efl.Io.Queue and two Efl.Io.Copier to pipe data to socket when it can operate. Then encapsulate the socket using the new Efl.Io.Buffered_Stream, this will allow the socket, be a dialer or a server client, to be operated as a single handle that internally carries about the buffering for you. As one can see in the examples, compared to their "manual" alternatives they are very easy to use, ressembling Ecore_Con_Server/Ecore_Con_Client, but also offers line-based delimiters and the possibility to let the socket to handle queueing for you in case you received partial messages (just do not read/clear/discard the received data).
Diffstat (limited to 'src')
-rw-r--r--src/Makefile_Ecore_Con.am6
-rw-r--r--src/examples/ecore/.gitignore2
-rw-r--r--src/examples/ecore/Makefile.am10
-rw-r--r--src/examples/ecore/efl_net_dialer_simple_example.c451
-rw-r--r--src/examples/ecore/efl_net_server_simple_example.c559
-rw-r--r--src/lib/ecore_con/Ecore_Con_Eo.h4
-rw-r--r--src/lib/ecore_con/efl_net_dialer_simple.c367
-rw-r--r--src/lib/ecore_con/efl_net_dialer_simple.eo85
-rw-r--r--src/lib/ecore_con/efl_net_server_simple.c243
-rw-r--r--src/lib/ecore_con/efl_net_server_simple.eo55
-rw-r--r--src/lib/ecore_con/efl_net_socket_simple.c35
-rw-r--r--src/lib/ecore_con/efl_net_socket_simple.eo45
12 files changed, 1862 insertions, 0 deletions
diff --git a/src/Makefile_Ecore_Con.am b/src/Makefile_Ecore_Con.am
index d661861..82221e7 100644
--- a/src/Makefile_Ecore_Con.am
+++ b/src/Makefile_Ecore_Con.am
@@ -7,15 +7,18 @@ ecore_con_eolian_files = \
7 lib/ecore_con/efl_network_server.eo \ 7 lib/ecore_con/efl_network_server.eo \
8 lib/ecore_con/efl_network_connector.eo \ 8 lib/ecore_con/efl_network_connector.eo \
9 lib/ecore_con/efl_net_socket.eo \ 9 lib/ecore_con/efl_net_socket.eo \
10 lib/ecore_con/efl_net_socket_simple.eo \
10 lib/ecore_con/efl_net_socket_fd.eo \ 11 lib/ecore_con/efl_net_socket_fd.eo \
11 lib/ecore_con/efl_net_socket_tcp.eo \ 12 lib/ecore_con/efl_net_socket_tcp.eo \
12 lib/ecore_con/efl_net_socket_udp.eo \ 13 lib/ecore_con/efl_net_socket_udp.eo \
13 lib/ecore_con/efl_net_dialer.eo \ 14 lib/ecore_con/efl_net_dialer.eo \
15 lib/ecore_con/efl_net_dialer_simple.eo \
14 lib/ecore_con/efl_net_dialer_tcp.eo \ 16 lib/ecore_con/efl_net_dialer_tcp.eo \
15 lib/ecore_con/efl_net_dialer_udp.eo \ 17 lib/ecore_con/efl_net_dialer_udp.eo \
16 lib/ecore_con/efl_net_dialer_http.eo \ 18 lib/ecore_con/efl_net_dialer_http.eo \
17 lib/ecore_con/efl_net_dialer_websocket.eo \ 19 lib/ecore_con/efl_net_dialer_websocket.eo \
18 lib/ecore_con/efl_net_server.eo \ 20 lib/ecore_con/efl_net_server.eo \
21 lib/ecore_con/efl_net_server_simple.eo \
19 lib/ecore_con/efl_net_server_fd.eo \ 22 lib/ecore_con/efl_net_server_fd.eo \
20 lib/ecore_con/efl_net_server_tcp.eo \ 23 lib/ecore_con/efl_net_server_tcp.eo \
21 lib/ecore_con/efl_net_server_udp.eo \ 24 lib/ecore_con/efl_net_server_udp.eo \
@@ -92,15 +95,18 @@ static_libs/http-parser/http_parser.h \
92lib/ecore_con/ecore_con_private.h \ 95lib/ecore_con/ecore_con_private.h \
93lib/ecore_con/ecore_con_info.c \ 96lib/ecore_con/ecore_con_info.c \
94lib/ecore_con/efl_net_socket.c \ 97lib/ecore_con/efl_net_socket.c \
98lib/ecore_con/efl_net_socket_simple.c \
95lib/ecore_con/efl_net_socket_fd.c \ 99lib/ecore_con/efl_net_socket_fd.c \
96lib/ecore_con/efl_net_socket_tcp.c \ 100lib/ecore_con/efl_net_socket_tcp.c \
97lib/ecore_con/efl_net_socket_udp.c \ 101lib/ecore_con/efl_net_socket_udp.c \
98lib/ecore_con/efl_net_dialer.c \ 102lib/ecore_con/efl_net_dialer.c \
103lib/ecore_con/efl_net_dialer_simple.c \
99lib/ecore_con/efl_net_dialer_tcp.c \ 104lib/ecore_con/efl_net_dialer_tcp.c \
100lib/ecore_con/efl_net_dialer_udp.c \ 105lib/ecore_con/efl_net_dialer_udp.c \
101lib/ecore_con/efl_net_dialer_http.c \ 106lib/ecore_con/efl_net_dialer_http.c \
102lib/ecore_con/efl_net_dialer_websocket.c \ 107lib/ecore_con/efl_net_dialer_websocket.c \
103lib/ecore_con/efl_net_server.c \ 108lib/ecore_con/efl_net_server.c \
109lib/ecore_con/efl_net_server_simple.c \
104lib/ecore_con/efl_net_server_fd.c \ 110lib/ecore_con/efl_net_server_fd.c \
105lib/ecore_con/efl_net_server_tcp.c \ 111lib/ecore_con/efl_net_server_tcp.c \
106lib/ecore_con/efl_net_server_udp.c \ 112lib/ecore_con/efl_net_server_udp.c \
diff --git a/src/examples/ecore/.gitignore b/src/examples/ecore/.gitignore
index b353fa7..88fc2bd 100644
--- a/src/examples/ecore/.gitignore
+++ b/src/examples/ecore/.gitignore
@@ -53,10 +53,12 @@
53/efl_io_queue_example 53/efl_io_queue_example
54/efl_io_buffered_stream_example 54/efl_io_buffered_stream_example
55/efl_net_server_example 55/efl_net_server_example
56/efl_net_server_simple_example
56/efl_net_dialer_http_example 57/efl_net_dialer_http_example
57/efl_net_dialer_websocket_example 58/efl_net_dialer_websocket_example
58/efl_net_dialer_websocket_autobahntestee 59/efl_net_dialer_websocket_autobahntestee
59/efl_net_dialer_udp_example 60/efl_net_dialer_udp_example
61/efl_net_dialer_simple_example
60/efl_net_dialer_unix_example 62/efl_net_dialer_unix_example
61/ecore_evas_vnc 63/ecore_evas_vnc
62/efl_net_socket_ssl_dialer_example 64/efl_net_socket_ssl_dialer_example
diff --git a/src/examples/ecore/Makefile.am b/src/examples/ecore/Makefile.am
index db23d30..88f2384 100644
--- a/src/examples/ecore/Makefile.am
+++ b/src/examples/ecore/Makefile.am
@@ -86,10 +86,12 @@ efl_io_copier_simple_example \
86efl_io_queue_example \ 86efl_io_queue_example \
87efl_io_buffered_stream_example \ 87efl_io_buffered_stream_example \
88efl_net_server_example \ 88efl_net_server_example \
89efl_net_server_simple_example \
89efl_net_dialer_http_example \ 90efl_net_dialer_http_example \
90efl_net_dialer_websocket_example \ 91efl_net_dialer_websocket_example \
91efl_net_dialer_websocket_autobahntestee \ 92efl_net_dialer_websocket_autobahntestee \
92efl_net_dialer_udp_example \ 93efl_net_dialer_udp_example \
94efl_net_dialer_simple_example \
93efl_net_socket_ssl_dialer_example \ 95efl_net_socket_ssl_dialer_example \
94efl_net_socket_ssl_server_example \ 96efl_net_socket_ssl_server_example \
95efl_net_session_example \ 97efl_net_session_example \
@@ -324,6 +326,9 @@ efl_io_buffered_stream_example_LDADD = $(ECORE_CON_COMMON_LDADD)
324efl_net_server_example_SOURCES = efl_net_server_example.c 326efl_net_server_example_SOURCES = efl_net_server_example.c
325efl_net_server_example_LDADD = $(ECORE_CON_COMMON_LDADD) 327efl_net_server_example_LDADD = $(ECORE_CON_COMMON_LDADD)
326 328
329efl_net_server_simple_example_SOURCES = efl_net_server_simple_example.c
330efl_net_server_simple_example_LDADD = $(ECORE_CON_COMMON_LDADD)
331
327efl_net_dialer_http_example_SOURCES = efl_net_dialer_http_example.c 332efl_net_dialer_http_example_SOURCES = efl_net_dialer_http_example.c
328efl_net_dialer_http_example_LDADD = $(ECORE_CON_COMMON_LDADD) 333efl_net_dialer_http_example_LDADD = $(ECORE_CON_COMMON_LDADD)
329 334
@@ -336,6 +341,9 @@ efl_net_dialer_websocket_autobahntestee_LDADD = $(ECORE_CON_COMMON_LDADD)
336efl_net_dialer_udp_example_SOURCES = efl_net_dialer_udp_example.c 341efl_net_dialer_udp_example_SOURCES = efl_net_dialer_udp_example.c
337efl_net_dialer_udp_example_LDADD = $(ECORE_CON_COMMON_LDADD) 342efl_net_dialer_udp_example_LDADD = $(ECORE_CON_COMMON_LDADD)
338 343
344efl_net_dialer_simple_example_SOURCES = efl_net_dialer_simple_example.c
345efl_net_dialer_simple_example_LDADD = $(ECORE_CON_COMMON_LDADD)
346
339if ! HAVE_WINDOWS 347if ! HAVE_WINDOWS
340EXTRA_PROGRAMS += efl_net_dialer_unix_example 348EXTRA_PROGRAMS += efl_net_dialer_unix_example
341efl_net_dialer_unix_example_SOURCES = efl_net_dialer_unix_example.c 349efl_net_dialer_unix_example_SOURCES = efl_net_dialer_unix_example.c
@@ -413,10 +421,12 @@ efl_io_copier_simple_example.c \
413efl_io_queue_example.c \ 421efl_io_queue_example.c \
414efl_io_buffered_stream_example.c \ 422efl_io_buffered_stream_example.c \
415efl_net_server_example.c \ 423efl_net_server_example.c \
424efl_net_server_simple_example.c \
416efl_net_dialer_http_example.c \ 425efl_net_dialer_http_example.c \
417efl_net_dialer_websocket_example.c \ 426efl_net_dialer_websocket_example.c \
418efl_net_dialer_websocket_autobahntestee.c \ 427efl_net_dialer_websocket_autobahntestee.c \
419efl_net_dialer_udp_example.c \ 428efl_net_dialer_udp_example.c \
429efl_net_dialer_simple_example.c \
420efl_net_socket_ssl_dialer_example.c \ 430efl_net_socket_ssl_dialer_example.c \
421efl_net_socket_ssl_server_example.c \ 431efl_net_socket_ssl_server_example.c \
422efl_net_session_example.c \ 432efl_net_session_example.c \
diff --git a/src/examples/ecore/efl_net_dialer_simple_example.c b/src/examples/ecore/efl_net_dialer_simple_example.c
new file mode 100644
index 0000000..d748e2f
--- /dev/null
+++ b/src/examples/ecore/efl_net_dialer_simple_example.c
@@ -0,0 +1,451 @@
1#define EFL_BETA_API_SUPPORT 1
2#define EFL_EO_API_SUPPORT 1
3#include <Ecore.h>
4#include <Ecore_Con.h>
5#include <Ecore_Getopt.h>
6#include <fcntl.h>
7#include <ctype.h>
8
9static int retval = EXIT_SUCCESS;
10static Eina_Bool do_read = EINA_FALSE;
11static Eina_Bool do_discard = EINA_FALSE;
12static Eina_Slice line_delm_slice;
13
14static void
15_connected(void *data EINA_UNUSED, const Efl_Event *event)
16{
17 fprintf(stderr,
18 "INFO: connected to '%s' (%s)\n"
19 "INFO: - local address=%s\n"
20 "INFO: - do read=%u\n"
21 "INFO: - do discard=%u\n",
22 efl_net_dialer_address_dial_get(event->object),
23 efl_net_socket_address_remote_get(event->object),
24 efl_net_socket_address_local_get(event->object),
25 do_read, do_discard);
26}
27
28static void
29_eos(void *data EINA_UNUSED, const Efl_Event *event)
30{
31 Eina_Slice s;
32
33 fprintf(stderr, "INFO: end of stream.\n");
34
35 /* on _error() we close it, then do not read as it has nothing */
36 if (efl_io_closer_closed_get(event->object))
37 return;
38
39 if (efl_io_buffered_stream_slice_get(event->object, &s))
40 {
41 fprintf(stderr,
42 "-- BEGIN RECEIVED DATA --\n"
43 EINA_SLICE_STR_FMT
44 "-- END RECEIVED DATA--\n",
45 EINA_SLICE_STR_PRINT(s));
46 }
47}
48
49static void
50_can_read(void *data EINA_UNUSED, const Efl_Event *event)
51{
52 Eina_Bool can_read = efl_io_reader_can_read_get(event->object);
53
54 /*
55 * Since we have more high level events, such as "slice,changed"
56 * and "line", it's not that interesting to monitor
57 * "can_read,changed" anymore. We do and print out, but no actual
58 * reads as we print from _line() or _eos().
59 *
60 * But reads can be done as usual, see the '#if' block below.
61 */
62
63 fprintf(stderr, "INFO: can read=%d\n", can_read);
64
65#if 0
66 if ((can_read) && (do_read))
67 {
68 char buf[4];
69 Eina_Rw_Slice rw_slice = EINA_SLICE_ARRAY(buf);
70 Eina_Error err;
71
72 do
73 {
74 err = efl_io_reader_read(event->object, &rw_slice);
75 if (err)
76 {
77 if (err == EAGAIN)
78 {
79 fprintf(stderr, "ERROR: read all available data\n");
80 break;
81 }
82 fprintf(stderr, "ERROR: could not read: %s\n", eina_error_msg_get(err));
83 retval = EXIT_FAILURE;
84 ecore_main_loop_quit();
85 return;
86 }
87
88 fprintf(stderr, "INFO: read '" EINA_SLICE_STR_FMT "'\n", EINA_SLICE_STR_PRINT(rw_slice));
89 }
90 while (err == 0);
91 }
92#endif
93}
94
95
96static void
97_line(void *data EINA_UNUSED, const Efl_Event *event)
98{
99 const Eina_Slice slice = *(const Eina_Slice *)event->info;
100
101 if (!eina_slice_endswith(slice, line_delm_slice))
102 {
103 fprintf(stderr, "WARNING: received without line-delimiter '"
104 EINA_SLICE_STR_FMT "'\n",
105 EINA_SLICE_STR_PRINT(slice));
106 }
107 else
108 {
109 Eina_Slice s = slice;
110 s.len -= line_delm_slice.len;
111 fprintf(stderr, "INFO: received '" EINA_SLICE_STR_FMT "'\n",
112 EINA_SLICE_STR_PRINT(s));
113 }
114
115 /*
116 * If you used the line and it's not interesting anymore, then you
117 * can discard it.
118 *
119 * It has the same effect as calling efl_io_reader_read() as per
120 * #if block below
121 */
122 if (do_discard)
123 {
124#if 1
125 efl_io_buffered_stream_discard(event->object, slice.len);
126#else
127 {
128 /* efl_io_buffered_stream_discard() paired with
129 * efl_io_buffered_stream_slice_get() + 'slice,changed' or
130 * 'line' events is a faster alternative than reading,
131 * since it doesn't copy the data.
132 */
133 char *buf = malloc(slice.len);
134 Eina_Rw_Slice rw_slice = {
135 .mem = buf,
136 .len = slice.len,
137 };
138 Eina_Error err = efl_io_reader_read(event->object, &rw_slice);
139 fprintf(stderr, "INFO: read error=%s '" EINA_SLICE_FMT "'\n", eina_error_msg_get(err) ? eina_error_msg_get(err) : "success", EINA_SLICE_PRINT(rw_slice));
140 free(buf);
141 }
142#endif
143 }
144}
145
146static void
147_resolved(void *data EINA_UNUSED, const Efl_Event *event)
148{
149 fprintf(stderr, "INFO: resolved %s => %s\n",
150 efl_net_dialer_address_dial_get(event->object),
151 efl_net_socket_address_remote_get(event->object));
152}
153
154static void
155_error(void *data EINA_UNUSED, const Efl_Event *event)
156{
157 const Eina_Error *perr = event->info;
158 fprintf(stderr, "INFO: error: %d '%s'\n", *perr, eina_error_msg_get(*perr));
159 if (!efl_io_closer_closed_get(event->object))
160 efl_io_closer_close(event->object);
161 retval = EXIT_FAILURE;
162}
163
164static void
165_done_sending(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
166{
167 fprintf(stderr, "INFO: done sending\n");
168 if (!do_read)
169 {
170 ecore_main_loop_quit();
171 return;
172 }
173}
174
175static void
176_done_receiving(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
177{
178 fprintf(stderr, "INFO: done receiving\n");
179}
180
181static void
182_done(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
183{
184 fprintf(stderr, "INFO: done sending and receiving\n");
185 ecore_main_loop_quit();
186}
187
188EFL_CALLBACKS_ARRAY_DEFINE(dialer_cbs,
189 { EFL_NET_DIALER_EVENT_CONNECTED, _connected }, /* optional */
190 { EFL_NET_DIALER_EVENT_RESOLVED, _resolved }, /* optional */
191 { EFL_IO_READER_EVENT_CAN_READ_CHANGED, _can_read }, /* optional, can be used to read data, here just for monitoring */
192 { EFL_IO_READER_EVENT_EOS, _eos }, /* recommended, notifies no more incoming data */
193 { EFL_IO_BUFFERED_STREAM_EVENT_LINE, _line }, /* optional, could use 'slice,changed' or 'can_read,changed' instead */
194 { EFL_IO_BUFFERED_STREAM_EVENT_ERROR, _error }, /* recommended */
195 { EFL_IO_BUFFERED_STREAM_EVENT_WRITE_FINISHED, _done_sending }, /* optional */
196 { EFL_IO_BUFFERED_STREAM_EVENT_READ_FINISHED, _done_receiving }, /* optional, same as 'eos' */
197 { EFL_IO_BUFFERED_STREAM_EVENT_FINISHED, _done }); /* recommended, notifies both send and receive are finished */
198
199static char *
200_unescape(const char *str)
201{
202 char *ret = strdup(str);
203 char *c, *w;
204 Eina_Bool escaped = EINA_FALSE;
205
206 for (c = ret, w = ret; *c != '\0'; c++)
207 {
208 if (escaped)
209 {
210 escaped = EINA_FALSE;
211 switch (*c)
212 {
213 case 'n': *w = '\n'; break;
214 case 'r': *w = '\r'; break;
215 case 't': *w = '\t'; break;
216 default: w++; /* no change */
217 }
218 w++;
219 }
220 else
221 {
222 if (*c == '\\')
223 escaped = EINA_TRUE;
224 else
225 w++;
226 }
227 }
228 *w = '\0';
229 return ret;
230}
231
232static const char * protocols[] = {
233 "tcp",
234 "udp",
235 "ssl",
236#ifndef _WIN32
237 "unix",
238#endif
239 NULL
240};
241
242static const Ecore_Getopt options = {
243 "efl_net_dialer_simple_example", /* program name */
244 NULL, /* usage line */
245 "1", /* version */
246 "(C) 2016 Enlightenment Project", /* copyright */
247 "BSD 2-Clause", /* license */
248 /* long description, may be multiline and contain \n */
249 "Example of Efl_Net_Dialer_Simple usage, sending a message and receiving a reply\n",
250 EINA_FALSE,
251 {
252 ECORE_GETOPT_STORE_TRUE('r', "read", "Wait for data to be read."),
253 ECORE_GETOPT_STORE_TRUE('D', "discard-lines", "Lines that are read are discarded from final output."),
254 ECORE_GETOPT_APPEND('s', "send", "send the given string to the server once connected.", ECORE_GETOPT_TYPE_STR),
255
256 ECORE_GETOPT_STORE_STR('d', "line-delimiter",
257 "If set will define a line delimiter for copy operation, instead of a fixed chunk size. This will trigger line events."),
258 ECORE_GETOPT_STORE_ULONG('l', "buffer-limit",
259 "If set will limit buffer size to this limit of bytes. If used alongside with --line-delimiter and that delimiter was not found but bffer limit was reached, the line event will be triggered without the delimiter at the end."),
260 ECORE_GETOPT_STORE_ULONG('c', "read-chunk-size",
261 "If set will change the base chunk size used while reading."),
262 ECORE_GETOPT_STORE_DOUBLE('i', "inactivity-timeout",
263 "If greater than zero, specifies the number of seconds without any reads or writes that the dialer will be timed out."),
264 ECORE_GETOPT_STORE_DOUBLE('t', "connect-timeout",
265 "If greater than zero, specifies the number of seconds without any reads or writes that the dialer will be timed out."),
266
267 ECORE_GETOPT_VERSION('V', "version"),
268 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
269 ECORE_GETOPT_LICENSE('L', "license"),
270 ECORE_GETOPT_HELP('h', "help"),
271
272 ECORE_GETOPT_CHOICE_METAVAR(0, NULL, "The dialer protocol.", "protocol",
273 protocols),
274 ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
275 "The address (URL) to dial", "address"),
276 ECORE_GETOPT_SENTINEL
277 }
278};
279
280int
281main(int argc, char **argv)
282{
283 const Efl_Class *cls;
284 Eina_List *to_send = NULL;
285 char *str;
286 char *line_delimiter_str = NULL;
287 char *address = NULL;
288 char *protocol = NULL;
289 unsigned long buffer_limit = 0;
290 unsigned long read_chunk_size = 0;
291 double inactivity_timeout = 0.0;
292 double connect_timeout = 0.0;
293 Eina_Bool quit_option = EINA_FALSE;
294 Ecore_Getopt_Value values[] = {
295 ECORE_GETOPT_VALUE_BOOL(do_read),
296 ECORE_GETOPT_VALUE_BOOL(do_discard),
297 ECORE_GETOPT_VALUE_LIST(to_send),
298
299 ECORE_GETOPT_VALUE_STR(line_delimiter_str),
300 ECORE_GETOPT_VALUE_ULONG(buffer_limit),
301 ECORE_GETOPT_VALUE_ULONG(read_chunk_size),
302 ECORE_GETOPT_VALUE_DOUBLE(inactivity_timeout),
303 ECORE_GETOPT_VALUE_DOUBLE(connect_timeout),
304
305 /* standard block to provide version, copyright, license and help */
306 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -V/--version quits */
307 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -C/--copyright quits */
308 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -L/--license quits */
309 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -h/--help quits */
310
311 /* positional argument */
312 ECORE_GETOPT_VALUE_STR(protocol),
313 ECORE_GETOPT_VALUE_STR(address),
314
315 ECORE_GETOPT_VALUE_NONE /* sentinel */
316 };
317 int args;
318 Eo *dialer, *loop;
319 Eina_Error err;
320
321 ecore_init();
322 ecore_con_init();
323
324 args = ecore_getopt_parse(&options, values, argc, argv);
325 if (args < 0)
326 {
327 fputs("ERROR: Could not parse command line options.\n", stderr);
328 retval = EXIT_FAILURE;
329 goto end;
330 }
331
332 if (quit_option) goto end;
333
334 loop = ecore_main_loop_get();
335
336 args = ecore_getopt_parse_positional(&options, values, argc, argv, args);
337 if (args < 0)
338 {
339 fputs("ERROR: Could not parse positional arguments.\n", stderr);
340 retval = EXIT_FAILURE;
341 goto end;
342 }
343
344 if (!protocol)
345 {
346 fputs("ERROR: missing protocol.\n", stderr);
347 retval = EXIT_FAILURE;
348 goto end;
349 }
350
351 if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_DIALER_TCP_CLASS;
352 else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_DIALER_UDP_CLASS;
353 else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_DIALER_SSL_CLASS;
354#ifndef _WIN32
355 else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_DIALER_UNIX_CLASS;
356#endif
357 else
358 {
359 fprintf(stderr, "ERROR: unsupported protocol: %s\n", protocol);
360 goto end;
361 }
362
363 /* A delimiter is optional, if empty or unset, buffered stream uses
364 * a copier that will execute writes based on read_chunk_size and
365 * only event "data" is emitted.
366 *
367 * If a line delimiter is set, it will hold writes until the
368 * delimiter is found, source reached End-of-Stream (eos) or the
369 * copier buffer limit is reached. The "line" event is emitted.
370 */
371 line_delimiter_str = _unescape(line_delimiter_str ? line_delimiter_str : "\\r\\n");
372 if (line_delimiter_str)
373 line_delm_slice = (Eina_Slice)EINA_SLICE_STR(line_delimiter_str);
374
375 dialer = efl_add(EFL_NET_DIALER_SIMPLE_CLASS, loop,
376 efl_name_set(efl_added, "dialer"),
377 efl_net_dialer_simple_inner_class_set(efl_added, cls), /* alternatively you could create the inner dialer and set with efl_io_buffered_stream_inner_io_set() */
378 efl_io_buffered_stream_line_delimiter_set(efl_added, &line_delm_slice), /* optional */
379 efl_io_buffered_stream_max_queue_size_input_set(efl_added, buffer_limit), /* optional, defaults to unlimited */
380 efl_io_buffered_stream_max_queue_size_output_set(efl_added, buffer_limit), /* optional, defaults to unlimited */
381 efl_io_buffered_stream_read_chunk_size_set(efl_added, read_chunk_size), /* optional, defaults to 4096 */
382 efl_io_buffered_stream_inactivity_timeout_set(efl_added, inactivity_timeout), /* optional, defaults to 0.0 (disabled) */
383 efl_net_dialer_timeout_dial_set(efl_added, connect_timeout), /* optional, defaults to 0.0 (disabled) */
384 efl_event_callback_array_add(efl_added, dialer_cbs(), NULL));
385
386 err = efl_net_dialer_dial(dialer, address);
387 if (err != 0)
388 {
389 fprintf(stderr, "ERROR: could not dial %s '%s': %s",
390 protocol, address, eina_error_msg_get(err));
391 goto no_mainloop;
392 }
393
394 /* unlike low-level I/O that wouldn't write data until it's
395 * connected, the simple dialer will queue it in memory, sending when
396 * it's ready. Thus just write & forget.
397 */
398 if (!to_send)
399 {
400 if (!do_read)
401 {
402 Eina_Slice s = EINA_SLICE_STR_LITERAL("Hello World!");
403
404 fprintf(stderr, "INFO: sending '" EINA_SLICE_STR_FMT "'\n", EINA_SLICE_STR_PRINT(s));
405 efl_io_writer_write(dialer, &s, NULL);
406
407 if (line_delm_slice.len)
408 {
409 Eina_Slice s = line_delm_slice;
410 efl_io_writer_write(dialer, &s, NULL);
411 }
412 }
413 else
414 fprintf(stderr, "INFO: nothing to send, just read...\n");
415 }
416 else
417 {
418 EINA_LIST_FREE(to_send, str)
419 {
420 /* ignore empty sends, but add line delimiter, so we can do HTTP's last line :-) */
421 if (str[0] != '\0')
422 {
423 Eina_Slice s = EINA_SLICE_STR(str);
424 fprintf(stderr, "INFO: sending '" EINA_SLICE_STR_FMT "'\n", EINA_SLICE_STR_PRINT(s));
425 efl_io_writer_write(dialer, &s, NULL);
426 }
427 free(str);
428
429 if (line_delm_slice.len)
430 {
431 Eina_Slice s = line_delm_slice;
432 efl_io_writer_write(dialer, &s, NULL);
433 }
434 }
435 }
436 efl_io_buffered_stream_eos_mark(dialer); /* we're done sending */
437
438 ecore_main_loop_begin();
439
440 fprintf(stderr, "INFO: main loop finished.\n");
441
442 no_mainloop:
443 efl_del(dialer);
444
445 end:
446 EINA_LIST_FREE(to_send, str) free(str);
447 ecore_con_shutdown();
448 ecore_shutdown();
449
450 return retval;
451}
diff --git a/src/examples/ecore/efl_net_server_simple_example.c b/src/examples/ecore/efl_net_server_simple_example.c
new file mode 100644
index 0000000..a7dc2b7
--- /dev/null
+++ b/src/examples/ecore/efl_net_server_simple_example.c
@@ -0,0 +1,559 @@
1#define EFL_BETA_API_SUPPORT 1
2#define EFL_EO_API_SUPPORT 1
3#include <Ecore.h>
4#include <Ecore_Con.h>
5#include <Ecore_Getopt.h>
6#include <fcntl.h>
7
8static int retval = EXIT_SUCCESS;
9static Eina_Bool echo = EINA_FALSE;
10static double timeout = 10.0;
11
12/* NOTE: client i/o events are only used as debug, you can omit these */
13
14static void
15_client_can_read_changed(void *data EINA_UNUSED, const Efl_Event *event)
16{
17 fprintf(stderr, "INFO: client %s can_read=%d\n",
18 efl_net_socket_address_remote_get(event->object),
19 efl_io_reader_can_read_get(event->object));
20}
21
22static void
23_client_can_write_changed(void *data EINA_UNUSED, const Efl_Event *event)
24{
25 fprintf(stderr, "INFO: client %s can_write=%d\n",
26 efl_net_socket_address_remote_get(event->object),
27 efl_io_writer_can_write_get(event->object));
28}
29
30static void
31_client_eos(void *data EINA_UNUSED, const Efl_Event *event)
32{
33 fprintf(stderr, "INFO: client %s eos.\n",
34 efl_net_socket_address_remote_get(event->object));
35}
36
37static void
38_client_read_finished(void *data EINA_UNUSED, const Efl_Event *event)
39{
40 Eina_Slice s;
41
42 /* on _error() we close it, then do not read as it has nothing */
43 if (efl_io_closer_closed_get(event->object))
44 return;
45
46 if (echo) return;
47
48 if (efl_io_buffered_stream_slice_get(event->object, &s))
49 {
50 fprintf(stderr,
51 "-- BEGIN RECEIVED DATA --\n"
52 EINA_SLICE_STR_FMT
53 "-- END RECEIVED DATA--\n",
54 EINA_SLICE_STR_PRINT(s));
55 }
56}
57
58static void
59_client_closed(void *data EINA_UNUSED, const Efl_Event *event)
60{
61 fprintf(stderr, "INFO: client %s closed.\n",
62 efl_net_socket_address_remote_get(event->object));
63}
64
65/* this is the only event that matters, from here we remove our extra
66 * reference from the client and let it be deleted.
67 */
68static void
69_client_finished(void *data EINA_UNUSED, const Efl_Event *event)
70{
71 fprintf(stderr, "INFO: client %s finished sending and receiving, remove extra reference.\n",
72 efl_net_socket_address_remote_get(event->object));
73 if (!efl_io_closer_closed_get(event->object))
74 efl_io_closer_close(event->object);
75 efl_unref(event->object);
76}
77
78/*
79 * On errors, such as ETIMEDOUT, we want to close the client if not
80 * happened yet.
81 */
82static void
83_client_error(void *data EINA_UNUSED, const Efl_Event *event)
84{
85 Eina_Error *perr = event->info;
86 fprintf(stderr, "ERROR: client %s error: %s\n",
87 efl_net_socket_address_remote_get(event->object),
88 eina_error_msg_get(*perr));
89 if (!efl_io_closer_closed_get(event->object))
90 efl_io_closer_close(event->object);
91}
92
93EFL_CALLBACKS_ARRAY_DEFINE(client_cbs,
94 { EFL_IO_READER_EVENT_CAN_READ_CHANGED, _client_can_read_changed },
95 { EFL_IO_READER_EVENT_EOS, _client_eos },
96 { EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, _client_can_write_changed },
97 { EFL_IO_CLOSER_EVENT_CLOSED, _client_closed },
98 { EFL_IO_BUFFERED_STREAM_EVENT_READ_FINISHED, _client_read_finished },
99 { EFL_IO_BUFFERED_STREAM_EVENT_FINISHED, _client_finished },
100 { EFL_IO_BUFFERED_STREAM_EVENT_ERROR, _client_error });
101
102
103/* copier events are of interest, you should hook to at least "done"
104 * and "error"
105 */
106
107/* echo copier is about the same socket, you can close it right away */
108
109static void
110_echo_copier_done(void *data EINA_UNUSED, const Efl_Event *event)
111{
112 Eo *copier = event->object;
113 fprintf(stderr, "INFO: echo copier done, close and del %p\n", copier);
114 efl_del(copier); /* set to close_on_destructor, will auto close copier and client */
115}
116
117static void
118_echo_copier_error(void *data EINA_UNUSED, const Efl_Event *event)
119{
120 Eo *copier = event->object;
121 const Eina_Error *perr = event->info;
122
123 if (*perr == ETIMEDOUT)
124 {
125 Eo *client = efl_io_copier_source_get(copier);
126 fprintf(stderr, "INFO: client '%s' timed out, delete it.\n",
127 efl_net_socket_address_remote_get(client));
128 efl_del(copier);
129 return;
130 }
131
132 retval = EXIT_FAILURE;
133
134 fprintf(stderr, "ERROR: echo copier %p failed %d '%s', close and del.\n",
135 copier, *perr, eina_error_msg_get(*perr));
136
137 efl_del(copier);
138}
139
140EFL_CALLBACKS_ARRAY_DEFINE(echo_copier_cbs,
141 { EFL_IO_COPIER_EVENT_DONE, _echo_copier_done },
142 { EFL_IO_COPIER_EVENT_ERROR, _echo_copier_error});
143
144/* server events are mandatory, afterall you need to define what's
145 * going to happen after a client socket is connected. This is the
146 * "client,add" event.
147 *
148 * if clients_limit and clients_reject_excess are set, then
149 * "client,rejected" is dispatched for rejected sockets, they contain
150 * the string with socket identification.
151 */
152static void
153_server_client_add(void *data EINA_UNUSED, const Efl_Event *event)
154{
155 Efl_Net_Socket *client = event->info;
156
157 fprintf(stderr, "INFO: accepted client %s\n",
158 efl_net_socket_address_remote_get(client));
159
160 /* to use a client, you must efl_ref() it. */
161 efl_ref(client);
162
163 /*
164 * monitor the client if it's done and for debug purposes
165 * (optional)
166 */
167 efl_event_callback_array_add(client, client_cbs(), NULL);
168
169 efl_io_buffered_stream_inactivity_timeout_set(client, timeout);
170
171 /*
172 * Since sockets are reader/writer/closer objects, we can use the
173 * Efl_Io_Copier utility.
174 */
175
176 if (echo)
177 {
178 /*
179 * An echo copier is pretty simple, use the socket as both
180 * source and destination.
181 *
182 * This is the same as efl_net_server_example.c
183 */
184 Eo *echo_copier = efl_add(EFL_IO_COPIER_CLASS, efl_parent_get(client),
185 efl_io_copier_source_set(efl_added, client),
186 efl_io_copier_destination_set(efl_added, client),
187 efl_event_callback_array_add(efl_added, echo_copier_cbs(), client),
188 efl_io_closer_close_on_destructor_set(efl_added, EINA_TRUE) /* we want to auto-close as we have a single copier */
189 );
190
191 fprintf(stderr, "INFO: using an echo copier=%p for client %s\n",
192 echo_copier, efl_net_socket_address_remote_get(client));
193 return;
194 }
195 else
196 {
197 /*
198 * Here is where the "simple" kicks in, instead of all the
199 * complexity listed in efl_net_server_example.c, we just
200 * "write & forget" the "Hello World!" and wait for all data
201 * to be received with a simple "finished" event.
202 */
203 Eina_Slice slice = EINA_SLICE_STR_LITERAL("Hello World!");
204
205 efl_io_writer_write(client, &slice, NULL);
206 efl_io_buffered_stream_eos_mark(client); /* say that's it */
207 }
208}
209
210static void
211_server_client_rejected(void *data EINA_UNUSED, const Efl_Event *event)
212{
213 const char *client_address = event->info;
214 fprintf(stderr, "INFO: rejected client %s\n", client_address);
215}
216
217static void
218_server_error(void *data EINA_UNUSED, const Efl_Event *event)
219{
220 const Eina_Error *perr = event->info;
221 fprintf(stderr, "ERROR: %d '%s'\n", *perr, eina_error_msg_get(*perr));
222 retval = EXIT_FAILURE;
223 ecore_main_loop_quit();
224}
225
226static void
227_server_serving(void *data EINA_UNUSED, const Efl_Event *event)
228{
229 fprintf(stderr, "INFO: serving at %s\n",
230 efl_net_server_address_get(event->object));
231
232 if (efl_class_get(event->object) == EFL_NET_SERVER_TCP_CLASS)
233 {
234 fprintf(stderr,
235 "TCP options:\n"
236 " - IPv6 only: %u\n",
237 efl_net_server_tcp_ipv6_only_get(event->object));
238 }
239 else if (efl_class_get(event->object) == EFL_NET_SERVER_UDP_CLASS)
240 {
241 Eina_Iterator *it;
242 const char *str;
243
244 fprintf(stderr,
245 "UDP options:\n"
246 " - IPv6 only: %u\n"
247 " - don't route: %u\n"
248 " - multicast TTL: %u\n"
249 " - multicast loopback: %u\n"
250 " - multicast groups:\n",
251 efl_net_server_udp_ipv6_only_get(event->object),
252 efl_net_server_udp_dont_route_get(event->object),
253 efl_net_server_udp_multicast_time_to_live_get(event->object),
254 efl_net_server_udp_multicast_loopback_get(event->object));
255
256 it = efl_net_server_udp_multicast_groups_get(event->object);
257 EINA_ITERATOR_FOREACH(it, str)
258 fprintf(stderr, " * %s\n", str);
259 eina_iterator_free(it);
260 }
261}
262
263EFL_CALLBACKS_ARRAY_DEFINE(server_cbs,
264 { EFL_NET_SERVER_EVENT_CLIENT_ADD, _server_client_add },
265 { EFL_NET_SERVER_EVENT_CLIENT_REJECTED, _server_client_rejected },
266 { EFL_NET_SERVER_EVENT_ERROR, _server_error },
267 { EFL_NET_SERVER_EVENT_SERVING, _server_serving });
268
269static const char * protocols[] = {
270 "tcp",
271 "udp",
272 "ssl",
273#ifndef _WIN32
274 "unix",
275#endif
276 NULL
277};
278
279static const char *ciphers_strs[] = {
280 "auto",
281 "sslv3",
282 "tlsv1",
283 "tlsv1.1",
284 "tlsv1.2",
285 NULL
286};
287
288static const Ecore_Getopt options = {
289 "efl_net_server_example", /* program name */
290 NULL, /* usage line */
291 "1", /* version */
292 "(C) 2016 Enlightenment Project", /* copyright */
293 "BSD 2-Clause", /* license */
294 /* long description, may be multiline and contain \n */
295 "Example of Efl_Net_Server objects usage.\n"
296 "\n"
297 "This example spawns a server of the given protocol at the given address.",
298 EINA_FALSE,
299 {
300 ECORE_GETOPT_STORE_TRUE('e', "echo",
301 "Behave as 'echo' server, send back to client all the data receive"),
302 ECORE_GETOPT_STORE_TRUE(0, "socket-activated",
303 "Try to use $LISTEN_FDS from systemd, if not do a regular serve()"),
304 ECORE_GETOPT_STORE_UINT('l', "clients-limit",
305 "If set will limit number of clients to accept"),
306 ECORE_GETOPT_STORE_TRUE('r', "clients-reject-excess",
307 "Immediately reject excess clients (over limit)"),
308 ECORE_GETOPT_STORE_FALSE(0, "ipv4-on-ipv6",
309 "IPv4 clients will be automatically converted into IPv6 and handled transparently."),
310 ECORE_GETOPT_STORE_DOUBLE('t', "inactivity-timeout",
311 "The timeout in seconds to disconnect a client. The timeout is restarted for each client when there is some activity. It's particularly useful for UDP where there is no disconnection event."),
312
313 ECORE_GETOPT_VERSION('V', "version"),
314 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
315 ECORE_GETOPT_LICENSE('L', "license"),
316 ECORE_GETOPT_HELP('h', "help"),
317
318 ECORE_GETOPT_CATEGORY("udp", "UDP options"),
319 ECORE_GETOPT_STORE_TRUE(0, "udp-dont-route",
320 "If true, datagrams won't be routed using a gateway, being restricted to the local network."),
321 ECORE_GETOPT_STORE_UINT(0, "udp-multicast-ttl",
322 "Multicast time to live in number of hops from 0-255. Defaults to 1 (only local network)."),
323 ECORE_GETOPT_STORE_FALSE(0, "udp-multicast-noloopback",
324 "Disable multicast loopback."),
325 ECORE_GETOPT_APPEND('M', "udp-multicast-group", "Join a multicast group in the form 'IP@INTERFACE', with optional '@INTERFACE', where INTERFACE is the IP address of the interface to join the multicast.", ECORE_GETOPT_TYPE_STR),
326
327 ECORE_GETOPT_CATEGORY("ssl", "SSL options"),
328 ECORE_GETOPT_CHOICE('c', "ssl-cipher", "Cipher to use, defaults to 'auto'", ciphers_strs),
329 ECORE_GETOPT_APPEND(0, "ssl-certificate", "certificate path to use.", ECORE_GETOPT_TYPE_STR),
330 ECORE_GETOPT_APPEND(0, "ssl-private-key", "private key path to use.", ECORE_GETOPT_TYPE_STR),
331 ECORE_GETOPT_APPEND(0, "ssl-crl", "certificate revogation list to use.", ECORE_GETOPT_TYPE_STR),
332 ECORE_GETOPT_APPEND(0, "ssl-ca", "certificate authorities path to use.", ECORE_GETOPT_TYPE_STR),
333
334 ECORE_GETOPT_CHOICE_METAVAR(0, NULL, "The server protocol.", "protocol",
335 protocols),
336 ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
337 "The server address to listen, such as "
338 "IPv4:PORT, [IPv6]:PORT, Unix socket path...",
339 "address"),
340
341 ECORE_GETOPT_SENTINEL
342 }
343};
344
345int
346main(int argc, char **argv)
347{
348 const Efl_Class *cls;
349 char *protocol = NULL;
350 char *address = NULL;
351 Eina_List *udp_mcast_groups = NULL;
352 char *str;
353 unsigned int clients_limit = 0;
354 unsigned udp_mcast_ttl = 1;
355 Eina_Bool clients_reject_excess = EINA_FALSE;
356 Eina_Bool ipv6_only = EINA_TRUE;
357 Eina_Bool udp_dont_route = EINA_FALSE;
358 Eina_Bool udp_mcast_loopback = EINA_TRUE;
359 Eina_List *certificates = NULL;
360 Eina_List *private_keys = NULL;
361 Eina_List *crls = NULL;
362 Eina_List *cas = NULL;
363 char *cipher_choice = NULL;
364 Eina_Bool socket_activated = EINA_FALSE;
365 Eina_Bool quit_option = EINA_FALSE;
366 Ecore_Getopt_Value values[] = {
367 ECORE_GETOPT_VALUE_BOOL(echo),
368 ECORE_GETOPT_VALUE_BOOL(socket_activated),
369 ECORE_GETOPT_VALUE_UINT(clients_limit),
370 ECORE_GETOPT_VALUE_BOOL(clients_reject_excess),
371 ECORE_GETOPT_VALUE_BOOL(ipv6_only),
372 ECORE_GETOPT_VALUE_DOUBLE(timeout),
373
374 /* standard block to provide version, copyright, license and help */
375 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -V/--version quits */
376 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -C/--copyright quits */
377 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -L/--license quits */
378 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -h/--help quits */
379
380 ECORE_GETOPT_VALUE_BOOL(quit_option), /* category: udp */
381 ECORE_GETOPT_VALUE_BOOL(udp_dont_route),
382 ECORE_GETOPT_VALUE_UINT(udp_mcast_ttl),
383 ECORE_GETOPT_VALUE_BOOL(udp_mcast_loopback),
384 ECORE_GETOPT_VALUE_LIST(udp_mcast_groups),
385
386 ECORE_GETOPT_VALUE_BOOL(quit_option), /* category: ssl */
387 ECORE_GETOPT_VALUE_STR(cipher_choice),
388 ECORE_GETOPT_VALUE_LIST(certificates),
389 ECORE_GETOPT_VALUE_LIST(private_keys),
390 ECORE_GETOPT_VALUE_LIST(crls),
391 ECORE_GETOPT_VALUE_LIST(cas),
392
393 /* positional argument */
394 ECORE_GETOPT_VALUE_STR(protocol),
395 ECORE_GETOPT_VALUE_STR(address),
396
397 ECORE_GETOPT_VALUE_NONE /* sentinel */
398 };
399 int args;
400 Eo *simple_server, *server;
401 Eina_Error err;
402
403 ecore_init();
404 ecore_con_init();
405
406 args = ecore_getopt_parse(&options, values, argc, argv);
407 if (args < 0)
408 {
409 fputs("ERROR: Could not parse command line options.\n", stderr);
410 retval = EXIT_FAILURE;
411 goto end;
412 }
413
414 if (quit_option) goto end;
415
416 args = ecore_getopt_parse_positional(&options, values, argc, argv, args);
417 if (args < 0)
418 {
419 fputs("ERROR: Could not parse positional arguments.\n", stderr);
420 retval = EXIT_FAILURE;
421 goto end;
422 }
423
424 if (!protocol)
425 {
426 fputs("ERROR: missing protocol.\n", stderr);
427 retval = EXIT_FAILURE;
428 goto end;
429 }
430
431 if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_SERVER_TCP_CLASS;
432 else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_SERVER_UDP_CLASS;
433 else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_SERVER_SSL_CLASS;
434#ifndef _WIN32
435 else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS;
436#endif
437 else
438 {
439 fprintf(stderr, "ERROR: unsupported protocol: %s\n", protocol);
440 goto end;
441 }
442
443 simple_server = efl_add(EFL_NET_SERVER_SIMPLE_CLASS, ecore_main_loop_get(), /* it's mandatory to use a main loop provider as the server parent */
444 efl_net_server_simple_inner_class_set(efl_added, cls), /* alternatively you could create the inner server and set with efl_net_server_simple_inner_server_set() */
445 efl_net_server_clients_limit_set(efl_added,
446 clients_limit,
447 clients_reject_excess), /* optional */
448 efl_event_callback_array_add(efl_added, server_cbs(), NULL)); /* mandatory to have "client,add" in order to be useful */
449 if (!simple_server)
450 {
451 fprintf(stderr, "ERROR: could not create simple server for class %p (%s)\n",
452 cls, efl_class_name_get(cls));
453 goto end;
454 }
455
456 /* get the inner server so we can configure it for each protocol */
457 server = efl_net_server_simple_inner_server_get(simple_server);
458
459 if (cls == EFL_NET_SERVER_TCP_CLASS)
460 {
461 efl_net_server_tcp_ipv6_only_set(server, ipv6_only);
462 efl_net_server_fd_close_on_exec_set(server, EINA_TRUE); /* recommended */
463 efl_net_server_fd_reuse_address_set(server, EINA_TRUE); /* optional, but nice for testing */
464 efl_net_server_fd_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
465
466 if (socket_activated) efl_net_server_fd_socket_activate(server, address);
467 }
468 else if (cls == EFL_NET_SERVER_UDP_CLASS)
469 {
470 const Eina_List *lst;
471
472 efl_net_server_udp_ipv6_only_set(server, ipv6_only);
473 efl_net_server_udp_dont_route_set(server, udp_dont_route);
474
475 efl_net_server_udp_multicast_time_to_live_set(server, udp_mcast_ttl);
476 efl_net_server_udp_multicast_loopback_set(server, udp_mcast_loopback);
477
478 EINA_LIST_FOREACH(udp_mcast_groups, lst, str)
479 efl_net_server_udp_multicast_join(server, str);
480
481
482 efl_net_server_fd_close_on_exec_set(server, EINA_TRUE); /* recommended */
483 efl_net_server_fd_reuse_address_set(server, EINA_TRUE); /* optional, but nice for testing */
484 efl_net_server_fd_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
485 if (socket_activated) efl_net_server_fd_socket_activate(server, address);
486 }
487 else if (cls == EFL_NET_SERVER_SSL_CLASS)
488 {
489 Eo *ssl_ctx;
490 Efl_Net_Ssl_Cipher cipher = EFL_NET_SSL_CIPHER_AUTO;
491 if (cipher_choice)
492 {
493 if (strcmp(cipher_choice, "auto") == 0)
494 cipher = EFL_NET_SSL_CIPHER_AUTO;
495 else if (strcmp(cipher_choice, "sslv3") == 0)
496 cipher = EFL_NET_SSL_CIPHER_SSLV3;
497 else if (strcmp(cipher_choice, "tlsv1") == 0)
498 cipher = EFL_NET_SSL_CIPHER_TLSV1;
499 else if (strcmp(cipher_choice, "tlsv1.1") == 0)
500 cipher = EFL_NET_SSL_CIPHER_TLSV1_1;
501 else if (strcmp(cipher_choice, "tlsv1.2") == 0)
502 cipher = EFL_NET_SSL_CIPHER_TLSV1_2;
503 }
504
505 ssl_ctx = efl_add(EFL_NET_SSL_CONTEXT_CLASS, NULL,
506 efl_net_ssl_context_certificates_set(efl_added, eina_list_iterator_new(certificates)),
507 efl_net_ssl_context_private_keys_set(efl_added, eina_list_iterator_new(private_keys)),
508 efl_net_ssl_context_certificate_revogation_lists_set(efl_added, eina_list_iterator_new(crls)),
509 efl_net_ssl_context_certificate_authorities_set(efl_added, eina_list_iterator_new(cas)),
510 efl_net_ssl_context_setup(efl_added, cipher, EINA_FALSE /* a server! */));
511
512 efl_net_server_ssl_context_set(server, ssl_ctx);
513
514 efl_net_server_ssl_close_on_exec_set(server, EINA_TRUE); /* recommended */
515 efl_net_server_ssl_reuse_address_set(server, EINA_TRUE); /* optional, but nice for testing */
516 efl_net_server_ssl_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
517 if (socket_activated) efl_net_server_ssl_socket_activate(server, address);
518 }
519#ifndef _WIN32
520 else if (cls == EFL_NET_SERVER_UNIX_CLASS)
521 {
522 efl_net_server_unix_unlink_before_bind_set(server, EINA_TRUE); /* makes testing easier */
523 if (socket_activated) efl_net_server_fd_socket_activate(server, address);
524 }
525#endif
526
527 /* an explicit call to efl_net_server_serve() after the object is
528 * constructed allows for more complex setup, such as interacting
529 * with the object to add more properties that couldn't be done
530 * during efl_add().
531 */
532 if (!efl_net_server_serving_get(simple_server))
533 {
534 if (socket_activated)
535 fprintf(stderr, "WARNING: --socket-activated, but not able to use $LISTEN_FDS descriptors. Try to start the server...\n");
536
537 err = efl_net_server_serve(simple_server, address);
538 if (err)
539 {
540 fprintf(stderr, "ERROR: could not serve(%s): %s\n",
541 address, eina_error_msg_get(err));
542 goto end_server;
543 }
544 }
545
546 ecore_main_loop_begin();
547
548 end_server:
549 efl_del(simple_server);
550 simple_server = NULL;
551
552 end:
553 EINA_LIST_FREE(udp_mcast_groups, str)
554 free(str);
555 ecore_con_shutdown();
556 ecore_shutdown();
557
558 return retval;
559}
diff --git a/src/lib/ecore_con/Ecore_Con_Eo.h b/src/lib/ecore_con/Ecore_Con_Eo.h
index 3c79b7a..931f2ed 100644
--- a/src/lib/ecore_con/Ecore_Con_Eo.h
+++ b/src/lib/ecore_con/Ecore_Con_Eo.h
@@ -8,6 +8,10 @@
8#include "efl_net_dialer.eo.h" 8#include "efl_net_dialer.eo.h"
9#include "efl_net_server.eo.h" 9#include "efl_net_server.eo.h"
10 10
11#include "efl_net_socket_simple.eo.h"
12#include "efl_net_dialer_simple.eo.h"
13#include "efl_net_server_simple.eo.h"
14
11#include "efl_net_socket_fd.eo.h" 15#include "efl_net_socket_fd.eo.h"
12#include "efl_net_server_fd.eo.h" 16#include "efl_net_server_fd.eo.h"
13 17
diff --git a/src/lib/ecore_con/efl_net_dialer_simple.c b/src/lib/ecore_con/efl_net_dialer_simple.c
new file mode 100644
index 0000000..178fe5d
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_dialer_simple.c
@@ -0,0 +1,367 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "Ecore.h"
6#include "Ecore_Con.h"
7#include "ecore_con_private.h"
8
9typedef struct
10{
11 const Efl_Class *inner_class;
12 Eina_Stringshare *proxy_url;
13 double dial_timeout;
14 double inactivity_timeout;
15 size_t max_queue_size_input;
16 size_t max_queue_size_output;
17 size_t read_chunk_size;
18 Eina_Slice line_delimiter;
19 struct {
20 Eina_Bool proxy_url;
21 Eina_Bool dial_timeout;
22 Eina_Bool inactivity_timeout;
23 Eina_Bool max_queue_size_input;
24 Eina_Bool max_queue_size_output;
25 Eina_Bool read_chunk_size;
26 Eina_Bool line_delimiter;
27 } pending;
28} Efl_Net_Dialer_Simple_Data;
29
30#define MY_CLASS EFL_NET_DIALER_SIMPLE_CLASS
31
32static void
33_efl_net_dialer_simple_inner_io_resolved(void *data, const Efl_Event *event)
34{
35 Eo *o = data;
36 efl_event_callback_call(o, EFL_NET_DIALER_EVENT_RESOLVED, event->info);
37}
38
39static void
40_efl_net_dialer_simple_inner_io_error(void *data, const Efl_Event *event)
41{
42 Eo *o = data;
43 efl_event_callback_call(o, EFL_NET_DIALER_EVENT_ERROR, event->info);
44 efl_event_callback_call(o, EFL_IO_BUFFERED_STREAM_EVENT_ERROR, event->info);
45}
46
47static void
48_efl_net_dialer_simple_inner_io_connected(void *data, const Efl_Event *event)
49{
50 Eo *o = data;
51 efl_event_callback_call(o, EFL_NET_DIALER_EVENT_CONNECTED, event->info);
52}
53
54EFL_CALLBACKS_ARRAY_DEFINE(_efl_net_dialer_simple_inner_io_cbs,
55 { EFL_NET_DIALER_EVENT_RESOLVED, _efl_net_dialer_simple_inner_io_resolved },
56 { EFL_NET_DIALER_EVENT_ERROR, _efl_net_dialer_simple_inner_io_error },
57 { EFL_NET_DIALER_EVENT_CONNECTED, _efl_net_dialer_simple_inner_io_connected });
58
59EOLIAN static Efl_Object *
60_efl_net_dialer_simple_efl_object_finalize(Eo *o, Efl_Net_Dialer_Simple_Data *pd)
61{
62 if (efl_io_buffered_stream_inner_io_get(o)) goto end;
63
64 if (!pd->inner_class)
65 {
66 ERR("no valid dialer was set with efl_io_buffered_stream_inner_io_set() and no class set with efl_net_dialer_simple_inner_class_set()!");
67 return NULL;
68 }
69 else
70 {
71 Eo *dialer = efl_add(pd->inner_class, o);
72 EINA_SAFETY_ON_NULL_RETURN_VAL(dialer, NULL);
73
74 if (!efl_isa(dialer, EFL_NET_DIALER_INTERFACE))
75 {
76 ERR("class %s=%p doesn't implement Efl.Net.Dialer interface!", efl_class_name_get(pd->inner_class), pd->inner_class);
77 efl_del(dialer);
78 return NULL;
79 }
80 DBG("created new inner dialer %p (%s)", dialer, efl_class_name_get(efl_class_get(dialer)));
81
82 efl_io_buffered_stream_inner_io_set(o, dialer);
83 }
84
85 end:
86 return efl_finalize(efl_super(o, MY_CLASS));
87}
88
89EOLIAN static void
90_efl_net_dialer_simple_efl_object_destructor(Eo *o, Efl_Net_Dialer_Simple_Data *pd)
91{
92 Eo *inner_io;
93
94 if (pd->inner_class) pd->inner_class = NULL;
95
96 eina_stringshare_replace(&pd->proxy_url, NULL);
97 if (pd->line_delimiter.mem)
98 {
99 free((void *)pd->line_delimiter.mem);
100 pd->line_delimiter.mem = NULL;
101 }
102
103 inner_io = efl_io_buffered_stream_inner_io_get(o);
104 if (inner_io)
105 {
106 efl_event_callback_array_del(inner_io, _efl_net_dialer_simple_inner_io_cbs(), o);
107 if (efl_parent_get(inner_io) == o)
108 efl_parent_set(inner_io, NULL);
109 }
110
111 efl_destructor(efl_super(o, EFL_NET_DIALER_SIMPLE_CLASS));
112}
113
114EOLIAN static void
115_efl_net_dialer_simple_efl_io_buffered_stream_inner_io_set(Eo *o, Efl_Net_Dialer_Simple_Data *pd, Efl_Object *io)
116{
117 EINA_SAFETY_ON_FALSE_RETURN(efl_isa(io, EFL_NET_DIALER_INTERFACE));
118 efl_io_buffered_stream_inner_io_set(efl_super(o, MY_CLASS), io);
119 efl_event_callback_array_add(io, _efl_net_dialer_simple_inner_io_cbs(), o);
120
121 /* apply pending dialer values */
122 if (pd->pending.proxy_url)
123 {
124 pd->pending.proxy_url = EINA_FALSE;
125 efl_net_dialer_proxy_set(io, pd->proxy_url);
126 eina_stringshare_replace(&pd->proxy_url, NULL);
127 }
128 if (pd->pending.dial_timeout)
129 {
130 pd->pending.dial_timeout = EINA_FALSE;
131 efl_net_dialer_timeout_dial_set(io, pd->dial_timeout);
132 }
133
134 /* apply pending io buffered stream (own) values */
135 if (pd->pending.inactivity_timeout)
136 {
137 pd->pending.inactivity_timeout = EINA_FALSE;
138 efl_io_buffered_stream_inactivity_timeout_set(o, pd->inactivity_timeout);
139 }
140 if (pd->pending.max_queue_size_input)
141 {
142 pd->pending.max_queue_size_input = EINA_FALSE;
143 efl_io_buffered_stream_max_queue_size_input_set(o, pd->max_queue_size_input);
144 }
145 if (pd->pending.max_queue_size_output)
146 {
147 pd->pending.max_queue_size_output = EINA_FALSE;
148 efl_io_buffered_stream_max_queue_size_output_set(o, pd->max_queue_size_output);
149 }
150 if (pd->pending.read_chunk_size)
151 {
152 pd->pending.read_chunk_size = EINA_FALSE;
153 efl_io_buffered_stream_read_chunk_size_set(o, pd->read_chunk_size);
154 }
155 if (pd->pending.line_delimiter)
156 {
157 pd->pending.line_delimiter = EINA_FALSE;
158 efl_io_buffered_stream_line_delimiter_set(o, &pd->line_delimiter);
159 free((void *)pd->line_delimiter.mem);
160 pd->line_delimiter.mem = NULL;
161 }
162}
163
164EOLIAN static Eina_Error
165_efl_net_dialer_simple_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Simple_Data *pd EINA_UNUSED, const char *address)
166{
167 return efl_net_dialer_dial(efl_io_buffered_stream_inner_io_get(o), address);
168}
169
170EOLIAN static const char *
171_efl_net_dialer_simple_efl_net_dialer_address_dial_get(Eo *o, Efl_Net_Dialer_Simple_Data *pd EINA_UNUSED)
172{
173 return efl_net_dialer_address_dial_get(efl_io_buffered_stream_inner_io_get(o));
174}
175
176EOLIAN static Eina_Bool
177_efl_net_dialer_simple_efl_net_dialer_connected_get(Eo *o, Efl_Net_Dialer_Simple_Data *pd EINA_UNUSED)
178{
179 return efl_net_dialer_connected_get(efl_io_buffered_stream_inner_io_get(o));
180}
181
182EOLIAN static void
183_efl_net_dialer_simple_efl_net_dialer_proxy_set(Eo *o, Efl_Net_Dialer_Simple_Data *pd, const char *proxy_url)
184{
185 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
186
187 if (!inner_io)
188 {
189 eina_stringshare_replace(&pd->proxy_url, proxy_url);
190 pd->pending.proxy_url = EINA_TRUE;
191 return;
192 }
193 efl_net_dialer_proxy_set(inner_io, proxy_url);
194}
195
196EOLIAN static const char *
197_efl_net_dialer_simple_efl_net_dialer_proxy_get(Eo *o, Efl_Net_Dialer_Simple_Data *pd)
198{
199 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
200 if (!inner_io) return pd->proxy_url;
201 return efl_net_dialer_proxy_get(inner_io);
202}
203
204EOLIAN static void
205_efl_net_dialer_simple_efl_net_dialer_timeout_dial_set(Eo *o, Efl_Net_Dialer_Simple_Data *pd, double seconds)
206{
207 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
208
209 if (!inner_io)
210 {
211 pd->dial_timeout = seconds;
212 pd->pending.dial_timeout = EINA_TRUE;
213 return;
214 }
215 efl_net_dialer_timeout_dial_set(inner_io, seconds);
216}
217
218EOLIAN static double
219_efl_net_dialer_simple_efl_net_dialer_timeout_dial_get(Eo *o, Efl_Net_Dialer_Simple_Data *pd)
220{
221 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
222 if (!inner_io) return pd->dial_timeout;
223 return efl_net_dialer_timeout_dial_get(inner_io);
224}
225
226EOLIAN static void
227_efl_net_dialer_simple_efl_io_buffered_stream_inactivity_timeout_set(Eo *o, Efl_Net_Dialer_Simple_Data *pd, double seconds)
228{
229 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
230
231 if (!inner_io)
232 {
233 pd->inactivity_timeout = seconds;
234 pd->pending.inactivity_timeout = EINA_TRUE;
235 return;
236 }
237 efl_io_buffered_stream_inactivity_timeout_set(efl_super(o, MY_CLASS), seconds);
238}
239
240EOLIAN static double
241_efl_net_dialer_simple_efl_io_buffered_stream_inactivity_timeout_get(Eo *o, Efl_Net_Dialer_Simple_Data *pd)
242{
243 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
244 if (!inner_io) return pd->inactivity_timeout;
245 return efl_io_buffered_stream_inactivity_timeout_get(efl_super(o, MY_CLASS));
246}
247
248EOLIAN static void
249_efl_net_dialer_simple_efl_io_buffered_stream_max_queue_size_input_set(Eo *o, Efl_Net_Dialer_Simple_Data *pd, size_t size)
250{
251 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
252
253 if (!inner_io)
254 {
255 pd->max_queue_size_input = size;
256 pd->pending.max_queue_size_input = EINA_TRUE;
257 return;
258 }
259 efl_io_buffered_stream_max_queue_size_input_set(efl_super(o, MY_CLASS), size);
260}
261
262EOLIAN static size_t
263_efl_net_dialer_simple_efl_io_buffered_stream_max_queue_size_input_get(Eo *o, Efl_Net_Dialer_Simple_Data *pd)
264{
265 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
266 if (!inner_io) return pd->max_queue_size_input;
267 return efl_io_buffered_stream_max_queue_size_input_get(efl_super(o, MY_CLASS));
268}
269
270EOLIAN static void
271_efl_net_dialer_simple_efl_io_buffered_stream_max_queue_size_output_set(Eo *o, Efl_Net_Dialer_Simple_Data *pd, size_t size)
272{
273 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
274
275 if (!inner_io)
276 {
277 pd->max_queue_size_output = size;
278 pd->pending.max_queue_size_output = EINA_TRUE;
279 return;
280 }
281 efl_io_buffered_stream_max_queue_size_output_set(efl_super(o, MY_CLASS), size);
282}
283
284EOLIAN static size_t
285_efl_net_dialer_simple_efl_io_buffered_stream_max_queue_size_output_get(Eo *o, Efl_Net_Dialer_Simple_Data *pd)
286{
287 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
288 if (!inner_io) return pd->max_queue_size_output;
289 return efl_io_buffered_stream_max_queue_size_output_get(efl_super(o, MY_CLASS));
290}
291
292EOLIAN static void
293_efl_net_dialer_simple_efl_io_buffered_stream_read_chunk_size_set(Eo *o, Efl_Net_Dialer_Simple_Data *pd, size_t size)
294{
295 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
296
297 if (!inner_io)
298 {
299 pd->read_chunk_size = size;
300 pd->pending.read_chunk_size = EINA_TRUE;
301 return;
302 }
303 efl_io_buffered_stream_read_chunk_size_set(efl_super(o, MY_CLASS), size);
304}
305
306EOLIAN static size_t
307_efl_net_dialer_simple_efl_io_buffered_stream_read_chunk_size_get(Eo *o, Efl_Net_Dialer_Simple_Data *pd)
308{
309 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
310 if (!inner_io) return pd->read_chunk_size;
311 return efl_io_buffered_stream_read_chunk_size_get(efl_super(o, MY_CLASS));
312}
313
314
315EOLIAN static void
316_efl_net_dialer_simple_efl_io_buffered_stream_line_delimiter_set(Eo *o, Efl_Net_Dialer_Simple_Data *pd, const Eina_Slice *slice)
317{
318 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
319
320 if (!inner_io)
321 {
322 free((void *)pd->line_delimiter.mem);
323 if ((!slice) || (!slice->len))
324 {
325 pd->line_delimiter.mem = NULL;
326 pd->line_delimiter.len = 0;
327 }
328 else
329 {
330 char *mem;
331 pd->line_delimiter.mem = mem = malloc(slice->len + 1);
332 EINA_SAFETY_ON_NULL_RETURN(pd->line_delimiter.mem);
333 memcpy(mem, slice->mem, slice->len);
334 mem[slice->len] = '\0';
335 pd->line_delimiter.len = slice->len;
336 }
337
338 pd->pending.line_delimiter = EINA_TRUE;
339 return;
340 }
341 efl_io_buffered_stream_line_delimiter_set(efl_super(o, MY_CLASS), slice);
342}
343
344EOLIAN static const Eina_Slice *
345_efl_net_dialer_simple_efl_io_buffered_stream_line_delimiter_get(Eo *o, Efl_Net_Dialer_Simple_Data *pd)
346{
347 Eo *inner_io = efl_io_buffered_stream_inner_io_get(o);
348 if (!inner_io) return &pd->line_delimiter;
349 return efl_io_buffered_stream_line_delimiter_get(efl_super(o, MY_CLASS));
350}
351
352EOLIAN static void
353_efl_net_dialer_simple_inner_class_set(Eo *o, Efl_Net_Dialer_Simple_Data *pd, const Efl_Class *klass)
354{
355 EINA_SAFETY_ON_TRUE_RETURN(efl_finalized_get(o));
356 EINA_SAFETY_ON_NULL_RETURN(klass);
357 pd->inner_class = klass;
358 DBG("%p inner_class=%p %s", o, klass, efl_class_name_get(klass));
359}
360
361EOLIAN static const Efl_Class *
362_efl_net_dialer_simple_inner_class_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Simple_Data *pd)
363{
364 return pd->inner_class;
365}
366
367#include "efl_net_dialer_simple.eo.c"
diff --git a/src/lib/ecore_con/efl_net_dialer_simple.eo b/src/lib/ecore_con/efl_net_dialer_simple.eo
new file mode 100644
index 0000000..f54b13e
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_dialer_simple.eo
@@ -0,0 +1,85 @@
1class Efl.Net.Dialer.Simple (Efl.Net.Socket.Simple, Efl.Net.Dialer) {
2 [[Connects to a remote server offering an easy to use, buffered I/O.
3
4 The simple dialer is based on @Efl.Net.Socket.Simple, that
5 encapsulates an actual @Efl.Net.Socket, and uses it with an
6 @Efl.Io.Buffered_Stream, which creates an input @Efl.Io.Queue,
7 an output @Efl.Io.Queue and these are linked using a receiver
8 and a sender @Efl.Io.Copier.
9
10 The idea is that unlike traditional @Efl.Net.Socket that will
11 attempt to write directly to socket and thus may take less data
12 than requested, this one will keep the pending data in its own
13 buffer, feeding to the actual socket when it
14 @Efl.Io.Writer.can_write. That makes its operation much simpler
15 as @Efl.Io.Writer.write will always take the full data -- allows
16 "write and forget", if unlimited (see
17 @Efl.Io.Buffered_Stream.max_queue_size_output).
18
19 Reading is also much simpler since received data is kept in an
20 @Efl.Io.Queue, thus its size can be queried with
21 @Efl.Io.Buffered_Stream.pending_read and read with
22 @Efl.Io.Reader.read or peeked with
23 @Efl.Io.Buffered_Stream.slice_get, then discarded with
24 @Efl.Io.Buffered_Stream.discard or
25 @Efl.Io.Buffered_Stream.clear.
26
27 Then when waiting for a complete message, just peek at its
28 contents, if not complete do nothing, if complete then either
29 @Efl.Io.Reader.read to get a copy or manipulate a read-only
30 reference from @Efl.Io.Buffered_Stream.slice_get and then
31 @Efl.Io.Buffered_Stream.discard
32
33 The actual dialer is created using the class given as the
34 constructor property @.inner_class and can be retrieved with
35 @Efl.Io.Buffered_Stream.inner_io, which should be used with
36 care, like extra configuration before @Efl.Net.Dialer.dial is
37 called.
38
39 If your object class requires some constructor-only properties
40 to be set prior to @Efl.Object.finalize, then use
41 @Efl.Io.Buffered_Stream.inner_io directly providing an already
42 created dialer.
43
44 @since 1.19
45 ]]
46
47 methods {
48 @property inner_class {
49 [[The class used to create @Efl.Io.Buffered_Stream.inner_io if none was provided.
50
51 This class could be set at construction time and will be
52 used to create the inner socket during
53 @Efl.Object.finalize.
54
55 It is a helper for users, removing the burden to
56 manually create and specify a dialer object.
57 ]]
58 get {
59 [[The internal class used to create the inner dialer.]]
60 }
61 set {
62 [[Constructor-only property to define the class used to create the inner dialer.]]
63 }
64 values {
65 klass: const(Efl.Class); [[The class]]
66 }
67 }
68 }
69
70 implements {
71 Efl.Object.finalize;
72 Efl.Object.destructor;
73 Efl.Io.Buffered_Stream.inner_io.set;
74 Efl.Net.Dialer.dial;
75 Efl.Net.Dialer.address_dial.get;
76 Efl.Net.Dialer.connected.get;
77 Efl.Net.Dialer.proxy;
78 Efl.Net.Dialer.timeout_dial;
79 Efl.Io.Buffered_Stream.inactivity_timeout;
80 Efl.Io.Buffered_Stream.max_queue_size_input;
81 Efl.Io.Buffered_Stream.max_queue_size_output;
82 Efl.Io.Buffered_Stream.read_chunk_size;
83 Efl.Io.Buffered_Stream.line_delimiter;
84 }
85}
diff --git a/src/lib/ecore_con/efl_net_server_simple.c b/src/lib/ecore_con/efl_net_server_simple.c
new file mode 100644
index 0000000..e42d4fc
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_server_simple.c
@@ -0,0 +1,243 @@
1#define EFL_NET_SERVER_PROTECTED 1
2
3#ifdef HAVE_CONFIG_H
4# include <config.h>
5#endif
6
7#include "Ecore.h"
8#include "Ecore_Con.h"
9#include "ecore_con_private.h"
10
11typedef struct
12{
13 const Efl_Class *inner_class;
14 Eo *inner_server;
15} Efl_Net_Server_Simple_Data;
16
17#define MY_CLASS EFL_NET_SERVER_SIMPLE_CLASS
18
19static void
20_efl_net_server_simple_client_event_closed(void *data, const Efl_Event *event)
21{
22 Eo *server = data;
23 Eo *client = event->object;
24
25 efl_event_callback_del(client, EFL_IO_CLOSER_EVENT_CLOSED, _efl_net_server_simple_client_event_closed, server);
26 if (efl_parent_get(client) == server)
27 efl_parent_set(client, NULL);
28
29 /* do NOT change count as we're using the underlying server's count */
30 //efl_net_server_clients_count_set(server, efl_net_server_clients_count_get(server) - 1);
31}
32
33static Eina_Bool
34_efl_net_server_simple_efl_net_server_client_announce(Eo *o, Efl_Net_Server_Simple_Data *pd EINA_UNUSED, Eo *client)
35{
36 EINA_SAFETY_ON_NULL_RETURN_VAL(client, EINA_FALSE);
37 EINA_SAFETY_ON_FALSE_GOTO(efl_isa(client, EFL_NET_SOCKET_SIMPLE_CLASS), wrong_type);
38 EINA_SAFETY_ON_FALSE_GOTO(efl_parent_get(client) == o, wrong_parent);
39
40 efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_ADD, client);
41
42 if (efl_parent_get(client) != o)
43 {
44 DBG("client %s was reparented! Ignoring it...",
45 efl_net_socket_address_remote_get(client));
46 return EINA_TRUE;
47 }
48
49 if (efl_ref_get(client) == 1) /* users must take a reference themselves */
50 {
51 DBG("client %s was not handled, closing it...",
52 efl_net_socket_address_remote_get(client));
53 efl_del(client);
54 return EINA_FALSE;
55 }
56 else if (efl_io_closer_closed_get(client))
57 {
58 DBG("client %s was closed from 'client,add', delete it...",
59 efl_net_socket_address_remote_get(client));
60 efl_del(client);
61 return EINA_FALSE;
62 }
63
64 /* do NOT change count as we're using the underlying server's count */
65 //efl_net_server_clients_count_set(o, efl_net_server_clients_count_get(o) + 1);
66 efl_event_callback_add(client, EFL_IO_CLOSER_EVENT_CLOSED, _efl_net_server_simple_client_event_closed, o);
67 return EINA_TRUE;
68
69 wrong_type:
70 ERR("%p client %p (%s) doesn't implement Efl.Net.Socket.Simple class, deleting it.", o, client, efl_class_name_get(efl_class_get(client)));
71 efl_del(client);
72 return EINA_FALSE;
73
74 wrong_parent:
75 ERR("%p client %p (%s) parent=%p is not our child, deleting it.", o, client, efl_class_name_get(efl_class_get(client)), efl_parent_get(client));
76 efl_del(client);
77 return EINA_FALSE;
78}
79
80static void
81_efl_net_server_simple_inner_server_client_add(void *data, const Efl_Event *event)
82{
83 Eo *o = data;
84 Eo *client_inner = event->info;
85 Eo *client_simple;
86 const char *addr = efl_net_socket_address_remote_get(client_inner);
87
88 client_simple = efl_add(EFL_NET_SOCKET_SIMPLE_CLASS, o,
89 efl_io_buffered_stream_inner_io_set(efl_added, client_inner));
90
91 if (!client_simple)
92 {
93 ERR("simple server %p could not wrap client %p '%s'", o, client_inner, addr);
94 efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_REJECTED, (void *)addr);
95 return;
96 }
97
98 efl_net_server_client_announce(o, client_simple);
99}
100
101static void
102_efl_net_server_simple_inner_server_client_rejected(void *data, const Efl_Event *event)
103{
104 Eo *o = data;
105 efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_REJECTED, event->info);
106}
107
108static void
109_efl_net_server_simple_inner_server_error(void *data, const Efl_Event *event)
110{
111 Eo *o = data;
112 efl_event_callback_call(o, EFL_NET_SERVER_EVENT_ERROR, event->info);
113}
114
115static void
116_efl_net_server_simple_inner_server_serving(void *data, const Efl_Event *event)
117{
118 Eo *o = data;
119 efl_event_callback_call(o, EFL_NET_SERVER_EVENT_SERVING, event->info);
120}
121
122EFL_CALLBACKS_ARRAY_DEFINE(_efl_net_server_simple_inner_server_cbs,
123 { EFL_NET_SERVER_EVENT_CLIENT_ADD, _efl_net_server_simple_inner_server_client_add },
124 { EFL_NET_SERVER_EVENT_CLIENT_REJECTED, _efl_net_server_simple_inner_server_client_rejected },
125 { EFL_NET_SERVER_EVENT_ERROR, _efl_net_server_simple_inner_server_error },
126 { EFL_NET_SERVER_EVENT_SERVING, _efl_net_server_simple_inner_server_serving });
127
128EOLIAN static Efl_Object *
129_efl_net_server_simple_efl_object_finalize(Eo *o, Efl_Net_Server_Simple_Data *pd)
130{
131 if (pd->inner_server) goto end;
132
133 if (!pd->inner_class)
134 {
135 ERR("no valid server was set with efl_net_server_simple_inner_server_set() and no class set with efl_net_server_simple_inner_class_set()!");
136 return NULL;
137 }
138 else
139 {
140 Eo *server = efl_add(pd->inner_class, o);
141 EINA_SAFETY_ON_NULL_RETURN_VAL(server, NULL);
142
143 if (!efl_isa(server, EFL_NET_SERVER_INTERFACE))
144 {
145 ERR("class %s=%p doesn't implement Efl.Net.Server interface!", efl_class_name_get(pd->inner_class), pd->inner_class);
146 efl_del(server);
147 return NULL;
148 }
149 DBG("created new inner server %p (%s)", server, efl_class_name_get(efl_class_get(server)));
150
151 efl_net_server_simple_inner_server_set(o, server);
152 }
153
154 end:
155 return efl_finalize(efl_super(o, MY_CLASS));
156}
157
158EOLIAN static void
159_efl_net_server_simple_efl_object_destructor(Eo *o, Efl_Net_Server_Simple_Data *pd)
160{
161 if (pd->inner_class) pd->inner_class = NULL;
162
163 if (pd->inner_server)
164 {
165 efl_event_callback_array_del(pd->inner_server, _efl_net_server_simple_inner_server_cbs(), o);
166 if (efl_parent_get(pd->inner_server) == o)
167 efl_parent_set(pd->inner_server, NULL);
168 }
169
170 efl_destructor(efl_super(o, MY_CLASS));
171}
172
173EOLIAN static Eina_Error
174_efl_net_server_simple_efl_net_server_serve(Eo *o EINA_UNUSED, Efl_Net_Server_Simple_Data *pd, const char *address)
175{
176 return efl_net_server_serve(pd->inner_server, address);
177}
178
179EOLIAN static const char *
180_efl_net_server_simple_efl_net_server_address_get(Eo *o EINA_UNUSED, Efl_Net_Server_Simple_Data *pd)
181{
182 return efl_net_server_address_get(pd->inner_server);
183}
184
185EOLIAN static unsigned int
186_efl_net_server_simple_efl_net_server_clients_count_get(Eo *o EINA_UNUSED, Efl_Net_Server_Simple_Data *pd)
187{
188 return efl_net_server_clients_count_get(pd->inner_server);
189}
190
191EOLIAN static void
192_efl_net_server_simple_efl_net_server_clients_limit_set(Eo *o EINA_UNUSED, Efl_Net_Server_Simple_Data *pd, unsigned int limit, Eina_Bool reject_excess)
193{
194 efl_net_server_clients_limit_set(pd->inner_server, limit, reject_excess);
195}
196
197EOLIAN static void
198_efl_net_server_simple_efl_net_server_clients_limit_get(Eo *o EINA_UNUSED, Efl_Net_Server_Simple_Data *pd, unsigned int *limit, Eina_Bool *reject_excess)
199{
200 efl_net_server_clients_limit_get(pd->inner_server, limit, reject_excess);
201}
202
203EOLIAN static Eina_Bool
204_efl_net_server_simple_efl_net_server_serving_get(Eo *o EINA_UNUSED, Efl_Net_Server_Simple_Data *pd)
205{
206 return efl_net_server_serving_get(pd->inner_server);
207}
208
209EOLIAN static void
210_efl_net_server_simple_inner_class_set(Eo *o, Efl_Net_Server_Simple_Data *pd, const Efl_Class *klass)
211{
212 EINA_SAFETY_ON_TRUE_RETURN(efl_finalized_get(o));
213 EINA_SAFETY_ON_NULL_RETURN(klass);
214 pd->inner_class = klass;
215 DBG("%p inner_class=%p %s", o, klass, efl_class_name_get(klass));
216}
217
218EOLIAN static const Efl_Class *
219_efl_net_server_simple_inner_class_get(Eo *o EINA_UNUSED, Efl_Net_Server_Simple_Data *pd)
220{
221 return pd->inner_class;
222}
223
224EOLIAN static void
225_efl_net_server_simple_inner_server_set(Eo *o, Efl_Net_Server_Simple_Data *pd, Efl_Object *server)
226{
227 EINA_SAFETY_ON_TRUE_RETURN(efl_finalized_get(o));
228 EINA_SAFETY_ON_NULL_RETURN(server);
229 EINA_SAFETY_ON_TRUE_RETURN(pd->inner_server != NULL);
230 EINA_SAFETY_ON_FALSE_RETURN(efl_isa(server, EFL_NET_SERVER_INTERFACE));
231
232 pd->inner_server = efl_ref(server);
233 efl_event_callback_array_add(server, _efl_net_server_simple_inner_server_cbs(), o);
234 DBG("%p inner_server=%p (%s)", o, server, efl_class_name_get(efl_class_get(server)));
235}
236
237EOLIAN static Efl_Object *
238_efl_net_server_simple_inner_server_get(Eo *o EINA_UNUSED, Efl_Net_Server_Simple_Data *pd)
239{
240 return pd->inner_server;
241}
242
243#include "efl_net_server_simple.eo.c"
diff --git a/src/lib/ecore_con/efl_net_server_simple.eo b/src/lib/ecore_con/efl_net_server_simple.eo
new file mode 100644
index 0000000..ec2af11
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_server_simple.eo
@@ -0,0 +1,55 @@
1class Efl.Net.Server.Simple (Efl.Loop_User, Efl.Net.Server) {
2 [[A network server wrapper that creates clients based on @Efl.Net.Socket.Simple.
3
4 This is just a wrapper server, it will take an actual server
5 using @.inner_server or create one using @.inner_class.
6
7 @since 1.19
8 ]]
9 methods {
10 @property inner_class {
11 [[The class used to create @.inner_server if none was provided.
12
13 This class must be set at construction time and will be
14 used to create the inner socket during
15 @Efl.Object.finalize.
16
17 It is a helper for users, removing the burden to
18 manually create and specify a dialer object.
19 ]]
20 get {
21 [[The internal class used to create the inner dialer.]]
22 }
23 set {
24 [[Constructor-only property to define the class used to create the inner dialer.]]
25 }
26 values {
27 klass: const(Efl.Class); [[The class]]
28 }
29 }
30
31 @property inner_server {
32 [[The inner @Efl.Net.Server this wrapper operates on.]]
33 get {
34 [[The internal server used for actual operations, use with care!]]
35 }
36 set {
37 [[Constructor-only property to set the inner_server.]]
38 }
39 values {
40 server: Efl.Object; [[The server instance]]
41 }
42 }
43 }
44
45 implements {
46 Efl.Object.finalize;
47 Efl.Object.destructor;
48 Efl.Net.Server.serve;
49 Efl.Net.Server.client_announce;
50 Efl.Net.Server.address.get;
51 Efl.Net.Server.clients_count.get;
52 Efl.Net.Server.clients_limit;
53 Efl.Net.Server.serving.get;
54 }
55}
diff --git a/src/lib/ecore_con/efl_net_socket_simple.c b/src/lib/ecore_con/efl_net_socket_simple.c
new file mode 100644
index 0000000..c549050
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_socket_simple.c
@@ -0,0 +1,35 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "Ecore.h"
6#include "Ecore_Con.h"
7#include "ecore_con_private.h"
8
9typedef struct
10{
11
12} Efl_Net_Socket_Simple_Data;
13
14#define MY_CLASS EFL_NET_SOCKET_SIMPLE_CLASS
15
16EOLIAN static void
17_efl_net_socket_simple_efl_io_buffered_stream_inner_io_set(Eo *o, Efl_Net_Socket_Simple_Data *pd EINA_UNUSED, Efl_Object *io)
18{
19 EINA_SAFETY_ON_FALSE_RETURN(efl_isa(io, EFL_NET_SOCKET_INTERFACE));
20 efl_io_buffered_stream_inner_io_set(efl_super(o, MY_CLASS), io);
21}
22
23EOLIAN static const char *
24_efl_net_socket_simple_efl_net_socket_address_local_get(Eo *o, Efl_Net_Socket_Simple_Data *pd EINA_UNUSED)
25{
26 return efl_net_socket_address_local_get(efl_io_buffered_stream_inner_io_get(o));
27}
28
29EOLIAN static const char *
30_efl_net_socket_simple_efl_net_socket_address_remote_get(Eo *o, Efl_Net_Socket_Simple_Data *pd EINA_UNUSED)
31{
32 return efl_net_socket_address_remote_get(efl_io_buffered_stream_inner_io_get(o));
33}
34
35#include "efl_net_socket_simple.eo.c"
diff --git a/src/lib/ecore_con/efl_net_socket_simple.eo b/src/lib/ecore_con/efl_net_socket_simple.eo
new file mode 100644
index 0000000..b6339ac
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_socket_simple.eo
@@ -0,0 +1,45 @@
1class Efl.Net.Socket.Simple (Efl.Io.Buffered_Stream, Efl.Net.Socket) {
2 [[A wrapper socket offering an easy to use, buffered I/O.
3
4 The simple socket encapsulates an actual @Efl.Net.Socket, and
5 uses it with an @Efl.Io.Buffered_Stream, which creates an input
6 @Efl.Io.Queue, an output @Efl.Io.Queue and these are linked
7 using a receiver and a sender @Efl.Io.Copier.
8
9 The idea is that unlike traditional @Efl.Net.Socket that will
10 attempt to write directly to socket and thus may take less data
11 than requested, this one will keep the pending data in its own
12 buffer, feeding to the actual socket when it
13 @Efl.Io.Writer.can_write. That makes its operation much simpler
14 as @Efl.Io.Writer.write will always take the full data -- allows
15 "write and forget", if unlimited (see
16 @Efl.Io.Buffered_Stream.max_queue_size_output).
17
18 Reading is also much simpler since received data is kept in an
19 @Efl.Io.Queue, thus its size can be queried with
20 @Efl.Io.Buffered_Stream.pending_read and read with
21 @Efl.Io.Reader.read or peeked with
22 @Efl.Io.Buffered_Stream.slice_get, then discarded with
23 @Efl.Io.Buffered_Stream.discard or
24 @Efl.Io.Buffered_Stream.clear.
25
26 Then when waiting for a complete message, just peek at its
27 contents, if not complete do nothing, if complete then either
28 @Efl.Io.Reader.read to get a copy or manipulate a read-only
29 reference from @Efl.Io.Buffered_Stream.slice_get and then
30 @Efl.Io.Buffered_Stream.discard
31
32 The actual socket is set with the constructor method
33 @Efl.Io.Buffered_Stream.inner_io.set and can be retrieved with
34 @Efl.Io.Buffered_Stream.inner_io.get, which should be used with
35 care.
36
37 @since 1.19
38 ]]
39
40 implements {
41 Efl.Io.Buffered_Stream.inner_io.set;
42 Efl.Net.Socket.address_local.get;
43 Efl.Net.Socket.address_remote.get;
44 }
45}