home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CDPD Public Domain Collection for CDTV 4
/
CDPD_IV.bin
/
networking
/
uucp
/
amigauucpsrc
/
bms
/
get.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-29
|
22KB
|
866 lines
/*
* GET.C - Get files and/or directories
*/
#include "defs.h"
Prototype void GetBMS(char *, char *);
Prototype void InitGet(void);
Prototype void SMGetNoChannel(DBHan *, record_t, RegNode *, long);
Prototype void SMRxGet(DBHan *, record_t, RegNode *, CtlNode *);
Prototype void SMTxGet(DBHan *, record_t, RegNode *, CtlNode *);
Prototype void SMToGet(DBHan *, record_t, RegNode *, CtlNode *);
Prototype bool_t CheckGetDone(RegNode *, CtlNode *);
Prototype void ConstructRetryPacket(DBHan *, record_t, RegNode *, CtlNode *);
Prototype void ProcessRetryPacket(DBHan *, record_t, RegNode *, CtlNode *);
void
InitGet(void)
{
SetStateMachine(SMACH_GET, SMRxGet, SMTxGet, SMToGet);
}
/*
* GET a file/directory from a destination. We are the client in this
* case.
*
* - create a control node to handle communication
*
* - create a FileNode to handle the GET operation. The node will be
* expanded on the ack. Note that we can receive file data before
* the ack. We can, in fact, receive file fragments totally out of
* order before the hierarchy is even created.
*/
void
GetBMS(remFileName, locFileName)
char *remFileName;
char *locFileName;
{
RegNode *rn;
CtlNode *cn;
FileNode *fn;
if ((rn = FindFirstMarked()) == NULL || rn->rn_Node.ln_Name == NULL) {
bmslog("Get", "No destination specified");
return;
}
if (locFileName == NULL) {
bmslog("Get", "Did not specify TO <localfile/dir>");
return;
}
if (rn->rn_Comm.com_DID == 0) {
bmslog("Get", "Registration for this destination is still in progress");
bmslog("Get", "Request will be initiated after registration is complete");
}
/*
* Allocate node and initiate communications. Can setup FileNode
* after communications has been initiated
*/
cn = AllocCtlNode(rn);
InitCommLocalSide(SMACH_GET, rn, &cn->cn_Comm);
{
char *buf = zalloc(strlen(remFileName) + strlen(locFileName) + 10);
sprintf(buf, "GET-REQ-SEND", locFileName, remFileName);
SetCommMessage(&cn->cn_Comm, buf);
}
cn->cn_Comm.com_State = 0;
/*
* Allocate and setup a FileNode (we can theoretically setup several
* but currently the command only supports one
*/
fn = AllocFileNode(cn);
fn->fn_Flags |= FNF_MASTER;
if (remFileName)
fn->fn_RemFileName = zstrdup(remFileName);
if (locFileName)
fn->fn_LocFileName = zstrdup(locFileName);
}
/************************************************************************
* *
* GET STATE MACHINE *
* *
************************************************************************
*
* state 0: Initiate request (client)
* state 1: Initiate/retry
* state 2: Receive data and/or ack (1 week to)
* state 3: Done, send ack (2 week hold)
*
* state 8: Initialize for request (server)
* state 9: Send Acknowledge
* state 10 Send data, recv retries (loop to state 9 if get another req)
* state 11: Send Done, recv retries
*
*/
/*
* [re]open request on channel, we received the request so we are the
* server.
*/
void
SMGetNoChannel(db, rid, rn, did)
DBHan *db;
record_t rid;
RegNode *rn;
long did;
{
long size;
long type;
CtlNode *cn;
bmslog("Open-Get", "Received GET from %s:%d", rn->rn_Node.ln_Name, did);
if ((cn = FindCtlNode(rn, 0, did)) == NULL) {
cn = AllocCtlNode(rn);
InitCommRemoteSide(SMACH_GET, rn, &cn->cn_Comm, did);
SetCommMessage(&cn->cn_Comm, "OUTGOING");
cn->cn_Comm.com_State = 8;
for (rid = ScanSubRecord(db, rid, &size, &type); rid; rid = ScanNextRecord(db, rid, &size, &type)) {
switch(type) {
case DBTYPE_BMS_NODE: /* file or dir (local only) */
{
FileNode *fn = AllocFileNode(cn);
fn->fn_LocFileName = LoadRecord(db, rid, NULL, size + 1);
GetFileInfo(rn, cn, fn, &cn->cn_FileList);
}
break;
}
}
AssignFileNumbers(&cn->cn_FileList);
} else {
switch(cn->cn_Comm.com_State) {
case 8:
case 9:
break;
case 10:
cn->cn_Comm.com_State = 9;
cn->cn_Flags |= GF_MODIFIED;
break;
default:
break;
}
}
}
/*
* Receive data on this channel, either data we requested or controls
* for the channel
*/
void
SMRxGet(db, rid, rn, cn)
DBHan *db;
record_t rid;
RegNode *rn;
CtlNode *cn;
{
long size;
long type;
cn->cn_Flags |= GF_MODIFIED;
cn->cn_Comm.com_Flags |= GF_MODIFIED;
switch(cn->cn_Comm.com_State) {
/*
* CLIENT - RECEIVE DATA
*/
case 0: /* shouldn't get receive data */
break;
case 1: /* expect acknowledge or data */
case 2: /* expect acknowledge or data */
case 3: /* done (all data received), handle incomming as redundant */
for (rid = ScanSubRecord(db, rid, &size, &type); rid; rid = ScanNextRecord(db, rid, &size, &type)) {
char *ptr = LoadRecord(db, rid, NULL, size + 1);
if (cn->cn_Comm.com_State == 1) {
cn->cn_Comm.com_State = 2;
cn->cn_Comm.com_Retries = 0;
SetCommMessage(&cn->cn_Comm, "RECEIVE");
}
SetCommTimeout(&cn->cn_Comm, ONEWEEK);
switch(type) {
case DBTYPE_BMS_ACK_OPEN_GET:
/*
* If got ack, move to next state
*/
break;
case DBTYPE_BMS_FILE:
{
record_t sid;
FileNode *fn = MakeFindRecFileNode(cn, ptr, 0); /* sets GF_MODIFIED */
FileChunk fc;
char *file_data = NULL;
char *tmp;
clrmem(&fc, sizeof(fc));
fn->fn_Flags |= GF_MODIFIED;
for (sid = ScanSubRecord(db, rid, &size, &type); sid; sid = ScanNextRecord(db, sid, &size, &type)) {
char *data = LoadRecord(db, sid, NULL, size + 1);
switch(type) {
case DBTYPE_BMS_FILENO:
fn->fn_FileNo = strtol(data, NULL, 0);
break;
case DBTYPE_BMS_TTLFILES:
fn->fn_Files = strtol(data, NULL, 0);
break;
case DBTYPE_BMS_NOFILE:
fn->fn_Flags |= FNF_BAD | FNF_SIZE;
puts("FIL BAD");
break;
case DBTYPE_BMS_NOACCESS:
fn->fn_Flags |= FNF_ILLEGAL | FNF_SIZE;
puts("FIL NO ACCESS");
break;
case DBTYPE_BMS_SIZE:
fn->fn_Size = strtol(data, NULL, 0);
fn->fn_Flags |= FNF_SIZE;
break;
case DBTYPE_BMS_OFFSET: /* before DATA */
fc.fc_Offset = strtol(data, NULL, 0);
break;
case DBTYPE_BMS_AMI_PROTECTION: /* w/offset 0 data */
fn->fn_Protection = strtol(data, NULL, 0);
break;
case DBTYPE_BMS_AMI_TIMESTAMP: /* w/offset 0 data */
fn->fn_Date[0] = strtol(data, &tmp, 0);
fn->fn_Date[1] = strtol(tmp + 1, &tmp, 0);
fn->fn_Date[2] = strtol(tmp + 2, &tmp, 0);
break;
case DBTYPE_BMS_AMI_COMMENT: /* w/offset 0 data */
if (fn->fn_Comment)
zfree(fn->fn_Comment);
fn->fn_Comment = data;
data = NULL;
break;
case DBTYPE_BMS_DATA: /* data */
fc.fc_Bytes = size;
file_data = data;
data = NULL;
break;
}
if (data)
zfree(data);
}
/*
* Incorporate what we got
*/
IncorporateRecFileNode(cn, fn, &fc, file_data);
if (file_data)
zfree(file_data);
}
break;
case DBTYPE_BMS_DIR:
{
record_t sid;
FileNode *fn = MakeFindRecFileNode(cn, ptr, 1);
char *tmp;
fn->fn_Flags |= FNF_DONE | FNF_DIR | GF_MODIFIED;
for (sid = ScanSubRecord(db, rid, &size, &type); sid; sid = ScanNextRecord(db, sid, &size, &type)) {
char *data = LoadRecord(db, sid, NULL, size + 1);
switch(type) {
case DBTYPE_BMS_FILENO:
fn->fn_FileNo = strtol(data, NULL, 0);
break;
case DBTYPE_BMS_TTLFILES:
fn->fn_Files = strtol(data, NULL, 0);
if (DebugOpt)
printf("Total %d\n", fn->fn_Files);
break;
case DBTYPE_BMS_NOFILE:
fn->fn_Flags |= FNF_BAD | FNF_SIZE;
break;
case DBTYPE_BMS_NOACCESS:
fn->fn_Flags |= FNF_ILLEGAL | FNF_SIZE;
break;
case DBTYPE_BMS_AMI_PROTECTION: /* w/offset 0 data */
fn->fn_Protection = strtol(data, NULL, 0);
break;
case DBTYPE_BMS_AMI_TIMESTAMP: /* w/offset 0 data */
fn->fn_Date[0] = strtol(data, &tmp, 0);
fn->fn_Date[1] = strtol(tmp + 1, &tmp, 0);
fn->fn_Date[2] = strtol(tmp + 2, &tmp, 0);
break;
case DBTYPE_BMS_AMI_COMMENT: /* w/offset 0 data */
fn->fn_Comment = data;
data = NULL;
break;
}
if (data)
zfree(data);
}
/*
* Incorporate what we got
*/
IncorporateRecFileNode(cn, fn, NULL, NULL);
}
break;
case DBTYPE_BMS_DEQUEUE:
EnterDequeueState(rn, cn, &cn->cn_Comm, (ptr) ? ptr : "Remote Dequeued Transfer", 0);
break;
case DBTYPE_BMS_DONE:
/*
* Shorten retry timeout when we receive a done
*/
bmslog("Get", "Received DONE!");
SetCommTimeout(&cn->cn_Comm, ONEDAY);
break;
case DBTYPE_BMS_STOP:
break;
case DBTYPE_BMS_START:
break;
}
zfree(ptr);
}
/*
* Check if done
*/
if (CheckGetDone(rn, cn) == 0) {
SetCommTimeout(&cn->cn_Comm, ONEWEEK * 2);
SetCommMessage(&cn->cn_Comm, "RXDONE-WAIT");
if (cn->cn_Comm.com_State != 3)
SendMailResults(rn, cn, "GET OPERATION COMPLETED");
cn->cn_Comm.com_State = 3;
}
break;
/*
* SERVER - RECEIVE CONTROLS WHILE WE ARE SENDING DATA
*/
case 8:
case 9:
case 10:
case 11:
for (rid = ScanSubRecord(db, rid, &size, &type); rid; rid = ScanNextRecord(db, rid, &size, &type)) {
char *ptr = LoadRecord(db, rid, NULL, size + 1);
switch(type) {
case DBTYPE_BMS_DEQUEUE:
EnterDequeueState(rn, cn, &cn->cn_Comm, (ptr) ? ptr : "Remote Dequeued Transfer", 0);
break;
case DBTYPE_BMS_DONE: /* XXX does not occur */
break;
case DBTYPE_BMS_STOP:
break;
case DBTYPE_BMS_START:
break;
case DBTYPE_BMS_RETRY:
ProcessRetryPacket(db, rid, rn, cn);
break;
}
zfree(ptr);
}
break;
}
}
void
SMTxGet(db, rid, rn, cn)
DBHan *db;
record_t rid;
RegNode *rn;
CtlNode *cn;
{
cn->cn_Comm.com_Flags |= GF_MODIFIED;
cn->cn_Flags |= GF_MODIFIED;
if (DebugOpt)
printf("TXGET STATE %d\n", cn->cn_Comm.com_State);
switch(cn->cn_Comm.com_State) {
/*
* CLIENT (we want to get a file)
*/
case 0: /* initialize operation, send request */
/*
* Initialization for our get operation involves nothing
*/
++cn->cn_Comm.com_State;
/* fall through */
case 1: /* [re]send request */
/*
* Our request is sent on the registration channel, the
* acknowledge will occur on our private ctl channel
*
* CHANNEL
* BMS_OPEN_GET(source_chan_no)
* BMS_NODE(file/dirName)
* ...
*
*/
if (++cn->cn_Comm.com_Retries == 4) {
EnterDequeueState(rn, cn, &cn->cn_Comm, "Initiate, Retries Exceeded", 0);
break;
}
{
char buf[64];
FileNode *fn;
sprintf(buf, "0x%lx", cn->cn_Comm.com_SID);
rid = WriteBMSChannelRecord(db, 0, rid, &rn->rn_Comm);
rid = WriteRecord(db, rid, 0, DBTYPE_BMS_OPEN_GET, buf, strlen(buf));
for (fn = GetHead(&cn->cn_FileList); fn; fn = GetSucc(&fn->fn_Node)) {
WriteRecord(db, rid, 0, DBTYPE_BMS_NODE, fn->fn_RemFileName, strlen(fn->fn_RemFileName));
}
}
SetCommTimeout(&cn->cn_Comm, ONEDAY * 4);
SetCommMessage(&cn->cn_Comm, "GET-REQ-SENT");
break;
case 2: /* receiver timed out, send a retry */
/*
* We timed out expecting more data, send a retry. We got
* some data.
*/
if (++cn->cn_Comm.com_Retries == 4) {
EnterDequeueState(rn, cn, &cn->cn_Comm, "Retries Exceeded", 0);
break;
}
SetCommTimeout(&cn->cn_Comm, ONEWEEK);
SetCommMessage(&cn->cn_Comm, "GET-TIMEOUT-SEND-RETRY");
ConstructRetryPacket(db, rid, rn, cn);
break;
case 3: /* done state, no operation */
/*
* Timeout has already been set for two weeks by receive side
*/
break;
/*
* SERVER
*/
case 8: /* initialize operation */
++cn->cn_Comm.com_State;
/* fall through */
case 9: /* send acknowledge */
/*
* Send acknowledge, calculate bytes remaining,
* set request size and ALERT flag again. We can't
* fall through because we do not know how much we
* are allowed to send.
*
* XXX what about files that are not available?
* XXX include text msg in acknowledgement (bytes being sent...)
* XXX up above, request should contain maximum bpd/bpw
*/
rid = WriteBMSChannelRecord(db, 0, rid, &cn->cn_Comm);
rid = WriteRecord(db, rid, 0, DBTYPE_BMS_ACK_OPEN_GET, NULL, 0);
CalculateBytesToSend(rn, cn);
++cn->cn_Comm.com_State;
break;
case 10: /* send data (or retries) */
/*
* We are allowed to send cn->cn_Comm.com_TxOk bytes
*/
rid = WriteBMSChannelRecord(db, 0, rid, &cn->cn_Comm);
{
FileNode *fn;
FileChunk *fc;
char *ptr;
record_t sid;
char buf[64];
while (ptr = SelectChunkForSend(rn, cn, &fn, &fc)) {
sid = WriteRecord(db, rid, 0, ((fc) ? DBTYPE_BMS_FILE : DBTYPE_BMS_DIR), fn->fn_LocFileName, strlen(fn->fn_LocFileName));
/*
* File number & total # of files always sent as this is
* how the receiver determines if/when it has gotten
* everything.
*/
sprintf(buf, "%d", fn->fn_FileNo);
WriteRecord(db, sid, 0, DBTYPE_BMS_FILENO, buf, strlen(buf));
sprintf(buf, "%d", fn->fn_Files);
WriteRecord(db, sid, 0, DBTYPE_BMS_TTLFILES, buf, strlen(buf));
/*
* For a directory (fc == NULL) or the first chunk of a
* file (offset == 0), send protection, timestamp, and
* comment information.
*
* For a file send additional info -- the data chunk!
*/
if (DebugOpt)
printf("SEND FILE NODE FLAGS %04lx\n", fn->fn_Flags);
if (fn->fn_Flags & FNF_BAD) {
WriteRecord(db, sid, 0, DBTYPE_BMS_NOFILE, NULL, 0);
} else if (fn->fn_Flags & FNF_ILLEGAL) {
WriteRecord(db, sid, 0, DBTYPE_BMS_NOACCESS, NULL, 0);
} else {
if ((fc && fc->fc_Offset == 0) || fc == NULL) {
sprintf(buf, "0x%lx", fn->fn_Protection);
WriteRecord(db, sid, 0, DBTYPE_BMS_AMI_PROTECTION, buf, strlen(buf));
sprintf(buf, "0x%lx:0x%lx:0x%lx", fn->fn_Date[0], fn->fn_Date[1], fn->fn_Date[2]);
WriteRecord(db, sid, 0, DBTYPE_BMS_AMI_TIMESTAMP, buf, strlen(buf));
if (fn->fn_Comment)
WriteRecord(db, sid, 0, DBTYPE_BMS_AMI_COMMENT, fn->fn_Comment, strlen(fn->fn_Comment));
}
if (fc) {
if (fc->fc_Offset == 0) {
sprintf(buf, "%d",fn->fn_Size);
WriteRecord(db, sid, 0, DBTYPE_BMS_SIZE, buf, strlen(buf));
} else {
sprintf(buf, "%d", fc->fc_Offset);
WriteRecord(db, sid, 0, DBTYPE_BMS_OFFSET, buf, strlen(buf));
}
WriteRecord(db, sid, 0, DBTYPE_BMS_DATA, ptr, fc->fc_Bytes);
}
}
zfree(ptr);
}
}
CalculateBytesToSend(rn, cn);
if (cn->cn_Flags & CNF_DONE) {
cn->cn_Comm.com_Flags |= GF_ALERT;
++cn->cn_Comm.com_State;
SetCommMessage(&cn->cn_Comm, "OUTGOING-COMPLETE");
}
break;
case 11: /* send done, then wait */
rid = WriteBMSChannelRecord(db, 0, rid, &cn->cn_Comm);
WriteRecord(db, rid, 0, DBTYPE_BMS_DONE, NULL, 0);
SetCommTimeout(&cn->cn_Comm, ONEWEEK * 2);
SetCommMessage(&cn->cn_Comm, "OUTGOING-DONE-WAIT");
cn->cn_Comm.com_TxReq = 0;
cn->cn_Comm.com_TxOk = 0;
break;
}
}
void
SMToGet(db, rid, rn, cn)
DBHan *db;
record_t rid;
RegNode *rn;
CtlNode *cn;
{
switch(cn->cn_Comm.com_State) {
/*
* CLIENT
*/
case 0: /* timeout on initiate shouldn't happen */
case 1: /* timeout on initiate, retry initiate */
case 2: /* timeout on receive data, send retry */
SMTxGet(db, rid, rn, cn);
break;
case 3: /* done state timed out, clear structure */
cn->cn_Flags |= GF_DELETED | GF_MODIFIED;
break;
/*
* SERVER
*/
case 8: /* should not happen */
case 9: /* should not happen */
case 10: /* should not happen */
case 11: /* done state timed out, clear structure */
cn->cn_Flags |= GF_DELETED | GF_MODIFIED;
break;
}
}
/*
* Check that the GET operation has been completed. Find our master
* node (FNF_MASTER)
*/
bool_t
CheckGetDone(rn, cn)
RegNode *rn;
CtlNode *cn;
{
FileNode *fn;
FileNode *fn2;
long cnt = 0;
long n = 0;
for (fn = GetHead(&cn->cn_FileList); fn; fn = GetSucc(&fn->fn_Node)) {
if (n == 0)
n = fn->fn_Files;
if (fn->fn_Flags & FNF_DONE)
++cnt;
}
if (n == 0) /* haven't gotten a file count from remote */
return(-1);
if (n == cnt) /* all files are competely in */
return(0);
return(-1);
}
/*
* construct a retry packet (DBTPE_BMS_RETRY)
*
* - If we don't know how many files we expect then send BMS_TTLFILES=0
* - Otherwise send BMS_FILENO for each file we do NOT have, with a sub
* tree indicating which *parts* of the file we do not have
*
* BMS_FILENO
* BMS_RETRY_CHUNK
* contains offset/bytes of chunks we did NOT receive
* format: offset:bytes
*/
void
ConstructRetryPacket(db, rid, rn, cn)
DBHan *db;
record_t rid;
RegNode *rn;
CtlNode *cn;
{
char buf[64];
FileNode *fn;
long ttlFiles = 0;
long n;
rid = WriteBMSChannelRecord(db, 0, rid, &cn->cn_Comm);
rid = WriteRecord(db, rid, 0, DBTYPE_BMS_RETRY, NULL, 0);
/*
* Attempt to find the total number of files we expect. If we
* do not know then send BMS_TTLFILES=0
*/
for (fn = GetHead(&cn->cn_FileList); fn; fn = GetSucc(&fn->fn_Node)) {
if (fn->fn_Files) {
ttlFiles = fn->fn_Files;
break;
}
}
if (ttlFiles == 0) {
WriteRecord(db, rid, 0, DBTYPE_BMS_TTLFILES, "0", 1);
return;
}
/*
* We know how many files we expect, now look for the file ID's
* for each file.
*/
for (n = 0; n < ttlFiles; ++n) {
record_t sid;
FileChunk *fc;
long offset;
for (fn = GetHead(&cn->cn_FileList); fn; fn = GetSucc(&fn->fn_Node)) {
if (fn->fn_FileNo == n)
break;
}
/*
* We don't have file number <n> at all!
*/
if (fn == NULL) {
sprintf(buf, "%d", n);
WriteRecord(db, rid, 0, DBTYPE_BMS_FILENO, buf, strlen(buf));
continue;
}
/*
* We have file number <n>, do we have all of it?
*/
if (fn->fn_Flags & FNF_DONE)
continue;
/*
* No, tell remote which chunks we need. Write an initial
* dummy chunk record to indicate to the remote that we have
* <part> of the file, even if due to a fluke we wind up
* having all of it (e.g. FNF_DONE was not set properly) and
* thus do not generate any additional chunks.
*/
sprintf(buf, "%d", n);
sid = WriteRecord(db, rid, 0, DBTYPE_BMS_FILENO, buf, strlen(buf));
sprintf(buf, "0:0");
WriteRecord(db, sid, 0, DBTYPE_BMS_RETRY_CHUNK, buf, strlen(buf));
offset = 0;
for (fc = GetHead(&fn->fn_ChunkList); fc; fc = GetSucc(&fc->fc_Node)) {
if (fc->fc_Flags & GF_DELETED)
continue;
if (offset < fc->fc_Offset) {
bmslog("TxRetry", "Chunk %s(%d-%d)", fn->fn_RemFileName, offset, fc->fc_Offset);
sprintf(buf, "%d:%d", offset, fc->fc_Offset - offset);
WriteRecord(db, sid, 0, DBTYPE_BMS_RETRY_CHUNK, buf, strlen(buf));
}
offset = fc->fc_Offset + fc->fc_Bytes;
}
if (offset < fn->fn_Size) {
bmslog("TxRetry", "Chunk %s(%d-%d)", fn->fn_RemFileName, offset, fn->fn_Size);
sprintf(buf, "%d:%d", offset, fn->fn_Size - offset);
WriteRecord(db, sid, 0, DBTYPE_BMS_RETRY_CHUNK, buf, strlen(buf));
}
}
}
/*
* Process a retry packet (DBTPE_BMS_RETRY)
*
* - If we get BMS_TTLFILES=0 (value ignored) we requeue the entire
* file set.
*
* - if we get BMS_FILENO with no subtree BMS_RETRY_CHUNK we requeue
* that entire file.
*
* - if we get BMS_FILENO with BMS_RETRY_CHUNK we requeue the specified
* chunks.
*/
void
ProcessRetryPacket(db, rid, rn, cn)
DBHan *db;
record_t rid;
RegNode *rn;
CtlNode *cn;
{
FileNode *fn;
record_t sid;
long size;
long type;
short requeue = 0;
char *ptr;
for (rid = ScanSubRecord(db, rid, &size, &type); rid; rid = ScanNextRecord(db, rid, &size, &type)) {
switch(type) {
case DBTYPE_BMS_TTLFILES:
requeue = 1;
for (fn = GetHead(&cn->cn_FileList); fn; fn = GetSucc(&fn->fn_Node)) {
FileChunk *fc;
for (fc = GetHead(&fn->fn_ChunkList); fc; fc = GetSucc(&fc->fc_Node))
fc->fc_Flags |= GF_DELETED;
fn->fn_Flags &= ~FNF_DONE;
fn->fn_Flags |= GF_MODIFIED;
}
break;
case DBTYPE_BMS_FILENO:
requeue = 1;
ptr = LoadRecord(db, rid, NULL, size + 1);
for (fn = GetHead(&cn->cn_FileList); fn; fn = GetSucc(&fn->fn_Node)) {
if (fn->fn_FileNo == strtol(ptr, NULL, 0)) {
short chunks = 0;
/*
* found node, remote specified chunks (if any)
*/
for (sid = ScanSubRecord(db, rid, &size, &type); sid; sid = ScanNextRecord(db, sid, &size, &type)) {
long offset = 0;
long bytes = 0;
FileChunk *fc;
switch(type) {
case DBTYPE_BMS_RETRY_CHUNK:
++chunks;
{
char *str = LoadRecord(db, sid, NULL, size + 2);
char *tmp;
offset = strtol(str, &tmp, 0);
bytes = strtol(tmp + 1, &tmp, 0);
zfree(str);
}
/*
* Scan for chunks to reclaim. To ease calculations
* remove the entire chunk if it overlaps at all.
* since the file was sent in the granularity of the
* chunks anyway this will be dead on 99% of the time.
*/
for (fc = GetHead(&fn->fn_ChunkList); fc; fc = GetSucc(&fc->fc_Node)) {
if (fc->fc_Flags & GF_DELETED)
continue;
if (bytes) {
if (offset < fc->fc_Offset + fc->fc_Bytes && offset + bytes > fc->fc_Offset) {
fc->fc_Flags |= GF_DELETED;
fn->fn_Flags |= GF_MODIFIED;
fn->fn_Flags &= ~FNF_DONE;
bmslog("RxRetry", "Chunk %s(%d-%d)", fn->fn_LocFileName, fc->fc_Offset, fc->fc_Offset + fc->fc_Bytes);
}
}
}
break;
}
}
if (chunks == 0) {
FileChunk *fc;
for (fc = GetHead(&fn->fn_ChunkList); fc; fc = GetSucc(&fc->fc_Node)) {
fc->fc_Flags |= GF_DELETED;
fn->fn_Flags |= GF_MODIFIED;
fn->fn_Flags &= ~FNF_DONE;
}
}
}
}
zfree(ptr);
break;
}
}
/*
* If requeue then go back to proper state and hit the transmitter
*/
if (requeue) {
cn->cn_Comm.com_Flags |= GF_ALERT | GF_MODIFIED;
cn->cn_Flags &= ~CNF_DONE;
cn->cn_Flags |= GF_MODIFIED;
if (cn->cn_Comm.com_State == 11) {
cn->cn_Comm.com_State = 10;
}
SetCommMessage(&cn->cn_Comm, "OUTGOING-RETRY");
SetCommTimeout(&cn->cn_Comm, ONEWEEK * 2);
}
}