From c844c9b1341d92c81f71d5e3bd1aae5c9faa3c89 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Tue, 24 Dec 1996 19:18:02 +0000 Subject: [PATCH] Drop back to using SockGets/SockWrite. svn path=/trunk/; revision=683 --- driver.c | 48 +++++++++++---------------- imap.c | 9 +++--- pop2.c | 3 +- pop3.c | 7 ++-- smtp.c | 15 +++++---- socket.c | 99 +++++++++++++++++++++++++++++++++++++++++++------------- socket.h | 26 ++++++++++++++- 7 files changed, 140 insertions(+), 67 deletions(-) diff --git a/driver.c b/driver.c index 633f29af..49d97c98 100644 --- a/driver.c +++ b/driver.c @@ -42,6 +42,7 @@ #endif /* KERBEROS_V4 */ #include "socket.h" #include "fetchmail.h" +#include "socket.h" #include "smtp.h" /* BSD portability hack...I know, this is an ugly place to put it */ @@ -279,7 +280,7 @@ static FILE *smtp_open(struct query *ctl) /* if no socket to this host is already set up, try to open one */ if (ctl->smtp_sockfp == (FILE *)NULL) { - if ((ctl->smtp_sockfp = sockopen(ctl->smtphost, SMTP_PORT)) == (FILE *)NULL) + if ((ctl->smtp_sockfp = SockOpen(ctl->smtphost, SMTP_PORT)) == (FILE *)NULL) return((FILE *)NULL); else if (SMTP_ok(ctl->smtp_sockfp) != SM_OK || SMTP_helo(ctl->smtp_sockfp, ctl->servernames->id) != SM_OK) @@ -292,26 +293,6 @@ static FILE *smtp_open(struct query *ctl) return(ctl->smtp_sockfp); } -static int SockGets(char *buf, int len, FILE *sockfp) -/* get a LF-terminated line, removing \r characters */ -{ - int rdlen = 0; - - while (--len) - { - if ((*buf = fgetc(sockfp)) == EOF) - return -1; - else - rdlen++; - if (*buf == '\n') - break; - if (*buf != '\r') /* remove all CRs */ - buf++; - } - *buf = 0; - return rdlen; -} - static int gen_readmsg (sockfp, len, delimited, ctl) /* read message content and ship to SMTP or MDA */ FILE *sockfp; /* to which the server is connected */ @@ -337,10 +318,17 @@ struct query *ctl; /* query control record */ oldlen = 0; while (delimited || len > 0) { - if ((n = SockGets(buf,sizeof(buf),sockfp)) < 0) + if (!SockGets(buf,sizeof(buf),sockfp)) return(PS_SOCKET); + n = strlen(buf); vtalarm(ctl->timeout); + /* squeeze out all carriage returns */ + for (fromhdr = tohdr = buf; *fromhdr; fromhdr++) + if (*fromhdr != '\r' && *fromhdr != '\n') + *tohdr++ = *fromhdr; + *tohdr = '\0'; + /* write the message size dots */ if (n > 0) { @@ -664,8 +652,10 @@ struct query *ctl; /* query control record */ /* write all the headers */ n = 0; - if (sinkfp) + if (ctl->mda[0]) n = fwrite(headers, 1, oldlen, sinkfp); + else if (sinkfp) + n = SockWrite(headers, 1, oldlen, sinkfp); if (n < 0) { @@ -749,8 +739,10 @@ struct query *ctl; /* query control record */ /* ship out the text line */ n = 0; - if (sinkfp) + if (ctl->mda[0]) n = fwrite(bufp, 1, strlen(bufp), sinkfp); + else if (sinkfp) + n = SockWrite(bufp, 1, strlen(bufp), sinkfp); if (!ctl->mda[0]) free(bufp); @@ -902,7 +894,7 @@ const struct method *proto; /* protocol method table */ FILE *sockfp; /* open a socket to the mail server */ - if ((sockfp = sockopen(ctl->servernames->id, + if ((sockfp = SockOpen(ctl->servernames->id, ctl->port ? ctl->port : protocol->port)) == NULL) { error(0, errno, "connecting to host"); @@ -1191,8 +1183,7 @@ va_dcl va_end(ap); strcat(buf, "\r\n"); - fputs(buf, sockfp); - fflush(sockfp); /* sockfp should be linebuffered, but let's be sure */ + SockWrite(buf, 1, strlen(buf), sockfp); if (outlevel == O_VERBOSE) { @@ -1234,8 +1225,7 @@ va_dcl va_end(ap); strcat(buf, "\r\n"); - fputs(buf, sockfp); - fflush(sockfp); /* sockfp should be linebuffered, but let's be sure */ + SockWrite(buf, 1, strlen(buf), sockfp); if (outlevel == O_VERBOSE) { diff --git a/imap.c b/imap.c index 944c246b..f9fdbbaa 100644 --- a/imap.c +++ b/imap.c @@ -14,6 +14,7 @@ #include #endif #include "fetchmail.h" +#include "socket.h" static int count, seen, recent, unseen, imap4; @@ -24,7 +25,7 @@ int imap_ok (FILE *sockfp, char *argbuf) seen = 0; do { - if (!fgets(buf, sizeof(buf), sockfp)) + if (!SockGets(buf, sizeof(buf), sockfp)) return(PS_SOCKET); if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; @@ -121,7 +122,7 @@ static int imap_getsizes(FILE *sockfp, int count, int *sizes) char buf [POPBUFSIZE+1]; gen_send(sockfp, "FETCH 1:%d RFC822.SIZE", count); - while (fgets(buf, sizeof(buf), sockfp)) + while (SockGets(buf, sizeof(buf), sockfp)) { int num, size; @@ -172,7 +173,7 @@ static int imap_fetch(FILE *sockfp, int number, int *lenp) /* looking for FETCH response */ do { - if (!fgets(buf, sizeof(buf), sockfp)) + if (!SockGets(buf, sizeof(buf), sockfp)) return(PS_SOCKET); } while (sscanf(buf+2, "%d FETCH (RFC822 {%d}", &num, lenp) != 2); @@ -188,7 +189,7 @@ static int imap_trail(FILE *sockfp, struct query *ctl, int number) { char buf [POPBUFSIZE+1]; - if (!fgets(buf, sizeof(buf), sockfp)) + if (!SockGets(buf, sizeof(buf), sockfp)) return(PS_SOCKET); else return(0); diff --git a/pop2.c b/pop2.c index 4b389f20..955e634e 100644 --- a/pop2.c +++ b/pop2.c @@ -12,6 +12,7 @@ #include #endif #include "fetchmail.h" +#include "socket.h" static int pound_arg, equal_arg; @@ -22,7 +23,7 @@ int pop2_ok (FILE *sockfp, char *argbuf) char buf [POPBUFSIZE+1]; pound_arg = equal_arg = -1; - if (fgets(buf, sizeof(buf), sockfp)) { + if (SockGets(buf, sizeof(buf), sockfp)) { if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; if (buf[strlen(buf)-1] == '\r') diff --git a/pop3.c b/pop3.c index 3ee5489b..0238fc35 100644 --- a/pop3.c +++ b/pop3.c @@ -17,6 +17,7 @@ #endif #include "fetchmail.h" +#include "socket.h" #define PROTOCOL_ERROR {error(0, 0, "protocol error"); return(PS_ERROR);} @@ -29,7 +30,7 @@ int pop3_ok (FILE *sockfp, char *argbuf) char buf [POPBUFSIZE+1]; char *bufp; - if (fgets(buf, sizeof(buf), sockfp)) { + if (SockGets(buf, sizeof(buf), sockfp)) { if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; if (buf[strlen(buf)-1] == '\r') @@ -168,7 +169,7 @@ static int pop3_getrange(FILE *sockfp, struct query *ctl, int*countp, int*newp) int num; *newp = 0; - while (fgets(buf, sizeof(buf), sockfp)) + while (SockGets(buf, sizeof(buf), sockfp)) { if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; @@ -205,7 +206,7 @@ static int pop3_getsizes(FILE *sockfp, int count, int *sizes) { char buf [POPBUFSIZE+1]; - while (fgets(buf, sizeof(buf), sockfp)) + while (SockGets(buf, sizeof(buf), sockfp)) { int num, size; diff --git a/smtp.c b/smtp.c index cee1841b..a5be0927 100644 --- a/smtp.c +++ b/smtp.c @@ -14,6 +14,7 @@ #include #include #include "fetchmail.h" +#include "socket.h" #include "smtp.h" int smtp_response; /* numeric value of SMTP response code */ @@ -23,7 +24,7 @@ int SMTP_helo(FILE *sockfp,char *host) { int ok; - fprintf(sockfp,"HELO %s\r\n", host); + SockPrintf(sockfp,"HELO %s\r\n", host); if (outlevel == O_VERBOSE) error(0, 0, "SMTP> HELO %s", host); ok = SMTP_ok(sockfp); @@ -35,7 +36,7 @@ int SMTP_from(FILE *sockfp, char *from) { int ok; - fprintf(sockfp,"MAIL FROM:<%s>\r\n", from); + SockPrintf(sockfp,"MAIL FROM:<%s>\r\n", from); if (outlevel == O_VERBOSE) error(0, 0, "SMTP> MAIL FROM:<%s>", from); ok = SMTP_ok(sockfp); @@ -47,7 +48,7 @@ int SMTP_rcpt(FILE *sockfp, char *to) { int ok; - fprintf(sockfp,"RCPT TO:<%s>\r\n", to); + SockPrintf(sockfp,"RCPT TO:<%s>\r\n", to); if (outlevel == O_VERBOSE) error(0, 0, "SMTP> RCPT TO:<%s>", to); ok = SMTP_ok(sockfp); @@ -59,7 +60,7 @@ int SMTP_data(FILE *sockfp) { int ok; - fprintf(sockfp,"DATA\r\n"); + SockPrintf(sockfp,"DATA\r\n"); if (outlevel == O_VERBOSE) error(0, 0, "SMTP> DATA"); ok = SMTP_ok(sockfp); @@ -71,7 +72,7 @@ int SMTP_quit(FILE *sockfp) { int ok; - fprintf(sockfp,"QUIT\r\n"); + SockPrintf(sockfp,"QUIT\r\n"); if (outlevel == O_VERBOSE) error(0, 0, "SMTP> QUIT"); ok = SMTP_ok(sockfp); @@ -83,7 +84,7 @@ int SMTP_eom(FILE *sockfp) { int ok; - fprintf(sockfp,".\r\n"); + SockPrintf(sockfp,".\r\n"); if (outlevel == O_VERBOSE) error(0, 0, "SMTP>. (EOM)"); ok = SMTP_ok(sockfp); @@ -95,7 +96,7 @@ int SMTP_ok(FILE *sockfp) { char buf[SMTPBUFSIZE], *ip; - while ((ip = fgets(buf, sizeof(buf)-1, sockfp))) + while ((ip = SockGets(buf, sizeof(buf)-1, sockfp))) { int n = strlen(ip); diff --git a/socket.c b/socket.c index 39b9f846..16974b69 100644 --- a/socket.c +++ b/socket.c @@ -34,21 +34,13 @@ #endif #endif -/* - * Size of buffer for internal buffering read function - * don't increase beyond the maximum atomic read/write size for - * your sockets, or you'll take a potentially huge performance hit - */ -#define INTERNAL_BUFSIZE 2048 - -FILE *sockopen(char *host, int clientPort) +FILE *SockOpen(char *host, int clientPort) { int sock; unsigned long inaddr; struct sockaddr_in ad; struct hostent *hp; - FILE *fp; - + memset(&ad, 0, sizeof(ad)); ad.sin_family = AF_INET; @@ -72,26 +64,89 @@ FILE *sockopen(char *host, int clientPort) close(sock); return (FILE *)NULL; } - fp = fdopen(sock, "r+"); + return fdopen(sock, "r+"); +} - /* the point of all this mishigoss ... dynamic per-stream buffering */ - setvbuf(fp, NULL, _IOLBF, INTERNAL_BUFSIZE); - return(fp); +#if defined(HAVE_STDARG_H) +int SockPrintf(FILE *sockfp, char* format, ...) +{ +#else +int SockPrintf(sockfp,format,va_alist) +FILE *sockfp; +char *format; +va_dcl { +#endif + + va_list ap; + char buf[8192]; + +#if defined(HAVE_STDARG_H) + va_start(ap, format) ; +#else + va_start(ap); +#endif + vsprintf(buf, format, ap); + va_end(ap); + return SockWrite(buf, 1, strlen(buf), sockfp); + } -#ifdef MAIN /* - * Use the chargen service to test buffering directly. + * FIXME: This needs to be recoded to use stdio, if that's possible. + * + * If you think these functions are too slow and inefficient, you're + * absolutely right. I wish I could figure out what to do about it. + * The ancestral popclient used static buffering here to cut down on the + * number of read(2) calls, but we can't do that because we can have + * two or more sockets open at a time. + * + * The right thing to do would be to use stdio for internal per-socket + * buffering here (which is why Socket() returns a file pointer) but + * this causes mysterious lossage. In case someone ever finds a way + * around this, a note on Carl Harris's original implementation said: + * + * Size of buffer for internal buffering read function + * don't increase beyond the maximum atomic read/write size for + * your sockets, or you'll take a potentially huge performance hit + * + * #define INTERNAL_BUFSIZE 2048 + * */ -main() + +int SockWrite(char *buf, int size, int len, FILE *sockfp) { - FILE *fp = sockopen("localhost", 19); - char buf[80]; + int n, wrlen = 0; + + len *= size; + while (len) + { + n = write(fileno(sockfp), buf, len); + if (n <= 0) + return -1; + len -= n; + wrlen += n; + buf += n; + } + return wrlen; +} - while (fgets(buf, sizeof(buf)-1, fp)) - fputs(buf, stdout); +char *SockGets(char *buf, int len, FILE *sockfp) +{ + int rdlen = 0; + char *cp = buf; + + while (--len) + { + if (read(fileno(sockfp), cp, 1) != 1) + return((char *)NULL); + else + rdlen++; + if (*cp++ == '\n') + break; + } + *cp = 0; + return buf; } -#endif /* MAIN */ /* socket.c ends here */ diff --git a/socket.h b/socket.h index 11d9e296..6c93c634 100644 --- a/socket.h +++ b/socket.h @@ -8,6 +8,30 @@ #define SOCKET__ /* Create a new client socket; returns (FILE *)NULL on error */ -FILE *sockopen(char *host, int clientPort); +FILE *SockOpen(char *host, int clientPort); +/* +Get a string terminated by an '\n' (matches interface of fgets). +Pass it a valid socket, a buffer for the string, and +the length of the buffer (including the trailing \0) +returns buffer on success, NULL on failure. +*/ +char *SockGets(char *buf, int len, FILE *sockfp); + +/* +Write a chunk of bytes to the socket (matches interface of fwrite). +Returns number of bytes successfully written. +*/ +int SockWrite(char *buf, int size, int nels, FILE *sockfp); + +/* +Send formatted output to the socket (matches interface of fprintf). +Returns number of bytes successfully written. +*/ +#if defined(HAVE_STDARG_H) +int SockPrintf(FILE *sockfp, char *format, ...) ; +#else +int SockPrintf(); +#endif + #endif /* SOCKET__ */ -- 2.43.2