From 4814f937e2e1b7705daf3c5cf7e32d9cb0fe120c Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Thu, 8 Sep 2016 16:12:18 -0300 Subject: [PATCH] efl_net_socket_fd: make it more win32 friendly. it seems that on windows read() and write() won't work with sockets, so use recv() and send(). Note that this code is still untested on windows, at least the errors must be fetched using WSAGetLastError() instead of errno directly, but I don't have a Windows machine I can test. --- src/lib/ecore_con/ecore_con_private.h | 74 +++++++++++++++++++++ src/lib/ecore_con/efl_net_socket_fd.c | 92 +++++++++++++++++++++++---- 2 files changed, 155 insertions(+), 11 deletions(-) diff --git a/src/lib/ecore_con/ecore_con_private.h b/src/lib/ecore_con/ecore_con_private.h index e2fab7a506..69102d7563 100644 --- a/src/lib/ecore_con/ecore_con_private.h +++ b/src/lib/ecore_con/ecore_con_private.h @@ -377,4 +377,78 @@ Eina_Bool efl_net_ip_port_fmt(char *buf, int buflen, const struct sockaddr *addr int efl_net_socket4(int domain, int type, int protocol, Eina_Bool close_on_exec); +static inline Eina_Error +efl_net_socket_error_get(void) +{ +#ifndef _WIN32 + return errno; +#else + Eina_Error err = WSAGetLastError(); + + if (0) { } + + /* used by send() */ +#if defined(WSAEACCES) && (WSAEACCES != EACCES) + else if (err == WSAEACCES) err = EACCES; +#endif +#if defined(WSAEWOULDBLOCK) && (WSAEWOULDBLOCK != EAGAIN) + else if (err == WSAEWOULDBLOCK) err = EAGAIN; +#endif +#if defined(WSAEBADF) && (WSAEBADF != EBADF) + else if (err == WSAEBADF) err = EBADF; +#endif +#if defined(WSAECONNRESET) && (WSAECONNRESET != ECONNRESET) + else if (err == WSAECONNRESET) err = ECONNRESET; +#endif +#if defined(WSAEDESTADDRREQ) && (WSAEDESTADDRREQ != EDESTADDRREQ) + else if (err == WSAEDESTADDRREQ) err = EDESTADDRREQ; +#endif +#if defined(WSAEFAULT) && (WSAEFAULT != EFAULT) + else if (err == WSAEFAULT) err = EFAULT; +#endif +#if defined(WSAEINTR) && (WSAEINTR != EINTR) + else if (err == WSAEINTR) err = EINTR; +#endif +#if defined(WSAEINVAL) && (WSAEINVAL != EINVAL) + else if (err == WSAEINVAL) err = EINVAL; +#endif +#if defined(WSAEISCONN) && (WSAEISCONN != EISCONN) + else if (err == WSAEISCONN) err = EISCONN; +#endif +#if defined(WSAEMSGSIZE) && (WSAEMSGSIZE != EMSGSIZE) + else if (err == WSAEMSGSIZE) err = EMSGSIZE; +#endif +#if defined(WSAENOBUFS) && (WSAENOBUFS != ENOBUFS) + else if (err == WSAENOBUFS) err = ENOBUFS; +#endif +#if defined(WSA_NOT_ENOUGH_MEMORY) && (WSA_NOT_ENOUGH_MEMORY != ENOMEM) + else if (err == WSA_NOT_ENOUGH_MEMORY) err = ENOMEM; +#endif +#if defined(WSAENOTCONN) && (WSAENOTCONN != ENOTCONN) + else if (err == WSAENOTCONN) err = ENOTCONN; +#endif +#if defined(WSAENOTSOCK) && (WSAENOTSOCK != ENOTSOCK) + else if (err == WSAENOTSOCK) err = ENOTSOCK; +#endif +#if defined(WSAEOPNOTSUPP) && (WSAEOPNOTSUPP != EOPNOTSUPP) + else if (err == WSAEOPNOTSUPP) err = EOPNOTSUPP; +#endif +#if defined(WSAESHUTDOWN) && (WSAESHUTDOWN != EPIPE) + else if (err == WSAESHUTDOWN) err = EPIPE; +#endif + + /* extras used by recv() */ +#if defined(WSAECONNREFUSED) && (WSAECONNREFUSED != ECONNREFUSED) + else if (err == WSAECONNREFUSED) err = ECONNREFUSED; +#endif + + /* extras used by getsockopt() */ +#if defined(WSAENOPROTOOPT) && (WSAENOPROTOOPT != ENOPROTOOPT) + else if (err == WSAENOPROTOOPT) err = ENOPROTOOPT; +#endif + + return err; +#endif +} + #endif diff --git a/src/lib/ecore_con/efl_net_socket_fd.c b/src/lib/ecore_con/efl_net_socket_fd.c index 0cc9152918..339e7efdfb 100644 --- a/src/lib/ecore_con/efl_net_socket_fd.c +++ b/src/lib/ecore_con/efl_net_socket_fd.c @@ -120,7 +120,7 @@ _efl_net_socket_fd_efl_loop_fd_fd_set(Eo *o, Efl_Net_Socket_Fd_Data *pd, int fd) struct sockaddr_storage addr; socklen_t addrlen = sizeof(addr); if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) < 0) - ERR("getsockname(%d): %s", fd, strerror(errno)); + ERR("getsockname(%d): %s", fd, eina_error_msg_get(efl_net_socket_error_get())); else efl_net_socket_fd_family_set(o, addr.ss_family); } @@ -157,25 +157,84 @@ _efl_net_socket_fd_efl_io_closer_close(Eo *o, Efl_Net_Socket_Fd_Data *pd EINA_UN EOLIAN static Eina_Error _efl_net_socket_fd_efl_io_reader_read(Eo *o, Efl_Net_Socket_Fd_Data *pd EINA_UNUSED, Eina_Rw_Slice *rw_slice) { - Eina_Error ret; + int fd = efl_io_reader_fd_reader_fd_get(o); + ssize_t r; - ret = efl_io_reader_read(efl_super(o, MY_CLASS), rw_slice); - if (rw_slice && rw_slice->len > 0) - efl_io_reader_can_read_set(o, EINA_FALSE); /* wait Efl.Loop.Fd "read" */ + EINA_SAFETY_ON_NULL_RETURN_VAL(rw_slice, EINVAL); + if (fd < 0) goto error; + do + { + r = recv(fd, rw_slice->mem, rw_slice->len, 0); + if (r < 0) + { + Eina_Error err = efl_net_socket_error_get(); - return ret; + if (err == EINTR) continue; + + rw_slice->len = 0; + rw_slice->mem = NULL; + + if (err == EAGAIN) efl_io_reader_can_read_set(o, EINA_FALSE); + return err; + } + } + while (r < 0); + + rw_slice->len = r; + efl_io_reader_can_read_set(o, EINA_FALSE); /* wait Efl.Loop.Fd "read" */ + if (r == 0) + efl_io_reader_eos_set(o, EINA_TRUE); + + return 0; + + error: + rw_slice->len = 0; + rw_slice->mem = NULL; + return EINVAL; } EOLIAN static Eina_Error _efl_net_socket_fd_efl_io_writer_write(Eo *o, Efl_Net_Socket_Fd_Data *pd EINA_UNUSED, Eina_Slice *ro_slice, Eina_Slice *remaining) { - Eina_Error ret; + int fd = efl_io_writer_fd_writer_fd_get(o); + ssize_t r; - ret = efl_io_writer_write(efl_super(o, MY_CLASS), ro_slice, remaining); - if (ro_slice && ro_slice->len > 0) - efl_io_writer_can_write_set(o, EINA_FALSE); /* wait Efl.Loop.Fd "write" */ + EINA_SAFETY_ON_NULL_RETURN_VAL(ro_slice, EINVAL); + if (fd < 0) goto error; - return ret; + do + { + r = send(fd, ro_slice->mem, ro_slice->len, 0); + if (r < 0) + { + Eina_Error err = efl_net_socket_error_get(); + + if (err == EINTR) continue; + + if (remaining) *remaining = *ro_slice; + ro_slice->len = 0; + ro_slice->mem = NULL; + if (err == EAGAIN) efl_io_writer_can_write_set(o, EINA_FALSE); + return err; + } + } + while (r < 0); + + if (remaining) + { + remaining->len = ro_slice->len - r; + remaining->bytes = ro_slice->bytes + r; + } + ro_slice->len = r; + efl_io_writer_can_write_set(o, EINA_FALSE); /* wait Efl.Loop.Fd "write" */ + + return 0; + + error: + if (remaining) *remaining = *ro_slice; + ro_slice->len = 0; + ro_slice->mem = NULL; + return EINVAL; } EOLIAN static void @@ -205,6 +264,11 @@ _efl_net_socket_fd_efl_net_socket_address_remote_get(Eo *o EINA_UNUSED, Efl_Net_ EOLIAN static Eina_Bool _efl_net_socket_fd_close_on_exec_set(Eo *o, Efl_Net_Socket_Fd_Data *pd, Eina_Bool close_on_exec) { +#ifdef _WIN32 + DBG("close on exec is not supported on windows"); + pd->close_on_exec = close_on_exec; + return EINA_FALSE; +#else int flags, fd; pd->close_on_exec = close_on_exec; @@ -229,11 +293,16 @@ _efl_net_socket_fd_close_on_exec_set(Eo *o, Efl_Net_Socket_Fd_Data *pd, Eina_Boo } return EINA_TRUE; +#endif } EOLIAN static Eina_Bool _efl_net_socket_fd_close_on_exec_get(Eo *o, Efl_Net_Socket_Fd_Data *pd) { +#ifdef _WIN32 + DBG("close on exec is not supported on windows"); + return pd->close_on_exec; +#else int flags, fd; fd = efl_loop_fd_get(o); @@ -251,6 +320,7 @@ _efl_net_socket_fd_close_on_exec_get(Eo *o, Efl_Net_Socket_Fd_Data *pd) pd->close_on_exec = !!(flags & FD_CLOEXEC); /* sync */ return pd->close_on_exec; +#endif } EOLIAN static void