Building Network Applications with GNU/EDMA
David Martnez Oliveira
September, 2002
--------------------------------------------------------------
EDMA: Entorno de Desarrollo Modular y Abierto
Object Oriented and Componentware Framework  

Copyright (C) 1998, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2013
           by David Martnez Oliveira

See the end of the file for license conditions.
--------------------------------------------------------------

1. INTRODUCTION
THis tutorial will show you how easy is to build network applications using GNU/EDMA classes. We will develop a very simple ECHO client/server service using the default classes provided with GNU/EDMA.

2. KHUMS
--------
KHUMS is a joke, a simple tool distributed with GNU/EDMA which name stands for Killer High-Tech Unusefull Multithreaded server. It is just a server mainloop container using the the GNU/EDMA MTSERVER_SKEL class. This class provides the base code of any multithread server, the programer just need to provide the code the server must run for each connection arriving.

This code must be provided as a GNU/EDMA class and the whole system is invoked with a command line like the one we show bellow:

./khums channel_class://host:port  service_class 

A concrete example could be:

khums SOCKET_TCP://localhost:12345 ECHO_SERVICE

where 12345 is the port in the localhost where our server will wait for connections, and ECHO_SERVICE is the GNU/EDMA class containing the code the server will run for each connection to our server.

Let's see khums in more detail.

2.1 Server Initialization
-------------------------
The first step is to set our server is up. In the code bellow we will remove error checking statements to make the code more readable.

First of all, we must create the MTSERVER_SKEL object that will manage the connection accept and the thread creation for each connection. Here is the code:

OBJID  my_server;

my_server = edma_new_obj ("MTSERVER_SKEL");

The we set the max number of clients our server will deal with the port our
server will listen to, and our service routine, that will be executed in its own thread.

edma_met3 (my_server, "init", "TCP_SOCKET://localhost:12345", 10);

The above instruction tells the MTSERVER_SKEL object to bind its accept socket
to the localhost at port 12345 and to deal with up to 10 connection.

Finally, we must need to override the virtual method 'onRequest'. This method
is invoked from the server main loop, each time a connection arrives to the
server. THis is done here:

edma_over_met (my_server, "onRequest", NULL, (PPROC) manage_request);

Once the server is set up we just run the main loop:

edma_met3 (my_server, "run");

2.2 The connection routine
--------------------------
The connection routine, the routine executed each time a conection arrives to
our server, is quite simple. Let's see the code:

ESint32 manage_request (OBJID id,OBJID idc)
{
serv_id = edma_new_obj (service_class))
edma_met3 (serv_id, "service", idc);
edma_free_obj (serv_id);
}

As we can see, this piece of code just create a object of some class, run the
service method passing 'idc' as parameter and finally destroys this object.

The parameter 'idc' is a CHANNEL object the MTSERVER_SKEL class pass to our
function, representating the asigned socket for this connection, basically it
is what 'accept' system call returns.

Any KHUMS service must be a class implementing a 'service' method that accepts
a object parameter that it will use to communicate with the connecte that it
will use to communicate with the connecte that it will use to communicate with
the connecte that it will use to communicate with the connected client.

3. Writting a KHUMS service
---------------------------
As pointed out in the previous section, any KHUMS service is a GNU/EDMA class
that must provide a 'service' method.

For our simple ECHO service, this method could look like this:

ESint32 EDMAPROC
ECHO_SERVICEserviceOrS23(OBJID IdObj, OBJID id)
{
  EDMAT_BUFFER          rbuf, sbuf;
  ESint32               len; 

  edma_buffer_alloc (&rbuf, 1024);
  edma_buffer_alloc (&sbuf, 1024);
  
  memset (rbuf.dat, 0, 1024);

  if (((ESint32)edma_met3 (id, "recv", &rbuf, &len)) == -1)
    {
      edma_printf_obj (IdObj, "[ERROR] receviving data");
      return -1;
    }

  memset (sbuf.dat, 0, 1024);
  ((char*)rbuf.dat)[strlen(rbuf.dat) - 1] = 0; /* chomp */
  sprintf ((char*)sbuf.dat, "server says:: %s .. %s\n", 
	   (char*)rbuf.dat, (char*)rbuf.dat);
  len = strlen ((char*) sbuf.dat);

  if (((ESint32) edma_met3 (id, "send", sbuf, len)) == -1)
    {
      edma_printf_obj (IdObj, "[ERROR] sending data");
      return -1;
    }

  edma_buffer_free (&rbuf);
  edma_buffer_free (&sbuf);
  return 0;
}

Quiet simple, isn't?. 
We use the standar CHANNEL methods send and recv that works on EDMAT_BUFFER
data structures, so the first thing we must to do is to allocate space for
such buffers using edma_buffer_alloc calls.

Then, we simple read the data sent through the network, build the response,
and resend back the built response to the client. When we are done we just
release the allocated EDMAT_BUFFER memory.

4. Writting an ECHO client
--------------------------
TO finish this tutorial we will write a simple ECHO client, in order to test
the whole system.

Our client will use a CHANNEL object to make the connection and the code is
quite simple:

OBJID         id_channel;
EDMAT_BUFFER  rbuf, sbuf;
int           len;

EDMAInit();
/* Alloc receive and send buffers */
edma_buffer_alloc (&sbuf,1024);
edma_buffer_alloc (&rbuf,1024);

/* Create the communication channel objects */
id_channel = edma_new_obj ("CHANNEL");

/* Open location to write... connect for TCP streams*/
edma_met3 (id_channel, "open", ">SOCKET_TCP://localhost:12345");

/* Build the message and send it*/
strcpy (sbuf.dat, "Hello World!!!");
edma_met3 (id_channel, "send", sbuf, strlen (sbuf.dat));

/* Wait for server response*/
memset (rbuf.dat, 0, 1024);
edma_met3 (id_channel, "recv", &rbuf, &len);

/* Show the information received*/
printf ("%d bytes received: %s", len, rbuf.dat);

/* Close connection and dispose the channel object */
edma_met3 (id_channel, "close");
edma_free_obj (id_channel);
EDMAEnd();

The comments in the code above are enough to understand with this little piece
of code does.

.

EDMA is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

EDMA is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with EDMA.  If not, see <http://www.gnu.org/licenses/>.
