From 216e4008069a5a1fe2c4270c6bd6209da27ba4bf Mon Sep 17 00:00:00 2001 From: fcolin Date: Fri, 20 May 2005 12:48:19 +0000 Subject: elimination des tailles de buffer par utilisation de realloc la plupart des fonctions utilisent un pointeur static pour eviter de multiple malloc/free ce qui veut dire que IvyC n'est pas reentrant !!!! --- src/Makefile | 14 ++++-- src/ivy.c | 80 +++++++++++++++--------------- src/ivysocket.c | 148 +++++++++++++++++++++++++++++++++++++++++++++----------- src/ivysocket.h | 9 +++- src/version.h | 2 +- 5 files changed, 181 insertions(+), 72 deletions(-) (limited to 'src') diff --git a/src/Makefile b/src/Makefile index c1f3d17..b3f6cd1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -17,7 +17,7 @@ # change this in version.h too !!!! MAJOR=3 -MINOR=6 +MINOR=7 XTINC = -I/usr/X11R6/include XTLIB = -L/usr/X11R6/lib -lXt -lX11 -lSM -lICE @@ -75,7 +75,7 @@ GLIBOBJ = ivyglibloop.o ivysocket.o ivy.o GLUTOBJ = ivyglutloop.o ivysocket.o ivy.o TCLOBJ = ivytcl.o timer.o ivysocket.o givy.o # WINDOWS add ivyloop.o if TCL_CHANNEL_INTEGRATION is not set -TARGETS = ivyprobe ivyglibprobe ivyxtprobe +TARGETS = ivyprobe ivyperf ivyglibprobe ivyxtprobe TARGETLIBS=libivy.so.$(MAJOR).$(MINOR) libgivy.so.$(MAJOR).$(MINOR) libxtivy.so.$(MAJOR).$(MINOR) libglibivy.so.$(MAJOR).$(MINOR) libtclivy.so.$(MAJOR).$(MINOR) # not yet need Modified Glut ivyglutprobe @@ -107,11 +107,17 @@ ivyglutloop.o: ivyglutloop.c ivyglutloop.h ivyglibloop.o: ivyglibloop.c ivyglibloop.h $(CC) -c $(CFLAGS) $(GLIBINC) ivyglibloop.c -ivyprobe: ivyprobe.o +ivyprobe: ivyprobe.o libivy.a $(CC) $(CFLAGS) -o $@ ivyprobe.o -L. -livy $(PCRELIB) $(EXTRALIB) -ivyprobe.o : ivyprobe.c +ivyprobe.o : ivyprobe.c $(CC) $(CFLAGS) $(REGEXP) -c ivyprobe.c -o $@ + +ivyperf: ivyperf.o libivy.a + $(CC) $(CFLAGS) -o $@ ivyperf.o -L. -livy $(PCRELIB) $(EXTRALIB) + +ivyperf.o : ivyperf.c + $(CC) $(CFLAGS) $(REGEXP) -c ivyperf.c -o $@ ivyxtprobe.o : ivyprobe.c $(CC) $(CFLAGS) $(REGEXP) -DXTMAINLOOP -c ivyprobe.c -o $@ $(XTINC) diff --git a/src/ivy.c b/src/ivy.c index 2fd0fa0..21e1841 100644 --- a/src/ivy.c +++ b/src/ivy.c @@ -201,17 +201,22 @@ MsgCall (const char *message, MsgSndPtr msg, Client client) #ifdef DEBUG printf( "Sending message id=%d '%s'\n",msg->id,message); #endif - SocketSend( client, "%d %d" ARG_START ,Msg, msg->id); + // il faut essayer d'envoyer le message en une seule fois sur la socket + // pour eviter au maximun de passer dans le select plusieur fois par message du protocole Ivy + // pour eviter la latence ( PB de perfo detecte par ivyperf ping roudtrip ) + SocketSendBuffered( client, "%d %d" ARG_START ,Msg, msg->id); #ifdef DEBUG printf( "Send matching args count %ld\n",msg->regexp.re_nsub); #endif index=1; while ( indexid,message); #endif - SocketSend( client, "%d %d" ARG_START ,Msg, msg->id); + // il faut essayer d'envoyer le message en une seule fois sur la socket + // pour eviter au maximun de passer dans le select plusieur fois par message du protocole Ivy + // pour eviter la latence ( PB detecte par ivyperf ping roudtrip ) + SocketSendBuffered( client, "%d %d" ARG_START ,Msg, msg->id); #ifdef DEBUG printf( "Send matching args count %ld\n",msg->regexp.re_nsub); @@ -241,7 +249,7 @@ MsgCall (const char *message, MsgSndPtr msg, Client client) #ifdef GNU_REGEXP p = &match[1]; while ( p->rm_so != -1 ) { - SocketSend( client, "%.*s" ARG_END , p->rm_eo - p->rm_so, + SocketSendBuffered( client, "%.*s" ARG_END , p->rm_eo - p->rm_so, message + p->rm_so); ++p; } @@ -253,10 +261,10 @@ MsgCall (const char *message, MsgSndPtr msg, Client client) printf ("Send matching arg%d %.*s\n",i,(int)(match[i].rm_eo - match[i].rm_so), message + match[i].rm_so); #endif - SocketSend (client, "%.*s" ARG_END ,(int)(match[i].rm_eo - match[i].rm_so), + SocketSendBuffered (client, "%.*s" ARG_END ,(int)(match[i].rm_eo - match[i].rm_so), message + match[i].rm_so); } else { - SocketSend (client, ARG_END); + SocketSendBuffered (client, ARG_END); #ifdef DEBUG printf( "Send matching arg%d VIDE\n",i); #endif //DEBUG @@ -264,7 +272,8 @@ MsgCall (const char *message, MsgSndPtr msg, Client client) } #endif - SocketSend (client, "\n"); + SocketSendBuffered (client, "\n"); + SocketFlush(client); return 1; } #endif /* USE_PCRE_REGEX */ @@ -815,17 +824,26 @@ IvyUnbindMsg (MsgRcvPtr msg) } /* demande de reception d'un message */ -static MsgRcvPtr -_BindMsg (MsgCallback callback, void *user_data, const char *regexp ) + +MsgRcvPtr +IvyBindMsg (MsgCallback callback, void *user_data, const char *fmt_regex, ... ) { + static char *buffer = NULL; + static int size = 0; + va_list ap; static int recv_id = 0; IvyClientPtr clnt; MsgRcvPtr msg; + + va_start (ap, fmt_regex ); + make_message( &buffer, &size, fmt_regex, ap ); + va_end (ap ); + /* add Msg to the query list */ IVY_LIST_ADD( msg_recv, msg ); if (msg) { msg->id = recv_id++; - msg->regexp = strdup(regexp); + msg->regexp = strdup(buffer); msg->callback = callback; msg->user_data = user_data; } @@ -837,27 +855,21 @@ _BindMsg (MsgCallback callback, void *user_data, const char *regexp ) return msg; } -MsgRcvPtr -IvyBindMsg (MsgCallback callback, void *user_data, const char *fmt_regex, ... ) -{ - char buffer[4096]; - va_list ap; - - va_start (ap, fmt_regex ); - vsprintf (buffer, fmt_regex, ap ); - va_end (ap ); - return _BindMsg (callback, user_data, buffer ); -} - -static int -_SendMsg (const char *message) +int IvySendMsg(const char *fmt, ...) { IvyClientPtr clnt; int match_count = 0; + static char *buffer = NULL; /* Use satic mem to eliminate multiple call to malloc /free */ + static int size = 0; /* donc non reentrant !!!! */ + va_list ap; + + va_start( ap, fmt ); + make_message( &buffer, &size, fmt, ap ); + va_end ( ap ); /* recherche dans la liste des requetes recues de mes clients */ IVY_LIST_EACH (clients, clnt) { - match_count += ClientCall (clnt, message); + match_count += ClientCall (clnt, buffer); } #ifdef DEBUG if ( match_count == 0 ) printf( "Warning no recipient for %s\n",message); @@ -865,24 +877,14 @@ _SendMsg (const char *message) return match_count; } -int IvySendMsg(const char *fmt, ...) -{ - char buffer[4096]; - va_list ap; - - va_start( ap, fmt ); - vsprintf( buffer, fmt, ap ); - va_end ( ap ); - return _SendMsg( buffer ); -} - void IvySendError( IvyClientPtr app, int id, const char *fmt, ... ) { - char buffer[4096]; + static char *buffer = NULL; /* Use satic mem to eliminate multiple call to malloc /free */ + static int size = 0; /* donc non reentrant !!!! */ va_list ap; va_start( ap, fmt ); - vsprintf( buffer, fmt, ap ); + make_message( &buffer, &size, fmt, ap ); va_end ( ap ); MsgSendTo( app->client, Error, id, buffer); } diff --git a/src/ivysocket.c b/src/ivysocket.c index 7565015..1ce7305 100644 --- a/src/ivysocket.c +++ b/src/ivysocket.c @@ -6,7 +6,7 @@ * * Sockets * - * Authors: Francois-Regis Colin + * Authors: Francois-Regis Colin * * $Id$ * @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef WIN32 #define close closesocket @@ -42,7 +43,7 @@ #include "ivysocket.h" #include "ivyloop.h" -#define MAX_BUFFER 2048 +#define BUFFER_SIZE 4096 /* taille buffer initiale on multiple pas deux a chaque realloc */ struct _server { Server next; @@ -62,7 +63,10 @@ struct _client { struct sockaddr_in from; SocketInterpretation interpretation; void (*handle_delete)(Client client, void *data); - char buffer[MAX_BUFFER+2]; + FILE *socket_output; /* Handle buffered output */ + char terminator; /* character delimiter of the message */ + long buffer_size; + char *buffer; /* dynamicaly reallocated */ char *ptr; void *data; }; @@ -74,6 +78,35 @@ static Client clients_list = NULL; WSADATA WsaData; #endif +// fonction de formtage a la printf d'un buffer avec reallocation dynamique +int make_message(char ** buffer, int *size, const char *fmt, va_list ap) +{ + /* Guess we need no more than BUFFER_INIT_SIZE bytes. */ + int n; + if ( *size == 0 || *buffer == NULL ) + { + *size = BUFFER_SIZE; + *buffer = malloc (BUFFER_SIZE); + if ( *buffer == NULL ) + return -1; + } + while (1) { + /* Try to print in the allocated space. */ + n = vsnprintf (*buffer, *size, fmt, ap); + /* If that worked, return the string size. */ + if (n > -1 && n < *size) + return n; + /* Else try again with more space. */ + if (n > -1) /* glibc 2.1 */ + *size = n+1; /* precisely what is needed */ + else /* glibc 2.0 */ + *size *= 2; /* twice the old size */ + if ((*buffer = realloc (*buffer, *size)) == NULL) + return -1; + } +} + + void SocketInit() { if (! channel_init ) @@ -113,13 +146,19 @@ static void HandleSocket (Channel channel, HANDLE fd, void *data) long nb_to_read = 0; long nb; socklen_t len; - + /* limitation taille buffer */ - nb_to_read = MAX_BUFFER - (client->ptr - client->buffer ); + nb_to_read = client->buffer_size - (client->ptr - client->buffer ); if (nb_to_read == 0 ) { - fprintf(stderr, "Erreur message trop long sans LF\n"); - client->ptr = client->buffer; - return; + client->buffer_size *= 2; /* twice old size */ + client->buffer = realloc( client->buffer, client->buffer_size ); + if (!client->buffer ) + { + fprintf(stderr,"HandleSocket Buffer Memory Alloc Error\n"); + exit(0); + } + fprintf(stderr, "Buffer Limit reached realloc new size %ld\n", client->buffer_size ); + nb_to_read = client->buffer_size - (client->ptr - client->buffer ); } len = sizeof (client->from ); nb = recvfrom (fd, client->ptr, nb_to_read,0,(struct sockaddr *)&client->from, @@ -133,22 +172,21 @@ static void HandleSocket (Channel channel, HANDLE fd, void *data) (*channel_close) (client->channel ); return; } - client->ptr += nb; - *(client->ptr) = '\0'; ptr = client->buffer; - while ((ptr_nl = strchr (ptr, '\n' ))) + while ((ptr_nl = memchr (ptr, client->terminator, client->ptr - ptr ))) { - *ptr_nl = '\0'; + *ptr_nl ='\0'; if (client->interpretation ) (*client->interpretation) (client, client->data, ptr ); else fprintf (stderr,"Socket No interpretation function ???\n"); ptr = ++ptr_nl; } - if (*ptr != '\0' ) + if (ptr < client->ptr ) { /* recopie ligne incomplete au debut du buffer */ - strcpy (client->buffer, ptr ); - client->ptr = client->buffer + strlen(client->buffer); + len = client->ptr - ptr; + memcpy (client->buffer, ptr, len ); + client->ptr = client->buffer + len; } else { @@ -182,6 +220,14 @@ static void HandleServer(Channel channel, HANDLE fd, void *data) close (fd ); exit(0); } + client->buffer_size = BUFFER_SIZE; + client->buffer = malloc( client->buffer_size ); + if (!client->buffer ) + { + fprintf(stderr,"HandleSocket Buffer Memory Alloc Error\n"); + exit(0); + } + client->terminator = '\n'; client->from = remote2; client->fd = ns; client->channel = (*channel_setup) (ns, client, DeleteSocket, HandleSocket ); @@ -189,7 +235,12 @@ static void HandleServer(Channel channel, HANDLE fd, void *data) client->ptr = client->buffer; client->handle_delete = server->handle_delete; client->data = (*server->create) (client ); - + client->socket_output = fdopen( client->fd, "w" ); + if (!client->socket_output ) + { + perror("Socket Buffered output fdopen:"); + exit(0); + } } Server SocketServer(unsigned short port, @@ -341,17 +392,32 @@ void SocketSetData (Client client, void *data ) void SocketSend (Client client, char *fmt, ... ) { - char buffer[4096]; + static char *buffer = NULL; /* Use satic mem to eliminate multiple call to malloc /free */ + static int size = 0; /* donc non reentrant !!!! */ va_list ap; int len; - if (!client) return; va_start (ap, fmt ); - len = vsprintf (buffer, fmt, ap ); + len = make_message (&buffer,&size, fmt, ap ); SocketSendRaw (client, buffer, len ); va_end (ap ); } +void SocketSendBuffered (Client client, char *fmt, ... ) +{ + va_list ap; + if (!client) + return; + va_start (ap, fmt ); + vfprintf (client->socket_output, fmt, ap ); + va_end (ap ); +} +void SocketFlush ( Client client ) +{ + if (!client) + return; + fflush( client->socket_output ); +} void *SocketGetData (Client client ) { @@ -361,12 +427,13 @@ void *SocketGetData (Client client ) void SocketBroadcast ( char *fmt, ... ) { Client client; - char buffer[4096]; + static char *buffer = NULL; /* Use satic mem to eliminate multiple call to malloc /free */ + static int size = 0; /* donc non reentrant !!!! */ va_list ap; int len; va_start (ap, fmt ); - len = vsprintf (buffer, fmt, ap ); + len = make_message (&buffer, &size, fmt, ap ); va_end (ap ); IVY_LIST_EACH (clients_list, client ) { @@ -423,6 +490,14 @@ Client SocketConnectAddr (struct in_addr * addr, unsigned short port, exit(0); } + client->buffer_size = BUFFER_SIZE; + client->buffer = malloc( client->buffer_size ); + if (!client->buffer ) + { + fprintf(stderr,"HandleSocket Buffer Memory Alloc Error\n"); + exit(0); + } + client->terminator = '\n'; client->fd = handle; client->channel = (*channel_setup) (handle, client, DeleteSocket, HandleSocket ); client->interpretation = interpretation; @@ -432,10 +507,15 @@ Client SocketConnectAddr (struct in_addr * addr, unsigned short port, client->from.sin_family = AF_INET; client->from.sin_addr = *addr; client->from.sin_port = htons (port); - + client->socket_output = fdopen( client->fd, "w" ); + if (!client->socket_output ) + { + perror("Socket Buffered output fdopen:"); + exit(0); + } return client; } - +// TODO factoriser avec HandleRead !!!! int SocketWaitForReply (Client client, char *buffer, int size, int delai) { fd_set rdset; @@ -483,7 +563,7 @@ int SocketWaitForReply (Client client, char *buffer, int size, int delai) ptr += nb; *ptr = '\0'; - ptr_nl = strchr (buffer, '\n' ); + ptr_nl = strchr (buffer, client->terminator ); } while (!ptr_nl ); *ptr_nl = '\0'; return (ptr_nl - buffer); @@ -544,19 +624,33 @@ Client SocketBroadcastCreate (unsigned short port, exit(0); } + client->buffer_size = BUFFER_SIZE; + client->buffer = malloc( client->buffer_size ); + if (!client->buffer ) + { + fprintf(stderr,"HandleSocket Buffer Memory Alloc Error\n"); + exit(0); + } + client->terminator = '\n'; client->fd = handle; client->channel = (*channel_setup) (handle, client, DeleteSocket, HandleSocket ); client->interpretation = interpretation; client->ptr = client->buffer; client->data = data; - + client->socket_output = fdopen( client->fd, "w" ); + if (!client->socket_output ) + { + perror("Socket Buffered output fdopen:"); + exit(0); + } return client; } void SocketSendBroadcast (Client client, unsigned long host, unsigned short port, char *fmt, ... ) { struct sockaddr_in remote; - char buffer[4096]; + static char *buffer = NULL; /* Use satic mem to eliminate multiple call to malloc /free */ + static int size = 0; /* donc non reentrant !!!! */ va_list ap; int err,len; @@ -564,7 +658,7 @@ void SocketSendBroadcast (Client client, unsigned long host, unsigned short port return; va_start (ap, fmt ); - len = vsprintf (buffer, fmt, ap ); + len = make_message (&buffer, &size, fmt, ap ); /* Send UDP packet to the dest */ remote.sin_family = AF_INET; remote.sin_addr.s_addr = htonl (host ); diff --git a/src/ivysocket.h b/src/ivysocket.h index 4afde64..5dfdf0a 100644 --- a/src/ivysocket.h +++ b/src/ivysocket.h @@ -20,7 +20,9 @@ #ifdef __cplusplus extern "C" { #endif - + +#include + /* general Handle */ #define ANYPORT 0 @@ -46,6 +48,9 @@ extern "C" { /* General Init */ extern void SocketInit(); +/* utility fonction do make vsprintf without buffer limit */ +extern int make_message(char ** buffer, int *size, const char *fmt, va_list ap); + /* Forward def */ typedef struct _client *Client; typedef void (*SocketInterpretation) (Client client, void *data, char *ligne); @@ -63,6 +68,8 @@ extern void SocketServerClose( Server server ); extern void SocketClose( Client client ); extern void SocketSend( Client client, char *fmt, ... ); +extern void SocketSendBuffered (Client client, char *fmt, ... ); +extern void SocketFlush ( Client client ); extern void SocketSendRaw( Client client, char *buffer, int len ); extern char *SocketGetPeerHost( Client client ); extern void SocketSetData( Client client, void *data ); diff --git a/src/version.h b/src/version.h index e2d3a82..89fb803 100644 --- a/src/version.h +++ b/src/version.h @@ -26,4 +26,4 @@ * */ #define IVYMAJOR_VERSION 3 -#define IVYMINOR_VERSION 6 +#define IVYMINOR_VERSION 7 -- cgit v1.1