hello all,
I've ported my multithreaded tcp server to L4 using flips but I am having some problems getting it to run properly. It is a quite a bit to explain so I've written a simple tcp echoserver to demonstrate my problem. The following happens when the server starts and the client connects and send data.
1. Echoserver starts and listens on port 2222 2. client connects, server creates a child_server thread to service client and starts listening again 3. client sends string to child_server thread which is received. child_server however is unable to complete send(echo), it seems to be blocked at this point. 4. The send is only completed when another client attempts a connect(..and the server moves on from the accept(..) statement).
I have appended my code at the bottom of this mail maybe someone can spot my mistake and highlight it.
To check if I've used the threads properly I also wrote a program in which each thread prints the numbers from 0 to 9 and that runs fine. So I am pointing my finger and the recv(), accept() and send() functions in my echo server :-|
Any suggestions will be greatly appreciated.
cheers david
=============================================================================
/*** GENERAL INCLUDES ***/ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h>
/*** L4 INCLUDES ***/ #include <l4/names/libnames.h> #include <l4/thread/thread.h> #include <l4/log/l4log.h> #include <l4/dm_mem/dm_mem.h>
#define BUF_SIZE 100
l4_threadid_t srv; char LOG_tag[9] = "tcpecho"; int data_key;
struct th_data{ int c; //socket char foo[10]; //.... };
/* exit handler */ void child_exit(l4thread_t thread, void * data); void child_exit(l4thread_t thread, void * data){ struct th_data *ptr = (struct th_data *)data;
/* close the connection and free up memory used by data structure*/ close(ptr->c); free(ptr); }
/* declare exit function descriptor */ L4THREAD_EXIT_FN(exit_fn,child_exit);
void child_server(void *data); void child_server(void *data){ char databuf[BUF_SIZE]; struct th_data *dptr = (struct th_data *)data; int ret, sock, n; void *ret_val; l4thread_t id; sock = dptr->c; LOG("got socket\n"); /* register exit function */ ret = l4thread_on_exit(&exit_fn, // exit function descriptor data // data pointer ); if (ret < 0){ /* register error function failed */ LOG_Error("Register error function failed\n"); } id = l4thread_myself(); LOG("Server thread starting with id %u\n",id); /* we are up */ if (l4thread_started(ret_val) < 0){ /* startup notification failed */ LOG_Error("Startup notification failed\n"); } LOG("Entering loop to wait for requests on socket %d.... \n",sock); while (1){ LOG("At top of while loop\n"); if((n = recv(sock, databuf, BUF_SIZE-1, 0)<=0)){ LOG_Error("recv failed %d returned \n",n); break; } databuf[4] = '\0'; databuf[5] = '\n'; LOG("GOT MESSAGE\n"); LOG(">%s; sending ....\n",databuf); databuf[0] = 'X'; send(sock,databuf,6,0); memset(databuf,0,BUF_SIZE); LOG("Looping\n"); } /* Call on exit function to terminate */ l4thread_exit(); }
/* Start the server */ int main(int argc, char *argv[]){
int c, s,err, ret_val, errcount=0; struct sockaddr_in addr;
if ((argc < 2) || strcmp("--nowait", argv[1])) while (names_waitfor_name("ifconfig", &srv, 30000) == 0) { LOG("Client(main): "mini_ifconfig" not available, keep trying..."); }
memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_family = AF_INET; addr.sin_port = htons(2222); LOG("try to open socket"); if ((s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { LOG("Couldn't create socket"); return -1; } if (bind(s, (struct sockaddr *)&addr, sizeof(struct sockaddr)) < 0) { LOG("Couldn't bind"); return -1; } LOG("bound to socket %d, call listen",s); if ((err=listen(s, 1)) < 0) { LOG("listen(%d): %d", s, err); return -1; }
LOG("echo server is up and accepting...");
names_register("echoserver"); while(1){ struct sockaddr dummyaddr; int addrlen; l4thread_t th; struct th_data *th_dptr; LOG("waiting for another connection\n"); if ((c=accept(s, &dummyaddr, &addrlen)) < 0) { LOG("accept(%d): %d", s, c); if (++errcount > 10) { LOG("maximum error count reached---giving up..."); exit(1); } continue; } LOG("Allocating thread data struct\n"); th_dptr = (struct th_data*)l4dm_mem_allocate( sizeof(struct th_data), L4DM_CONTIGUOUS); memset(th_dptr,0,sizeof(struct th_data)); th_dptr->c = c; LOG("Got a connection request, creating thread to handle client on socket %d\n", c); th = l4thread_create( child_server ,(void *)th_dptr ,L4THREAD_CREATE_SYNC); ret_val = l4thread_startup_return(th); /* Thread started ... listening for other requests */ LOG("thread created ... listening again\n"); } return 0; }
__________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com