static void releaseSdrAcsSignal(Object signalLElt) { Sdr bpSdr = getIonsdr(); Sdr acsSdr = getAcssdr(); Object signalAddr; SdrAcsSignal signal; SdrAcsPendingCust pendingCust; assert(signalLElt != 0); ASSERT_ACSSDR_XN; ASSERT_BPSDR_XN; if (acsSdr == NULL) { putErrmsg("Can't release ACS, SDR not available.", NULL); return; } signalAddr = sdr_list_data(acsSdr, signalLElt); if (signalAddr == 0) { ACSLOG_ERROR("Can't derefence ACS signal to release it."); return; } sdr_peek(acsSdr, signal, signalAddr); sdr_peek(acsSdr, pendingCust, signal.pendingCustAddr); /* Destroy the objects this AcsSignal contains */ sdr_list_destroy(acsSdr, signal.acsFills, releaseSdrAcsFill, NULL); if(signal.acsDue != 0) { destroyBpTimelineEvent(signal.acsDue); } if(signal.serializedZco != 0) { zco_destroy(bpSdr, signal.serializedZco); } /* Destroy this AcsSignal */ sdr_free(acsSdr, signalAddr); sdr_list_delete(acsSdr, signalLElt, NULL, NULL); }
int trySendAcs(SdrAcsPendingCust *custodian, BpCtReason reasonCode, unsigned char succeeded, const CtebScratchpad *cteb) { Object signalLElt; Object signalAddr; SdrAcsSignal signal; BpEvent timelineEvent; Object newSerializedZco; unsigned long newSerializedLength; int result; Sdr bpSdr = getIonsdr(); /* To prevent deadlock, take bpSdr before acsSdr. */ CHKERR(sdr_begin_xn(bpSdr)); CHKERR(sdr_begin_xn(acsSdr)); signalLElt = findSdrAcsSignal(custodian->signals, reasonCode, succeeded, &signalAddr); if (signalAddr == 0) { ACSLOG_ERROR("Can't find ACS signal"); sdr_exit_xn(acsSdr); sdr_exit_xn(bpSdr); return -1; } sdr_peek(acsSdr, signal, signalAddr); newSerializedLength = serializeAcs(signalAddr, &newSerializedZco, signal.serializedZcoLength); if (newSerializedLength == 0) { ACSLOG_ERROR("Can't serialize new ACS (%lu)", signal.serializedZcoLength); sdr_cancel_xn(acsSdr); sdr_cancel_xn(bpSdr); return -1; } ACSLOG_DEBUG("Serialized a new ACS to %s that is %lu long (old: %lu)", custodian->eid, newSerializedLength, signal.serializedZcoLength); /* If serializeAcs() (which serializes an ACS that covers all the "old" * custody IDs as well as 1 "new" custody ID that we're trying to append) * returned an ACS that's larger than the custodian' preferred size, then: * 1) Send the old ACS (the biggest ACS that's smaller than custodian's * preferred size), covering all the old custody IDs but not the new * one. * 2) Make a new ACS that includes only the new custody ID. */ if (custodian->acsSize > 0 && newSerializedLength >= custodian->acsSize) { if(signal.serializedZco == 0) { /* We don't have an old unserialized ACS to send. This means the * first custody signal appended to this ACS exceeded the acsSize * parameter. The best we can do is send this ACS even though it's * bigger than the recommended acsSize. */ ACSLOG_WARN("Appending first CS to %s was bigger than %lu", custodian->eid, custodian->acsSize); signal.serializedZcoLength = newSerializedLength; signal.serializedZco = newSerializedZco; sdr_poke(acsSdr, signalAddr, signal); sendAcs(signalLElt); if(sdr_end_xn(acsSdr) < 0) { ACSLOG_ERROR("Can't serialize ACS bundle."); sdr_cancel_xn(bpSdr); return -1; } if (sdr_end_xn(bpSdr) < 0) { ACSLOG_ERROR("Can't send ACS bundle."); return -1; } return 0; } /* Calling this invalidates our signalLElt and signalAddr pointers, so * we must re-find the signal before using them again. */ sendAcs(signalLElt); /* Add the one that was uncovered by the serialized payload back in */ result = appendToSdrAcsSignals(custodian->signals, signal.pendingCustAddr, reasonCode, succeeded, cteb); switch (result) { case 0: /* Success; continue processing. */ break; default: ACSLOG_ERROR("Can't carry size-limited ID to new ACS"); sdr_cancel_xn(acsSdr); sdr_cancel_xn(bpSdr); return -1; } /* Find the uncovered one that we just added. */ signalLElt = findSdrAcsSignal(custodian->signals, reasonCode, succeeded, &signalAddr); if (signalAddr == 0) { ACSLOG_ERROR("Can't find ACS signal"); sdr_cancel_xn(acsSdr); sdr_cancel_xn(bpSdr); return -1; } sdr_peek(acsSdr, signal, signalAddr); /* Serialize the new one */ newSerializedLength = serializeAcs(signalAddr, &newSerializedZco, 0); if (newSerializedLength <= 0) { ACSLOG_ERROR("Can't serialize new ACS (%lu)", newSerializedLength); sdr_cancel_xn(acsSdr); sdr_cancel_xn(bpSdr); return -1; } } else { if (signal.serializedZco != 0) { /* Free the old payload zco. */ zco_destroy(bpSdr, signal.serializedZco); } } /* Store the new ZCO */ signal.serializedZco = newSerializedZco; signal.serializedZcoLength = newSerializedLength; /* If there is not an ACS generation countdown timer, create one. */ if(signal.acsDue == 0) { timelineEvent.type = csDue; if(custodian->acsDelay == 0) { timelineEvent.time = getUTCTime() + DEFAULT_ACS_DELAY; } else { timelineEvent.time = getUTCTime() + custodian->acsDelay; } timelineEvent.ref = signalLElt; signal.acsDue = insertBpTimelineEvent(&timelineEvent); if (signal.acsDue == 0) { ACSLOG_ERROR("Can't add timeline event to generate ACS"); sdr_cancel_xn(acsSdr); sdr_cancel_xn(bpSdr); return -1; } } sdr_poke(acsSdr, signalAddr, signal); if(sdr_end_xn(acsSdr) < 0) { ACSLOG_ERROR("Can't track ACS"); sdr_cancel_xn(bpSdr); return -1; } if (sdr_end_xn(bpSdr) < 0) { ACSLOG_ERROR("Can't add timeline event to generate ACS"); return -1; } return 0; }
int sendAcs(Object signalLElt) { BpExtendedCOS ecos = { 0, 0, 255 }; Object signalAddr; Object acsBundleObj; /* Unused write-out of bpSend */ SdrAcsSignal signal; SdrAcsPendingCust pendingCust; int result; Sdr bpSdr = getIonsdr(); assert(signalLElt != 0); if ((acsSdr = getAcssdr()) == NULL) { putErrmsg("Can't send ACS, SDR not available.", NULL); return -1; } /* To prevent deadlock, we take the BP SDR before the ACS SDR. */ CHKERR(sdr_begin_xn(bpSdr)); CHKERR(sdr_begin_xn(acsSdr)); signalAddr = sdr_list_data(acsSdr, signalLElt); if (signalAddr == 0) { ACSLOG_ERROR("Can't derefence ACS signal to send it."); sdr_cancel_xn(acsSdr); sdr_cancel_xn(bpSdr); return -1; } sdr_peek(acsSdr, signal, signalAddr); sdr_peek(acsSdr, pendingCust, signal.pendingCustAddr); /* Remove ref to this serialized ZCO from signal; also remove the bundle * IDs covered by this serialized ZCO. */ result = bpSend(NULL, pendingCust.eid, NULL, ACS_TTL, BP_EXPEDITED_PRIORITY, NoCustodyRequested, 0, 0, &ecos, signal.serializedZco, &acsBundleObj, BP_CUSTODY_SIGNAL); switch (result) { /* All return codes from bpSend() still cause us to continue processing * to free this ACS. If it was sent successfully, good. If it wasn't, * that's due to a system failure or problem with this ACS, so the best * we can do is delete it from our node without sending. */ case -1: ACSLOG_ERROR("Can't send custody transfer signal."); zco_destroy(bpSdr, signal.serializedZco); break; case 0: ACSLOG_ERROR("Custody transfer signal not transmitted."); zco_destroy(bpSdr, signal.serializedZco); break; default: /* bpSend() gave the serializedZco to a forwarder, so don't * zco_destroy(). */ break; } if (signal.acsDue != 0) { destroyBpTimelineEvent(signal.acsDue); } signal.acsDue = 0; signal.serializedZco = 0; sdr_poke(acsSdr, signalAddr, signal); releaseSdrAcsSignal(signalLElt); if (sdr_end_xn(acsSdr) < 0) { ACSLOG_ERROR("Couldn't mark a serialized ACS as sent."); sdr_cancel_xn(bpSdr); return -1; } if(sdr_end_xn(bpSdr) < 0) { return -1; } return result > 0 ? 0 : -1; }
static void *handleNotices(void *parm) { /* Main loop for LTP notice reception and handling. */ Sdr sdr = getIonsdr(); ReceiverThreadParms *rtp = (ReceiverThreadParms *) parm; char *procName = "ltpcli"; AcqWorkArea *redWork; AcqWorkArea *greenWork; LtpNoticeType type; LtpSessionId sessionId; unsigned char reasonCode; unsigned char endOfBlock; unsigned int dataOffset; unsigned int dataLength; Object data; /* ZCO reference. */ unsigned int greenBuflen = 0; char *greenBuffer = NULL; snooze(1); /* Let main thread become interruptable. */ if (ltp_open(BpLtpClientId) < 0) { putErrmsg("ltpcli can't open client access.", itoa(BpLtpClientId)); ionKillMainThread(procName); return NULL; } redWork = bpGetAcqArea(rtp->vduct); greenWork = bpGetAcqArea(rtp->vduct); if (redWork == NULL || greenWork == NULL) { ltp_close(BpLtpClientId); putErrmsg("ltpcli can't get acquisition work areas", NULL); ionKillMainThread(procName); return NULL; } /* Can now start receiving notices. On failure, take * down the CLI. */ while (rtp->running) { if (ltp_get_notice(BpLtpClientId, &type, &sessionId, &reasonCode, &endOfBlock, &dataOffset, &dataLength, &data) < 0) { putErrmsg("Can't get LTP notice.", NULL); ionKillMainThread(procName); rtp->running = 0; continue; } switch (type) { case LtpExportSessionComplete: /* Xmit success. */ if (data == 0) /* Ignore it. */ { break; /* Out of switch. */ } if (bpHandleXmitSuccess(data, 0) < 0) { putErrmsg("Crashed on xmit success.", NULL); ionKillMainThread(procName); rtp->running = 0; break; /* Out of switch. */ } CHKNULL(sdr_begin_xn(sdr)); zco_destroy(sdr, data); if (sdr_end_xn(sdr) < 0) { putErrmsg("Crashed on data cleanup.", NULL); ionKillMainThread(procName); rtp->running = 0; } break; /* Out of switch. */ case LtpExportSessionCanceled: /* Xmit failure. */ if (data == 0) /* Ignore it. */ { break; /* Out of switch. */ } if (bpHandleXmitFailure(data) < 0) { putErrmsg("Crashed on xmit failure.", NULL); ionKillMainThread(procName); rtp->running = 0; break; /* Out of switch. */ } CHKNULL(sdr_begin_xn(sdr)); zco_destroy(sdr, data); if (sdr_end_xn(sdr) < 0) { putErrmsg("Crashed on data cleanup.", NULL); ionKillMainThread(procName); rtp->running = 0; } break; /* Out of switch. */ case LtpImportSessionCanceled: /* None of the red data for the import * session (if any) have been received * yet, so nothing to discard. In case * part or all of the import session was * green data, force deletion of retained * data. */ sessionId.sourceEngineId = 0; sessionId.sessionNbr = 0; if (handleGreenSegment(greenWork, &sessionId, 0, 0, 0, 0, NULL, NULL) < 0) { putErrmsg("Can't cancel green session.", NULL); ionKillMainThread(procName); rtp->running = 0; } break; /* Out of switch. */ case LtpRecvRedPart: if (!endOfBlock) { /* Block is partially red and * partially green. Too risky * to wait for green EOB before * clearing the work area, so * just discard the data. */ CHKNULL(sdr_begin_xn(sdr)); zco_destroy(sdr, data); if (sdr_end_xn(sdr) < 0) { putErrmsg("Crashed: partially red.", NULL); ionKillMainThread(procName); rtp->running = 0; } break; /* Out of switch. */ } if (acquireRedBundles(redWork, data, sessionId.sourceEngineId) < 0) { putErrmsg("Can't acquire bundle(s).", NULL); ionKillMainThread(procName); rtp->running = 0; } break; /* Out of switch. */ case LtpRecvGreenSegment: if (handleGreenSegment(greenWork, &sessionId, endOfBlock, dataOffset, dataLength, data, &greenBuflen, &greenBuffer) < 0) { putErrmsg("Can't handle green segment.", NULL); ionKillMainThread(procName); rtp->running = 0; } /* Discard the ZCO in any case. */ CHKNULL(sdr_begin_xn(sdr)); zco_destroy(sdr, data); if (sdr_end_xn(sdr) < 0) { putErrmsg("Crashed: green segment.", NULL); ionKillMainThread(procName); rtp->running = 0; } break; /* Out of switch. */ default: break; /* Out of switch. */ } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } writeErrmsgMemos(); writeMemo("[i] ltpcli receiver thread has ended."); /* Free resources. */ if (greenBuffer) { MRELEASE(greenBuffer); } bpReleaseAcqArea(greenWork); bpReleaseAcqArea(redWork); ltp_close(BpLtpClientId); return NULL; }
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); }
static void *sendItems(void *parm) { SenderThreadParms *stp = (SenderThreadParms *) parm; Sdr sdr; char buffer[MAX_LINE_LEN + 1]; int length; Object extent; Object item = 0; snooze(3); /* Let sda_run get started. */ sdr = getIonsdr(); while (stp->running) { if (fgets(buffer, MAX_LINE_LEN, stdin) == NULL) { sda_interrupt(); stp->running = 0; continue; /* End of file, and test. */ } length = istrlen(buffer, MAX_LINE_LEN) + 1; /* Send NULL-terminated text line as an SDA item. */ CHKNULL(sdr_begin_xn(sdr)); extent = sdr_insert(sdr, buffer, length); if (extent) { item = ionCreateZco(ZcoSdrSource, extent, 0, length, 0, 0, ZcoOutbound, NULL); } if (sdr_end_xn(sdr) < 0 || item == 0 || item == (Object) ERROR) { putErrmsg("Service data item insertion failed.", NULL); sda_interrupt(); stp->running = 0; continue; } if (sda_send(stp->destEngineId, SDA_TEST_CLIENT, item) < 0) { putErrmsg("Service data item sending failed.", NULL); sda_interrupt(); stp->running = 0; continue; } CHKNULL(sdr_begin_xn(sdr)); zco_destroy(sdr, item); if (sdr_end_xn(sdr) < 0) { putErrmsg("Service data item deletion failed.", NULL); sda_interrupt(); stp->running = 0; continue; } } writeErrmsgMemos(); writeMemo("[i] sdatest sender thread has ended."); return NULL; }
int bsspclo(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10) { char *ductName = (char *) a1; #else int main(int argc, char *argv[]) { char *ductName = (argc > 1 ? argv[1] : NULL); #endif Sdr sdr; VOutduct *vduct; PsmAddress vductElt; vast destEngineNbr; Outduct outduct; ClProtocol protocol; Outflow outflows[3]; int i; int running = 1; Object bundleZco; BpExtendedCOS extendedCOS; char destDuctName[MAX_CL_DUCT_NAME_LEN + 1]; BsspSessionId sessionId; unsigned char *buffer; Lyst streams; Bundle bundleImage; char *dictionary = 0; unsigned int bundleLength; if (ductName == NULL) { PUTS("Usage: bsspclo [-]<destination engine number>"); return 0; } if (bpAttach() < 0) { putErrmsg("bsspclo can't attach to BP.", NULL); return -1; } sdr = getIonsdr(); findOutduct("bssp", ductName, &vduct, &vductElt); if (vductElt == 0) { putErrmsg("No such bssp duct.", ductName); return -1; } if (vduct->cloPid != ERROR && vduct->cloPid != sm_TaskIdSelf()) { putErrmsg("BSSPCLO task is already started for this duct.", itoa(vduct->cloPid)); return -1; } /* All command-line arguments are now validated. */ buffer = (unsigned char *) MTAKE(BP_MAX_BLOCK_SIZE); if (buffer == NULL) { putErrmsg("Can't get buffer for decoding bundle ZCOs.", NULL); return -1; } streams = lyst_create_using(getIonMemoryMgr()); if (streams == NULL) { putErrmsg("Can't create lyst of streams.", NULL); MRELEASE(buffer); return -1; } lyst_delete_set(streams, eraseStream, NULL); CHKERR(sdr_begin_xn(sdr)); sdr_read(sdr, (char *) &outduct, sdr_list_data(sdr, vduct->outductElt), sizeof(Outduct)); sdr_read(sdr, (char *) &protocol, outduct.protocol, sizeof(ClProtocol)); sdr_exit_xn(sdr); destEngineNbr = strtovast(ductName); if (protocol.nominalRate == 0) { vduct->xmitThrottle.nominalRate = DEFAULT_BSSP_RATE; } else { vduct->xmitThrottle.nominalRate = protocol.nominalRate; } 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; } if (bssp_attach() < 0) { putErrmsg("bsspclo can't initialize BSSP.", NULL); lyst_destroy(streams); MRELEASE(buffer); return -1; } /* Set up signal handling. SIGTERM is shutdown signal. */ oK(bsspcloSemaphore(&(vduct->semaphore))); isignal(SIGTERM, shutDownClo); /* Can now begin transmitting to remote duct. */ writeMemo("[i] bsspclo is running."); while (running && !(sm_SemEnded(bsspcloSemaphore(NULL)))) { if (bpDequeue(vduct, outflows, &bundleZco, &extendedCOS, destDuctName, 0, -1) < 0) { running = 0; /* Terminate CLO. */ continue; } if (bundleZco == 0) /* Interrupted. */ { continue; } if (decodeBundle(sdr, bundleZco, buffer, &bundleImage, &dictionary, &bundleLength) < 0) { putErrmsg("Can't decode bundle ZCO.", NULL); CHKERR(sdr_begin_xn(sdr)); zco_destroy(sdr, bundleZco); if (sdr_end_xn(sdr) < 0) { putErrmsg("Failed destroying ZCO.", NULL); break; } continue; } switch (bssp_send(destEngineNbr, BpBsspClientId, bundleZco, isInOrder(streams, &bundleImage), &sessionId)) { case 0: putErrmsg("Unable to send this bundle via BSSP.", NULL); break; case -1: putErrmsg("BsspSend failed.", NULL); running = 0; /* Terminate CLO. */ } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); /* Note: bundleZco is destroyed later, when BSSP's * ExportSession is closed following transmission * of bundle ZCOs as aggregated into a block. */ } writeErrmsgMemos(); writeMemo("[i] bsspclo duct has ended."); lyst_destroy(streams); MRELEASE(buffer); ionDetach(); return 0; }