efl_net_socket_fd: make it more win32 friendly.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Thu, 8 Sep 2016 19:12:18 +0000 (16:12 -0300)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Thu, 8 Sep 2016 20:01:13 +0000 (17:01 -0300)
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
src/lib/ecore_con/efl_net_socket_fd.c

index e2fab7a..69102d7 100644 (file)
@@ -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
index 0cc9152..339e7ef 100644 (file)
@@ -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