static int adjustThrottles() { PsmPartition ionwm = getIonwm(); IonVdb *ionvdb = getIonVdb(); BpVdb *bpvdb = getBpVdb(); PsmAddress elt; VOutduct *outduct; unsigned long nodeNbr; IonNeighbor *neighbor; PsmAddress nextElt; int delta; VInduct *induct; /* Only the LTP induct and outduct throttles can be * dynamically adjusted in response to changes in data * rate between the local node and its neighbors, because * (currently) there is no mechanism for mapping neighbor * node number to duct name for any other CL protocol. * For LTP, duct name is LTP engine number which, by * convention, is identical to BP node number. For all * other CL protocols, duct nominal data rate is initially * set to the protocol's configured nominal data rate and * is never subsequently modified. * * So, first we find the LTP induct if any. */ for (elt = sm_list_first(ionwm, bpvdb->inducts); elt; elt = sm_list_next(ionwm, elt)) { induct = (VInduct *) psp(ionwm, sm_list_data(ionwm, elt)); if (strcmp(induct->protocolName, "ltp") == 0) { break; /* Found the LTP induct. */ } } if (elt == 0) /* No LTP induct; nothing to do. */ { return 0; } /* Now update all LTP outducts, and the induct as well, * inferring the existence of Neighbors in the process. */ for (elt = sm_list_first(ionwm, bpvdb->outducts); elt; elt = sm_list_next(ionwm, elt)) { outduct = (VOutduct *) psp(ionwm, sm_list_data(ionwm, elt)); if (strcmp(outduct->protocolName, "ltp") != 0) { continue; } nodeNbr = atol(outduct->ductName); neighbor = findNeighbor(ionvdb, nodeNbr, &nextElt); if (neighbor == NULL) { neighbor = addNeighbor(ionvdb, nodeNbr, nextElt); if (neighbor == NULL) { putErrmsg("Can't adjust outduct throttle.", NULL); return -1; } } if (neighbor->xmitRate != neighbor->prevXmitRate) { #ifndef ION_NOSTATS if (neighbor->nodeNbr != getOwnNodeNbr()) { /* We report and clear transmission * statistics as necessary. NOTE that * this procedure is based on the * assumption that the local node is * in LTP transmission contact with * AT MOST ONE neighbor at any time. * For more complex topologies it will * need to be redesigned. */ if (neighbor->xmitRate == 0) { /* End of xmit contact. */ reportAllStateStats(); clearAllStateStats(); } else if (neighbor->prevXmitRate == 0) { /* Start of xmit contact. */ reportAllStateStats(); clearAllStateStats(); } } #endif outduct->xmitThrottle.nominalRate = neighbor->xmitRate; neighbor->prevXmitRate = neighbor->xmitRate; } /* Note that the LTP induct is aggregate; the * duct's nominal rate is the sum of the rates * at which all neighbors are expected to be * transmitting to the local node at any given * moment. So we must add the change in rate * for each known neighbor to the aggregate * nominal reception rate for the induct. */ if (neighbor->recvRate != neighbor->prevRecvRate) { #ifndef ION_NOSTATS if (neighbor->nodeNbr != getOwnNodeNbr()) { /* We report and clear reception * statistics as necessary. NOTE that * this procedure is based on the * assumption that the local node is * in LTP reception contact with * AT MOST ONE neighbor at any time. * For more complex topologies it will * need to be redesigned. */ if (neighbor->recvRate == 0) { /* End of recv contact. */ reportAllStateStats(); clearAllStateStats(); } else if (neighbor->prevRecvRate == 0) { /* Start of recv contact. */ reportAllStateStats(); clearAllStateStats(); } } #endif delta = neighbor->recvRate - neighbor->prevRecvRate; induct->acqThrottle.nominalRate += delta; neighbor->prevRecvRate = neighbor->recvRate; } } return 0; }
static void *receivePdus(void *parm) { RxThreadParms *parms = (RxThreadParms *) parm; char ownEid[64]; Sdr sdr; BpDelivery dlv; int contentLength; ZcoReader reader; unsigned char *buffer; buffer = MTAKE(CFDP_MAX_PDU_SIZE); if (buffer == NULL) { putErrmsg("bputa receiver thread can't get buffer.", NULL); parms->running = 0; return NULL; } isprintf(ownEid, sizeof ownEid, "ipn:" UVAST_FIELDSPEC ".%u", getOwnNodeNbr(), CFDP_RECV_SVC_NBR); if (bp_open(ownEid, &(parms->rxSap)) < 0) { MRELEASE(buffer); putErrmsg("CFDP can't open own 'recv' endpoint.", ownEid); parms->running = 0; return NULL; } sdr = bp_get_sdr(); writeMemo("[i] bputa input has started."); while (parms->running) { if (bp_receive(parms->rxSap, &dlv, BP_BLOCKING) < 0) { putErrmsg("bputa bundle reception failed.", NULL); parms->running = 0; continue; } switch (dlv.result) { case BpEndpointStopped: parms->running = 0; break; case BpPayloadPresent: contentLength = zco_source_data_length(sdr, dlv.adu); CHKNULL(sdr_begin_xn(sdr)); zco_start_receiving(dlv.adu, &reader); if (zco_receive_source(sdr, &reader, contentLength, (char *) buffer) < 0) { sdr_cancel_xn(sdr); putErrmsg("bputa can't receive bundle ADU.", itoa(contentLength)); parms->running = 0; continue; } if (sdr_end_xn(sdr) < 0) { putErrmsg("bputa can't handle bundle delivery.", NULL); parms->running = 0; continue; } if (cfdpHandleInboundPdu(buffer, contentLength) < 0) { putErrmsg("bputa can't handle inbound PDU.", NULL); parms->running = 0; } break; default: break; } bp_release_delivery(&dlv, 1); /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } bp_close(parms->rxSap); MRELEASE(buffer); writeMemo("[i] bputa input has stopped."); return NULL; }
int bputa(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 char ownEid[64]; BpSAP txSap; RxThreadParms parms; Sdr sdr; pthread_t rxThread; int haveRxThread = 0; Object pduZco; OutFdu fduBuffer; BpUtParms utParms; uvast destinationNodeNbr; char destEid[64]; char reportToEidBuf[64]; char *reportToEid; Object newBundle; Object pduElt; if (bp_attach() < 0) { putErrmsg("CFDP can't attach to BP.", NULL); return 0; } isprintf(ownEid, sizeof ownEid, "ipn:" UVAST_FIELDSPEC ".%u", getOwnNodeNbr(), CFDP_SEND_SVC_NBR); if (bp_open(ownEid, &txSap) < 0) { putErrmsg("CFDP can't open own 'send' endpoint.", ownEid); return 0; } if (txSap == NULL) { putErrmsg("bputa can't get Bundle Protocol SAP.", NULL); return 0; } if (cfdpAttach() < 0) { bp_close(txSap); putErrmsg("bputa can't attach to CFDP.", NULL); return 0; } sdr = bp_get_sdr(); parms.mainThread = pthread_self(); parms.running = 1; if (pthread_begin(&rxThread, NULL, receivePdus, &parms)) { bp_close(txSap); putSysErrmsg("bputa can't create receiver thread", NULL); return -1; } haveRxThread = 1; writeMemo("[i] bputa is running."); while (parms.running) { /* Get an outbound CFDP PDU for transmission. */ if (cfdpDequeueOutboundPdu(&pduZco, &fduBuffer) < 0) { writeMemo("[?] bputa can't dequeue outbound CFDP PDU; \ terminating."); parms.running = 0; continue; } /* Determine quality of service for transmission. */ if (fduBuffer.utParmsLength == sizeof(BpUtParms)) { memcpy((char *) &utParms, (char *) &fduBuffer.utParms, sizeof(BpUtParms)); } else { memset((char *) &utParms, 0, sizeof(BpUtParms)); utParms.reportToNodeNbr = 0; utParms.lifespan = 86400; /* 1 day. */ utParms.classOfService = BP_STD_PRIORITY; utParms.custodySwitch = NoCustodyRequested; utParms.srrFlags = 0; utParms.ackRequested = 0; utParms.extendedCOS.flowLabel = 0; utParms.extendedCOS.flags = 0; utParms.extendedCOS.ordinal = 0; } cfdp_decompress_number(&destinationNodeNbr, &fduBuffer.destinationEntityNbr); if (destinationNodeNbr == 0) { writeMemo("[?] bputa declining to send to node 0."); continue; } isprintf(destEid, sizeof destEid, "ipn:" UVAST_FIELDSPEC ".%u", destinationNodeNbr, CFDP_RECV_SVC_NBR); if (utParms.reportToNodeNbr == 0) { reportToEid = NULL; } else { isprintf(reportToEidBuf, sizeof reportToEidBuf, "ipn:" UVAST_FIELDSPEC ".%u", utParms.reportToNodeNbr, CFDP_RECV_SVC_NBR); reportToEid = reportToEidBuf; } /* Send PDU in a bundle. */ newBundle = 0; if (bp_send(txSap, destEid, reportToEid, utParms.lifespan, utParms.classOfService, utParms.custodySwitch, utParms.srrFlags, utParms.ackRequested, &utParms.extendedCOS, pduZco, &newBundle) <= 0) { putErrmsg("bputa can't send PDU in bundle; terminated.", NULL); parms.running = 0; } if (newBundle == 0) { continue; /* Must have stopped. */ } /* Enable cancellation of this PDU. */ if (sdr_begin_xn(sdr) == 0) { parms.running = 0; continue; } pduElt = sdr_list_insert_last(sdr, fduBuffer.extantPdus, newBundle); if (pduElt) { bp_track(newBundle, pduElt); } if (sdr_end_xn(sdr) < 0) { putErrmsg("bputa can't track PDU; terminated.", NULL); parms.running = 0; } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); }
static PsmAddress insertCXref(IonCXref *cxref) { PsmPartition ionwm = getIonwm(); IonVdb *vdb = getIonVdb(); IonNode *node; PsmAddress nextElt; PsmAddress cxaddr; Object iondbObj; IonDB iondb; PsmAddress cxelt; PsmAddress addr; IonEvent *event; time_t currentTime = getUTCTime(); /* Load the affected nodes. */ node = findNode(vdb, cxref->toNode, &nextElt); if (node == NULL) { node = addNode(vdb, cxref->toNode); if (node == NULL) { return 0; } } node = findNode(vdb, cxref->fromNode, &nextElt); if (node == NULL) { node = addNode(vdb, cxref->fromNode); if (node == NULL) { return 0; } } /* Construct the contact index entry. */ cxaddr = psm_zalloc(ionwm, sizeof(IonCXref)); if (cxaddr == 0) { return 0; } /* Compute times of relevant events. */ iondbObj = getIonDbObject(); sdr_read(getIonsdr(), (char *) &iondb, iondbObj, sizeof(IonDB)); if (cxref->fromNode == getOwnNodeNbr()) { /* Be a little slow to start transmission, and * a little quick to stop, to ensure that * segments arrive only when neighbor is * expecting them. */ cxref->startXmit = cxref->fromTime + iondb.maxClockError; cxref->stopXmit = cxref->toTime - iondb.maxClockError; } if (cxref->toNode == getOwnNodeNbr()) { /* Be a little slow to resume timers, and a * little quick to suspend them, to minimize the * chance of premature timeout. */ cxref->startFire = cxref->fromTime + iondb.maxClockError; cxref->stopFire = cxref->toTime - iondb.maxClockError; } else /* Not a transmission to the local node. */ { cxref->purgeTime = cxref->toTime; } memcpy((char *) psp(ionwm, cxaddr), (char *) cxref, sizeof(IonCXref)); cxelt = sm_rbt_insert(ionwm, vdb->contactIndex, cxaddr, rfx_order_contacts, cxref); if (cxelt == 0) { psm_free(ionwm, cxaddr); return 0; } /* Insert relevant timeline events. */ if (cxref->startXmit) { addr = psm_zalloc(ionwm, sizeof(IonEvent)); if (addr == 0) { return 0; } event = (IonEvent *) psp(ionwm, addr); event->time = cxref->startXmit; event->type = IonStartXmit; event->ref = cxaddr; if (sm_rbt_insert(ionwm, vdb->timeline, addr, rfx_order_events, event) == 0) { psm_free(ionwm, addr); return 0; } } if (cxref->stopXmit) { addr = psm_zalloc(ionwm, sizeof(IonEvent)); if (addr == 0) { return 0; } event = (IonEvent *) psp(ionwm, addr); event->time = cxref->stopXmit; event->type = IonStopXmit; event->ref = cxaddr; if (sm_rbt_insert(ionwm, vdb->timeline, addr, rfx_order_events, event) == 0) { psm_free(ionwm, addr); return 0; } } if (cxref->startFire) { addr = psm_zalloc(ionwm, sizeof(IonEvent)); if (addr == 0) { return 0; } event = (IonEvent *) psp(ionwm, addr); event->time = cxref->startFire; event->type = IonStartFire; event->ref = cxaddr; if (sm_rbt_insert(ionwm, vdb->timeline, addr, rfx_order_events, event) == 0) { psm_free(ionwm, addr); return 0; } } if (cxref->stopFire) { addr = psm_zalloc(ionwm, sizeof(IonEvent)); if (addr == 0) { return 0; } event = (IonEvent *) psp(ionwm, addr); event->time = cxref->stopFire; event->type = IonStopFire; event->ref = cxaddr; if (sm_rbt_insert(ionwm, vdb->timeline, addr, rfx_order_events, event) == 0) { psm_free(ionwm, addr); return 0; } } if (cxref->purgeTime) { addr = psm_zalloc(ionwm, sizeof(IonEvent)); if (addr == 0) { return 0; } event = (IonEvent *) psp(ionwm, addr); event->time = cxref->purgeTime; event->type = IonPurgeContact; event->ref = cxaddr; if (sm_rbt_insert(ionwm, vdb->timeline, addr, rfx_order_events, event) == 0) { psm_free(ionwm, addr); return 0; } } if (cxref->toTime > currentTime) /* Affects routes. */ { vdb->lastEditTime = currentTime; } return cxaddr; }
static void deleteRange(PsmAddress rxaddr, int conditional) { Sdr sdr = getIonsdr(); PsmPartition ionwm = getIonwm(); IonVdb *vdb = getIonVdb(); time_t currentTime = getUTCTime(); IonRXref *rxref; Object obj; IonEvent event; IonNeighbor *neighbor; PsmAddress nextElt; rxref = (IonRXref *) psp(ionwm, rxaddr); /* Delete range from non-volatile database. */ if (rxref->rangeElt) /* An asserted range. */ { if (conditional) /* Delete only if imputed. */ { return; /* Retain asserted range. */ } /* Unconditional deletion; remove range from DB. */ obj = sdr_list_data(sdr, rxref->rangeElt); sdr_free(sdr, obj); sdr_list_delete(sdr, rxref->rangeElt, NULL, NULL); } /* Delete range events from timeline. */ event.ref = rxaddr; event.time = rxref->fromTime; if (rxref->rangeElt) { event.type = IonStartAssertedRange; } else { event.type = IonStartImputedRange; } sm_rbt_delete(ionwm, vdb->timeline, rfx_order_events, &event, rfx_erase_data, NULL); event.time = rxref->toTime; if (rxref->rangeElt) { event.type = IonStopAssertedRange; } else { event.type = IonStopImputedRange; } sm_rbt_delete(ionwm, vdb->timeline, rfx_order_events, &event, rfx_erase_data, NULL); /* Apply to current state as necessary. */ if (currentTime >= rxref->fromTime && currentTime <= rxref->toTime) { if (rxref->fromNode == getOwnNodeNbr()) { neighbor = findNeighbor(vdb, rxref->toNode, &nextElt); if (neighbor) { neighbor->owltOutbound = 0; } } if (rxref->toNode == getOwnNodeNbr()) { neighbor = findNeighbor(vdb, rxref->fromNode, &nextElt); if (neighbor) { neighbor->owltInbound = 0; } } } /* Delete range from index. */ if (rxref->toTime > currentTime) /* Affects routes. */ { vdb->lastEditTime = currentTime; } sm_rbt_delete(ionwm, vdb->rangeIndex, rfx_order_ranges, rxref, rfx_erase_data, NULL); }
static void *getBundles(void *parm) { RxThreadParms *parms = (RxThreadParms *) parm; char ownEid[64]; Sdr sdr = getIonsdr(); BpDelivery dlv; uvast profNum; Scalar seqNum; char type; unsigned int aduLength; int bytesRemaining; ZcoReader reader; unsigned char *buffer; int bytesToRead; int sdnvLength; unsigned char *cursor; isprintf(ownEid, sizeof ownEid, "ipn:" UVAST_FIELDSPEC ".%d", getOwnNodeNbr(), DTPC_RECV_SVC_NBR); if (bp_open(ownEid, &(parms->rxSap)) < 0) { putErrmsg("DTPC can't open own 'recv' endpoint.", ownEid); parms->running = 0; return NULL; } writeMemo("[i] dtpcd receiver thread has started."); while (parms->running) { if (bp_receive(parms->rxSap, &dlv, BP_BLOCKING) < 0) { putErrmsg("dtpcd bundle reception failed.", NULL); parms->running = 0; continue; } switch (dlv.result) { case BpEndpointStopped: parms->running = 0; break; case BpPayloadPresent: CHKNULL(sdr_begin_xn(sdr)); /* Since the max length of a Sdnv is 10 bytes, * read 21 bytes to be sure that the Profile * and Sequence number Sdnvs plus the type * were read. */ aduLength = zco_source_data_length(sdr, dlv.adu); bytesRemaining = aduLength; if (aduLength < 21) /* Just in case we receive * a very small adu. */ { bytesToRead = aduLength; } else { bytesToRead = 21; } buffer = MTAKE(bytesToRead); if (buffer == NULL) { putErrmsg("Out of memory.",NULL); return NULL; } cursor = buffer; zco_start_receiving(dlv.adu, &reader); if (zco_receive_headers(sdr, &reader, bytesToRead, (char *) buffer) < 0) { putErrmsg("dtpcd can't receive ADU header.", itoa(bytesToRead)); sdr_cancel_xn(sdr); MRELEASE(buffer); parms->running = 0; continue; } type = *cursor; /* Get the type byte. */ cursor++; bytesRemaining--; sdnvLength = decodeSdnv(&profNum, cursor); cursor += sdnvLength; bytesRemaining -= sdnvLength; sdnvLength = sdnvToScalar(&seqNum, cursor); cursor += sdnvLength; bytesRemaining -= sdnvLength; /* Mark remaining bytes as source data. */ zco_delimit_source(sdr, dlv.adu, cursor - buffer, bytesRemaining); zco_strip(sdr, dlv.adu); MRELEASE(buffer); if (sdr_end_xn(sdr) < 0) { putErrmsg("dtpcd can't handle bundle delivery.", NULL); parms->running = 0; continue; } switch (type) { case 0x00: /* Received an adu. */ switch (handleInAdu(sdr, &dlv, profNum, seqNum)) { case -1: putErrmsg("dtpcd can't handle inbound \ adu.", NULL); parms->running = 0; continue; case 1: if (parseInAdus(sdr) < 0) { putErrmsg("dtpcd can't parse \ inbound adus.", NULL); parms->running = 0; continue; } case 0: /* Intentional fall-through to * next case. */ default: if (dlv.ackRequested) { if (sendAck(parms->txSap, profNum, seqNum, &dlv) < 0) { putErrmsg("dtpcd can't \ send ack.", NULL); parms->running = 0; continue; } } break; } break; case 0x01: /* Received an ACK. */ if (handleAck(sdr, &dlv, profNum, seqNum) < 0) { putErrmsg("dtpcd can't handle ACK.", NULL); parms->running = 0; continue; } break; default: writeMemo("[?] Invalid item type. Corrupted \ item?"); break; } default: break; }