|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T x
Length: 8604 (0x219c) Types: TextFile Names: »xfer.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦f91e15335⟧ »EurOpenD3/news/nntp/nntplink2.0.0.tar.Z« └─⟦2c70c5e6b⟧ └─⟦this⟧ »xfer.c«
#include "global.h" /* ** Perform one transfer operation: ** Give IHAVE command ** Wait for reply, and send article if they ask for it ** Wait for transfer confirmation, and requeue the article ** if they drop it. ** Watch all network I/O for errors, return FALSE if ** the connection fails and we have to cleanup. ** Return TRUE means it was successful, or at least that it ** doesn't have to be requeued. ** Return FALSE means it needs to be requeued. This implies the ** connection is closed and reopened. */ sendarticle(host, fp, mesgid) char *host; FILE *fp; char *mesgid; { register int code; char buf[BUFSIZ]; char *e_xfer = "%s xfer %s: %s"; switch(code = ihave(fp, mesgid)) { case CONT_XFER: /* ** They want it. Give it to 'em. */ if (!sendfile(fp)) { sprintf(buf, e_xfer, host, Article, errmsg(errno)); log(L_NOTICE, buf); Stats.failed++; return(FALSE); } /* ** Did the article transfer OK? ** Stay tuned to this same socket to find out! */ if ((code = readreply(buf, sizeof(buf))) != OK_XFERED) { Stats.failed++; if (code < 0) { if (errno > 0) { sprintf(buf, e_xfer, host, Article, errmsg(errno)); log(L_NOTICE, buf); } else { char errbuf[BUFSIZ]; sprintf(errbuf, e_xfer, host, Article, buf); log(L_NOTICE, errbuf); } } if (code == ERR_XFERRJCT) { /* * it failed, but they don't want it retransfered. * we fake success so that it is not requeued. */ return(TRUE); } return(FALSE); } break; case ERR_GOTIT: /* they don't want it */ break; case ERR_XFERFAIL: /* they can't do it right now, but maybe later */ return(FALSE); /*NOTREACHED*/ break; case ERR_GOODBYE: /* Load ave too high */ goodbye(DONT_WAIT); connected = 0; return(FALSE); /*NOTREACHED*/ break; default: if (code < 0) { if (errno > 0) { sprintf(buf, e_xfer, host, Article, errmsg(errno)); log(L_NOTICE, buf); } else { char nbuf[100]; sprintf(nbuf, "ihave, code=%d errno=%d", code, errno); sprintf(buf, e_xfer, host, Article, nbuf); log(L_NOTICE, buf); } } else { sprintf(buf, "%s improper response to IHAVE: %d while offering %s", host, code, Article); log(L_WARNING, buf); } return(FALSE); } return(TRUE); } /* ** Given a hostname to connect to, and a file of filenames (which contain ** netnews articles), send those articles to the named host using NNTP. ** ** ** Return code: ** TRUE - if at least one article was offered without ** an error. We don't care whether it was rejected ** or not, or whether an error ocurred on any later ** article. The object is measure the health of ** the server so that we know when to backoff on ** the retry frequency. If the server can negotiate ** at least one article, it's healthy and we don't ** backoff. ** Note that any error causes the connection to be closed. ** ** FALSE - if an error ocurred before an article could be ** offered. e.g., if the first sendarticle() fails. ** This implies the server is not healthy and that we ** close/reopen the connection using exponential backoff. ** */ sendnews(host, transport, file) char *host, *file; int transport; { register FILE *fp; register int progress; /* the number of successful sendarticle()s */ #ifdef FTRUNCATE char *mode = "r+"; /* so we can use ftruncate() */ #else char *mode = "r"; #endif FTRUNCATE char mesgid[255]; dprintf(stderr,"%s: Entering sendnews\n", Pname); #ifdef VERIFYQFILE if (!In_Log_File) vrfy(file); #endif if ((Qfp = fopen(file, In_Log_File ? "r" : mode)) == (FILE *)NULL) { char buf[BUFSIZ]; sprintf(buf, E_fopen, file, In_Log_File ? "r" : mode, errmsg(errno)); log(L_WARNING, buf); In_Log_File = FALSE; return(FALSE); } /* ** interlock with other copies of this process. (if not using log file) ** non-blocking. */ if ( In_Log_File ) { if (!skip_to_pos(file)) return(FALSE); } else if (!lockfd(fileno(Qfp), file, DONT_BLOCK)) { FCLOSE(Qfp); return(FALSE); } /* ** start an exchange with the remote server */ /* we have work to do now; if we logged our stats during the last pause, we must reset our timers here to include only active time */ if (resetstats) { resetstats = FALSE; dprintf(stderr,"resetting timers\n"); Tbegin = Tend; ouser = user; osys = sys; Stats.offered = Stats.accepted = Stats.rejected = Stats.failed = 0L; } /* open a connection if not already open */ if (!connected) { if (hello(host, transport) == FAIL) { FCLOSE(Qfp); In_Log_File=FALSE; sleep(Sleep_Time); return(FALSE); } else connected = 1; } /* ** We're sending a batch queue: ** open article ** get message-ID ** send "IHAVE <message-ID>" to remote ** read their reply ** send article if appropriate ** iterate to end of queue file */ /* catchsig(interrupted);*/ dprintf(stderr,"starting to send\n"); progress = 0; while((fp = getfp(Qfp, Article, sizeof(Article), mesgid, host)) != (FILE *)NULL) { if (!sendarticle(host, fp, mesgid)) { FCLOSE(fp); if (!In_Log_File) requeue(Article, mesgid); cleanup(); goodbye(DONT_WAIT); connected = 0; In_Log_File = FALSE; return progress? TRUE:FALSE; } FCLOSE(fp); progress++; } cleanup(); In_Log_File = FALSE; return(TRUE); } skip_to_pos(file) char *file; { char temp[MAXFNAME]; FILE *Linkfp; #ifdef FTRUNCATE char *mode = "r+"; /* so we can use ftruncate() */ #else char *mode = "r"; #endif FTRUNCATE char buf[BUFSIZ]; dprintf(stderr, "Entering skip_to_pos..."); sprintf(temp, "%s.link", orig_Qfile); if ((Linkfp = fopen(temp, "r")) == (FILE *)NULL) return(TRUE); (void) fgets(old_logline, MAXLOGLENGTH, Linkfp); (void) fgets(logline, MAXLOGLENGTH, Qfp); while ((fgets(logline, MAXLOGLENGTH, Qfp) != NULL) && (strncmp(logline, old_logline, strlen(logline) - 1) != 0)) ; /* If we've reached the end of the file and the lines don't match then * we want to start at the beginning (old_logline is probably from a * different log file) */ if (feof(Qfp) && (strncmp(logline, old_logline, strlen(logline) -1) != 0)) { FCLOSE(Qfp); if ((Qfp = fopen(file, In_Log_File ? "r" : mode)) == (FILE *)NULL) { sprintf(buf, E_fopen, file, In_Log_File ? "r" : mode, errmsg(errno)); log(L_WARNING, buf); FCLOSE(Linkfp); In_Log_File = FALSE; return(FALSE); } } dprintf(stderr, "done\n"); FCLOSE(Linkfp); return(TRUE); } /** strnindex: return index of t in s (starting at n), -1 if none ** as found in "The C Programming Language", 2nd Ed, K & R ** and slightly modified :-) **/ int strnindex(s, t, n) char s[], t[]; int n; { int i, j, k; for (i = n; s[i] != '\0'; i++) { for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++) ; if (k > 0 && t[k] == '\0') return i; } return -1; } /** my very own fgets that doesn't stop at EOF ** We sleep Sleep_Time until a line has started to be written, then ** we keep banging away until we get the rest of the article **/ char * my_fgets(s, n, iop) char *s; int n; FILE *iop; { register int c; register char *cs; register int count = 0; cs = s; dprintf(stderr, "Waiting for log entry: ", Sleep_Time); while ((c = getc(iop)) == EOF) { clearerr(iop); count++; if (connected && CheckIdleTimeout && count*Sleep_Time > IdleTimeOut) { dprintf(stderr, "%s: reached idle time-out, closing link temporarily.\n", Pname); fflush(stderr); goodbye(WAIT); connected = 0; Stats.since_close = 0L; } if (CheckExitTimeout && count*Sleep_Time > ExitTimeOut) { dprintf(stderr, "%s: reached exit time-out. %s Exiting.\n", Pname, Report_Stats ? " Logging stats and" : ""); fflush(stderr); if (Report_Stats) logstats(); cleanup(); goodbye(DONT_WAIT); exit(0); } sleep(Sleep_Time); dprintf(stderr,"."); } dprintf(stderr, "got it!\n"); while (((*cs++ = c) != '\n') && (--n > 0)) while ((c = getc(iop)) == EOF) clearerr(iop); cs--; /* replace "<blah>/n" with "<blah> /n" */ *cs++ = ' '; /* so that the last sysname has an extra */ *cs++ = '\n'; /* space after it (used in matching) */ *cs = '\0'; return s; }