 |
|
 |
When I run the server, it shows message below:
Webio server starting...
It seems the server is running. But when I try to brower to it, the webio terminal, and show this message: Segmentation fault
I run on embedded sytem. Our System: mips chip, RAM 512MB, linux 2.6.22.19-12.
Our compile: gcc4
Thanks
|
|
|
|
 |
|
 |
Hello,
If I leave my embedded device webserver working for hours, with 4-10 clients (Internet Explorer) calling periodically a CGI function my heap keeps filling until I get an exception. My opinion is that some sessions are not well closed and generate some memory leak. I can reproduce this behaviour in this way: start.....20%heap open 10 IE clients....30% heap keep working some time.... close 10 clients...HEAP doesnt reduce open 10 new IE clients....40% heap and so on
Any ideas ? Thanks, regards Paolo
|
|
|
|
 |
|
 |
Hi Paolo,
I sure does sound like a memory leak. I'll try to reproduce it over the next few days and see if I can spot it.
In your example above, when you "close 10 clients...", how do you close them? Do you lose the IE application with an exit, kill it from the process controller, or something else?
Please let me know,
-JB-
|
|
|
|
 |
|
 |
Hi JB,
I made some more investigation and found a memory leak. My webpage sends a GET avery 10 seconds to WebIO. Here some logs with caller routine in evidence:
****WI_MALLOC (0654) = 380031F4...wi_newsess:wi_alloc(sizeof(wi_sess)) = 380031FC ****WI_MALLOC (0024) = 3800D868...wi_buildform:wi_alloc(sizeof(total 24 bytes)) = 3800D870 ****WI_MALLOC (001C) = 3800D894...em_fopen:wi_alloc(sizeof(EOFILE)) = 3800D89C ****WI_MALLOC (0824) = 38003850...wi_newfile:wi_alloc(sizeof(wi_file)) = 38003858 wi_newfile GetUpdate.cgi ****WI_FREE (3800D894)...em_fclose:wi_free(passedfd) = 3800D89C wi_fclose ****WI_FREE (38003850)...wi_delfile:wi_free(delfile) = 38003858 wi_delfile wi_txdone:socket close wi_delsess:oldsess->ws_socket == INVALID_SOCKET ****WI_FREE (3800D868)...****WI_FREE (380031F4)...wi_delsess:wi_free(oldsess) = 380031FC
The form data (24 bytes) malloc never get freed. I think the problem in resourse freeing in wi_delsess:
................. /* Unlink from master session list */ lastsess = NULL; for(tmpsess = wi_sessions; tmpsess; tmpsess = tmpsess->ws_next) { if(tmpsess == oldsess) /* Found session to unlink? */ { if(lastsess) lastsess->ws_next = tmpsess->ws_next; else wi_sessions = tmpsess->ws_next; break; } lastsess= tmpsess; }
/* Make sure there are no dangling resources */ if(oldsess->ws_txbufs) { while(oldsess->ws_txbufs) { wi_txfree(oldsess->ws_txbufs); } } if(oldsess->ws_filelist) { if(oldsess->ws_filelist) // THIS IS STRANGE INDEED { wi_fclose( oldsess->ws_filelist); } } // PB 09/11/2009 18.39.29 if(oldsess->ws_formlist) { if(oldsess->ws_formlist) { wi_free( oldsess->ws_formlist); } } // PB 09/11/2009 18.39.29 ...........................
I added the oldsess->ws_formlist cleanup, but I'm not sure if you can have more than 1 form attached to a session; in that case, my correction would not be enough
I Wait for news from you, best regards,
Paolo
|
|
|
|
 |
|
 |
Yup, looks like a leak. Sorry about that. I'm pretty sure the form is a linked list, so I'll have to come with some code that traverses the list, free()ing memory as it goes. What you've posted should be OK for pages with only one form. I finally have the code on a public SVN server - I'll check in these fixes and publish the link in a note here as soon permissions are set up.
Thanks for the fix,
-JB-
|
|
|
|
 |
|
 |
Hi, this is my (tested) upload routine:
/* wi_putfile() * * This is called when a session receives a PUT command. * * * Returns: 0 if no error, else negative WIE_ error code. * */
int wi_putfile( wi_sess * sess) { wi_file *fi; /* info about current file */
char * cp; char * cl; char * rxend; int res; long b_read, b_remain; /* First find end of HTTP header */ rxend = strstr(sess->ws_rxbuf, "\r\n\r\n" ); /* Extract the URL */ cp = wi_nextarg(&sess->ws_rxbuf[3]); if(!cp) { wi_senderr(sess, 400); /* Bad request */ return WIE_CLIENT; } if(*cp == '/') { if(*(cp+1) == ' ') sess->ws_uri = wi_rootfile; else sess->ws_uri = cp+1; /* strip leading slash */ } else sess->ws_uri = cp;
/* Extract other useful fields from header */ sess->ws_auth = wi_getline("Authorization:", cp); sess->ws_referer = wi_getline("Referer:", cp); sess->ws_host = wi_getline("Host:", cp);
cl = wi_getline("Content-Length:", cp); if(cl) sess->ws_contentLength = atoi(cl); else sess->ws_contentLength = 0; /* unset */ /* insert the null terminators in any strings in the rxbuf */ if((sess->ws_uri > sess->ws_rxbuf) && (sess->ws_uri < rxend)) wi_argterm(sess->ws_uri); /* Null terminate the URI */ if((sess->ws_auth > sess->ws_rxbuf) && (sess->ws_auth < rxend)) wi_argterm(sess->ws_auth); /* etc */ if((sess->ws_referer > sess->ws_rxbuf) && (sess->ws_referer < rxend)) wi_argterm(sess->ws_referer); if((sess->ws_uri > sess->ws_host) && (sess->ws_host < rxend)) wi_argterm(sess->ws_host); /* --------------------------------------------- */ /* Decode filename */ wi_urldecode(sess->ws_uri); /* Inizio a leggere il file da scrivere nel mio filesystem */ b_remain = sess->ws_contentLength; res = wi_fopen(sess, fname_path, "w"); if (res == 0) { /* file da scrivere */ fi = sess->ws_filelist; /* vedo se nel primo pacchetto ci sono anche dati da scrivere */ if (sess->ws_data) { b_read = sess->ws_rxsize - (sess->ws_data - sess->ws_rxbuf); b_remain -= b_read; res = wi_fwrite(sess->ws_data, 1, b_read, fi); }
if (b_remain > 0) do { b_read = recv (sess->ws_socket, sess->ws_rxbuf, sizeof(sess->ws_rxbuf), 0); if (b_read != -1) { b_remain -= b_read; res = wi_fwrite(sess->ws_rxbuf, 1, b_read, fi); /* all data written ? */ if (res != b_read) { /* TODO: check, why not all data was written */ b_remain = -1; // segnalo abort } } else { b_remain = -1; // segnalo abort break; } } // do while (b_remain > 0); if (b_remain == 0) { wi_replyhdr(sess, sess->ws_contentLength); wi_fclose(fi); } else { wi_fclose(fi); wi_fremove(sess->ws_uri); wi_senderr(sess, 501); /* Send "Internal server error" reply */ } } else { wi_senderr(sess, 503); /* Send "Service Unavailable" reply */ } return 0; /* No Error */ }
Hope will be useful...
|
|
|
|
 |
|
 |
hi again,
if I ask Webio a "big" file (25Kbytes) it seems like wi_readfile allocates more and more sessions with wi_txalloc(sess), until my embedded system runs out of memory. Is that true ? could you help me modify this routine so no more than, say, 3 sessions get allocated at any time ? I understand 26K is insignificant on Linux and Windows, but can be a problem in embedded system with limited heap...
|
|
|
|
 |
|
 |
Hi -
Is this a binary file, or is a "normal" one which may have SSI-type includes?
This could be a bug (after all you've found 'em before ) or it could be an artifact of the way Webio handles the SSI-containing (I'll call them dynamic) files. To return the Content-Length of a dymanic file Webio reads the whole file, including files inside SSIs, into a chain of buffers; then measures the ready-to-send set of buffers to get the length. These buffers can eat a lot of space.
So - is the file binary?
Let me know, -JB-
|
|
|
|
 |
|
 |
Hi, tanks for replying so fast,
it is a normal text file (license_lgpl.txt). If I change the extension to htm nothing changes. I guess It's treated as binary file.
|
|
|
|
 |
|
 |
Update: if I force sess->ws_flags |= WF_BINARY in wi_setftype download goes OK. The problem arise with non-binary files (wich get parsed and transferred to RAM before sending via Ethernet)
|
|
|
|
 |
|
 |
Glad to hear you got it working. IIRC there's an option in the web page generator to force this flag on a per file basis, but when I went to check this out in the online manual I discovered the Praemio.com web site is defunct . Look like I have to find a new home for Webio and get everything moved. More soon..... -JB-
|
|
|
|
 |
|
 |
hi again (!)
If I refresh countinuosly my webpage my ARM system throws an ADDR_ABORT exception, probably due to recursion (but my stacks seem healty...) Any suggestion on how to avoid recursion on wi_readfile ?
|
|
|
|
 |
|
 |
Perhaps I've found the solution (memory leak). wi_alloc needs a check on malloc success:
wi_alloc(int bufsize) { char * buffer; struct memmarker * mark; int totalsize;
totalsize = bufsize + sizeof(struct memmarker) + 4;
buffer = WI_MALLOC(totalsize); if (buffer == 0) // PB 03/07/2009 17.58.07 return (0); // PB 03/07/2009 17.58.12 ...................
Hope this will help somebody
|
|
|
|
 |
|
 |
This is definitely a bug. I'd better review the code for making sure I check all results of malloc. Thanks for pointing this out. -JB-
|
|
|
|
 |
|
 |
Hi, I am porting your webserver to an ARM processor. I woud need to upload my files (with curl) and wi_putfile seem perfect - but it's empty... Did you put some work on this routine ? Any suggestion should I implement it by myself ?
|
|
|
|
 |
|
 |
Hi, very good work. How about adding AJAX support for dynamic refresh of portions of page ? I've already done some work on this, maybe we can cooperate....
|
|
|
|
 |
|
 |
I thought AJAX was mostly client side. As such it should "just work" with Webio. Are there any specific features that are needed? -JB-
|
|
|
|
 |
|
 |
yes, you are right, it's almost client side. I was thinking to automate some functions (like XMLHttpRequest creation and handling) via fsbuilder, who creates callback stubs already....
|
|
|
|
 |
|
 |
I couldn't compile but, codes written is exelent !!!
Zqr
|
|
|
|
 |
|
 |
Several users have quite rightly pointed out that I forgot the Linux makefile. A Makefile for Linux is now available at the link below. I've tested it building the code base down-loadable from this page on Fedora 7. Let me know if it works (or not) with other code bases and Linux versions.
Here's the link:
http://www.praemio.com/webio/makefile
|
|
|
|
 |
|
 |
Code works fine in Windows, but how to compile in Linux? There is no make file included! The explanation of compiling in Linux is quite short and I can't follow... 
regards
|
|
|
|
 |
|
 |
Hi - sorry about forgetting the Linux makefile. I think the easiest way to provide one is to paste it directly into this message. Just copy into a local file, delete these leading lines, and make. Hope this works.... #=================================================== #-------------------------------------------------------------------------------
# Makefile for webio - Linux demo app
#
# The code files (object names) for webio.
WEBIO_OBJS = webclib.o webfs.o webio.o webobjs.o \
websys.o webutils.o webtest.o
# The Content-containing C files produced by fsbuilder CONTENT_C = wsfdata.c wsfcode.c
# Object versions of the content-containing C files CONTENT_OBJS = wsfdata.o
# The Ultimate Target of this makefile
WEBIO = webio
# File system builder utility to convert content into C files FSBUILDER = fsbuilder
# C flags. If you forget the -DLINUX it will try to build a windows version CC_FLAGS = -c -DLINUX
.c.o:
$(CC) $(CC_FLAGS) $*.c
# Build the actual server. This links both the code files (WEBIO_OBJS) and # some embedded content $(CONTENT_OBJS) $(WEBIO): $(WEBIO_OBJS) $(CONTENT_OBJS) gcc $(WEBIO_OBJS) $(CONTENT_OBJS)
# Build C files containing content. $(CONTENT_C): $(FSBUILDER) filelist ./fsbuilder filelist
# Make the fsbuilder utillity. This is required for this example. webio apps # with no embedded content (i.e. content is all regular disk files) don't # need fsbuilder $(FSBUILDER): fsbuilder.cpp g++ -o fsbuilder fsbuilder.cpp
clean:
rm -f *.o rm -f $(CONTENT_C)
rm -f webio
|
|
|
|
 |
|
 |
This is not working for me.
I am getting cc -c -o webfs.o webfs.c webfs.c:167:21: error: wsfdata.h: No such file or directory webfs.c:175: error: ‘efslist’ undeclared here (not in a function) make: *** [webfs.o] Error 1
If anyone has got the same error and fixed .please do shre the fix with me.
Thanks
|
|
|
|
 |
|
 |
execute shell and type buildfs to compile the embedded file system then will appear wsfdata.h in your local project folder.
|
|
|
|
 |
|
|
 |