static void manageMtusize(int tokenCount, char **tokens) { Sdr sdr = getIonsdr(); Object cfdpdbObj = getCfdpDbObject(); CfdpDB cfdpdb; int newMtusize; if (tokenCount != 3) { SYNTAX_ERROR; } newMtusize = atoi(tokens[2]); if (newMtusize < 0) { putErrmsg("mtuSize invalid.", tokens[2]); return; } sdr_begin_xn(sdr); sdr_stage(sdr, (char *) &cfdpdb, cfdpdbObj, sizeof(CfdpDB)); cfdpdb.mtuSize = newMtusize; sdr_write(sdr, cfdpdbObj, (char *) &cfdpdb, sizeof(CfdpDB)); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't change mtuSize.", NULL); } }
static void manageMaxtimeouts(int tokenCount, char **tokens) { Sdr sdr = getIonsdr(); Object cfdpdbObj = getCfdpDbObject(); CfdpDB cfdpdb; int newMaxtimeouts; if (tokenCount != 3) { SYNTAX_ERROR; } newMaxtimeouts = atoi(tokens[2]); if (newMaxtimeouts < 0) { putErrmsg("checkTimeoutLimit invalid.", tokens[2]); return; } sdr_begin_xn(sdr); sdr_stage(sdr, (char *) &cfdpdb, cfdpdbObj, sizeof(CfdpDB)); cfdpdb.checkTimeoutLimit = newMaxtimeouts; sdr_write(sdr, cfdpdbObj, (char *) &cfdpdb, sizeof(CfdpDB)); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't change checkTimerPeriod.", NULL); } }
static void manageMaxtrnbr(int tokenCount, char **tokens) { Sdr sdr = getIonsdr(); Object cfdpdbObj = getCfdpDbObject(); CfdpDB cfdpdb; int newMaxtrnbr; if (tokenCount != 3) { SYNTAX_ERROR; } newMaxtrnbr = atoi(tokens[2]); if (newMaxtrnbr < 0) { putErrmsg("maxTransactionNbr invalid.", tokens[2]); return; } sdr_begin_xn(sdr); sdr_stage(sdr, (char *) &cfdpdb, cfdpdbObj, sizeof(CfdpDB)); cfdpdb.maxTransactionNbr = newMaxtrnbr; sdr_write(sdr, cfdpdbObj, (char *) &cfdpdb, sizeof(CfdpDB)); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't change maxTransactionNbr.", NULL); } }
static void manageFillchar(int tokenCount, char **tokens) { Sdr sdr = getIonsdr(); Object cfdpdbObj = getCfdpDbObject(); CfdpDB cfdpdb; int newFillchar; char *trailing; if (tokenCount != 3) { SYNTAX_ERROR; } newFillchar = strtol(tokens[2], &trailing, 16); if (*trailing != '\0') { putErrmsg("fillCharacter invalid.", tokens[2]); return; } sdr_begin_xn(sdr); sdr_stage(sdr, (char *) &cfdpdb, cfdpdbObj, sizeof(CfdpDB)); cfdpdb.fillCharacter = newFillchar; sdr_write(sdr, cfdpdbObj, (char *) &cfdpdb, sizeof(CfdpDB)); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't change fillCharacter.", NULL); } }
static void manageRequirecrc(int tokenCount, char **tokens) { Sdr sdr = getIonsdr(); Object cfdpdbObj = getCfdpDbObject(); CfdpDB cfdpdb; int newRequirecrc; if (tokenCount != 3) { SYNTAX_ERROR; } newRequirecrc = atoi(tokens[2]); if (newRequirecrc != 0 && newRequirecrc != 1) { putErrmsg("crcRequired switch invalid.", tokens[2]); return; } sdr_begin_xn(sdr); sdr_stage(sdr, (char *) &cfdpdb, cfdpdbObj, sizeof(CfdpDB)); cfdpdb.crcRequired = newRequirecrc; sdr_write(sdr, cfdpdbObj, (char *) &cfdpdb, sizeof(CfdpDB)); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't change crcRequired switch.", NULL); } }
static void manageDiscard(int tokenCount, char **tokens) { Sdr sdr = getIonsdr(); Object cfdpdbObj = getCfdpDbObject(); CfdpDB cfdpdb; int newDiscard; if (tokenCount != 3) { SYNTAX_ERROR; } newDiscard = atoi(tokens[2]); if (newDiscard != 0 && newDiscard != 1) { putErrmsg("discardIncompleteFile switch invalid.", tokens[2]); return; } sdr_begin_xn(sdr); sdr_stage(sdr, (char *) &cfdpdb, cfdpdbObj, sizeof(CfdpDB)); cfdpdb.discardIncompleteFile = newDiscard; sdr_write(sdr, cfdpdbObj, (char *) &cfdpdb, sizeof(CfdpDB)); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't change discardIncompleteFile switch.", NULL); } }
int dtn2_updateRule(char *nodeNm, char *demux, FwdDirective *directive) { Sdr sdr = getIonsdr(); char nodeName[SDRSTRING_BUFSZ]; Object elt; OBJ_POINTER(Dtn2Plan, plan); Object ruleAddr; Dtn2Rule ruleBuf; CHKERR(nodeNm && demux && directive); if (*demux == '\0') { writeMemo("[?] Zero-length DTN2 rule demux."); return 0; } if (filterNodeName(nodeName, nodeNm) < 0) { return 0; } CHKERR(sdr_begin_xn(sdr)); elt = locatePlan(nodeName, NULL); if (elt == 0) { sdr_exit_xn(sdr); writeMemoNote("[?] No plan defined for this node", nodeNm); return 0; } GET_OBJ_POINTER(sdr, Dtn2Plan, plan, sdr_list_data(sdr, elt)); dtn2_findRule(nodeName, demux, plan, &ruleAddr, &elt); if (elt == 0) { sdr_exit_xn(sdr); writeMemoNote("[?] Unknown rule", demux); return 0; } /* All parameters validated, okay to update the rule. */ sdr_stage(sdr, (char *) &ruleBuf, ruleAddr, sizeof(Dtn2Rule)); dtn2_destroyDirective(&ruleBuf.directive); memcpy((char *) &ruleBuf.directive, (char *) directive, sizeof(FwdDirective)); sdr_write(sdr, ruleAddr, (char *) &ruleBuf, sizeof(Dtn2Rule)); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't update rule.", NULL); return -1; } return 1; }
static int scanInFdus(Sdr sdr, time_t currentTime) { CfdpDB *cfdpConstants; Object entityElt; OBJ_POINTER(Entity, entity); Object elt; Object nextElt; Object fduObj; OBJ_POINTER(InFdu, fdu); CfdpHandler handler; cfdpConstants = getCfdpConstants(); sdr_begin_xn(sdr); for (entityElt = sdr_list_first(sdr, cfdpConstants->entities); entityElt; entityElt = sdr_list_next(sdr, entityElt)) { GET_OBJ_POINTER(sdr, Entity, entity, sdr_list_data(sdr, entityElt)); for (elt = sdr_list_first(sdr, entity->inboundFdus); elt; elt = nextElt) { nextElt = sdr_list_next(sdr, elt); fduObj = sdr_list_data(sdr, elt); GET_OBJ_POINTER(sdr, InFdu, fdu, fduObj); if (fdu->eofReceived && fdu->checkTime < currentTime) { sdr_stage(sdr, NULL, fduObj, 0); fdu->checkTimeouts++; fdu->checkTime += cfdpConstants->checkTimerPeriod; sdr_write(sdr, fduObj, (char *) fdu, sizeof(InFdu)); } if (fdu->checkTimeouts > cfdpConstants->checkTimeoutLimit) { if (handleFault(&(fdu->transactionId), CfdpCheckLimitReached, &handler) < 0) { sdr_cancel_xn(sdr); putErrmsg("Can't handle check limit \ reached.", NULL); return -1; } } } }
int setDeltaFromUTC(int newDelta) { Sdr ionsdr = _ionsdr(NULL); Object iondbObject = _iondbObject(NULL); IonDB *ionConstants = _ionConstants(); IonVdb *ionvdb = _ionvdb(NULL); sdr_begin_xn(ionsdr); sdr_stage(ionsdr, (char *) ionConstants, iondbObject, sizeof(IonDB)); ionConstants->deltaFromUTC = newDelta; sdr_write(ionsdr, iondbObject, (char *) ionConstants, sizeof(IonDB)); if (sdr_end_xn(ionsdr) < 0) { putErrmsg("Can't change delta from UTC.", NULL); return -1; } ionvdb->deltaFromUTC = newDelta; return 0; }
void ionVacate(int size) { Sdr ionsdr = _ionsdr(NULL); Object iondbObject = _iondbObject(NULL); IonDB iondbBuf; CHKVOID(ionLocked()); CHKVOID(size >= 0); sdr_stage(ionsdr, (char *) &iondbBuf, iondbObject, sizeof(IonDB)); if (size > iondbBuf.currentOccupancy) /* Underflow. */ { iondbBuf.currentOccupancy = 0; } else { iondbBuf.currentOccupancy -= size; } sdr_write(ionsdr, iondbObject, (char *) &iondbBuf, sizeof(IonDB)); }
void ionOccupy(int size) { Sdr ionsdr = _ionsdr(NULL); Object iondbObject = _iondbObject(NULL); IonDB iondbBuf; CHKVOID(ionLocked()); CHKVOID(size >= 0); sdr_stage(ionsdr, (char *) &iondbBuf, iondbObject, sizeof(IonDB)); if (iondbBuf.currentOccupancy + size < 0)/* Overflow. */ { iondbBuf.currentOccupancy = iondbBuf.occupancyCeiling; } else { iondbBuf.currentOccupancy += size; } sdr_write(ionsdr, iondbObject, (char *) &iondbBuf, sizeof(IonDB)); }
int dtn2_updatePlan(char *nodeNm, FwdDirective *defaultDir) { Sdr sdr = getIonsdr(); char nodeName[SDRSTRING_BUFSZ]; Object elt; Object planObj; Dtn2Plan plan; CHKERR(nodeNm && defaultDir); if (filterNodeName(nodeName, nodeNm) < 0) { return 0; } CHKERR(sdr_begin_xn(sdr)); elt = locatePlan(nodeName, NULL); if (elt == 0) { sdr_exit_xn(sdr); writeMemoNote("[?] No plan defined for this node", nodeNm); return 0; } /* Okay to update this plan. */ planObj = sdr_list_data(sdr, elt); sdr_stage(sdr, (char *) &plan, planObj, sizeof(Dtn2Plan)); dtn2_destroyDirective(&plan.defaultDirective); memcpy((char *) &plan.defaultDirective, (char *) defaultDir, sizeof(FwdDirective)); sdr_write(sdr, planObj, (char *) &plan, sizeof(Dtn2Plan)); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't update plan.", nodeNm); return -1; } return 1; }
int bp_receive(BpSAP sap, BpDelivery *dlvBuffer, int timeoutSeconds) { Sdr sdr = getIonsdr(); VEndpoint *vpoint; OBJ_POINTER(Endpoint, endpoint); Object dlvElt; Object bundleAddr; Bundle bundle; TimerParms timerParms; pthread_t timerThread; int result; char *dictionary; CHKERR(sap && dlvBuffer); if (timeoutSeconds < BP_BLOCKING) { putErrmsg("Illegal timeout interval.", itoa(timeoutSeconds)); return -1; } vpoint = sap->vpoint; sdr_begin_xn(sdr); if (vpoint->appPid != sm_TaskIdSelf()) { sdr_exit_xn(sdr); putErrmsg("Can't receive: not owner of endpoint.", itoa(vpoint->appPid)); return -1; } if (sm_SemEnded(vpoint->semaphore)) { sdr_exit_xn(sdr); writeMemo("[?] Endpoint has been stopped."); /* End task, but without error. */ return -1; } /* Get oldest bundle in delivery queue, if any; wait * for one if necessary. */ GET_OBJ_POINTER(sdr, Endpoint, endpoint, sdr_list_data(sdr, vpoint->endpointElt)); dlvElt = sdr_list_first(sdr, endpoint->deliveryQueue); if (dlvElt == 0) { sdr_exit_xn(sdr); if (timeoutSeconds == BP_POLL) { dlvBuffer->result = BpReceptionTimedOut; return 0; } /* Wait for semaphore to be given, either by the * deliverBundle() function or by timer thread. */ if (timeoutSeconds == BP_BLOCKING) { timerParms.interval = -1; } else /* This is a receive() with a deadline. */ { timerParms.interval = timeoutSeconds; timerParms.semaphore = vpoint->semaphore; if (pthread_create(&timerThread, NULL, timerMain, &timerParms) < 0) { putSysErrmsg("Can't enable interval timer", NULL); return -1; } } /* Take endpoint semaphore. */ if (sm_SemTake(vpoint->semaphore) < 0) { putErrmsg("Can't take endpoint semaphore.", NULL); return -1; } if (sm_SemEnded(vpoint->semaphore)) { writeMemo("[i] Endpoint has been stopped."); /* End task, but without error. */ return -1; } /* Have taken the semaphore, one way or another. */ sdr_begin_xn(sdr); dlvElt = sdr_list_first(sdr, endpoint->deliveryQueue); if (dlvElt == 0) /* Still nothing. */ { /* Either sm_SemTake() was interrupted * or else timer thread gave semaphore. */ sdr_exit_xn(sdr); if (timerParms.interval == 0) { /* Timer expired. */ dlvBuffer->result = BpReceptionTimedOut; pthread_join(timerThread, NULL); } else /* Interrupted. */ { dlvBuffer->result = BpReceptionInterrupted; if (timerParms.interval != -1) { pthread_cancel(timerThread); pthread_join(timerThread, NULL); } } return 0; } else /* Bundle was delivered. */ { if (timerParms.interval != -1) { pthread_cancel(timerThread); pthread_join(timerThread, NULL); } } } /* At this point, we have got a dlvElt and are in an SDR * transaction. */ bundleAddr = sdr_list_data(sdr, dlvElt); sdr_stage(sdr, (char *) &bundle, bundleAddr, sizeof(Bundle)); dictionary = retrieveDictionary(&bundle); if (dictionary == (char *) &bundle) { sdr_cancel_xn(sdr); putErrmsg("Can't retrieve dictionary.", NULL); return -1; } /* Now fill in the data indication structure. */ dlvBuffer->result = BpPayloadPresent; if (printEid(&bundle.id.source, dictionary, &dlvBuffer->bundleSourceEid) < 0) { sdr_cancel_xn(sdr); putErrmsg("Can't print source EID.", NULL); return -1; } dlvBuffer->bundleCreationTime.seconds = bundle.id.creationTime.seconds; dlvBuffer->bundleCreationTime.count = bundle.id.creationTime.count; dlvBuffer->adminRecord = bundle.bundleProcFlags & BDL_IS_ADMIN; dlvBuffer->adu = zco_add_reference(sdr, bundle.payload.content); dlvBuffer->ackRequested = bundle.bundleProcFlags & BDL_APP_ACK_REQUEST; /* Now before returning we send delivery status report * if it is requested. */ if (SRR_FLAGS(bundle.bundleProcFlags) & BP_DELIVERED_RPT) { bundle.statusRpt.flags |= BP_DELIVERED_RPT; getCurrentDtnTime(&bundle.statusRpt.deliveryTime); } if (bundle.statusRpt.flags) { result = sendStatusRpt(&bundle, dictionary); if (result < 0) { sdr_cancel_xn(sdr); putErrmsg("Can't send status report.", NULL); return -1; } } /* Finally delete the delivery list element and, if * possible, destroy the bundle itself. */ if (dictionary) { MRELEASE(dictionary); } sdr_list_delete(sdr, dlvElt, (SdrListDeleteFn) NULL, NULL); bundle.dlvQueueElt = 0; sdr_write(sdr, bundleAddr, (char *) &bundle, sizeof(Bundle)); if (bpDestroyBundle(bundleAddr, 0) < 0) { sdr_cancel_xn(sdr); putErrmsg("Can't destroy bundle.", NULL); return -1; } if (sdr_end_xn(sdr) < 0) { putErrmsg("Failure in bundle reception.", NULL); return -1; } return 0; }
static int manageLinks(Sdr sdr, time_t currentTime) { PsmPartition ionwm = getIonwm(); LtpVdb *ltpvdb = getLtpVdb(); IonVdb *ionvdb = getIonVdb(); PsmAddress elt; LtpVspan *vspan; Object obj; LtpSpan span; IonNeighbor *neighbor; PsmAddress nextElt; unsigned long priorXmitRate; sdr_begin_xn(sdr); for (elt = sm_list_first(ionwm, ltpvdb->spans); elt; elt = sm_list_next(ionwm, elt)) { vspan = (LtpVspan *) psp(ionwm, sm_list_data(ionwm, elt)); /* Finish aggregation as necessary. */ obj = sdr_list_data(sdr, vspan->spanElt); sdr_stage(sdr, (char *) &span, obj, sizeof(LtpSpan)); if (span.lengthOfBufferedBlock > 0) { span.ageOfBufferedBlock++; sdr_write(sdr, obj, (char *) &span, sizeof(LtpSpan)); if (span.ageOfBufferedBlock >= span.aggrTimeLimit) { sm_SemGive(vspan->bufFullSemaphore); } } /* Find Neighbor object encapsulating the current * known state of this LTP engine. */ neighbor = findNeighbor(ionvdb, vspan->engineId, &nextElt); if (neighbor == NULL) { neighbor = addNeighbor(ionvdb, vspan->engineId, nextElt); if (neighbor == NULL) { putErrmsg("Can't update span.", NULL); return -1; } } if (neighbor->xmitRate == 0) { if (vspan->localXmitRate > 0) { vspan->localXmitRate = 0; ltpStopXmit(vspan); } } else { if (vspan->localXmitRate == 0) { vspan->localXmitRate = neighbor->xmitRate; ltpStartXmit(vspan); } } if (neighbor->fireRate == 0) { if (vspan->remoteXmitRate > 0) { priorXmitRate = vspan->remoteXmitRate; vspan->remoteXmitRate = 0; if (ltpSuspendTimers(vspan, elt, currentTime, priorXmitRate)) { putErrmsg("Can't manage links.", NULL); return -1; } } } else { if (vspan->remoteXmitRate == 0) { vspan->remoteXmitRate = neighbor->fireRate; if (ltpResumeTimers(vspan, elt, currentTime, vspan->remoteXmitRate)) { putErrmsg("Can't manage links.", NULL); return -1; } } } if (neighbor->recvRate == 0) { vspan->receptionRate = 0; } else { vspan->receptionRate = neighbor->recvRate; } if (neighbor->owltInbound != vspan->owltInbound) { vspan->owltInbound = neighbor->owltInbound; } if (neighbor->owltOutbound != vspan->owltOutbound) { vspan->owltOutbound = neighbor->owltOutbound; } } if (sdr_end_xn(sdr) < 0) { putErrmsg("ltpclock failed managing links.", NULL); return -1; } return 0; }
int dtn2fw(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10) { #else int main(int argc, char *argv[]) { #endif int running = 1; Sdr sdr; VScheme *vscheme; PsmAddress vschemeElt; Scheme scheme; Object elt; Object bundleAddr; Bundle bundle; if (bpAttach() < 0) { putErrmsg("dtn2fw can't attach to BP.", NULL); return 1; } if (dtn2Init(NULL) < 0) { putErrmsg("dtn2fw can't load routing database.", NULL); return 1; } sdr = getIonsdr(); findScheme("dtn", &vscheme, &vschemeElt); if (vschemeElt == 0) { putErrmsg("Scheme name for dtn2 is unknown.", "dtn"); return 1; } CHKZERO(sdr_begin_xn(sdr)); sdr_read(sdr, (char *) &scheme, sdr_list_data(sdr, vscheme->schemeElt), sizeof(Scheme)); sdr_exit_xn(sdr); oK(_dtn2fwSemaphore(&vscheme->semaphore)); isignal(SIGTERM, shutDown); /* Main loop: wait until forwarding queue is non-empty, * then drain it. */ writeMemo("[i] dtn2fw is running."); while (running && !(sm_SemEnded(vscheme->semaphore))) { /* We wrap forwarding in an SDR transaction to * prevent race condition with bpclock (which * is destroying bundles as their TTLs expire). */ CHKZERO(sdr_begin_xn(sdr)); elt = sdr_list_first(sdr, scheme.forwardQueue); if (elt == 0) /* Wait for forwarding notice. */ { sdr_exit_xn(sdr); if (sm_SemTake(vscheme->semaphore) < 0) { putErrmsg("Can't take forwarder semaphore.", NULL); running = 0; } continue; } bundleAddr = (Object) sdr_list_data(sdr, elt); sdr_stage(sdr, (char *) &bundle, bundleAddr, sizeof(Bundle)); sdr_list_delete(sdr, elt, NULL, NULL); bundle.fwdQueueElt = 0; /* Must rewrite bundle to note removal of * fwdQueueElt, in case the bundle is abandoned * and bpDestroyBundle re-reads it from the * database. */ sdr_write(sdr, bundleAddr, (char *) &bundle, sizeof(Bundle)); if (enqueueBundle(&bundle, bundleAddr) < 0) { sdr_cancel_xn(sdr); putErrmsg("Can't enqueue bundle.", NULL); running = 0; /* Terminate loop. */ continue; } if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't enqueue bundle.", NULL); running = 0; /* Terminate loop. */ } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } writeErrmsgMemos(); writeMemo("[i] dtn2fw forwarder has ended."); ionDetach(); return 0; }
static void *sendBundles(void *parm) { /* Main loop for single bundle transmission thread * serving all BRS sockets. */ SenderThreadParms *parms = (SenderThreadParms *) parm; char *procName = "brsscla"; unsigned char *buffer; Outduct outduct; Sdr sdr; Outflow outflows[3]; int i; Object bundleZco; BpExtendedCOS extendedCOS; char destDuctName[MAX_CL_DUCT_NAME_LEN + 1]; unsigned int bundleLength; int ductNbr; int bytesSent; Object bundleAddr; Bundle bundle; snooze(1); /* Let main thread become interruptable. */ buffer = MTAKE(TCPCLA_BUFSZ); if (buffer == NULL) { putErrmsg("No memory for TCP buffer in brsscla.", NULL); ionKillMainThread(procName); return terminateSenderThread(parms); } sdr = getIonsdr(); CHKNULL(sdr_begin_xn(sdr)); sdr_read(sdr, (char *) &outduct, sdr_list_data(sdr, parms->vduct->outductElt), sizeof(Outduct)); sdr_exit_xn(sdr); memset((char *) outflows, 0, sizeof outflows); outflows[0].outboundBundles = outduct.bulkQueue; outflows[1].outboundBundles = outduct.stdQueue; outflows[2].outboundBundles = outduct.urgentQueue; for (i = 0; i < 3; i++) { outflows[i].svcFactor = 1 << i; } /* Can now begin transmitting to clients. */ while (!(sm_SemEnded(parms->vduct->semaphore))) { if (bpDequeue(parms->vduct, outflows, &bundleZco, &extendedCOS, destDuctName, 0, -1) < 0) { break; } if (bundleZco == 0) /* Interrupted. */ { continue; } CHKNULL(sdr_begin_xn(sdr)); bundleLength = zco_length(sdr, bundleZco); sdr_exit_xn(sdr); ductNbr = atoi(destDuctName); if (ductNbr >= parms->baseDuctNbr && ductNbr <= parms->lastDuctNbr && parms->brsSockets[(i = ductNbr - parms->baseDuctNbr)] != -1) { bytesSent = sendBundleByTCP(NULL, parms->brsSockets + i, bundleLength, bundleZco, buffer); /* Note that TCP I/O errors never block * the brsscla induct's output functions; * those functions never connect to remote * sockets and never behave like a TCP * outduct, so the _tcpOutductId table is * never populated. */ if (bytesSent < 0) { putErrmsg("Can't send bundle.", NULL); break; } } else /* Can't send it; try again later? */ { bytesSent = 0; } if (bytesSent < bundleLength) { /* Couldn't send the bundle, so put it * in limbo so we can try again later * -- except that if bundle has already * been destroyed then just lose the ADU. */ CHKNULL(sdr_begin_xn(sdr)); if (retrieveSerializedBundle(bundleZco, &bundleAddr)) { putErrmsg("Can't locate unsent bundle.", NULL); sdr_cancel_xn(sdr); break; } if (bundleAddr == 0) { /* Bundle not found, so we can't * put it in limbo for another * attempt later; discard the ADU. */ zco_destroy(sdr, bundleZco); } else { sdr_stage(sdr, (char *) &bundle, bundleAddr, sizeof(Bundle)); if (bundle.extendedCOS.flags & BP_MINIMUM_LATENCY) { /* We never put critical * bundles into limbo. */ zco_destroy(sdr, bundleZco); } else { if (enqueueToLimbo(&bundle, bundleAddr) < 0) { putErrmsg("Can't save bundle.", NULL); sdr_cancel_xn(sdr); break; } } } if (sdr_end_xn(sdr) < 0) { putErrmsg("Failed handling brss xmit.", NULL); break; } } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } ionKillMainThread(procName); writeMemo("[i] brsscla outduct has ended."); MRELEASE(buffer); return terminateSenderThread(parms); }