Hello,
With this patch, ecore will have full UDP client/server support.
Tooling UDP into the framework wasn't the easiest thing in the world
because a UDP server has a single socket (i.e. file handle) that is
used to handle all clients, whereas a TCP server generates a new
socket for each client that encapsulates all the details of the
connection. So here's how I implemented it:
UDP Server (Unicast and Multicast):
1. When there is data on the socket, the callback uses recvfrom() to
read the datagram and client address (struct sockaddr_in)
2. Create a new Ecore_Con_Client and save the client address
(sockaddr_in) details with the "data" field. Leave the "fd", "buf",
and "fd_handler" fields NULL.
3. Create a new Ecore_Con_Event_Client_Data and save the datagram in
the "data" field, and the client in the "client" field
4. ecore_con_client_send() is updated to check for a
client->server->type of ECORE_CON_REMOTE_UDP and use sendto() with
client->data as the destination instead of appending the buffer to
client->buf
5. relevant portions of ecore_con_client_del() and
_ecore_con_event_client_data_free() are updated to ensure the client
and data memory are freed
The use of recvfrom() and sendto() feels a little dirty to me, but I'm
not sure how else to preserve the client address so that packets can
be sent back to the client. AFAIK, there isn't any way to do an
accept() on a UDP socket such that a new file handle is created that
encapsulates the end points of the UDP socket. Would appreciate some
"enlightenment" on this topic if I'm wrong. ;)
UDP Client support fits nicely into the framework as a new socket is
created each time ecore_con_server_connect() is called.
A UDP Server example program is included with the patch, and examples
of multicast and UDP client support can be found in SVN:
TEST/orig/ecore/
Regards,
Matt
Index: ecore/src/lib/ecore_con/ecore_con.c
===================================================================
--- ecore/src/lib/ecore_con/ecore_con.c (revision 36438)
+++ ecore/src/lib/ecore_con/ecore_con.c (working copy)
@@ -33,7 +33,7 @@
static int _ecore_con_svr_handler(void *data, Ecore_Fd_Handler *fd_handler);
static int _ecore_con_cl_handler(void *data, Ecore_Fd_Handler *fd_handler);
static int _ecore_con_cl_udp_handler(void *data, Ecore_Fd_Handler *fd_handler);
-static int _ecore_con_mcast_handler(void *data, Ecore_Fd_Handler *fd_handler);
+static int _ecore_con_svr_udp_handler(void *data, Ecore_Fd_Handler *fd_handler);
static int _ecore_con_svr_cl_handler(void *data, Ecore_Fd_Handler *fd_handler);
static void _ecore_con_server_flush(Ecore_Con_Server *svr);
static void _ecore_con_client_flush(Ecore_Con_Client *cl);
@@ -323,23 +323,31 @@
_ecore_con_svr_handler, svr, NULL, NULL);
if (!svr->fd_handler) goto error;
}
- else if (type == ECORE_CON_REMOTE_MCAST)
+ else if (type == ECORE_CON_REMOTE_MCAST || type == ECORE_CON_REMOTE_UDP)
{
svr->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(svr->fd < 0) goto error;
- mreq.imr_multiaddr.s_addr = inet_addr(name);
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,sizeof(mreq)) != 0) goto error;
+
+ socket_addr.sin_family = AF_INET;
+ socket_addr.sin_port = htons(port);
+
+ if (type == ECORE_CON_REMOTE_MCAST)
+ {
+ socket_addr.sin_addr.s_addr = inet_addr(name);
+ mreq.imr_multiaddr.s_addr = inet_addr(name);
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,sizeof(mreq)) != 0) goto error;
+ }
+ else
+ socket_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, &on,sizeof(on)) != 0) goto error;
if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
- socket_addr.sin_family = AF_INET;
- socket_addr.sin_port = htons(port);
- socket_addr.sin_addr.s_addr = inet_addr(name);
if (bind(svr->fd, (struct sockaddr *)&socket_addr,sizeof(struct sockaddr_in)) < 0) goto error;
svr->fd_handler =
ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
- _ecore_con_mcast_handler, svr, NULL, NULL);
+ _ecore_con_svr_udp_handler, svr, NULL, NULL);
if (!svr->fd_handler) goto error;
}
@@ -806,16 +814,21 @@
if (size < 1) return 0;
if (cl->fd_handler)
ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
- if (cl->buf)
+
+ if(cl->server && cl->server->type == ECORE_CON_REMOTE_UDP)
{
- unsigned char *newbuf;
-
- newbuf = realloc(cl->buf, cl->buf_size + size);
- if (newbuf) cl->buf = newbuf;
- else return 0;
- memcpy(cl->buf + cl->buf_size, data, size);
- cl->buf_size += size;
+ sendto(cl->server->fd, data, size, 0, (struct sockaddr *) cl->data, sizeof(struct sockaddr_in));
}
+ else if (cl->buf)
+ {
+ unsigned char *newbuf;
+
+ newbuf = realloc(cl->buf, cl->buf_size + size);
+ if (newbuf) cl->buf = newbuf;
+ else return 0;
+ memcpy(cl->buf + cl->buf_size, data, size);
+ cl->buf_size += size;
+ }
else
{
cl->buf = malloc(size);
@@ -853,14 +866,20 @@
EAPI void *
ecore_con_client_del(Ecore_Con_Client *cl)
{
- void *data;
+ void *data = NULL;
if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
{
ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_del");
return NULL;
}
- data = cl->data;
+
+ if(cl->data && cl->server && (cl->server->type == ECORE_CON_REMOTE_UDP ||
+ cl->server->type == ECORE_CON_REMOTE_MCAST))
+ free(cl->data);
+ else
+ data = cl->data;
+
cl->data = NULL;
cl->delete_me = 1;
if (cl->event_count > 0)
@@ -972,6 +991,8 @@
{
double t_start, t;
+ printf("_ecore_con_server_free(0x%08x)\n", svr);
+
ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE);
t_start = ecore_time_get();
while ((svr->write_buf) && (!svr->dead))
@@ -1540,36 +1561,73 @@
}
static int
-_ecore_con_mcast_handler(void *data, Ecore_Fd_Handler *fd_handler)
+_ecore_con_svr_udp_handler(void *data, Ecore_Fd_Handler *fd_handler)
{
- Ecore_Con_Client *cl;
+ Ecore_Con_Server *svr;
+ Ecore_Con_Client *cl;
- cl = data;
- if (cl->dead) return 1;
- if (cl->delete_me) return 1;
+ svr = data;
+ if (svr->dead) return 1;
+ if (svr->delete_me) return 1;
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
{
- unsigned char buf[65536];
- int num;
+ unsigned char buf[READBUFSIZ];
+ struct sockaddr_in client_addr;
+ int num, client_addr_len = sizeof(client_addr);
errno = 0;
- num = read(cl->fd, buf, 65536);
+ num = recvfrom(svr->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*) &client_addr, &client_addr_len);
+
if (num > 0)
{
- if (!cl->delete_me)
+ if (!svr->delete_me)
{
Ecore_Con_Event_Client_Data *e;
unsigned char *inbuf;
+ uint32_t ip;
+ char ipbuf[64];
+ /* Create a new client for use in the client data event */
+ cl = calloc(1, sizeof(Ecore_Con_Client));
+ if(cl == NULL)
+ return 1;
+ cl->buf = NULL;
+ cl->fd = 0;
+ cl->fd_handler = NULL;
+ cl->server = svr;
+ cl->data = calloc(1, sizeof(client_addr));
+ if(cl->data == NULL)
+ {
+ free(cl);
+ return 1;
+ }
+ memcpy(cl->data, &client_addr, sizeof(client_addr));
+ ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT);
+ ecore_list_append(svr->clients, cl);
+
+ ip = client_addr.sin_addr.s_addr;
+ snprintf(ipbuf, sizeof(ipbuf),
+ "%i.%i.%i.%i",
+ (ip ) & 0xff,
+ (ip >> 8 ) & 0xff,
+ (ip >> 16) & 0xff,
+ (ip >> 24) & 0xff);
+ cl->ip = strdup(ipbuf);
+
inbuf = malloc(num);
if(inbuf == NULL)
- return 1;
+ {
+ free(cl->data);
+ free(cl);
+ return 1;
+ }
+
memcpy(inbuf, buf, num);
-
+
e = calloc(1, sizeof(Ecore_Con_Event_Client_Data));
if (e)
{
- cl->event_count++;
+ svr->event_count++;
e->client = cl;
e->data = inbuf;
e->size = num;
@@ -1577,12 +1635,26 @@
_ecore_con_event_client_data_free,
NULL);
}
+
+ if(!cl->delete_me)
+ {
+ Ecore_Con_Event_Client_Add *add;
+
+ add = calloc(1, sizeof(Ecore_Con_Event_Client_Add));
+ if(add)
+ {
+ /*cl->event_count++;*/
+ add->client = cl;
+ ecore_event_add(ECORE_CON_EVENT_CLIENT_ADD, add,
+ _ecore_con_event_client_add_free, NULL);
+ }
+ }
}
if ((errno == EIO) || (errno == EBADF) ||
(errno == EPIPE) || (errno == EINVAL) ||
(errno == ENOSPC) || (num == 0)/* is num == 0 right? */)
{
- if (!cl->delete_me)
+ if (!svr->delete_me)
{
/* we lost our client! */
Ecore_Con_Event_Client_Del *e;
@@ -1590,17 +1662,17 @@
e = calloc(1, sizeof(Ecore_Con_Event_Client_Del));
if (e)
{
- cl->event_count++;
+ svr->event_count++;
e->client = cl;
ecore_event_add(ECORE_CON_EVENT_CLIENT_DEL, e,
_ecore_con_event_client_del_free,
NULL);
}
}
- cl->dead = 1;
- if (cl->fd_handler)
- ecore_main_fd_handler_del(cl->fd_handler);
- cl->fd_handler = NULL;
+ svr->dead = 1;
+ if (svr->fd_handler)
+ ecore_main_fd_handler_del(svr->fd_handler);
+ svr->fd_handler = NULL;
}
}
}
@@ -1842,7 +1914,9 @@
e = ev;
e->client->event_count--;
if (e->data) free(e->data);
- if ((e->client->event_count == 0) && (e->client->delete_me))
+ if ((e->client->event_count == 0) && (e->client->delete_me) ||
+ (e->client->server && (e->client->server->type == ECORE_CON_REMOTE_UDP ||
+ e->client->server->type == ECORE_CON_REMOTE_MCAST)))
ecore_con_client_del(e->client);
free(e);
}
Index: TEST/orig/ecore/con_client_udp_example.c
===================================================================
--- TEST/orig/ecore/con_client_udp_example.c (revision 36423)
+++ TEST/orig/ecore/con_client_udp_example.c (working copy)
@@ -9,11 +9,12 @@
#include <string.h>
Ecore_Con_Server *svr;
+Ecore_Con_Server *mcast;
#define SOCKET_NAME "con_example"
#define SOCKET_PORT 0
-char *msg = "get http://www.enlightenment.org\n";
+char *msg = "EFL UDP CLIENT";
typedef int (*Handler_Func) (void *data, int type, void *event);
@@ -22,7 +23,7 @@
int ev_type,
Ecore_Con_Event_Server_Data *ev) {
printf("Data received from the server! Data was:\n");
- printf("%d, %s \n", ev->size, (char *)ev->data);
+ printf("%d, %s \n", ev->size, ev->data);
ecore_con_server_send(svr, ev->data, ev->size);
@@ -35,19 +36,28 @@
ecore_con_init();
// Try to conect to server.
- svr = ecore_con_server_connect(ECORE_CON_REMOTE_UDP, "239.255.2.1",
- 6767, NULL);
+ svr = ecore_con_server_connect(ECORE_CON_REMOTE_UDP, "127.0.0.1",6767, NULL);
if (NULL == svr) {
printf("*** This really shouldn't happen. Bad port? DNS lookup couldn't fork? \n");
return 0;
}
printf("Sending Datagrams to localhost:6767 \n");
+ // Try to conect to server.
+ mcast = ecore_con_server_connect(ECORE_CON_REMOTE_UDP, "239.255.2.1", 1199, NULL);
+ if (NULL == svr) {
+ printf("*** This really shouldn't happen. Bad port? DNS lookup couldn't fork? \n");
+ return 0;
+ }
+ printf("Sending Datagrams to 239.255.2.1:1199 \n");
+
ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA,
(Handler_Func)server_data, NULL);
ecore_con_server_send(svr, msg, strlen(msg));
+ ecore_con_server_send(mcast, msg, strlen(msg));
+
ecore_main_loop_begin();
ecore_con_server_del(svr);
Index: TEST/orig/ecore/con_mcast_example.c
===================================================================
--- TEST/orig/ecore/con_mcast_example.c (revision 36423)
+++ TEST/orig/ecore/con_mcast_example.c (working copy)
@@ -12,6 +12,10 @@
typedef int (*Handler_Func) (void *data, int type, void *event);
+/*
+Please note that ev->client->data points to a sockaddr_in stucture. If you overwrite that pointer
+your program will have a memory leak
+*/
int
client_data (void *data,
int ev_type,
@@ -38,7 +42,7 @@
svr = ecore_con_server_add(ECORE_CON_REMOTE_MCAST, "239.255.2.1", 1199, NULL);
if( NULL == svr )
{
- printf("Unable to add server\n");
+ printf("Unable to add server. Bad port? No route to the multicast network?\n");
return 1;
}
else
Index: TEST/orig/ecore/Makefile
===================================================================
--- TEST/orig/ecore/Makefile (revision 36423)
+++ TEST/orig/ecore/Makefile (working copy)
@@ -1,7 +1,7 @@
FLAGS = `pkg-config ecore ecore-evas ecore-job ecore-config ecore-x evas --cflags`
LIBS = `pkg-config ecore ecore-evas ecore-job ecore-config ecore-x evas --libs`
-BINS = ecore_config ecore_evas_test ecore_test
+BINS = ecore_config ecore_evas_test ecore_test con_client_udp_example con_mcast_example con_server_udp_example
all: $(BINS)
ecore_config_SRCS = ecore_config.c
@@ -40,6 +40,24 @@
$(RM) $@
$(CC) $(LIBS) $(LDFLAGS) $(ecore_dbus_receiver_test_OBJS) -o $@
+con_client_udp_example_SRCS = con_client_udp_example.c
+con_client_udp_example_OBJS = $(con_client_udp_example_SRCS:.c=.o)
+con_client_udp_example: $(con_client_udp_example_OBJS)
+ $(RM) $@
+ $(CC) $(LIBS) $(LDFLAGS) $(con_client_udp_example_OBJS) -o $@
+
+con_mcast_example_SRCS = con_mcast_example.c
+con_mcast_example_OBJS = $(con_mcast_example_SRCS:.c=.o)
+con_mcast_example: $(con_mcast_example_OBJS)
+ $(RM) $@
+ $(CC) $(LIBS) $(LDFLAGS) $(con_mcast_example_OBJS) -o $@
+
+con_server_udp_example_SRCS = con_server_udp_example.c
+con_server_udp_example_OBJS = $(con_server_udp_example_SRCS:.c=.o)
+con_server_udp_example: $(con_server_udp_example_OBJS)
+ $(RM) $@
+ $(CC) $(LIBS) $(LDFLAGS) $(con_server_udp_example_OBJS) -o $@
+
############################################################################
#### boilerplate
.c.o:
/* Ecore_Con Usage Example
*/
#include <Ecore.h>
#include <Ecore_Con.h>
//#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
Ecore_Con_Server *svr;
typedef int (*Handler_Func) (void *data, int type, void *event);
/*
Please note that ev->client->data points to a sockaddr_in stucture. If you overwrite that pointer
A) your program will have a memory leak
B) you will be unable send packets back to the client
*/
int
client_data (void *data,
int ev_type,
Ecore_Con_Event_Client_Data *ev) {
printf("Client sent data! Replying...");
ecore_con_client_send(ev->client, ev->data, ev->size);
printf("done! Data was:\n");
printf(" %d, %s \n", ev->size, ev->data);
return 1;
}
int main (int argc, char *argv[]) {
ecore_con_init();
svr = ecore_con_server_add(ECORE_CON_REMOTE_UDP, "con_udp_example", 6767, NULL);
printf("Server is running on 0.0.0.0:6767 waiting for connections\n");
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA,
(Handler_Func)client_data, NULL);
ecore_main_loop_begin();
ecore_con_shutdown();
return 0;
}
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel