|
|
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;
}