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.
This commit is contained in:
Gustavo Sverzut Barbieri 2016-09-08 16:12:18 -03:00
parent 088c9675ef
commit 4814f937e2
2 changed files with 155 additions and 11 deletions

View 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

View 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