From cefb204e5f12410e4f082fbdc48a9742194507f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net> Date: Fri, 3 Jan 2025 04:21:36 -0500 Subject: [PATCH] Bring some sanity to sendfilesocket() Not that there's any need to, it appears that it was written for the web server, then discarded for that purpose and now is only called from the JS Socket.sendfile() method, which always passes NULL and 0 for the last two parameters, and has a copy/pasted implementation for TLS sockets. The only consumer of that in the tree appears to be gopher_service.js. It was apparently to use as a wrapper for the high-performance FreeBSD sendfile(), but that code behaved differently than all the other platforms, and was disabled (behind USE_SENDFILE, which isn't defined anywhere). This should really just be folded into either js_socket_sendfilesocket() or js_sendfile() with the extra knobs broken off and all the TODO comments I'm adding here addressed. Though, since Socket.sendfile() returns a bool where true indicates that either the size of the file at the start of the function was sent, or an EOF was reached, and false indicates that "something else happened", some of the TODO comments don't really need to be addressed. Basically, this is a crap function and it's only used by an even more crap JS wrapper, it should be tucked into a backward compatibility function, removed from the JSDocs, and forgotten about. If Coverity keeps complaining about this, I'll wait until after the next release and drag this out back and shoot it. Otherwise, I'll just forget it ever existed. --- src/xpdev/sockwrap.c | 62 +++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/src/xpdev/sockwrap.c b/src/xpdev/sockwrap.c index ed4bb4d8d1..5e0e527f05 100644 --- a/src/xpdev/sockwrap.c +++ b/src/xpdev/sockwrap.c @@ -153,67 +153,57 @@ socket_option_t* getSocketOptionList(void) return(socket_options); } +// TODO: Only called with *offset == NULL and count == 0... off_t sendfilesocket(int sock, int file, off_t *offset, off_t count) { char buf[1024*16]; off_t len; - ssize_t rd; - ssize_t wr=0; off_t total=0; - ssize_t i; -/* sendfile() on Linux may or may not work with non-blocking sockets ToDo */ - len=filelength(file); + // TODO: Race condition here... length may change. + // But note that js_socket_sendfilesocket() reimplements all of this + // for encrypted sockets. + len = filelength(file); if(offset!=NULL) if(lseek(file,*offset,SEEK_SET)<0) return(-1); - if(count<1 || count>len) { - count=len; - count-=tell(file); /* don't try to read beyond EOF */ + if (count < 1 || count > len) { + count = len; + count -= tell(file); /* don't try to read beyond EOF (why not? --- Deuce) */ } -#if USE_SENDFILE - while((i=sendfile(file,sock,(offset==NULL?0:*offset)+total,count-total,NULL,&wr,0))==-1 && errno==EAGAIN) { - total+=wr; - SLEEP(1); - } - if(i==0) - return(count); -#endif - if(count<0) { - errno=EINVAL; + if (count < 0) { + errno = EINVAL; return(-1); } - while(total<count) { - rd = read(file, buf, sizeof(buf)); - if (rd < 0) + while (total < count) { + ssize_t rd = read(file, buf, sizeof(buf)); + if (rd < 0) // Error return(-1); - if (rd == 0) + if (rd == 0) // EOF break; - for (i = wr = 0; i < rd; i += wr) { - wr = sendsocket(sock,buf+i,rd-i); + ssize_t sent = 0; + while (sent < rd) { + ssize_t wr = sendsocket(sock, buf + sent, rd - sent); if (wr > 0) { - if ((rd - i) < wr) - wr = rd - i; - continue; + sent += wr; } - if (wr == SOCKET_ERROR && SOCKET_ERRNO == EWOULDBLOCK) { - wr = 0; + else if (wr == SOCKET_ERROR && SOCKET_ERRNO == EWOULDBLOCK) { SLEEP(1); - continue; } - return(wr); + else { + // TODO: This is sketchy to return 0 on write failure + return(wr); + } } - if(i!=rd) - return(-1); - total+=rd; + total += rd; } - if(offset!=NULL) - (*offset)+=total; + if (offset != NULL) + (*offset) += total; return(total); } -- GitLab