summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>2017-03-22 04:29:16 -0300
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>2017-03-22 04:29:16 -0300
commite552e7ea14e28b1085058667177883a42fbd0004 (patch)
tree29df6b3711e897c8557a0a2b478994664b5a193b
parent76b5749ea00b1009a5a9621b76604e4883e0e6e2 (diff)
WIP: efl_net_{socket,dialer,server}_windowsdevs/barbieri/efl_net_socket_windows
This is the local socket for windows, analogous to AF_UNIX. WIP: This is being worked out by vtorri and myself. WIP: still untested
-rw-r--r--src/Makefile_Ecore_Con.am9
-rw-r--r--src/examples/ecore/Makefile.am6
-rw-r--r--src/examples/ecore/efl_io_copier_example.c72
-rw-r--r--src/examples/ecore/efl_net_dialer_windows_example.c212
-rw-r--r--src/examples/ecore/efl_net_server_example.c12
-rw-r--r--src/examples/ecore/efl_net_server_simple_example.c12
-rw-r--r--src/lib/ecore_con/Ecore_Con_Eo.h3
-rw-r--r--src/lib/ecore_con/ecore_con_private.h22
-rw-r--r--src/lib/ecore_con/efl_net_dialer_windows.c130
-rw-r--r--src/lib/ecore_con/efl_net_dialer_windows.eo20
-rw-r--r--src/lib/ecore_con/efl_net_server_windows.c454
-rw-r--r--src/lib/ecore_con/efl_net_server_windows.eo36
-rw-r--r--src/lib/ecore_con/efl_net_socket_windows.c599
-rw-r--r--src/lib/ecore_con/efl_net_socket_windows.eo24
14 files changed, 1598 insertions, 13 deletions
diff --git a/src/Makefile_Ecore_Con.am b/src/Makefile_Ecore_Con.am
index b22c3f6c0d..cfae980ed4 100644
--- a/src/Makefile_Ecore_Con.am
+++ b/src/Makefile_Ecore_Con.am
@@ -33,6 +33,10 @@ ecore_con_eolian_files = \
33 lib/ecore_con/ecore_con_eet_client_obj.eo 33 lib/ecore_con/ecore_con_eet_client_obj.eo
34 34
35if HAVE_WINDOWS 35if HAVE_WINDOWS
36ecore_con_eolian_files += \
37 lib/ecore_con/efl_net_socket_windows.eo \
38 lib/ecore_con/efl_net_dialer_windows.eo \
39 lib/ecore_con/efl_net_server_windows.eo
36else 40else
37ecore_con_eolian_files += \ 41ecore_con_eolian_files += \
38 lib/ecore_con/efl_net_socket_unix.eo \ 42 lib/ecore_con/efl_net_socket_unix.eo \
@@ -145,7 +149,10 @@ lib/ecore_con/efl_net_ssl_ctx-gnutls.c \
145lib/ecore_con/efl_net_ssl_ctx-none.c 149lib/ecore_con/efl_net_ssl_ctx-none.c
146 150
147if HAVE_WINDOWS 151if HAVE_WINDOWS
148#lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local_win32.c 152lib_ecore_con_libecore_con_la_SOURCES += \
153lib/ecore_con/efl_net_socket_windows.c \
154lib/ecore_con/efl_net_dialer_windows.c \
155lib/ecore_con/efl_net_server_windows.c
149else 156else
150lib_ecore_con_libecore_con_la_SOURCES += \ 157lib_ecore_con_libecore_con_la_SOURCES += \
151lib/ecore_con/efl_net_socket_unix.c \ 158lib/ecore_con/efl_net_socket_unix.c \
diff --git a/src/examples/ecore/Makefile.am b/src/examples/ecore/Makefile.am
index c90e0c6f2b..e10dfc7827 100644
--- a/src/examples/ecore/Makefile.am
+++ b/src/examples/ecore/Makefile.am
@@ -353,7 +353,11 @@ efl_net_dialer_udp_example_LDADD = $(ECORE_CON_COMMON_LDADD)
353efl_net_dialer_simple_example_SOURCES = efl_net_dialer_simple_example.c 353efl_net_dialer_simple_example_SOURCES = efl_net_dialer_simple_example.c
354efl_net_dialer_simple_example_LDADD = $(ECORE_CON_COMMON_LDADD) 354efl_net_dialer_simple_example_LDADD = $(ECORE_CON_COMMON_LDADD)
355 355
356if ! HAVE_WINDOWS 356if HAVE_WINDOWS
357EXTRA_PROGRAMS += efl_net_dialer_windows_example
358efl_net_dialer_windows_example_SOURCES = efl_net_dialer_windows_example.c
359efl_net_dialer_windows_example_LDADD = $(ECORE_CON_COMMON_LDADD)
360else
357EXTRA_PROGRAMS += efl_net_dialer_unix_example 361EXTRA_PROGRAMS += efl_net_dialer_unix_example
358efl_net_dialer_unix_example_SOURCES = efl_net_dialer_unix_example.c 362efl_net_dialer_unix_example_SOURCES = efl_net_dialer_unix_example.c
359efl_net_dialer_unix_example_LDADD = $(ECORE_CON_COMMON_LDADD) 363efl_net_dialer_unix_example_LDADD = $(ECORE_CON_COMMON_LDADD)
diff --git a/src/examples/ecore/efl_io_copier_example.c b/src/examples/ecore/efl_io_copier_example.c
index 5e5cbebc66..1abb486985 100644
--- a/src/examples/ecore/efl_io_copier_example.c
+++ b/src/examples/ecore/efl_io_copier_example.c
@@ -330,7 +330,10 @@ static const Ecore_Getopt options = {
330 "http://address to do a GET request\n" 330 "http://address to do a GET request\n"
331 "ws://address or wss:// to do WebSocket request (must send some data once connected)\n" 331 "ws://address or wss:// to do WebSocket request (must send some data once connected)\n"
332 "udp://IP:PORT to bind using UDP and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n" 332 "udp://IP:PORT to bind using UDP and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
333#ifndef _WIN32 333#ifdef EFL_NET_DIALER_WINDOWS_CLASS
334 "windows://path to connect to an Windows NamedPipe server. It will have '\\\\.pipe\\' prepended.\n"
335#endif
336#ifdef EFL_NET_DIALER_UNIX_CLASS
334 "unix://path to connect to an AF_UNIX server. For Linux one can create abstract sockets with unix://abstract:name.\n" 337 "unix://path to connect to an AF_UNIX server. For Linux one can create abstract sockets with unix://abstract:name.\n"
335#endif 338#endif
336 "ssl://IP:PORT to connect using TCP+SSL and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n" 339 "ssl://IP:PORT to connect using TCP+SSL and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
@@ -346,7 +349,10 @@ static const Ecore_Getopt options = {
346 "http://address to do a PUT request\n" 349 "http://address to do a PUT request\n"
347 "ws://address or wss:// to do WebSocket request\n" 350 "ws://address or wss:// to do WebSocket request\n"
348 "udp://IP:PORT to connect using UDP and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n" 351 "udp://IP:PORT to connect using UDP and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
349#ifndef _WIN32 352#ifdef EFL_NET_DIALER_WINDOWS_CLASS
353 "windows://path to connect to an Windows NamedPipe server. It will have '\\\\.pipe\\' prepended.\n"
354#endif
355#ifdef EFL_NET_SERVER_UNIX_CLASS
350 "unix://path to connect to an AF_UNIX server. For Linux one can create abstract sockets with unix://abstract:name.\n" 356 "unix://path to connect to an AF_UNIX server. For Linux one can create abstract sockets with unix://abstract:name.\n"
351#endif 357#endif
352 "ssl://IP:PORT to connect using TCP+SSL and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n" 358 "ssl://IP:PORT to connect using TCP+SSL and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
@@ -542,7 +548,7 @@ main(int argc, char **argv)
542 goto end_input; 548 goto end_input;
543 } 549 }
544 } 550 }
545#ifndef _WIN32 551#ifdef EFL_NET_DIALER_UNIX_CLASS
546 else if (strncmp(input_fname, "unix://", strlen("unix://")) == 0) 552 else if (strncmp(input_fname, "unix://", strlen("unix://")) == 0)
547 { 553 {
548 /* 554 /*
@@ -571,6 +577,35 @@ main(int argc, char **argv)
571 } 577 }
572 } 578 }
573#endif 579#endif
580#ifdef EFL_NET_DIALER_WINDOWS_CLASS
581 else if (strncmp(input_fname, "windows://", strlen("windows://")) == 0)
582 {
583 /*
584 * Since Efl.Net.Socket implements the required interfaces,
585 * they can be used here as well.
586 */
587 const char *address = input_fname + strlen("windows://");
588 Eina_Error err;
589 input = efl_add(EFL_NET_DIALER_WINDOWS_CLASS, ecore_main_loop_get(),
590 efl_event_callback_array_add(efl_added, input_cbs(), NULL), /* optional */
591 efl_event_callback_array_add(efl_added, dialer_cbs(), NULL) /* optional */
592 );
593 if (!input)
594 {
595 fprintf(stderr, "ERROR: could not create Windows NamedPipe Dialer.\n");
596 retval = EXIT_FAILURE;
597 goto end;
598 }
599
600 err = efl_net_dialer_dial(input, address);
601 if (err)
602 {
603 fprintf(stderr, "ERROR: could not Windows NamedPipe dial %s: %s\n",
604 address, eina_error_msg_get(err));
605 goto end_input;
606 }
607 }
608#endif
574 else if (strncmp(input_fname, "ssl://", strlen("ssl://")) == 0) 609 else if (strncmp(input_fname, "ssl://", strlen("ssl://")) == 0)
575 { 610 {
576 /* 611 /*
@@ -787,7 +822,7 @@ main(int argc, char **argv)
787 goto end_output; 822 goto end_output;
788 } 823 }
789 } 824 }
790#ifndef _WIN32 825#ifdef EFL_NET_DIALER_UNIX_CLASS
791 else if (strncmp(output_fname, "unix://", strlen("unix://")) == 0) 826 else if (strncmp(output_fname, "unix://", strlen("unix://")) == 0)
792 { 827 {
793 /* 828 /*
@@ -816,6 +851,35 @@ main(int argc, char **argv)
816 } 851 }
817 } 852 }
818#endif 853#endif
854#ifdef EFL_NET_DIALER_WINDOWS_CLASS
855 else if (strncmp(output_fname, "windows://", strlen("windows://")) == 0)
856 {
857 /*
858 * Since Efl.Net.Socket implements the required interfaces,
859 * they can be used here as well.
860 */
861 const char *address = output_fname + strlen("windows://");
862 Eina_Error err;
863 output = efl_add(EFL_NET_DIALER_WINDOWS_CLASS, ecore_main_loop_get(),
864 efl_event_callback_array_add(efl_added, output_cbs(), NULL), /* optional */
865 efl_event_callback_array_add(efl_added, dialer_cbs(), NULL) /* optional */
866 );
867 if (!output)
868 {
869 fprintf(stderr, "ERROR: could not create Windows NamedPipe Dialer.\n");
870 retval = EXIT_FAILURE;
871 goto end_input;
872 }
873
874 err = efl_net_dialer_dial(output, address);
875 if (err)
876 {
877 fprintf(stderr, "ERROR: could not Windows NamedPipe dial %s: %s\n",
878 address, eina_error_msg_get(err));
879 goto end_output;
880 }
881 }
882#endif
819 else if (strncmp(output_fname, "ssl://", strlen("ssl://")) == 0) 883 else if (strncmp(output_fname, "ssl://", strlen("ssl://")) == 0)
820 { 884 {
821 /* 885 /*
diff --git a/src/examples/ecore/efl_net_dialer_windows_example.c b/src/examples/ecore/efl_net_dialer_windows_example.c
new file mode 100644
index 0000000000..fd24dc852d
--- /dev/null
+++ b/src/examples/ecore/efl_net_dialer_windows_example.c
@@ -0,0 +1,212 @@
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;
11
12static void
13_connected(void *data EINA_UNUSED, const Efl_Event *event)
14{
15 fprintf(stderr,
16 "INFO: connected to '%s' (%s)\n"
17 "INFO: - local address=%s\n"
18 "INFO: - read-after-write=%u\n",
19 efl_net_dialer_address_dial_get(event->object),
20 efl_net_socket_address_remote_get(event->object),
21 efl_net_socket_address_local_get(event->object),
22 do_read);
23}
24
25static void
26_eos(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
27{
28 fprintf(stderr, "INFO: end of stream. \n");
29 ecore_main_loop_quit();
30}
31
32static void
33_can_read(void *data EINA_UNUSED, const Efl_Event *event)
34{
35 char buf[4];
36 Eina_Rw_Slice rw_slice = EINA_SLICE_ARRAY(buf);
37 Eina_Error err;
38 Eina_Bool can_read = efl_io_reader_can_read_get(event->object);
39
40 /* NOTE: this message may appear with can read=0 BEFORE
41 * "read '...'" because efl_io_reader_read() will change the status
42 * of can_read to FALSE prior to return so we can print it!
43 */
44 fprintf(stderr, "INFO: can read=%d\n", can_read);
45 if (!can_read) return;
46 if (!do_read) return;
47
48 err = efl_io_reader_read(event->object, &rw_slice);
49 if (err)
50 {
51 fprintf(stderr, "ERROR: could not read: %s\n", eina_error_msg_get(err));
52 retval = EXIT_FAILURE;
53 ecore_main_loop_quit();
54 return;
55 }
56
57 fprintf(stderr, "INFO: read '" EINA_SLICE_STR_FMT "'\n", EINA_SLICE_STR_PRINT(rw_slice));
58}
59
60static void
61_can_write(void *data EINA_UNUSED, const Efl_Event *event)
62{
63 static Eina_Slice slice = EINA_SLICE_STR_LITERAL("Hello World!");
64 Eina_Slice to_write;
65 Eina_Error err;
66 Eina_Bool can_write = efl_io_writer_can_write_get(event->object);
67
68 /* NOTE: this message may appear with can write=0 BEFORE
69 * "wrote '...'" because efl_io_writer_write() will change the status
70 * of can_write to FALSE prior to return so we can print it!
71 */
72 fprintf(stderr, "INFO: can write=%d (wanted bytes=%zd)\n", can_write, slice.len);
73 if (!can_write) return;
74 if (slice.len == 0) return;
75
76 to_write = slice;
77 err = efl_io_writer_write(event->object, &to_write, &slice);
78 if (err)
79 {
80 fprintf(stderr, "ERROR: could not write: %s\n", eina_error_msg_get(err));
81 retval = EXIT_FAILURE;
82 ecore_main_loop_quit();
83 return;
84 }
85
86 fprintf(stderr, "INFO: wrote '" EINA_SLICE_STR_FMT "', still pending=%zd bytes\n", EINA_SLICE_STR_PRINT(to_write), slice.len);
87
88 if ((!do_read) && (slice.len == 0))
89 {
90 retval = EXIT_SUCCESS;
91 ecore_main_loop_quit();
92 return;
93 }
94}
95
96static void
97_resolved(void *data EINA_UNUSED, const Efl_Event *event)
98{
99 fprintf(stderr, "INFO: resolved %s => %s\n",
100 efl_net_dialer_address_dial_get(event->object),
101 efl_net_socket_address_remote_get(event->object));
102}
103
104static void
105_error(void *data EINA_UNUSED, const Efl_Event *event)
106{
107 const Eina_Error *perr = event->info;
108 fprintf(stderr, "INFO: error: %d '%s'\n", *perr, eina_error_msg_get(*perr));
109 retval = EXIT_FAILURE;
110}
111
112EFL_CALLBACKS_ARRAY_DEFINE(dialer_cbs,
113 { EFL_NET_DIALER_EVENT_CONNECTED, _connected },
114 { EFL_NET_DIALER_EVENT_RESOLVED, _resolved },
115 { EFL_NET_DIALER_EVENT_ERROR, _error },
116 { EFL_IO_READER_EVENT_EOS, _eos },
117 { EFL_IO_READER_EVENT_CAN_READ_CHANGED, _can_read },
118 { EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, _can_write }
119 );
120
121static const Ecore_Getopt options = {
122 "efl_net_dialer_windows_example", /* program name */
123 NULL, /* usage line */
124 "1", /* version */
125 "(C) 2017 Enlightenment Project", /* copyright */
126 "BSD 2-Clause", /* license */
127 /* long description, may be multiline and contain \n */
128 "Example of Efl_Net_Dialer_Windows usage, sending a message and receiving a reply\n",
129 EINA_FALSE,
130 {
131 ECORE_GETOPT_STORE_TRUE('r', "read-after-write", "Do a read after writes are done."),
132 ECORE_GETOPT_VERSION('V', "version"),
133 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
134 ECORE_GETOPT_LICENSE('L', "license"),
135 ECORE_GETOPT_HELP('h', "help"),
136 ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
137 "The address (URL) to dial", "address"),
138 ECORE_GETOPT_SENTINEL
139 }
140};
141
142int
143main(int argc, char **argv)
144{
145 char *address = NULL;
146 Eina_Bool quit_option = EINA_FALSE;
147 Ecore_Getopt_Value values[] = {
148 ECORE_GETOPT_VALUE_BOOL(do_read),
149
150 /* standard block to provide version, copyright, license and help */
151 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -V/--version quits */
152 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -C/--copyright quits */
153 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -L/--license quits */
154 ECORE_GETOPT_VALUE_BOOL(quit_option), /* -h/--help quits */
155
156 /* positional argument */
157 ECORE_GETOPT_VALUE_STR(address),
158
159 ECORE_GETOPT_VALUE_NONE /* sentinel */
160 };
161 int args;
162 Eo *dialer, *loop;
163 Eina_Error err;
164
165 ecore_init();
166 ecore_con_init();
167
168 args = ecore_getopt_parse(&options, values, argc, argv);
169 if (args < 0)
170 {
171 fputs("ERROR: Could not parse command line options.\n", stderr);
172 retval = EXIT_FAILURE;
173 goto end;
174 }
175
176 if (quit_option) goto end;
177
178 loop = ecore_main_loop_get();
179
180 args = ecore_getopt_parse_positional(&options, values, argc, argv, args);
181 if (args < 0)
182 {
183 fputs("ERROR: Could not parse positional arguments.\n", stderr);
184 retval = EXIT_FAILURE;
185 goto end;
186 }
187
188 dialer = efl_add(EFL_NET_DIALER_WINDOWS_CLASS, loop,
189 efl_name_set(efl_added, "dialer"),
190 efl_event_callback_array_add(efl_added, dialer_cbs(), NULL));
191
192 err = efl_net_dialer_dial(dialer, address);
193 if (err != 0)
194 {
195 fprintf(stderr, "ERROR: could not dial '%s': %s",
196 address, eina_error_msg_get(err));
197 goto no_mainloop;
198 }
199
200 ecore_main_loop_begin();
201
202 fprintf(stderr, "INFO: main loop finished.\n");
203
204 no_mainloop:
205 efl_del(dialer);
206
207 end:
208 ecore_con_shutdown();
209 ecore_shutdown();
210
211 return retval;
212}
diff --git a/src/examples/ecore/efl_net_server_example.c b/src/examples/ecore/efl_net_server_example.c
index 3a9598e2cb..c3b19ec3fc 100644
--- a/src/examples/ecore/efl_net_server_example.c
+++ b/src/examples/ecore/efl_net_server_example.c
@@ -461,7 +461,10 @@ static const char * protocols[] = {
461 "tcp", 461 "tcp",
462 "udp", 462 "udp",
463 "ssl", 463 "ssl",
464#ifndef _WIN32 464#ifdef EFL_NET_SERVER_WINDOWS_CLASS
465 "windows",
466#endif
467#ifdef EFL_NET_SERVER_UNIX_CLASS
465 "unix", 468 "unix",
466#endif 469#endif
467 NULL 470 NULL
@@ -622,7 +625,10 @@ main(int argc, char **argv)
622 if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_SERVER_TCP_CLASS; 625 if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_SERVER_TCP_CLASS;
623 else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_SERVER_UDP_CLASS; 626 else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_SERVER_UDP_CLASS;
624 else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_SERVER_SSL_CLASS; 627 else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_SERVER_SSL_CLASS;
625#ifndef _WIN32 628#ifdef EFL_NET_SERVER_WINDOWS_CLASS
629 else if (strcmp(protocol, "windows") == 0) cls = EFL_NET_SERVER_WINDOWS_CLASS;
630#endif
631#ifdef EFL_NET_SERVER_UNIX_CLASS
626 else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS; 632 else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS;
627#endif 633#endif
628 else 634 else
@@ -703,7 +709,7 @@ main(int argc, char **argv)
703 efl_net_server_ssl_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */ 709 efl_net_server_ssl_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
704 if (socket_activated) efl_net_server_ssl_socket_activate(server, address); 710 if (socket_activated) efl_net_server_ssl_socket_activate(server, address);
705 } 711 }
706#ifndef _WIN32 712#ifdef EFL_NET_SERVER_UNIX_CLASS
707 else if (cls == EFL_NET_SERVER_UNIX_CLASS) 713 else if (cls == EFL_NET_SERVER_UNIX_CLASS)
708 { 714 {
709 efl_net_server_unix_unlink_before_bind_set(server, EINA_TRUE); /* makes testing easier */ 715 efl_net_server_unix_unlink_before_bind_set(server, EINA_TRUE); /* makes testing easier */
diff --git a/src/examples/ecore/efl_net_server_simple_example.c b/src/examples/ecore/efl_net_server_simple_example.c
index 548dd92ccc..ddce4c86cd 100644
--- a/src/examples/ecore/efl_net_server_simple_example.c
+++ b/src/examples/ecore/efl_net_server_simple_example.c
@@ -265,7 +265,10 @@ static const char * protocols[] = {
265 "tcp", 265 "tcp",
266 "udp", 266 "udp",
267 "ssl", 267 "ssl",
268#ifndef _WIN32 268#ifdef EFL_NET_SERVER_WINDOWS_CLASS
269 "windows",
270#endif
271#ifdef EFL_NET_SERVER_UNIX_CLASS
269 "unix", 272 "unix",
270#endif 273#endif
271 NULL 274 NULL
@@ -426,7 +429,10 @@ main(int argc, char **argv)
426 if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_SERVER_TCP_CLASS; 429 if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_SERVER_TCP_CLASS;
427 else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_SERVER_UDP_CLASS; 430 else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_SERVER_UDP_CLASS;
428 else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_SERVER_SSL_CLASS; 431 else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_SERVER_SSL_CLASS;
429#ifndef _WIN32 432#ifdef EFL_NET_SERVER_WINDOWS_CLASS
433 else if (strcmp(protocol, "windows") == 0) cls = EFL_NET_SERVER_WINDOWS_CLASS;
434#endif
435#ifdef EFL_NET_SERVER_UNIX_CLASS
430 else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS; 436 else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS;
431#endif 437#endif
432 else 438 else
@@ -511,7 +517,7 @@ main(int argc, char **argv)
511 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 efl_net_server_ssl_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
512 if (socket_activated) efl_net_server_ssl_socket_activate(server, address); 518 if (socket_activated) efl_net_server_ssl_socket_activate(server, address);
513 } 519 }
514#ifndef _WIN32 520#ifdef EFL_NET_SERVER_UNIX_CLASS
515 else if (cls == EFL_NET_SERVER_UNIX_CLASS) 521 else if (cls == EFL_NET_SERVER_UNIX_CLASS)
516 { 522 {
517 efl_net_server_unix_unlink_before_bind_set(server, EINA_TRUE); /* makes testing easier */ 523 efl_net_server_unix_unlink_before_bind_set(server, EINA_TRUE); /* makes testing easier */
diff --git a/src/lib/ecore_con/Ecore_Con_Eo.h b/src/lib/ecore_con/Ecore_Con_Eo.h
index 03ade071de..9825a2b2a6 100644
--- a/src/lib/ecore_con/Ecore_Con_Eo.h
+++ b/src/lib/ecore_con/Ecore_Con_Eo.h
@@ -18,6 +18,9 @@
18#include "efl_net_server_tcp.eo.h" 18#include "efl_net_server_tcp.eo.h"
19 19
20#ifdef _WIN32 20#ifdef _WIN32
21#include "efl_net_socket_windows.eo.h"
22#include "efl_net_dialer_windows.eo.h"
23#include "efl_net_server_windows.eo.h"
21#else 24#else
22#include "efl_net_socket_unix.eo.h" 25#include "efl_net_socket_unix.eo.h"
23#include "efl_net_dialer_unix.eo.h" 26#include "efl_net_dialer_unix.eo.h"
diff --git a/src/lib/ecore_con/ecore_con_private.h b/src/lib/ecore_con/ecore_con_private.h
index 42f6dedef7..20c76fa000 100644
--- a/src/lib/ecore_con/ecore_con_private.h
+++ b/src/lib/ecore_con/ecore_con_private.h
@@ -170,7 +170,27 @@ void _ecore_con_local_mkpath(const char *path, mode_t mode);
170void _efl_net_server_udp_client_init(Eo *client, SOCKET fd, const struct sockaddr *addr, socklen_t addrlen, const char *str); 170void _efl_net_server_udp_client_init(Eo *client, SOCKET fd, const struct sockaddr *addr, socklen_t addrlen, const char *str);
171void _efl_net_server_udp_client_feed(Eo *client, Eina_Rw_Slice slice); 171void _efl_net_server_udp_client_feed(Eo *client, Eina_Rw_Slice slice);
172 172
173#ifndef _WIN32 173#ifdef EFL_NET_SOCKET_WINDOWS_CLASS
174Eina_Error _efl_net_socket_windows_init(Eo *o, HANDLE h);
175Eina_Error _efl_net_socket_windows_io_start(Eo *o);
176HANDLE _efl_net_socket_windows_handle_get(const Eo *o);
177
178typedef struct _Efl_Net_Socket_Windows_Operation Efl_Net_Socket_Windows_Operation;
179typedef void (*Efl_Net_Socket_Windows_Operation_Success_Cb)(void *data, Eo *sock, Eina_Rw_Slice slice);
180typedef void (*Efl_Net_Socket_Windows_Operation_Failure_Cb)(void *data, Eo *sock, Eina_Error err);
181
182Efl_Net_Socket_Windows_Operation *_efl_net_socket_windows_operation_new(Eo *sock, Efl_Net_Socket_Windows_Operation_Success_Cb success_cb, Efl_Net_Socket_Windows_Operation_Failure_Cb failure_cb, const void *data);
183void _efl_net_socket_windows_operation_failed(Efl_Net_Socket_Windows_Operation *op, Eina_Error err);
184void _efl_net_socket_windows_operation_succeeded(Efl_Net_Socket_Windows_Operation *op, Eina_Rw_Slice slice);
185
186static inline OVERLAPPED *
187_efl_net_socket_windows_operation_overlapped_get(Efl_Net_Socket_Windows_Operation *op)
188{
189 return (OVERLAPPED *)op;
190}
191#endif
192
193#ifdef EFL_NET_SOCKET_UNIX_CLASS
174Eina_Bool efl_net_unix_fmt(char *buf, size_t buflen, SOCKET fd, const struct sockaddr_un *addr, socklen_t addrlen); 194Eina_Bool efl_net_unix_fmt(char *buf, size_t buflen, SOCKET fd, const struct sockaddr_un *addr, socklen_t addrlen);
175#endif 195#endif
176Eina_Bool efl_net_ip_port_parse(const char *address, struct sockaddr_storage *storage); 196Eina_Bool efl_net_ip_port_parse(const char *address, struct sockaddr_storage *storage);
diff --git a/src/lib/ecore_con/efl_net_dialer_windows.c b/src/lib/ecore_con/efl_net_dialer_windows.c
new file mode 100644
index 0000000000..e3ce95f3ea
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_dialer_windows.c
@@ -0,0 +1,130 @@
1#define EFL_NET_SOCKET_WINDOWS_PROTECTED 1
2#define EFL_IO_READER_PROTECTED 1
3#define EFL_IO_WRITER_PROTECTED 1
4#define EFL_IO_CLOSER_PROTECTED 1
5#define EFL_NET_DIALER_PROTECTED 1
6#define EFL_NET_SOCKET_PROTECTED 1
7
8#ifndef _WIN32_WINNT
9#define _WIN32_WINNT 0x0600
10#elif _WIN32_WINNT < 0x0600
11#error "This version of Windows is too old"
12#endif
13
14#ifdef HAVE_CONFIG_H
15# include <config.h>
16#endif
17
18#include "Ecore.h"
19#include "Ecore_Con.h"
20#include "ecore_con_private.h"
21
22#define MY_CLASS EFL_NET_DIALER_WINDOWS_CLASS
23
24typedef struct _Efl_Net_Dialer_Windows_Data
25{
26 Eina_Stringshare *address_dial;
27 double timeout_dial;
28 Eina_Bool connected;
29} Efl_Net_Dialer_Windows_Data;
30
31EOLIAN static void
32_efl_net_dialer_windows_efl_object_destructor(Eo *o, Efl_Net_Dialer_Windows_Data *pd)
33{
34 efl_destructor(efl_super(o, MY_CLASS));
35
36 eina_stringshare_replace(&pd->address_dial, NULL);
37}
38
39EOLIAN static Eina_Error
40_efl_net_dialer_windows_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Windows_Data *pd, const char *address)
41{
42 Eina_Error err;
43 HANDLE h;
44
45 EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
46 EINA_SAFETY_ON_TRUE_RETURN_VAL(strchr(address, '/') != NULL, EINVAL);
47 EINA_SAFETY_ON_TRUE_RETURN_VAL(strchr(address, '\\') != NULL, EINVAL);
48 EINA_SAFETY_ON_TRUE_RETURN_VAL(strlen("\\\\.pipe\\") + strlen(address) >= 256, EINVAL);
49 EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_net_dialer_connected_get(o), EISCONN);
50 EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), EBADF);
51
52 efl_net_dialer_address_dial_set(o, address);
53
54 h = CreateFile(pd->address_dial,
55 FILE_READ_ATTRIBUTES | FILE_READ_DATA |
56 FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA,
57 FILE_SHARE_READ | FILE_SHARE_WRITE,
58 NULL, OPEN_EXISTING,
59 FILE_FLAG_OVERLAPPED, NULL);
60 if (h == INVALID_HANDLE_VALUE)
61 return GetLastError();
62
63 // TODO vtorri: will this CreateFile() take a while if the server
64 // waits to accept? If so, we may need to move this to an
65 // Ecore_Thread and call _efl_net_socket_windows_init() and the
66 // rest of this function from "end_cb"
67
68 err = _efl_net_socket_windows_init(o, h);
69 if (err)
70 {
71 CloseHandle(h);
72 return err;
73 }
74
75 efl_net_socket_address_remote_set(o, efl_net_dialer_address_dial_get(o));
76 efl_net_socket_address_local_set(o, "TODO"); // TODO vtorri: can we get the local peer address, like getsockname()?
77 efl_event_callback_call(o, EFL_NET_DIALER_EVENT_RESOLVED, NULL);
78 efl_net_dialer_connected_set(o, EINA_TRUE);
79
80 return _efl_net_socket_windows_io_start(o);
81}
82
83EOLIAN static void
84_efl_net_dialer_windows_efl_net_dialer_address_dial_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Windows_Data *pd, const char *address)
85{
86 const char *tmp = eina_stringshare_printf("\\\\.pipe\\%s", address);
87 eina_stringshare_del(pd->address_dial);
88 pd->address_dial = tmp;
89}
90
91EOLIAN static const char *
92_efl_net_dialer_windows_efl_net_dialer_address_dial_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Windows_Data *pd)
93{
94 return pd->address_dial + strlen("\\\\.pipe\\");;
95}
96
97EOLIAN static void
98_efl_net_dialer_windows_efl_net_dialer_connected_set(Eo *o, Efl_Net_Dialer_Windows_Data *pd, Eina_Bool connected)
99{
100 if (pd->connected == connected) return;
101 pd->connected = connected;
102 if (connected) efl_event_callback_call(o, EFL_NET_DIALER_EVENT_CONNECTED, NULL);
103}
104
105EOLIAN static Eina_Bool
106_efl_net_dialer_windows_efl_net_dialer_connected_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Windows_Data *pd)
107{
108 return pd->connected;
109}
110
111EOLIAN static void
112_efl_net_dialer_windows_efl_net_dialer_timeout_dial_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Windows_Data *pd, double seconds)
113{
114 pd->timeout_dial = seconds;
115}
116
117EOLIAN static double
118_efl_net_dialer_windows_efl_net_dialer_timeout_dial_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Windows_Data *pd)
119{
120 return pd->timeout_dial;
121}
122
123EOLIAN static Eina_Error
124_efl_net_dialer_windows_efl_io_closer_close(Eo *o, Efl_Net_Dialer_Windows_Data *pd EINA_UNUSED)
125{
126 efl_net_dialer_connected_set(o, EINA_FALSE);
127 return efl_io_closer_close(efl_super(o, MY_CLASS));
128}
129
130#include "efl_net_dialer_windows.eo.c"
diff --git a/src/lib/ecore_con/efl_net_dialer_windows.eo b/src/lib/ecore_con/efl_net_dialer_windows.eo
new file mode 100644
index 0000000000..5432bcb766
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_dialer_windows.eo
@@ -0,0 +1,20 @@
1class Efl.Net.Dialer.Windows (Efl.Net.Socket.Windows, Efl.Net.Dialer) {
2 [[Connects to a Windows NamedPipe server.
3
4 The dial address will have "\\.pipe\" prepended as required by
5 Windows CreateNamedPipe().
6
7 \@note Proxies are meaningless, thus are not implemented.
8
9 @since 1.19
10 ]]
11
12 implements {
13 Efl.Object.destructor;
14 Efl.Net.Dialer.dial; [[address parameter will have "\\.pipe\" prepended]]
15 Efl.Net.Dialer.address_dial { get; set; }
16 Efl.Net.Dialer.connected { get; set; }
17 Efl.Net.Dialer.timeout_dial { get; set; }
18 Efl.Io.Closer.close;
19 }
20}
diff --git a/src/lib/ecore_con/efl_net_server_windows.c b/src/lib/ecore_con/efl_net_server_windows.c
new file mode 100644
index 0000000000..2c7021e961
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_server_windows.c
@@ -0,0 +1,454 @@
1#define EFL_NET_SERVER_WINDOWS_PROTECTED 1
2#define EFL_NET_SERVER_PROTECTED 1
3#define EFL_NET_SOCKET_PROTECTED 1
4
5#ifndef _WIN32_WINNT
6#define _WIN32_WINNT 0x0600
7#elif _WIN32_WINNT < 0x0600
8#error "This version of Windows is too old"
9#endif
10
11#ifdef HAVE_CONFIG_H
12# include <config.h>
13#endif
14
15#include "Ecore.h"
16#include "Ecore_Con.h"
17#include "ecore_con_private.h"
18
19/*
20 * See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365601(v=vs.85).aspx
21 * Named Pipe Server Using Completion Routines
22 *
23 * See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365603(v=vs.85).aspx
24 * Named Pipe Server Using Overlapped I/O
25 *
26 * Each instance (PIPEINST) is an Efl_Net_Socket_Windows. Instead of
27 * pre-creating all possible instances and having all of them to
28 * accept connections (ConnectNamedPipe()), we create a single one
29 * (Efl_Net_Server_Windows_Data::next_client), once it's connected we
30 * announce the client and if it's used, a new "next_client" is
31 * started, otherwise if the announced client is not used, then it's
32 * disconnected and reused with a new ConnectNamedPipe().
33 */
34
35#define MY_CLASS EFL_NET_SERVER_WINDOWS_CLASS
36
37typedef struct _Efl_Net_Server_Windows_Data
38{
39 Eo *next_client;
40 Eina_List *pending_clients;
41
42 Eina_Stringshare *address; /* includes prefix: \\.pipe\, returned without it */
43 Efl_Future *pending_announcer_job;
44 unsigned int clients_count;
45 unsigned int clients_limit;
46 Eina_Bool clients_reject_excess;
47 Eina_Bool serving;
48 Eina_Bool first;
49 Eina_Bool allow_remote;
50} Efl_Net_Server_Windows_Data;
51
52static Eina_Error _efl_net_server_windows_client_listen(Eo *o, Efl_Net_Server_Windows_Data *pd);
53static Eina_Error _efl_net_server_windows_client_new(Eo *o, Efl_Net_Server_Windows_Data *pd);
54
55static void
56_efl_net_server_windows_client_listen_success(void *data, Eo *client, Eina_Rw_Slice slice EINA_UNUSED)
57{
58 Eo *o = data;
59 Efl_Net_Server_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
60 char str[256];
61
62 EINA_SAFETY_ON_NULL_RETURN(pd);
63
64 snprintf(str, sizeof(str), "XXXTODO"); // TODO vtorri: do we have a way to identify the client?
65
66 DBG("server=%p received incoming connection at %s (%s)", o, efl_net_server_address_get(o), str);
67
68 efl_ref(o); /* will trigger events, which call user which may delete us */
69
70 if ((pd->clients_limit > 0) && (pd->clients_count >= pd->clients_limit))
71 {
72 if (!pd->clients_reject_excess)
73 {
74 /* keep queueing, but do not call user */
75
76 pd->pending_clients = eina_list_append(pd->pending_clients, client);
77 if (pd->next_client == client)
78 pd->next_client = NULL;
79
80 efl_net_socket_address_local_set(client, efl_net_server_address_get(o));
81 efl_net_socket_address_remote_set(client, str);
82
83 DBG("server=%p queued client %p", o, client);
84 }
85 else
86 {
87 DBG("server=%p rejecting client %p", o, client);
88 efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_REJECTED, str);
89
90 if (pd->next_client != client)
91 efl_del(client);
92 else
93 {
94 HANDLE h = _efl_net_socket_windows_handle_get(client);
95 DisconnectNamedPipe(h);
96
97 /* reuse existing pipe for a new connection */
98 _efl_net_server_windows_client_listen(o, pd);
99 }
100 }
101 }
102 else
103 {
104 DBG("server=%p announcing client %p", o, client);
105 if (pd->next_client == client)
106 pd->next_client = NULL;
107 efl_net_server_client_announce(o, client);
108 }
109
110 if (!pd->next_client)
111 _efl_net_server_windows_client_new(o, pd);
112
113 efl_unref(o);
114}
115
116static void
117_efl_net_server_windows_client_listen_failure(void *data, Eo *client EINA_UNUSED, Eina_Error err)
118{
119 Eo *o = data;
120
121 WRN("server=%p failed to accept connection at %s: #%d %s",
122 o, efl_net_server_address_get(o), err, eina_error_msg_get(err));
123
124 efl_event_callback_call(o, EFL_NET_SERVER_EVENT_ERROR, &err);
125
126 // TODO: create a new one on failure?
127}
128
129static Eina_Error
130_efl_net_server_windows_client_listen(Eo *o, Efl_Net_Server_Windows_Data *pd)
131{
132 Efl_Net_Socket_Windows_Operation *op;
133 HANDLE h;
134 OVERLAPPED *ovl;
135 Eina_Error err = 0;
136
137 op = _efl_net_socket_windows_operation_new(pd->next_client,
138 _efl_net_server_windows_client_listen_success,
139 _efl_net_server_windows_client_listen_failure,
140 o);
141
142 EINA_SAFETY_ON_NULL_RETURN_VAL(op, EINVAL);
143
144 h = _efl_net_socket_windows_handle_get(pd->next_client);
145 ovl = _efl_net_socket_windows_operation_overlapped_get(op);
146
147 DBG("server=%p connecting to %s...", o, efl_net_server_address_get(o));
148
149 if (!ConnectNamedPipe(h, ovl))
150 {
151 err = GetLastError();
152 if (err == ERROR_IO_PENDING)
153 return 0;
154 else if (err == ERROR_PIPE_CONNECTED)
155 {
156 _efl_net_socket_windows_operation_succeeded(op, (Eina_Rw_Slice){});
157 return 0;
158 }
159 else
160 {
161 _efl_net_socket_windows_operation_failed(op, err);
162 return err;
163 }
164 }
165
166 _efl_net_socket_windows_operation_failed(op, EINVAL);
167 return EINVAL;
168}
169
170static Eina_Error
171_efl_net_server_windows_client_new(Eo *o, Efl_Net_Server_Windows_Data *pd)
172{
173 Eina_Error err;
174 HANDLE h;
175
176 h = CreateNamedPipe(pd->address,
177 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
178 pd->first ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0,
179 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
180 pd->allow_remote ? PIPE_ACCEPT_REMOTE_CLIENTS : PIPE_REJECT_REMOTE_CLIENTS,
181 pd->clients_limit > 0 ? pd->clients_limit : PIPE_UNLIMITED_INSTANCES,
182 4096, 4096, INFINITE, NULL);
183 if (h == INVALID_HANDLE_VALUE)
184 return GetLastError();
185
186 pd->next_client = efl_add(EFL_NET_SOCKET_WINDOWS_CLASS, o,
187 efl_io_closer_close_on_destructor_set(efl_added, EINA_TRUE));
188 if (!pd->next_client)
189 {
190 err = ENOMEM;
191 goto error_socket;
192 }
193
194 err = _efl_net_socket_windows_init(pd->next_client, h);
195 if (err) goto error_init;
196
197 pd->first = EINA_FALSE;
198
199 err = _efl_net_server_windows_client_listen(o, pd);
200 if (err) return err;
201
202 efl_net_server_serving_set(o, EINA_TRUE);
203 return 0;
204
205 error_init:
206 efl_del(pd->next_client);
207 error_socket:
208 CloseHandle(h);
209 return err;
210}
211
212EOLIAN static void
213_efl_net_server_windows_allow_remote_set(Eo *o EINA_UNUSED, Efl_Net_Server_Windows_Data *pd, Eina_Bool allow_remote)
214{
215 pd->allow_remote = allow_remote;
216}
217
218EOLIAN static Eina_Bool
219_efl_net_server_windows_allow_remote_get(Eo *o EINA_UNUSED, Efl_Net_Server_Windows_Data *pd)
220{
221 return pd->allow_remote;
222}
223
224EOLIAN static Eo *
225_efl_net_server_windows_efl_object_constructor(Eo *o, Efl_Net_Server_Windows_Data *pd)
226{
227 pd->first = EINA_TRUE;
228
229 return efl_constructor(efl_super(o, MY_CLASS));
230}
231
232EOLIAN static void
233_efl_net_server_windows_efl_object_destructor(Eo *o, Efl_Net_Server_Windows_Data *pd)
234{
235 if (pd->next_client)
236 {
237 efl_del(pd->next_client);
238 pd->next_client = NULL;
239 }
240
241 while (pd->pending_clients)
242 {
243 Eo *client = pd->pending_clients->data;
244 pd->pending_clients = eina_list_remove_list(pd->pending_clients, pd->pending_clients);
245 efl_del(client);
246 }
247
248 efl_destructor(efl_super(o, MY_CLASS));
249}
250
251EOLIAN static void
252_efl_net_server_windows_efl_net_server_address_set(Eo *o EINA_UNUSED, Efl_Net_Server_Windows_Data *pd, const char *address)
253{
254 const char *tmp = eina_stringshare_printf("\\\\.pipe\\%s", address);
255 eina_stringshare_del(pd->address);
256 pd->address = tmp;
257}
258
259EOLIAN static const char *
260_efl_net_server_windows_efl_net_server_address_get(Eo *o EINA_UNUSED, Efl_Net_Server_Windows_Data *pd)
261{
262 return pd->address + strlen("\\\\.pipe\\");
263}
264
265static void
266_efl_net_server_windows_pending_announce_job(void *data, const Efl_Event *ev EINA_UNUSED)
267{
268 Eo *o = data;
269 Efl_Net_Server_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
270 Eo *client;
271
272 pd->pending_announcer_job = NULL;
273
274 if (!pd->pending_clients) return;
275 if ((pd->clients_limit > 0) && (pd->clients_limit <= pd->clients_count)) return;
276
277 client = pd->pending_clients->data;
278 pd->pending_clients = eina_list_remove_list(pd->pending_clients, pd->pending_clients);
279
280 efl_net_server_client_announce(o, client);
281}
282
283static void
284_efl_net_server_windows_pending_announce_job_schedule(Eo *o, Efl_Net_Server_Windows_Data *pd)
285{
286 Eo *loop;
287
288 if (pd->pending_announcer_job) return;
289 if (!pd->pending_clients) return;
290 if ((pd->clients_limit > 0) && (pd->clients_limit <= pd->clients_count)) return;
291
292 loop = efl_loop_get(o);
293 if (!loop) return;
294 efl_future_use(&pd->pending_announcer_job, efl_loop_job(loop, o));
295 efl_future_then(pd->pending_announcer_job, _efl_net_server_windows_pending_announce_job, NULL, NULL, o);
296 efl_future_link(o, pd->pending_announcer_job);
297}
298
299EOLIAN static void
300_efl_net_server_windows_efl_net_server_clients_count_set(Eo *o, Efl_Net_Server_Windows_Data *pd, unsigned int count)
301{
302 pd->clients_count = count;
303
304 /* a job to avoid blowing the stack with recursion,
305 * do each announcement from main loop
306 */
307 _efl_net_server_windows_pending_announce_job_schedule(o, pd);
308}
309
310EOLIAN static unsigned int
311_efl_net_server_windows_efl_net_server_clients_count_get(Eo *o EINA_UNUSED, Efl_Net_Server_Windows_Data *pd)
312{
313 return pd->clients_count;
314}
315
316EOLIAN static void
317_efl_net_server_windows_efl_net_server_clients_limit_set(Eo *o EINA_UNUSED, Efl_Net_Server_Windows_Data *pd, unsigned int limit, Eina_Bool reject_excess)
318{
319 pd->clients_limit = limit;
320 pd->clients_reject_excess = reject_excess;
321
322 if ((limit > 0) && (reject_excess))
323 {
324 while (pd->pending_clients)
325 {
326 Eina_List *last = eina_list_last(pd->pending_clients);
327 Eo *client = eina_list_data_get(last);
328 efl_del(client);
329 pd->pending_clients = eina_list_remove_list(pd->pending_clients, last);
330 }
331 }
332
333 _efl_net_server_windows_pending_announce_job_schedule(o, pd);
334}
335
336EOLIAN static void
337_efl_net_server_windows_efl_net_server_clients_limit_get(Eo *o EINA_UNUSED, Efl_Net_Server_Windows_Data *pd, unsigned int *limit, Eina_Bool *reject_excess)
338{
339 if (limit) *limit = pd->clients_limit;
340 if (reject_excess) *reject_excess = pd->clients_reject_excess;
341}
342
343EOLIAN static void
344_efl_net_server_windows_efl_net_server_serving_set(Eo *o EINA_UNUSED, Efl_Net_Server_Windows_Data *pd, Eina_Bool serving)
345{
346 if (pd->serving == serving) return;
347 pd->serving = serving;
348 if (serving)
349 efl_event_callback_call(o, EFL_NET_SERVER_EVENT_SERVING, NULL);
350}
351
352EOLIAN static Eina_Bool
353_efl_net_server_windows_efl_net_server_serving_get(Eo *o EINA_UNUSED, Efl_Net_Server_Windows_Data *pd)
354{
355 return pd->serving;
356}
357
358EOLIAN static Eina_Error
359_efl_net_server_windows_efl_net_server_serve(Eo *o, Efl_Net_Server_Windows_Data *pd, const char *address)
360{
361 EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
362 EINA_SAFETY_ON_TRUE_RETURN_VAL(strchr(address, '/') != NULL, EINVAL);
363 EINA_SAFETY_ON_TRUE_RETURN_VAL(strchr(address, '\\') != NULL, EINVAL);
364 EINA_SAFETY_ON_TRUE_RETURN_VAL(strlen("\\\\.pipe\\") + strlen(address) >= 256, EINVAL);
365 EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->serving, EALREADY);
366
367 efl_net_server_address_set(o, address);
368
369 return _efl_net_server_windows_client_new(o, pd);
370}
371
372static void
373_efl_net_server_windows_client_event_closed(void *data, const Efl_Event *event)
374{
375 Eo *server = data;
376 Eo *client = event->object;
377
378 efl_event_callback_del(client, EFL_IO_CLOSER_EVENT_CLOSED, _efl_net_server_windows_client_event_closed, server);
379 if (efl_parent_get(client) == server)
380 efl_parent_set(client, NULL);
381
382 efl_net_server_clients_count_set(server, efl_net_server_clients_count_get(server) - 1);
383}
384
385EOLIAN static Eina_Bool
386_efl_net_server_windows_efl_net_server_client_announce(Eo *o, Efl_Net_Server_Windows_Data *pd, Efl_Net_Socket *client)
387{
388 Eina_Error err;
389
390 EINA_SAFETY_ON_NULL_RETURN_VAL(client, EINA_FALSE);
391 EINA_SAFETY_ON_FALSE_GOTO(efl_isa(client, EFL_NET_SOCKET_INTERFACE), wrong_type);
392 EINA_SAFETY_ON_FALSE_GOTO(efl_parent_get(client) == o, wrong_parent);
393 efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_ADD, client);
394
395 if (efl_parent_get(client) != o)
396 {
397 DBG("client %s was reparented! Ignoring it...",
398 efl_net_socket_address_remote_get(client));
399 return EINA_TRUE;
400 }
401
402 if (efl_ref_get(client) == 1) /* users must take a reference themselves */
403 {
404 DBG("client %s was not handled, closing it...",
405 efl_net_socket_address_remote_get(client));
406 if (pd->next_client)
407 efl_del(client);
408 else
409 {
410 HANDLE h = _efl_net_socket_windows_handle_get(client);
411 DisconnectNamedPipe(h);
412
413 /* reuse existing pipe for a new connection */
414 pd->next_client = client;
415 _efl_net_server_windows_client_listen(o, pd);
416 }
417 return EINA_FALSE;
418 }
419 else if (efl_io_closer_closed_get(client))
420 {
421 DBG("client %s was closed from 'client,add', delete it...",
422 efl_net_socket_address_remote_get(client));
423 efl_del(client);
424 return EINA_FALSE;
425 }
426
427 efl_net_server_clients_count_set(o, efl_net_server_clients_count_get(o) + 1);
428 efl_event_callback_add(client, EFL_IO_CLOSER_EVENT_CLOSED, _efl_net_server_windows_client_event_closed, o);
429
430 err = _efl_net_socket_windows_io_start(client);
431 if (err)
432 {
433 WRN("server=%p client=%p failed to start I/O: %s", o, client, eina_error_msg_get(err));
434 if (!efl_io_closer_closed_get(client))
435 efl_io_closer_close(client);
436 }
437
438 return EINA_TRUE;
439
440 wrong_type:
441 ERR("%p client %p (%s) doesn't implement Efl.Net.Socket interface, deleting it.", o, client, efl_class_name_get(efl_class_get(client)));
442 efl_io_closer_close(client);
443 efl_del(client);
444 return EINA_FALSE;
445
446 wrong_parent:
447 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));
448 efl_io_closer_close(client);
449 efl_del(client);
450 return EINA_FALSE;
451
452}
453
454#include "efl_net_server_windows.eo.c"
diff --git a/src/lib/ecore_con/efl_net_server_windows.eo b/src/lib/ecore_con/efl_net_server_windows.eo
new file mode 100644
index 0000000000..74c4e51917
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_server_windows.eo
@@ -0,0 +1,36 @@
1class Efl.Net.Server.Windows (Efl.Loop_User, Efl.Net.Server) {
2 [[A Windows NamedPipe server.
3
4 The @Efl.Net.Server.serve method will call CreateNamedPipe()
5 directly, thus path will be accessed and created in that
6 method. If the created socket must be subject to some special
7 mode or user, change before executing that method.
8
9 @since 1.19
10 ]]
11
12 methods {
13 @property allow_remote {
14 [[If server allows remote (different machine) clients.
15
16 If this property is $true, then it will allow clients to
17 connect from remote machines. If $false (default), then
18 just local clients are allowed.
19 ]]
20 values {
21 allow_remote: bool; [[If $true, server will allow remote machines to connect.]]
22 }
23 }
24 }
25
26 implements {
27 Efl.Object.constructor;
28 Efl.Object.destructor;
29 Efl.Net.Server.address { get; set; }
30 Efl.Net.Server.clients_count { get; set; }
31 Efl.Net.Server.clients_limit { get; set; }
32 Efl.Net.Server.serving { get; set; }
33 Efl.Net.Server.serve; [[address parameter will have "\\.pipe\" prepended]]
34 Efl.Net.Server.client_announce;
35 }
36}
diff --git a/src/lib/ecore_con/efl_net_socket_windows.c b/src/lib/ecore_con/efl_net_socket_windows.c
new file mode 100644
index 0000000000..514c80c9c8
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_socket_windows.c
@@ -0,0 +1,599 @@
1#define EFL_NET_SOCKET_WINDOWS_PROTECTED 1
2#define EFL_IO_READER_PROTECTED 1
3#define EFL_IO_WRITER_PROTECTED 1
4#define EFL_IO_CLOSER_PROTECTED 1
5#define EFL_NET_SOCKET_PROTECTED 1
6
7#ifndef _WIN32_WINNT
8#define _WIN32_WINNT 0x0600
9#elif _WIN32_WINNT < 0x0600
10#error "This version of Windows is too old"
11#endif
12
13#ifdef HAVE_CONFIG_H
14# include <config.h>
15#endif
16
17#include "Ecore.h"
18#include "Ecore_Con.h"
19#include "ecore_con_private.h"
20
21#define MY_CLASS EFL_NET_SOCKET_WINDOWS_CLASS
22
23#define BUFFER_SIZE (4 * 4096)
24
25typedef struct _Efl_Net_Socket_Windows_Data
26{
27 Eina_Stringshare *address_local;
28 Eina_Stringshare *address_remote;
29 Eina_List *pending_ops;
30 struct {
31 union {
32 uint8_t *bytes;
33 void *mem;
34 };
35 DWORD len;
36 DWORD used;
37 Eina_Bool pending;
38 } recv;
39 struct {
40 union {
41 uint8_t *bytes;
42 void *mem;
43 };
44 DWORD len;
45 DWORD used;
46 Eina_Bool pending;
47 } send;
48 HANDLE handle;
49 PTP_IO io;
50 Eina_Bool can_read;
51 Eina_Bool eos;
52 Eina_Bool pending_eos;
53 Eina_Bool can_write;
54 Eina_Bool io_started;
55} Efl_Net_Socket_Windows_Data;
56
57struct _Efl_Net_Socket_Windows_Operation
58{
59 OVERLAPPED base;
60 Efl_Net_Socket_Windows_Operation_Success_Cb success_cb;
61 Efl_Net_Socket_Windows_Operation_Failure_Cb failure_cb;
62 const void *data;
63 Eo *o;
64 Eina_Bool deleting;
65};
66
67Efl_Net_Socket_Windows_Operation *
68_efl_net_socket_windows_operation_new(Eo *o, Efl_Net_Socket_Windows_Operation_Success_Cb success_cb, Efl_Net_Socket_Windows_Operation_Failure_Cb failure_cb, const void *data)
69{
70 Efl_Net_Socket_Windows_Operation *op;
71 Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, EFL_NET_SOCKET_WINDOWS_CLASS);
72
73 EINA_SAFETY_ON_NULL_RETURN_VAL(pd, NULL);
74 EINA_SAFETY_ON_NULL_RETURN_VAL(success_cb, NULL);
75 EINA_SAFETY_ON_NULL_RETURN_VAL(failure_cb, NULL);
76
77 op = calloc(1, sizeof(*op));
78 EINA_SAFETY_ON_NULL_RETURN_VAL(op, NULL);
79
80 op->success_cb = success_cb;
81 op->failure_cb = failure_cb;
82 op->data = data;
83 op->o = o;
84 pd->pending_ops = eina_list_append(pd->pending_ops, op);
85 StartThreadpoolIo(pd->io);
86
87 // TODO vtorri: I'm not sure the same pd->io can be used for concurrent
88 // operations, like read + write. If it's not, then we'll have to
89 // CreateThreadpoolIo() for each operation (op->io)...
90
91 DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p",
92 op, op->o, op->success_cb, op->failure_cb, op->data);
93
94 return op;
95}
96
97static void
98_efl_net_socket_windows_operation_done(Efl_Net_Socket_Windows_Operation *op, Eina_Error err, Eina_Rw_Slice slice)
99{
100 Efl_Net_Socket_Windows_Data *pd;
101
102 DBG("op=%p (socket=%p), success_cb=%p, failure_cb=%p, data=%p, err=%d (%s), slice=" EINA_SLICE_FMT,
103 op, op->o, op->success_cb, op->failure_cb, op->data,
104 err, eina_error_msg_get(err), EINA_SLICE_PRINT(slice));
105
106 op->deleting = EINA_TRUE;
107
108 pd = efl_data_scope_get(op->o, EFL_NET_SOCKET_WINDOWS_CLASS);
109 if (pd)
110 {
111 pd->pending_ops = eina_list_remove(pd->pending_ops, op);
112 CancelThreadpoolIo(pd->io);
113 }
114
115 if (err)
116 op->failure_cb((void *)op->data, op->o, err);
117 else
118 op->success_cb((void *)op->data, op->o, slice);
119
120 free(op);
121}
122
123void
124_efl_net_socket_windows_operation_failed(Efl_Net_Socket_Windows_Operation *op, Eina_Error err)
125{
126 EINA_SAFETY_ON_NULL_RETURN(op);
127 EINA_SAFETY_ON_TRUE_RETURN(op->deleting);
128
129 _efl_net_socket_windows_operation_done(op, err, (Eina_Rw_Slice){});
130}
131
132void
133_efl_net_socket_windows_operation_succeeded(Efl_Net_Socket_Windows_Operation *op, Eina_Rw_Slice slice)
134{
135 EINA_SAFETY_ON_NULL_RETURN(op);
136 EINA_SAFETY_ON_TRUE_RETURN(op->deleting);
137
138 _efl_net_socket_windows_operation_done(op, 0, slice);
139}
140
141static void CALLBACK
142_efl_net_socket_windows_io_completed(PTP_CALLBACK_INSTANCE inst EINA_UNUSED,
143 PVOID data,
144 PVOID overlapped,
145 ULONG result,
146 ULONG_PTR bytes_nbr,
147 PTP_IO io EINA_UNUSED)
148{
149 Eo *o = data;
150 Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
151 Efl_Net_Socket_Windows_Operation *op = overlapped;
152
153 EINA_SAFETY_ON_NULL_RETURN(pd);
154
155 // TODO: check if this happens on the main thread, otherwise migrate to main!
156
157 if (result == NO_ERROR)
158 _efl_net_socket_windows_operation_succeeded(op, (Eina_Rw_Slice){.len = bytes_nbr}); // TODO k-s: slice with actual memory
159 else
160 _efl_net_socket_windows_operation_failed(op, result);
161}
162
163Eina_Error
164_efl_net_socket_windows_init(Eo *o, HANDLE h)
165{
166 Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
167
168 EINA_SAFETY_ON_TRUE_RETURN_VAL(h == INVALID_HANDLE_VALUE, EINVAL);
169 EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EINVAL);
170 EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->handle != INVALID_HANDLE_VALUE, EALREADY);
171
172 pd->io = CreateThreadpoolIo(h, _efl_net_socket_windows_io_completed, o, 0);
173 if (!pd->io)
174 return GetLastError(); // TODO vtorri: is this compatible with errno/strerror()?
175
176 pd->handle = h;
177
178 DBG("socket=%p adopted handle=%p, ThreadpoolIo=%p", o, h, pd->io);
179 return 0;
180}
181
182static Eina_Error _efl_net_socket_windows_recv(Eo *o, Efl_Net_Socket_Windows_Data *pd);
183
184static void
185_efl_net_socket_windows_recv_success(void *data EINA_UNUSED, Eo *o, Eina_Rw_Slice slice)
186{
187 Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
188
189 pd->recv.used += slice.len;
190 pd->recv.pending = EINA_FALSE;
191
192 efl_io_reader_can_read_set(o, pd->recv.used > 0);
193
194 if (pd->handle == INVALID_HANDLE_VALUE) return;
195 if (pd->recv.used == pd->recv.len) return;
196
197 _efl_net_socket_windows_recv(o, pd);
198}
199
200static void
201_efl_net_socket_windows_recv_failure(void *data EINA_UNUSED, Eo *o, Eina_Error err)
202{
203 Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
204
205 // TODO k-s
206 ERR("TODO: handle err=%d (%s)", err, eina_error_msg_get(err));
207 pd->recv.pending = EINA_FALSE;
208 pd->pending_eos = EINA_TRUE; /* eos when buffer drains */
209}
210
211static Eina_Error
212_efl_net_socket_windows_recv(Eo *o, Efl_Net_Socket_Windows_Data *pd)
213{
214 Efl_Net_Socket_Windows_Operation *op;
215 OVERLAPPED *ovl;
216 DWORD used_size = 0;
217
218 if (pd->handle == INVALID_HANDLE_VALUE) return EBADF;
219 if (pd->recv.len == 0) return ENOMEM;
220 if (pd->recv.used == pd->recv.len) return ENOSPC;
221
222 op = _efl_net_socket_windows_operation_new(o,
223 _efl_net_socket_windows_recv_success,
224 _efl_net_socket_windows_recv_failure,
225 NULL);
226 EINA_SAFETY_ON_NULL_RETURN_VAL(op, EINVAL);
227
228 ovl = _efl_net_socket_windows_operation_overlapped_get(op);
229
230 if (!ReadFile(pd->handle,
231 pd->recv.bytes + pd->recv.used,
232 pd->recv.len - pd->recv.used,
233 &used_size, ovl))
234 {
235 Eina_Error err = GetLastError();
236 if (err == ERROR_IO_PENDING)
237 {
238 pd->recv.pending = EINA_TRUE;
239 return 0;
240 }
241 else
242 {
243 _efl_net_socket_windows_operation_failed(op, err);
244 return err;
245 }
246 }
247
248 _efl_net_socket_windows_operation_succeeded(op, (Eina_Rw_Slice){
249 .mem = pd->recv.mem, .len = pd->recv.used + used_size});
250 return 0;
251}
252
253static Eina_Error _efl_net_socket_windows_send(Eo *o, Efl_Net_Socket_Windows_Data *pd);
254
255static void
256_efl_net_socket_windows_send_success(void *data EINA_UNUSED, Eo *o, Eina_Rw_Slice slice)
257{
258 Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
259
260 if (slice.len)
261 memmove(pd->send.bytes, pd->send.bytes + slice.len, pd->send.used - slice.len);
262
263 pd->send.used -= slice.len;
264 pd->send.pending = EINA_FALSE;
265
266 efl_io_writer_can_write_set(o, pd->send.used < pd->send.len);
267
268 if (pd->handle == INVALID_HANDLE_VALUE) return;
269 if (pd->send.used == 0) return;
270
271 _efl_net_socket_windows_send(o, pd);
272}
273
274static void
275_efl_net_socket_windows_send_failure(void *data EINA_UNUSED, Eo *o, Eina_Error err)
276{
277 Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
278
279 // TODO k-s
280 ERR("TODO: handle err=%d (%s)", err, eina_error_msg_get(err));
281 pd->send.pending = EINA_FALSE;
282}
283
284static Eina_Error
285_efl_net_socket_windows_send(Eo *o, Efl_Net_Socket_Windows_Data *pd)
286{
287 Efl_Net_Socket_Windows_Operation *op;
288 OVERLAPPED *ovl;
289 DWORD used_size = 0;
290
291 if (pd->handle == INVALID_HANDLE_VALUE) return EBADF;
292 if (pd->send.used == 0) return EINVAL;
293
294 op = _efl_net_socket_windows_operation_new(o,
295 _efl_net_socket_windows_send_success,
296 _efl_net_socket_windows_send_failure,
297 NULL);
298 EINA_SAFETY_ON_NULL_RETURN_VAL(op, EINVAL);
299
300 ovl = _efl_net_socket_windows_operation_overlapped_get(op);
301
302 if (!WriteFile(pd->handle,
303 pd->send.bytes,
304 pd->send.used,
305 &used_size, ovl))
306 {
307 Eina_Error err = GetLastError();
308 if (err == ERROR_IO_PENDING)
309 {
310 pd->send.pending = EINA_TRUE;
311 return 0;
312 }
313 else
314 {
315 _efl_net_socket_windows_operation_failed(op, err);
316 return err;
317 }
318 }
319
320 _efl_net_socket_windows_operation_succeeded(op, (Eina_Rw_Slice){
321 .mem = pd->send.mem, .len = used_size});
322 return 0;
323}
324
325
326Eina_Error
327_efl_net_socket_windows_io_start(Eo *o)
328{
329 Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
330 Eina_Error err;
331
332 EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EINVAL);
333 EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->io_started, EALREADY);
334
335 if (!pd->recv.mem)
336 {
337 pd->recv.mem = malloc(BUFFER_SIZE);
338 EINA_SAFETY_ON_NULL_RETURN_VAL(pd->recv.mem, ENOMEM);
339 pd->recv.len = BUFFER_SIZE;
340 pd->recv.used = 0;
341 }
342
343 if (!pd->send.mem)
344 {
345 pd->send.mem = malloc(BUFFER_SIZE);
346 EINA_SAFETY_ON_NULL_RETURN_VAL(pd->send.mem, ENOMEM);
347 pd->send.len = BUFFER_SIZE;
348 pd->send.used = 0;
349 }
350
351 DBG("socket=%p starting I/O...", o);
352 err = _efl_net_socket_windows_recv(o, pd);
353 if (err) return err;
354
355 pd->io_started = EINA_TRUE;
356 return 0;
357}
358
359HANDLE
360_efl_net_socket_windows_handle_get(const Eo *o)
361{
362 Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS);
363 EINA_SAFETY_ON_NULL_RETURN_VAL(pd, INVALID_HANDLE_VALUE);
364 return pd->handle;
365}
366
367EOLIAN static Eo *
368_efl_net_socket_windows_efl_object_constructor(Eo *o, Efl_Net_Socket_Windows_Data *pd)
369{
370 pd->handle = INVALID_HANDLE_VALUE;
371
372 return efl_constructor(efl_super(o, MY_CLASS));
373}
374
375EOLIAN static void
376_efl_net_socket_windows_efl_object_destructor(Eo *o, Efl_Net_Socket_Windows_Data *pd)
377{
378 while (pd->pending_ops)
379 _efl_net_socket_windows_operation_failed(pd->pending_ops->data, ECANCELED);
380
381 if (efl_io_closer_close_on_destructor_get(o) &&
382 (!efl_io_closer_closed_get(o)))
383 {
384 efl_event_freeze(o);
385 efl_io_closer_close(o);
386 efl_event_thaw(o);
387 }
388
389 efl_destructor(efl_super(o, MY_CLASS));
390
391 eina_stringshare_replace(&pd->address_local, NULL);
392 eina_stringshare_replace(&pd->address_remote, NULL);
393
394 free(pd->recv.mem);
395 pd->recv.mem = NULL;
396 pd->recv.len = 0;
397 pd->recv.used = 0;
398
399 free(pd->send.mem);
400 pd->send.mem = NULL;
401 pd->send.len = 0;
402 pd->send.used = 0;
403}
404
405EOLIAN static Eina_Error
406_efl_net_socket_windows_efl_io_closer_close(Eo *o, Efl_Net_Socket_Windows_Data *pd)
407{
408 HANDLE h;
409
410 EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), EBADF);
411
412 efl_io_writer_can_write_set(o, EINA_FALSE);
413 efl_io_reader_can_read_set(o, EINA_FALSE);
414 efl_io_reader_eos_set(o, EINA_TRUE);
415
416 if (pd->io)
417 {
418 CloseThreadpoolIo(pd->io);
419 pd->io = NULL;
420 }
421
422 h = InterlockedExchangePointer(&pd->handle, INVALID_HANDLE_VALUE);
423 if (h != INVALID_HANDLE_VALUE)
424 CloseHandle(h);
425
426 return 0;
427}
428
429EOLIAN static Eina_Bool
430_efl_net_socket_windows_efl_io_closer_closed_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd)
431{
432 return pd->handle == INVALID_HANDLE_VALUE;
433}
434
435EOLIAN static Eina_Error
436_efl_net_socket_windows_efl_io_reader_read(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Rw_Slice *rw_slice)
437{
438 Eina_Slice ro_slice;
439 DWORD remaining;
440
441 EINA_SAFETY_ON_NULL_RETURN_VAL(rw_slice, EINVAL);
442
443 ro_slice.len = pd->recv.used;
444 if (ro_slice.len == 0)
445 {
446 rw_slice->len = 0;
447 if (pd->pending_eos)
448 {
449 efl_io_reader_eos_set(o, EINA_TRUE);
450 efl_io_closer_close(o);
451 }
452 return EAGAIN;
453 }
454 ro_slice.bytes = pd->recv.bytes;
455
456 *rw_slice = eina_rw_slice_copy(*rw_slice, ro_slice);
457
458 remaining = pd->recv.used - rw_slice->len;
459 if (remaining)
460 memmove(pd->recv.bytes, pd->recv.bytes + rw_slice->len, remaining);
461
462 pd->recv.used = remaining;
463 efl_io_reader_can_read_set(o, remaining > 0);
464
465 if ((pd->pending_eos) && (remaining == 0))
466 {
467 efl_io_reader_eos_set(o, EINA_TRUE);
468 efl_io_closer_close(o);
469 return 0;
470 }
471
472 if ((!pd->recv.pending) && (pd->recv.used < pd->recv.len))
473 {
474 DBG("recv %lu bytes more from socket=%p", pd->recv.len - pd->recv.used, o);
475 return _efl_net_socket_windows_recv(o, pd);
476 }
477
478 return 0;
479}
480
481EOLIAN static void
482_efl_net_socket_windows_efl_io_reader_can_read_set(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Bool can_read)
483{
484 EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o) && can_read);
485 if (pd->can_read == can_read) return;
486 pd->can_read = can_read;
487 efl_event_callback_call(o, EFL_IO_READER_EVENT_CAN_READ_CHANGED, NULL);
488}
489
490EOLIAN static Eina_Bool
491_efl_net_socket_windows_efl_io_reader_can_read_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd)
492{
493 return pd->can_read;
494}
495
496EOLIAN static void
497_efl_net_socket_windows_efl_io_reader_eos_set(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Bool is_eos)
498{
499 if (pd->eos == is_eos) return;
500 pd->eos = is_eos;
501 if (is_eos)
502 efl_event_callback_call(o, EFL_IO_READER_EVENT_EOS, NULL);
503}
504
505EOLIAN static Eina_Bool
506_efl_net_socket_windows_efl_io_reader_eos_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd)
507{
508 return pd->eos;
509}
510
511EOLIAN static Eina_Error
512_efl_net_socket_windows_efl_io_writer_write(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Slice *slice, Eina_Slice *remaining)
513{
514 Eina_Error err = EINVAL;
515 DWORD available, todo;
516
517 EINA_SAFETY_ON_NULL_RETURN_VAL(slice, EINVAL);
518 EINA_SAFETY_ON_NULL_GOTO(slice->mem, error);
519 EINA_SAFETY_ON_TRUE_GOTO(efl_io_closer_closed_get(o), error);
520 err = ENOMEM;
521 EINA_SAFETY_ON_TRUE_GOTO(pd->send.mem != NULL, error);
522
523 if (pd->send.len <= pd->send.used)
524 {
525 efl_io_writer_can_write_set(o, EINA_FALSE);
526 return EAGAIN;
527 }
528
529 available = pd->send.len - pd->send.used;
530 if (slice->len < available)
531 todo = slice->len;
532 else
533 todo = available;
534
535 memcpy(pd->send.bytes + pd->send.used, slice->mem, todo);
536 if (remaining)
537 {
538 remaining->len = slice->len - todo;
539 remaining->bytes = slice->bytes + todo;
540 }
541 slice->len = todo;
542
543 efl_io_writer_can_write_set(o, pd->send.used < pd->send.len);
544
545 if ((!pd->send.pending) && (pd->send.used > 0))
546 {
547 DBG("send %lu bytes more to socket=%p", pd->send.used, o);
548 return _efl_net_socket_windows_send(o, pd);
549 }
550
551 return 0;
552
553 error:
554 if (remaining) *remaining = *slice;
555 slice->len = 0;
556 slice->mem = NULL;
557 return err;
558}
559
560EOLIAN static void
561_efl_net_socket_windows_efl_io_writer_can_write_set(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Bool can_write)
562{
563 EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o) && can_write);
564 if (pd->can_write == can_write) return;
565 pd->can_write = can_write;
566 efl_event_callback_call(o, EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, NULL);
567}
568
569EOLIAN static Eina_Bool
570_efl_net_socket_windows_efl_io_writer_can_write_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd)
571{
572 return pd->can_write;
573}
574
575EOLIAN static void
576_efl_net_socket_windows_efl_net_socket_address_local_set(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd, const char *address)
577{
578 eina_stringshare_replace(&pd->address_local, address);
579}
580
581EOLIAN static const char *
582_efl_net_socket_windows_efl_net_socket_address_local_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd)
583{
584 return pd->address_local;
585}
586
587EOLIAN static void
588_efl_net_socket_windows_efl_net_socket_address_remote_set(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd, const char *address)
589{
590 eina_stringshare_replace(&pd->address_remote, address);
591}
592
593EOLIAN static const char *
594_efl_net_socket_windows_efl_net_socket_address_remote_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd)
595{
596 return pd->address_remote;
597}
598
599#include "efl_net_socket_windows.eo.c"
diff --git a/src/lib/ecore_con/efl_net_socket_windows.eo b/src/lib/ecore_con/efl_net_socket_windows.eo
new file mode 100644
index 0000000000..cbe9f583f5
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_socket_windows.eo
@@ -0,0 +1,24 @@
1class Efl.Net.Socket.Windows (Efl.Loop_User, Efl.Net.Socket) {
2 [[A base Windows NamedPipe socket.
3
4 This is the common class and takes an existing file HANDLE,
5 usually created by an dialer (CreatFile()) or server
6 (CreateNamedPipe()).
7
8 @since 1.19
9 ]]
10
11 implements {
12 Efl.Object.constructor;
13 Efl.Object.destructor;
14 Efl.Io.Closer.close;
15 Efl.Io.Closer.closed { get; }
16 Efl.Io.Reader.read;
17 Efl.Io.Reader.can_read { get; set; }
18 Efl.Io.Reader.eos { get; set; }
19 Efl.Io.Writer.write;
20 Efl.Io.Writer.can_write { get; set; }
21 Efl.Net.Socket.address_local { get; set; }
22 Efl.Net.Socket.address_remote { get; set; }
23 }
24}