diff options
-rw-r--r-- | src/Makefile_Ecore_Con.am | 6 | ||||
-rw-r--r-- | src/examples/ecore/.gitignore | 2 | ||||
-rw-r--r-- | src/examples/ecore/Makefile.am | 10 | ||||
-rw-r--r-- | src/examples/ecore/efl_net_dialer_simple_example.c | 451 | ||||
-rw-r--r-- | src/examples/ecore/efl_net_server_simple_example.c | 559 | ||||
-rw-r--r-- | src/lib/ecore_con/Ecore_Con_Eo.h | 4 | ||||
-rw-r--r-- | src/lib/ecore_con/efl_net_dialer_simple.c | 367 | ||||
-rw-r--r-- | src/lib/ecore_con/efl_net_dialer_simple.eo | 85 | ||||
-rw-r--r-- | src/lib/ecore_con/efl_net_server_simple.c | 243 | ||||
-rw-r--r-- | src/lib/ecore_con/efl_net_server_simple.eo | 55 | ||||
-rw-r--r-- | src/lib/ecore_con/efl_net_socket_simple.c | 35 | ||||
-rw-r--r-- | src/lib/ecore_con/efl_net_socket_simple.eo | 45 |
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 \ | |||
92 | lib/ecore_con/ecore_con_private.h \ | 95 | lib/ecore_con/ecore_con_private.h \ |
93 | lib/ecore_con/ecore_con_info.c \ | 96 | lib/ecore_con/ecore_con_info.c \ |
94 | lib/ecore_con/efl_net_socket.c \ | 97 | lib/ecore_con/efl_net_socket.c \ |
98 | lib/ecore_con/efl_net_socket_simple.c \ | ||
95 | lib/ecore_con/efl_net_socket_fd.c \ | 99 | lib/ecore_con/efl_net_socket_fd.c \ |
96 | lib/ecore_con/efl_net_socket_tcp.c \ | 100 | lib/ecore_con/efl_net_socket_tcp.c \ |
97 | lib/ecore_con/efl_net_socket_udp.c \ | 101 | lib/ecore_con/efl_net_socket_udp.c \ |
98 | lib/ecore_con/efl_net_dialer.c \ | 102 | lib/ecore_con/efl_net_dialer.c \ |
103 | lib/ecore_con/efl_net_dialer_simple.c \ | ||
99 | lib/ecore_con/efl_net_dialer_tcp.c \ | 104 | lib/ecore_con/efl_net_dialer_tcp.c \ |
100 | lib/ecore_con/efl_net_dialer_udp.c \ | 105 | lib/ecore_con/efl_net_dialer_udp.c \ |
101 | lib/ecore_con/efl_net_dialer_http.c \ | 106 | lib/ecore_con/efl_net_dialer_http.c \ |
102 | lib/ecore_con/efl_net_dialer_websocket.c \ | 107 | lib/ecore_con/efl_net_dialer_websocket.c \ |
103 | lib/ecore_con/efl_net_server.c \ | 108 | lib/ecore_con/efl_net_server.c \ |
109 | lib/ecore_con/efl_net_server_simple.c \ | ||
104 | lib/ecore_con/efl_net_server_fd.c \ | 110 | lib/ecore_con/efl_net_server_fd.c \ |
105 | lib/ecore_con/efl_net_server_tcp.c \ | 111 | lib/ecore_con/efl_net_server_tcp.c \ |
106 | lib/ecore_con/efl_net_server_udp.c \ | 112 | lib/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 \ | |||
86 | efl_io_queue_example \ | 86 | efl_io_queue_example \ |
87 | efl_io_buffered_stream_example \ | 87 | efl_io_buffered_stream_example \ |
88 | efl_net_server_example \ | 88 | efl_net_server_example \ |
89 | efl_net_server_simple_example \ | ||
89 | efl_net_dialer_http_example \ | 90 | efl_net_dialer_http_example \ |
90 | efl_net_dialer_websocket_example \ | 91 | efl_net_dialer_websocket_example \ |
91 | efl_net_dialer_websocket_autobahntestee \ | 92 | efl_net_dialer_websocket_autobahntestee \ |
92 | efl_net_dialer_udp_example \ | 93 | efl_net_dialer_udp_example \ |
94 | efl_net_dialer_simple_example \ | ||
93 | efl_net_socket_ssl_dialer_example \ | 95 | efl_net_socket_ssl_dialer_example \ |
94 | efl_net_socket_ssl_server_example \ | 96 | efl_net_socket_ssl_server_example \ |
95 | efl_net_session_example \ | 97 | efl_net_session_example \ |
@@ -324,6 +326,9 @@ efl_io_buffered_stream_example_LDADD = $(ECORE_CON_COMMON_LDADD) | |||
324 | efl_net_server_example_SOURCES = efl_net_server_example.c | 326 | efl_net_server_example_SOURCES = efl_net_server_example.c |
325 | efl_net_server_example_LDADD = $(ECORE_CON_COMMON_LDADD) | 327 | efl_net_server_example_LDADD = $(ECORE_CON_COMMON_LDADD) |
326 | 328 | ||
329 | efl_net_server_simple_example_SOURCES = efl_net_server_simple_example.c | ||
330 | efl_net_server_simple_example_LDADD = $(ECORE_CON_COMMON_LDADD) | ||
331 | |||
327 | efl_net_dialer_http_example_SOURCES = efl_net_dialer_http_example.c | 332 | efl_net_dialer_http_example_SOURCES = efl_net_dialer_http_example.c |
328 | efl_net_dialer_http_example_LDADD = $(ECORE_CON_COMMON_LDADD) | 333 | efl_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) | |||
336 | efl_net_dialer_udp_example_SOURCES = efl_net_dialer_udp_example.c | 341 | efl_net_dialer_udp_example_SOURCES = efl_net_dialer_udp_example.c |
337 | efl_net_dialer_udp_example_LDADD = $(ECORE_CON_COMMON_LDADD) | 342 | efl_net_dialer_udp_example_LDADD = $(ECORE_CON_COMMON_LDADD) |
338 | 343 | ||
344 | efl_net_dialer_simple_example_SOURCES = efl_net_dialer_simple_example.c | ||
345 | efl_net_dialer_simple_example_LDADD = $(ECORE_CON_COMMON_LDADD) | ||
346 | |||
339 | if ! HAVE_WINDOWS | 347 | if ! HAVE_WINDOWS |
340 | EXTRA_PROGRAMS += efl_net_dialer_unix_example | 348 | EXTRA_PROGRAMS += efl_net_dialer_unix_example |
341 | efl_net_dialer_unix_example_SOURCES = efl_net_dialer_unix_example.c | 349 | efl_net_dialer_unix_example_SOURCES = efl_net_dialer_unix_example.c |
@@ -413,10 +421,12 @@ efl_io_copier_simple_example.c \ | |||
413 | efl_io_queue_example.c \ | 421 | efl_io_queue_example.c \ |
414 | efl_io_buffered_stream_example.c \ | 422 | efl_io_buffered_stream_example.c \ |
415 | efl_net_server_example.c \ | 423 | efl_net_server_example.c \ |
424 | efl_net_server_simple_example.c \ | ||
416 | efl_net_dialer_http_example.c \ | 425 | efl_net_dialer_http_example.c \ |
417 | efl_net_dialer_websocket_example.c \ | 426 | efl_net_dialer_websocket_example.c \ |
418 | efl_net_dialer_websocket_autobahntestee.c \ | 427 | efl_net_dialer_websocket_autobahntestee.c \ |
419 | efl_net_dialer_udp_example.c \ | 428 | efl_net_dialer_udp_example.c \ |
429 | efl_net_dialer_simple_example.c \ | ||
420 | efl_net_socket_ssl_dialer_example.c \ | 430 | efl_net_socket_ssl_dialer_example.c \ |
421 | efl_net_socket_ssl_server_example.c \ | 431 | efl_net_socket_ssl_server_example.c \ |
422 | efl_net_session_example.c \ | 432 | efl_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 | |||
9 | static int retval = EXIT_SUCCESS; | ||
10 | static Eina_Bool do_read = EINA_FALSE; | ||
11 | static Eina_Bool do_discard = EINA_FALSE; | ||
12 | static Eina_Slice line_delm_slice; | ||
13 | |||
14 | static 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 | |||
28 | static 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 | |||
49 | static 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 | |||
96 | static 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 | |||
146 | static 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 | |||
154 | static 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 | |||
164 | static 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 | |||
175 | static void | ||
176 | _done_receiving(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) | ||
177 | { | ||
178 | fprintf(stderr, "INFO: done receiving\n"); | ||
179 | } | ||
180 | |||
181 | static 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 | |||
188 | EFL_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 | |||
199 | static 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 | |||
232 | static const char * protocols[] = { | ||
233 | "tcp", | ||
234 | "udp", | ||
235 | "ssl", | ||
236 | #ifndef _WIN32 | ||
237 | "unix", | ||
238 | #endif | ||
239 | NULL | ||
240 | }; | ||
241 | |||
242 | static 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 | |||
280 | int | ||
281 | main(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 | |||
8 | static int retval = EXIT_SUCCESS; | ||
9 | static Eina_Bool echo = EINA_FALSE; | ||
10 | static double timeout = 10.0; | ||
11 | |||
12 | /* NOTE: client i/o events are only used as debug, you can omit these */ | ||
13 | |||
14 | static 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 | |||
22 | static 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 | |||
30 | static 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 | |||
37 | static 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 | |||
58 | static 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 | */ | ||
68 | static 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 | */ | ||
82 | static 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 | |||
93 | EFL_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 | |||
109 | static 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 | |||
117 | static 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 | |||
140 | EFL_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 | */ | ||
152 | static 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 | |||
210 | static 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 | |||
217 | static 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 | |||
226 | static 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 | |||
263 | EFL_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 | |||
269 | static const char * protocols[] = { | ||
270 | "tcp", | ||
271 | "udp", | ||
272 | "ssl", | ||
273 | #ifndef _WIN32 | ||
274 | "unix", | ||
275 | #endif | ||
276 | NULL | ||
277 | }; | ||
278 | |||
279 | static const char *ciphers_strs[] = { | ||
280 | "auto", | ||
281 | "sslv3", | ||
282 | "tlsv1", | ||
283 | "tlsv1.1", | ||
284 | "tlsv1.2", | ||
285 | NULL | ||
286 | }; | ||
287 | |||
288 | static 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 | |||
345 | int | ||
346 | main(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 | |||
9 | typedef 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 | |||
32 | static 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 | |||
39 | static 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 | |||
47 | static 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 | |||
54 | EFL_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 | |||
59 | EOLIAN 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 | |||
89 | EOLIAN 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 | |||
114 | EOLIAN 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 | |||
164 | EOLIAN 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 | |||
170 | EOLIAN 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 | |||
176 | EOLIAN 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 | |||
182 | EOLIAN 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 | |||
196 | EOLIAN 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 | |||
204 | EOLIAN 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 | |||
218 | EOLIAN 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 | |||
226 | EOLIAN 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 | |||
240 | EOLIAN 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 | |||
248 | EOLIAN 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 | |||
262 | EOLIAN 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 | |||
270 | EOLIAN 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 | |||
284 | EOLIAN 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 | |||
292 | EOLIAN 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 | |||
306 | EOLIAN 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 | |||
315 | EOLIAN 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 | |||
344 | EOLIAN 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 | |||
352 | EOLIAN 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 | |||
361 | EOLIAN 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 @@ | |||
1 | class 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 | |||
11 | typedef 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 | |||
19 | static 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 | |||
33 | static 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 | |||
80 | static 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 | |||
101 | static 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 | |||
108 | static 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 | |||
115 | static 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 | |||
122 | EFL_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 | |||
128 | EOLIAN 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 | |||
158 | EOLIAN 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 | |||
173 | EOLIAN 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 | |||
179 | EOLIAN 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 | |||
185 | EOLIAN 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 | |||
191 | EOLIAN 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 | |||
197 | EOLIAN 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 | |||
203 | EOLIAN 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 | |||
209 | EOLIAN 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 | |||
218 | EOLIAN 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 | |||
224 | EOLIAN 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 | |||
237 | EOLIAN 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 @@ | |||
1 | class 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 | |||
9 | typedef struct | ||
10 | { | ||
11 | |||
12 | } Efl_Net_Socket_Simple_Data; | ||
13 | |||
14 | #define MY_CLASS EFL_NET_SOCKET_SIMPLE_CLASS | ||
15 | |||
16 | EOLIAN 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 | |||
23 | EOLIAN 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 | |||
29 | EOLIAN 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 @@ | |||
1 | class 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 | } | ||