efl.net: socket, server and dialer for TCP.
Efl.Net.Server defines how to accept new connections, doing the
bind(), listen() and accept() for protocols such as TCP.
Efl.Net.Dialer defines to to reach a server.
Both are based on Efl.Net.Socket as communication interface that is
based on Efl.Io.Reader, Efl.Io.Writer and Efl.Io.Closer, thus being
usable with code such as Efl.Io.Copier.
The Server will emit an event "client,add" with the established
Socket, which is a child and can be closed by both the server or the
user.
The Dialer extends the Socket and allows for creating one given an
address, that will be resolved and connected.
TCP is the initial implementation so we an validate the
interfaces. UDP, Unix-Local and SSL will come later as derivate
classes.
The examples are documented and should cover the basic principles:
- efl_io_copier_example can accept "tcp://IP:PORT" and will work as a
"netcat", can send data from socket, file or stdin to a socket,
file, stdout or stderr.
- efl_net_server_example listens for connections and can either reply
"Hello World!" and take some data or work as an echo-server,
looping back all received data to the user.
More complex interactions that require a "chat" between client and
server will be covered with new classes later, such as a queue that
empties itself once data is read.
2016-08-17 21:53:16 -07:00
|
|
|
#define EFL_NET_SOCKET_TCP_PROTECTED 1
|
|
|
|
#define EFL_NET_SOCKET_FD_PROTECTED 1
|
|
|
|
#define EFL_LOOP_FD_PROTECTED 1
|
|
|
|
#define EFL_IO_READER_FD_PROTECTED 1
|
|
|
|
#define EFL_IO_WRITER_FD_PROTECTED 1
|
|
|
|
#define EFL_IO_CLOSER_FD_PROTECTED 1
|
|
|
|
#define EFL_IO_READER_PROTECTED 1
|
|
|
|
#define EFL_IO_WRITER_PROTECTED 1
|
|
|
|
#define EFL_IO_CLOSER_PROTECTED 1
|
|
|
|
#define EFL_NET_SOCKET_PROTECTED 1
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "Ecore.h"
|
|
|
|
#include "Ecore_Con.h"
|
|
|
|
#include "ecore_con_private.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
|
|
# include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NETINET_TCP_H
|
|
|
|
# include <netinet/tcp.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NETINET_IN_H
|
|
|
|
# include <netinet/in.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ARPA_INET_H
|
|
|
|
# include <arpa/inet.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_EVIL
|
|
|
|
# include <Evil.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define MY_CLASS EFL_NET_SOCKET_TCP_CLASS
|
|
|
|
|
|
|
|
typedef struct _Efl_Net_Socket_Tcp_Data
|
|
|
|
{
|
|
|
|
Eina_Bool keep_alive;
|
|
|
|
Eina_Bool no_delay;
|
|
|
|
Eina_Bool cork;
|
|
|
|
} Efl_Net_Socket_Tcp_Data;
|
|
|
|
|
|
|
|
EOLIAN static void
|
|
|
|
_efl_net_socket_tcp_efl_loop_fd_fd_set(Eo *o, Efl_Net_Socket_Tcp_Data *pd EINA_UNUSED, int fd)
|
|
|
|
{
|
|
|
|
efl_loop_fd_set(efl_super(o, MY_CLASS), fd);
|
|
|
|
|
|
|
|
if (fd >= 0)
|
|
|
|
{
|
|
|
|
struct sockaddr_storage addr;
|
|
|
|
socklen_t addrlen;
|
|
|
|
int family;
|
|
|
|
|
|
|
|
/* apply postponed values */
|
|
|
|
efl_net_socket_tcp_keep_alive_set(o, pd->keep_alive);
|
|
|
|
efl_net_socket_tcp_no_delay_set(o, pd->no_delay);
|
|
|
|
efl_net_socket_tcp_cork_set(o, pd->cork);
|
|
|
|
|
|
|
|
family = efl_net_socket_fd_family_get(o);
|
|
|
|
if (family == AF_UNSPEC) return;
|
|
|
|
|
|
|
|
addrlen = sizeof(addr);
|
|
|
|
if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) < 0)
|
|
|
|
ERR("getsockname(%d): %s", fd, strerror(errno));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char str[INET6_ADDRSTRLEN + sizeof("[]:65536")];
|
|
|
|
if (efl_net_ip_port_fmt(str, sizeof(str), (struct sockaddr *)&addr))
|
|
|
|
efl_net_socket_address_local_set(o, str);
|
|
|
|
}
|
|
|
|
|
|
|
|
addrlen = sizeof(addr);
|
|
|
|
if (getpeername(fd, (struct sockaddr *)&addr, &addrlen) < 0)
|
|
|
|
ERR("getpeername(%d): %s", fd, strerror(errno));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char str[INET6_ADDRSTRLEN + sizeof("[]:65536")];
|
|
|
|
if (efl_net_ip_port_fmt(str, sizeof(str), (struct sockaddr *)&addr))
|
|
|
|
efl_net_socket_address_remote_set(o, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eina_Bool
|
|
|
|
_efl_net_socket_tcp_keep_alive_set(Eo *o, Efl_Net_Socket_Tcp_Data *pd, Eina_Bool keep_alive)
|
|
|
|
{
|
|
|
|
int value, fd;
|
|
|
|
Eina_Bool old = pd->keep_alive;
|
|
|
|
|
|
|
|
pd->keep_alive = keep_alive;
|
|
|
|
|
|
|
|
fd = efl_loop_fd_get(o);
|
|
|
|
if (fd < 0) return EINA_TRUE; /* postpone until fd_set() */
|
|
|
|
|
|
|
|
value = keep_alive;
|
|
|
|
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value)) < 0)
|
|
|
|
{
|
|
|
|
ERR("setsockopt(%d, SOL_SOCKET, SO_KEEPALIVE, %d): %s",
|
|
|
|
fd, value, strerror(errno));
|
|
|
|
pd->keep_alive = old;
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eina_Bool
|
|
|
|
_efl_net_socket_tcp_keep_alive_get(Eo *o, Efl_Net_Socket_Tcp_Data *pd)
|
|
|
|
{
|
|
|
|
int value = 0, fd;
|
|
|
|
socklen_t valuelen;
|
|
|
|
|
|
|
|
fd = efl_loop_fd_get(o);
|
|
|
|
if (fd < 0) return pd->keep_alive;
|
|
|
|
|
|
|
|
/* if there is a fd, always query it directly as it may be modified
|
|
|
|
* elsewhere by nasty users.
|
|
|
|
*/
|
|
|
|
valuelen = sizeof(value);
|
|
|
|
if (getsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &value, &valuelen) < 0)
|
|
|
|
{
|
|
|
|
ERR("getsockopt(%d, SOL_SOCKET, SO_KEEPALIVE): %s",
|
|
|
|
fd, strerror(errno));
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
pd->keep_alive = !!value; /* sync */
|
|
|
|
return pd->keep_alive;
|
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eina_Bool
|
|
|
|
_efl_net_socket_tcp_no_delay_set(Eo *o, Efl_Net_Socket_Tcp_Data *pd, Eina_Bool no_delay)
|
|
|
|
{
|
|
|
|
int value, fd;
|
|
|
|
Eina_Bool old = pd->no_delay;
|
|
|
|
|
|
|
|
pd->no_delay = no_delay;
|
|
|
|
|
|
|
|
fd = efl_loop_fd_get(o);
|
|
|
|
if (fd < 0) return EINA_TRUE; /* postpone until fd_set() */
|
|
|
|
|
|
|
|
value = no_delay;
|
|
|
|
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)) < 0)
|
|
|
|
{
|
|
|
|
ERR("setsockopt(%d, IPPROTO_TCP, TCP_NODELAY, %d): %s",
|
|
|
|
fd, value, strerror(errno));
|
|
|
|
pd->no_delay = old;
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eina_Bool
|
|
|
|
_efl_net_socket_tcp_no_delay_get(Eo *o, Efl_Net_Socket_Tcp_Data *pd)
|
|
|
|
{
|
|
|
|
int value = 0, fd;
|
|
|
|
socklen_t valuelen;
|
|
|
|
|
|
|
|
fd = efl_loop_fd_get(o);
|
|
|
|
if (fd < 0) return pd->no_delay;
|
|
|
|
|
|
|
|
/* if there is a fd, always query it directly as it may be modified
|
|
|
|
* elsewhere by nasty users.
|
|
|
|
*/
|
|
|
|
valuelen = sizeof(value);
|
|
|
|
if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &value, &valuelen) < 0)
|
|
|
|
{
|
|
|
|
ERR("getsockopt(%d, IPPROTO_TCP, TCP_NODELAY): %s",
|
|
|
|
fd, strerror(errno));
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
pd->no_delay = !!value; /* sync */
|
|
|
|
return pd->no_delay;
|
|
|
|
}
|
|
|
|
|
2016-08-23 02:32:21 -07:00
|
|
|
static inline int
|
|
|
|
_cork_option_get(void)
|
|
|
|
{
|
|
|
|
#if defined(HAVE_TCP_CORK)
|
|
|
|
return TCP_CORK;
|
|
|
|
#elif defined(HAVE_TCP_NOPUSH)
|
|
|
|
return TCP_NOPUSH;
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
efl.net: socket, server and dialer for TCP.
Efl.Net.Server defines how to accept new connections, doing the
bind(), listen() and accept() for protocols such as TCP.
Efl.Net.Dialer defines to to reach a server.
Both are based on Efl.Net.Socket as communication interface that is
based on Efl.Io.Reader, Efl.Io.Writer and Efl.Io.Closer, thus being
usable with code such as Efl.Io.Copier.
The Server will emit an event "client,add" with the established
Socket, which is a child and can be closed by both the server or the
user.
The Dialer extends the Socket and allows for creating one given an
address, that will be resolved and connected.
TCP is the initial implementation so we an validate the
interfaces. UDP, Unix-Local and SSL will come later as derivate
classes.
The examples are documented and should cover the basic principles:
- efl_io_copier_example can accept "tcp://IP:PORT" and will work as a
"netcat", can send data from socket, file or stdin to a socket,
file, stdout or stderr.
- efl_net_server_example listens for connections and can either reply
"Hello World!" and take some data or work as an echo-server,
looping back all received data to the user.
More complex interactions that require a "chat" between client and
server will be covered with new classes later, such as a queue that
empties itself once data is read.
2016-08-17 21:53:16 -07:00
|
|
|
EOLIAN static Eina_Bool
|
|
|
|
_efl_net_socket_tcp_cork_set(Eo *o, Efl_Net_Socket_Tcp_Data *pd, Eina_Bool cork)
|
|
|
|
{
|
2016-08-23 02:32:21 -07:00
|
|
|
int value, fd, option;
|
efl.net: socket, server and dialer for TCP.
Efl.Net.Server defines how to accept new connections, doing the
bind(), listen() and accept() for protocols such as TCP.
Efl.Net.Dialer defines to to reach a server.
Both are based on Efl.Net.Socket as communication interface that is
based on Efl.Io.Reader, Efl.Io.Writer and Efl.Io.Closer, thus being
usable with code such as Efl.Io.Copier.
The Server will emit an event "client,add" with the established
Socket, which is a child and can be closed by both the server or the
user.
The Dialer extends the Socket and allows for creating one given an
address, that will be resolved and connected.
TCP is the initial implementation so we an validate the
interfaces. UDP, Unix-Local and SSL will come later as derivate
classes.
The examples are documented and should cover the basic principles:
- efl_io_copier_example can accept "tcp://IP:PORT" and will work as a
"netcat", can send data from socket, file or stdin to a socket,
file, stdout or stderr.
- efl_net_server_example listens for connections and can either reply
"Hello World!" and take some data or work as an echo-server,
looping back all received data to the user.
More complex interactions that require a "chat" between client and
server will be covered with new classes later, such as a queue that
empties itself once data is read.
2016-08-17 21:53:16 -07:00
|
|
|
Eina_Bool old = pd->cork;
|
|
|
|
|
2016-08-23 02:32:21 -07:00
|
|
|
option = _cork_option_get();
|
|
|
|
if (EINA_UNLIKELY(option < 0))
|
|
|
|
{
|
|
|
|
ERR("Could not find a TCP_CORK equivalent on your system");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
efl.net: socket, server and dialer for TCP.
Efl.Net.Server defines how to accept new connections, doing the
bind(), listen() and accept() for protocols such as TCP.
Efl.Net.Dialer defines to to reach a server.
Both are based on Efl.Net.Socket as communication interface that is
based on Efl.Io.Reader, Efl.Io.Writer and Efl.Io.Closer, thus being
usable with code such as Efl.Io.Copier.
The Server will emit an event "client,add" with the established
Socket, which is a child and can be closed by both the server or the
user.
The Dialer extends the Socket and allows for creating one given an
address, that will be resolved and connected.
TCP is the initial implementation so we an validate the
interfaces. UDP, Unix-Local and SSL will come later as derivate
classes.
The examples are documented and should cover the basic principles:
- efl_io_copier_example can accept "tcp://IP:PORT" and will work as a
"netcat", can send data from socket, file or stdin to a socket,
file, stdout or stderr.
- efl_net_server_example listens for connections and can either reply
"Hello World!" and take some data or work as an echo-server,
looping back all received data to the user.
More complex interactions that require a "chat" between client and
server will be covered with new classes later, such as a queue that
empties itself once data is read.
2016-08-17 21:53:16 -07:00
|
|
|
pd->cork = cork;
|
|
|
|
|
|
|
|
fd = efl_loop_fd_get(o);
|
|
|
|
if (fd < 0) return EINA_TRUE; /* postpone until fd_set() */
|
|
|
|
|
|
|
|
value = cork;
|
2016-08-23 02:32:21 -07:00
|
|
|
if (setsockopt(fd, IPPROTO_TCP, option, &value, sizeof(value)) < 0)
|
efl.net: socket, server and dialer for TCP.
Efl.Net.Server defines how to accept new connections, doing the
bind(), listen() and accept() for protocols such as TCP.
Efl.Net.Dialer defines to to reach a server.
Both are based on Efl.Net.Socket as communication interface that is
based on Efl.Io.Reader, Efl.Io.Writer and Efl.Io.Closer, thus being
usable with code such as Efl.Io.Copier.
The Server will emit an event "client,add" with the established
Socket, which is a child and can be closed by both the server or the
user.
The Dialer extends the Socket and allows for creating one given an
address, that will be resolved and connected.
TCP is the initial implementation so we an validate the
interfaces. UDP, Unix-Local and SSL will come later as derivate
classes.
The examples are documented and should cover the basic principles:
- efl_io_copier_example can accept "tcp://IP:PORT" and will work as a
"netcat", can send data from socket, file or stdin to a socket,
file, stdout or stderr.
- efl_net_server_example listens for connections and can either reply
"Hello World!" and take some data or work as an echo-server,
looping back all received data to the user.
More complex interactions that require a "chat" between client and
server will be covered with new classes later, such as a queue that
empties itself once data is read.
2016-08-17 21:53:16 -07:00
|
|
|
{
|
2016-08-23 02:32:21 -07:00
|
|
|
ERR("setsockopt(%d, IPPROTO_TCP, 0x%x, %d): %s",
|
|
|
|
fd, option, value, strerror(errno));
|
efl.net: socket, server and dialer for TCP.
Efl.Net.Server defines how to accept new connections, doing the
bind(), listen() and accept() for protocols such as TCP.
Efl.Net.Dialer defines to to reach a server.
Both are based on Efl.Net.Socket as communication interface that is
based on Efl.Io.Reader, Efl.Io.Writer and Efl.Io.Closer, thus being
usable with code such as Efl.Io.Copier.
The Server will emit an event "client,add" with the established
Socket, which is a child and can be closed by both the server or the
user.
The Dialer extends the Socket and allows for creating one given an
address, that will be resolved and connected.
TCP is the initial implementation so we an validate the
interfaces. UDP, Unix-Local and SSL will come later as derivate
classes.
The examples are documented and should cover the basic principles:
- efl_io_copier_example can accept "tcp://IP:PORT" and will work as a
"netcat", can send data from socket, file or stdin to a socket,
file, stdout or stderr.
- efl_net_server_example listens for connections and can either reply
"Hello World!" and take some data or work as an echo-server,
looping back all received data to the user.
More complex interactions that require a "chat" between client and
server will be covered with new classes later, such as a queue that
empties itself once data is read.
2016-08-17 21:53:16 -07:00
|
|
|
pd->cork = old;
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eina_Bool
|
|
|
|
_efl_net_socket_tcp_cork_get(Eo *o, Efl_Net_Socket_Tcp_Data *pd)
|
|
|
|
{
|
|
|
|
int value = 0, fd;
|
|
|
|
socklen_t valuelen;
|
2016-08-23 02:32:21 -07:00
|
|
|
int option;
|
|
|
|
|
|
|
|
option = _cork_option_get();
|
|
|
|
if (EINA_UNLIKELY(option < 0))
|
|
|
|
{
|
|
|
|
ERR("Could not find a TCP_CORK equivalent on your system");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
efl.net: socket, server and dialer for TCP.
Efl.Net.Server defines how to accept new connections, doing the
bind(), listen() and accept() for protocols such as TCP.
Efl.Net.Dialer defines to to reach a server.
Both are based on Efl.Net.Socket as communication interface that is
based on Efl.Io.Reader, Efl.Io.Writer and Efl.Io.Closer, thus being
usable with code such as Efl.Io.Copier.
The Server will emit an event "client,add" with the established
Socket, which is a child and can be closed by both the server or the
user.
The Dialer extends the Socket and allows for creating one given an
address, that will be resolved and connected.
TCP is the initial implementation so we an validate the
interfaces. UDP, Unix-Local and SSL will come later as derivate
classes.
The examples are documented and should cover the basic principles:
- efl_io_copier_example can accept "tcp://IP:PORT" and will work as a
"netcat", can send data from socket, file or stdin to a socket,
file, stdout or stderr.
- efl_net_server_example listens for connections and can either reply
"Hello World!" and take some data or work as an echo-server,
looping back all received data to the user.
More complex interactions that require a "chat" between client and
server will be covered with new classes later, such as a queue that
empties itself once data is read.
2016-08-17 21:53:16 -07:00
|
|
|
|
|
|
|
fd = efl_loop_fd_get(o);
|
|
|
|
if (fd < 0) return pd->cork;
|
|
|
|
|
|
|
|
/* if there is a fd, always query it directly as it may be modified
|
|
|
|
* elsewhere by nasty users.
|
|
|
|
*/
|
|
|
|
valuelen = sizeof(value);
|
2016-08-23 02:32:21 -07:00
|
|
|
if (getsockopt(fd, IPPROTO_TCP, option, &value, &valuelen) < 0)
|
efl.net: socket, server and dialer for TCP.
Efl.Net.Server defines how to accept new connections, doing the
bind(), listen() and accept() for protocols such as TCP.
Efl.Net.Dialer defines to to reach a server.
Both are based on Efl.Net.Socket as communication interface that is
based on Efl.Io.Reader, Efl.Io.Writer and Efl.Io.Closer, thus being
usable with code such as Efl.Io.Copier.
The Server will emit an event "client,add" with the established
Socket, which is a child and can be closed by both the server or the
user.
The Dialer extends the Socket and allows for creating one given an
address, that will be resolved and connected.
TCP is the initial implementation so we an validate the
interfaces. UDP, Unix-Local and SSL will come later as derivate
classes.
The examples are documented and should cover the basic principles:
- efl_io_copier_example can accept "tcp://IP:PORT" and will work as a
"netcat", can send data from socket, file or stdin to a socket,
file, stdout or stderr.
- efl_net_server_example listens for connections and can either reply
"Hello World!" and take some data or work as an echo-server,
looping back all received data to the user.
More complex interactions that require a "chat" between client and
server will be covered with new classes later, such as a queue that
empties itself once data is read.
2016-08-17 21:53:16 -07:00
|
|
|
{
|
2016-08-23 02:32:21 -07:00
|
|
|
ERR("getsockopt(%d, IPPROTO_TCP, 0x%x): %s",
|
|
|
|
fd, option, strerror(errno));
|
efl.net: socket, server and dialer for TCP.
Efl.Net.Server defines how to accept new connections, doing the
bind(), listen() and accept() for protocols such as TCP.
Efl.Net.Dialer defines to to reach a server.
Both are based on Efl.Net.Socket as communication interface that is
based on Efl.Io.Reader, Efl.Io.Writer and Efl.Io.Closer, thus being
usable with code such as Efl.Io.Copier.
The Server will emit an event "client,add" with the established
Socket, which is a child and can be closed by both the server or the
user.
The Dialer extends the Socket and allows for creating one given an
address, that will be resolved and connected.
TCP is the initial implementation so we an validate the
interfaces. UDP, Unix-Local and SSL will come later as derivate
classes.
The examples are documented and should cover the basic principles:
- efl_io_copier_example can accept "tcp://IP:PORT" and will work as a
"netcat", can send data from socket, file or stdin to a socket,
file, stdout or stderr.
- efl_net_server_example listens for connections and can either reply
"Hello World!" and take some data or work as an echo-server,
looping back all received data to the user.
More complex interactions that require a "chat" between client and
server will be covered with new classes later, such as a queue that
empties itself once data is read.
2016-08-17 21:53:16 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
pd->cork = !!value; /* sync */
|
|
|
|
return pd->cork;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "efl_net_socket_tcp.eo.c"
|