static void *handleMessages(void *parm) { /* Main loop for message reception and handling. */ ReceiverThreadParms *rtp = (ReceiverThreadParms *) parm; int segLength; char msgbuf[PMQLSA_MSGSIZE]; unsigned int mqp; /* Priority of rec'd msg. */ iblock(SIGTERM); while (rtp->running) { segLength = mq_receive(rtp->mq, msgbuf, sizeof msgbuf, &mqp); switch (segLength) { case 1: /* Normal stop. */ continue; case -1: putSysErrmsg("pmqlsi failed receiving msg", NULL); pthread_kill(rtp->mainThread, SIGTERM); rtp->running = 0; continue; } if (ltpHandleInboundSegment(msgbuf, segLength) < 0) { putErrmsg("Can't handle inbound segment.", NULL); pthread_kill(rtp->mainThread, SIGTERM); rtp->running = 0; continue; } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } writeErrmsgMemos(); writeMemo("[i] pmqlsi receiver thread has ended."); return NULL; }
int tcpclo(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 unsigned char *buffer; VOutduct *vduct; PsmAddress vductElt; Sdr sdr; Outduct duct; ClProtocol protocol; Outflow outflows[3]; int i; char *hostName; unsigned short portNbr; unsigned int hostNbr; struct sockaddr socketName; struct sockaddr_in *inetName; int running = 1; pthread_mutex_t mutex; KeepaliveThreadParms parms; ReceiveThreadParms rparms; pthread_t keepaliveThread; pthread_t receiverThread; Object bundleZco; BpExtendedCOS extendedCOS; char destDuctName[MAX_CL_DUCT_NAME_LEN + 1]; unsigned int bundleLength; int ductSocket = -1; int bytesSent; int keepalivePeriod = 0; VInduct *viduct; if (ductName == NULL) { PUTS("Usage: tcpclo <remote host name>[:<port number>]"); return 0; } if (bpAttach() < 0) { putErrmsg("tcpclo can't attach to BP", NULL); return 1; } buffer = MTAKE(TCPCLA_BUFSZ); if (buffer == NULL) { putErrmsg("No memory for TCP buffer in tcpclo.", NULL); return 1; } findOutduct("tcp", ductName, &vduct, &vductElt); if (vductElt == 0) { putErrmsg("No such tcp duct.", ductName); MRELEASE(buffer); return 1; } if (vduct->cloPid != ERROR && vduct->cloPid != sm_TaskIdSelf()) { putErrmsg("CLO task is already started for this duct.", itoa(vduct->cloPid)); MRELEASE(buffer); return 1; } /* All command-line arguments are now validated. */ sdr = getIonsdr(); CHKERR(sdr_begin_xn(sdr)); sdr_read(sdr, (char *) &duct, sdr_list_data(sdr, vduct->outductElt), sizeof(Outduct)); sdr_read(sdr, (char *) &protocol, duct.protocol, sizeof(ClProtocol)); sdr_exit_xn(sdr); if (protocol.nominalRate == 0) { vduct->xmitThrottle.nominalRate = DEFAULT_TCP_RATE; } else { vduct->xmitThrottle.nominalRate = protocol.nominalRate; } memset((char *) outflows, 0, sizeof outflows); outflows[0].outboundBundles = duct.bulkQueue; outflows[1].outboundBundles = duct.stdQueue; outflows[2].outboundBundles = duct.urgentQueue; for (i = 0; i < 3; i++) { outflows[i].svcFactor = 1 << i; } hostName = ductName; parseSocketSpec(ductName, &portNbr, &hostNbr); if (portNbr == 0) { portNbr = BpTcpDefaultPortNbr; } portNbr = htons(portNbr); if (hostNbr == 0) { putErrmsg("Can't get IP address for host.", hostName); MRELEASE(buffer); return 1; } hostNbr = htonl(hostNbr); memset((char *) &socketName, 0, sizeof socketName); inetName = (struct sockaddr_in *) &socketName; inetName->sin_family = AF_INET; inetName->sin_port = portNbr; memcpy((char *) &(inetName->sin_addr.s_addr), (char *) &hostNbr, 4); if (_tcpOutductId(&socketName, "tcp", ductName) < 0) { putErrmsg("Can't record TCP Outduct ID for connection.", NULL); MRELEASE(buffer); return -1; } /* Set up signal handling. SIGTERM is shutdown signal. */ oK(tcpcloSemaphore(&(vduct->semaphore))); isignal(SIGTERM, shutDownClo); #ifndef mingw isignal(SIGPIPE, handleConnectionLoss); #endif /* Start the keepalive thread for the eventual connection. */ tcpDesiredKeepAlivePeriod = KEEPALIVE_PERIOD; parms.cloRunning = &running; pthread_mutex_init(&mutex, NULL); parms.mutex = &mutex; parms.socketName = &socketName; parms.ductSocket = &ductSocket; parms.keepalivePeriod = &keepalivePeriod; if (pthread_begin(&keepaliveThread, NULL, sendKeepalives, &parms)) { putSysErrmsg("tcpclo can't create keepalive thread", NULL); MRELEASE(buffer); pthread_mutex_destroy(&mutex); return 1; } // Returns the VInduct Object of first induct with same protocol // as the outduct. The VInduct is required to create an acq area. // The Acq Area inturn uses the throttle information from VInduct // object while receiving bundles. The throttle information // of all inducts of the same induct will be the same, so choosing // any induct will serve the purpose. findVInduct(&viduct,protocol.name); if(viduct == NULL) { putErrmsg("tcpclo can't get VInduct", NULL); MRELEASE(buffer); pthread_mutex_destroy(&mutex); return 1; } rparms.vduct = viduct; rparms.bundleSocket = &ductSocket; rparms.mutex = &mutex; rparms.cloRunning = &running; if (pthread_begin(&receiverThread, NULL, receiveBundles, &rparms)) { putSysErrmsg("tcpclo can't create receive thread", NULL); MRELEASE(buffer); pthread_mutex_destroy(&mutex); return 1; } /* Can now begin transmitting to remote duct. */ { char txt[500]; isprintf(txt, sizeof(txt), "[i] tcpclo is running, spec=[%s:%d].", inet_ntoa(inetName->sin_addr), ntohs(inetName->sin_port)); writeMemo(txt); } while (running && !(sm_SemEnded(tcpcloSemaphore(NULL)))) { if (bpDequeue(vduct, outflows, &bundleZco, &extendedCOS, destDuctName, 0, -1) < 0) { running = 0; /* Terminate CLO. */ continue; } if (bundleZco == 0) /* Interrupted. */ { continue; } CHKZERO(sdr_begin_xn(sdr)); bundleLength = zco_length(sdr, bundleZco); sdr_exit_xn(sdr); pthread_mutex_lock(&mutex); bytesSent = sendBundleByTCPCL(&socketName, &ductSocket, bundleLength, bundleZco, buffer, &keepalivePeriod); pthread_mutex_unlock(&mutex); if(bytesSent < 0) { running = 0; /* Terminate CLO. */ } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } writeMemo("[i] tcpclo done sending"); if (sendShutDownMessage(&ductSocket, SHUT_DN_NO, -1, &socketName) < 0) { putErrmsg("Sending Shutdown message failed!!",NULL); } if (ductSocket != -1) { closesocket(ductSocket); ductSocket=-1; } running = 0; pthread_join(keepaliveThread, NULL); writeMemo("[i] tcpclo keepalive thread killed"); pthread_join(receiverThread, NULL); writeMemo("[i] tcpclo receiver thread killed"); writeErrmsgMemos(); writeMemo("[i] tcpclo duct has ended."); oK(_tcpOutductId(&socketName, NULL, NULL)); MRELEASE(buffer); pthread_mutex_destroy(&mutex); bp_detach(); return 0; }
static void *receiveBundles(void *parm) { /* Main loop for bundle reception thread */ ReceiveThreadParms *parms = (ReceiveThreadParms *) parm; int threadRunning = 1; AcqWorkArea *work; char *buffer; buffer = MTAKE(TCPCLA_BUFSZ); if (buffer == NULL) { putErrmsg("tcpclo receiver can't get TCP buffer", NULL); return NULL; } work = bpGetAcqArea(parms->vduct); if (work == NULL) { putErrmsg("tcpclo receiver can't get acquisition work area", NULL); MRELEASE(buffer); return NULL; } iblock(SIGTERM); while (threadRunning && *(parms->cloRunning)) { if(*(parms->bundleSocket) < 0) { snooze(1); /*Retry later*/ continue; } if (bpBeginAcq(work, 0, NULL) < 0) { putErrmsg("Can't begin acquisition of bundle.", NULL); threadRunning = 0; continue; } switch (receiveBundleByTcpCL(*(parms->bundleSocket), work, buffer)) { case -1: putErrmsg("Can't acquire bundle.", NULL); pthread_mutex_lock(parms->mutex); closesocket(*(parms->bundleSocket)); *(parms->bundleSocket) = -1; pthread_mutex_unlock(parms->mutex); continue; case 0: /* Shutdown message */ /* Go back to the start of the while loop */ pthread_mutex_lock(parms->mutex); closesocket(*(parms->bundleSocket)); *(parms->bundleSocket) = -1; pthread_mutex_unlock(parms->mutex); continue; default: break; /* Out of switch. */ } if (bpEndAcq(work) < 0) { putErrmsg("Can't end acquisition of bundle.", NULL); threadRunning = 0; } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } /* End of receiver thread; release resources. */ bpReleaseAcqArea(work); MRELEASE(buffer); return NULL; }
static void *handleDatagrams(void *parm) { /* Main loop for UDP datagram reception and handling. */ ReceiverThreadParms *rtp = (ReceiverThreadParms *) parm; char *procName = "udplsi"; char *buffer; int segmentLength; struct sockaddr_in fromAddr; socklen_t fromSize; snooze(1); /* Let main thread become interruptable. */ buffer = MTAKE(UDPLSA_BUFSZ); if (buffer == NULL) { putErrmsg("udplsi can't get UDP buffer.", NULL); ionKillMainThread(procName); return NULL; } /* Can now start receiving bundles. On failure, take * down the LSI. */ while (rtp->running) { fromSize = sizeof fromAddr; segmentLength = irecvfrom(rtp->linkSocket, buffer, UDPLSA_BUFSZ, 0, (struct sockaddr *) &fromAddr, &fromSize); switch (segmentLength) { case -1: putSysErrmsg("Can't acquire segment", NULL); ionKillMainThread(procName); /* Intentional fall-through to next case. */ case 1: /* Normal stop. */ rtp->running = 0; continue; } if (ltpHandleInboundSegment(buffer, segmentLength) < 0) { putErrmsg("Can't handle inbound segment.", NULL); ionKillMainThread(procName); rtp->running = 0; continue; } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } writeErrmsgMemos(); writeMemo("[i] udplsi receiver thread has ended."); /* Free resources. */ MRELEASE(buffer); return NULL; }
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; }
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 *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; }
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); }
int stcpclo(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 unsigned char *buffer; VOutduct *vduct; PsmAddress vductElt; Sdr sdr; Outduct duct; ClProtocol protocol; Outflow outflows[3]; int i; char *hostName; unsigned short portNbr; unsigned int hostNbr; struct sockaddr socketName; struct sockaddr_in *inetName; int running = 1; pthread_mutex_t mutex; KeepaliveThreadParms parms; pthread_t keepaliveThread; Object bundleZco; BpExtendedCOS extendedCOS; char destDuctName[MAX_CL_DUCT_NAME_LEN + 1]; unsigned int bundleLength; int ductSocket = -1; int bytesSent; if (ductName == NULL) { PUTS("Usage: stcpclo <remote host name>[:<port number>]"); return 0; } if (bpAttach() < 0) { putErrmsg("stcpclo can't attach to BP.", NULL); return -1; } buffer = MTAKE(TCPCLA_BUFSZ); if (buffer == NULL) { putErrmsg("No memory for TCP buffer in stcpclo.", NULL); return -1; } findOutduct("stcp", ductName, &vduct, &vductElt); if (vductElt == 0) { putErrmsg("No such stcp duct.", ductName); MRELEASE(buffer); return -1; } if (vduct->cloPid > 0 && vduct->cloPid != sm_TaskIdSelf()) { putErrmsg("CLO task is already started for this duct.", itoa(vduct->cloPid)); MRELEASE(buffer); return -1; } /* All command-line arguments are now validated. */ sdr = getIonsdr(); sdr_read(sdr, (char *) &duct, sdr_list_data(sdr, vduct->outductElt), sizeof(Outduct)); sdr_read(sdr, (char *) &protocol, duct.protocol, sizeof(ClProtocol)); if (protocol.nominalRate <= 0) { vduct->xmitThrottle.nominalRate = DEFAULT_TCP_RATE; } else { vduct->xmitThrottle.nominalRate = protocol.nominalRate; } memset((char *) outflows, 0, sizeof outflows); outflows[0].outboundBundles = duct.bulkQueue; outflows[1].outboundBundles = duct.stdQueue; outflows[2].outboundBundles = duct.urgentQueue; for (i = 0; i < 3; i++) { outflows[i].svcFactor = 1 << i; } hostName = ductName; parseSocketSpec(ductName, &portNbr, &hostNbr); if (portNbr == 0) { portNbr = BpTcpDefaultPortNbr; } portNbr = htons(portNbr); if (hostNbr == 0) { putErrmsg("Can't get IP address for host.", hostName); MRELEASE(buffer); return -1; } hostNbr = htonl(hostNbr); memset((char *) &socketName, 0, sizeof socketName); inetName = (struct sockaddr_in *) &socketName; inetName->sin_family = AF_INET; inetName->sin_port = portNbr; memcpy((char *) &(inetName->sin_addr.s_addr), (char *) &hostNbr, 4); /* Set up signal handling. SIGTERM is shutdown signal. */ oK(stcpcloSemaphore(&(vduct->semaphore))); isignal(SIGTERM, shutDownClo); isignal(SIGPIPE, handleConnectionLoss); /* Start the keepalive thread for the eventual connection. */ parms.cloRunning = &running; pthread_mutex_init(&mutex, NULL); parms.mutex = &mutex; parms.socketName = &socketName; parms.ductSocket = &ductSocket; if (pthread_create(&keepaliveThread, NULL, sendKeepalives, &parms)) { putSysErrmsg("stcpclo can't create keepalive thread", NULL); MRELEASE(buffer); pthread_mutex_destroy(&mutex); return 1; } /* Can now begin transmitting to remote duct. */ writeMemo("[i] stcpclo is running."); while (!(sm_SemEnded(stcpcloSemaphore(NULL)))) { if (bpDequeue(vduct, outflows, &bundleZco, &extendedCOS, destDuctName) < 0) { sm_SemEnd(stcpcloSemaphore(NULL));/* Stop. */ continue; } if (bundleZco == 0) /* Interrupted. */ { continue; } bundleLength = zco_length(sdr, bundleZco); pthread_mutex_lock(&mutex); bytesSent = sendBundleByTCP(&socketName, &ductSocket, bundleLength, bundleZco, buffer); pthread_mutex_unlock(&mutex); if (bytesSent < bundleLength) { sm_SemEnd(stcpcloSemaphore(NULL));/* Stop. */ continue; } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } running = 0; /* Terminate keepalive. */ pthread_join(keepaliveThread, NULL); if (ductSocket != -1) { close(ductSocket); } pthread_mutex_destroy(&mutex); writeErrmsgMemos(); writeMemo("[i] stcpclo duct has ended."); MRELEASE(buffer); ionDetach(); return 0; }
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 void *sendBundles(void *parm) { /* Main loop for single bundle transmission thread * serving all BRS sockets. */ SenderThreadParms *parms = (SenderThreadParms *) parm; 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; int failedTransmissions = 0; buffer = MTAKE(TCPCLA_BUFSZ); if (buffer == NULL) { putErrmsg("No memory for TCP buffer in brsscla.", NULL); return terminateSenderThread(parms); } sdr = getIonsdr(); sdr_read(sdr, (char *) &outduct, sdr_list_data(sdr, parms->vduct->outductElt), sizeof(Outduct)); 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. */ iblock(SIGTERM); while (!(sm_SemEnded(parms->vduct->semaphore))) { if (bpDequeue(parms->vduct, outflows, &bundleZco, &extendedCOS, destDuctName) < 0) { break; } if (bundleZco == 0) /* Interrupted. */ { continue; } bundleLength = zco_length(sdr, bundleZco); 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); if (bytesSent < 0) { putErrmsg("Can't send bundle.", NULL); break; } if (bytesSent < bundleLength) { failedTransmissions++; } } else /* Can't send it; just discard it. */ { sdr_begin_xn(sdr); zco_destroy_reference(sdr, bundleZco); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't destroy ZCO reference.", NULL); break; } } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } pthread_kill(brssclaMainThread(0), SIGTERM); writeMemoNote("[i] brsscla outduct has ended", itoa(failedTransmissions)); MRELEASE(buffer); return terminateSenderThread(parms); }
int pmqlso(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10) { char *mqName = (char *) a1; uvast remoteEngineId = a2 != 0 ? strtouvast((char *) a2) : 0; #else int main(int argc, char *argv[]) { char *mqName = argc > 1 ? argv[1] : NULL; uvast remoteEngineId = argc > 2 ? strtouvast(argv[2]) : 0; #endif Sdr sdr; LtpVspan *vspan; PsmAddress vspanElt; struct mq_attr mqAttributes = { 0, PMQLSA_MAXMSG, PMQLSA_MSGSIZE, 0 }; mqd_t mq; int running; int segmentLength; char *segment; if (remoteEngineId == 0 || mqName == NULL) { puts("Usage: pmqlso <message queue name> <remote engine ID>"); return 0; } /* Note that ltpadmin must be run before the first * invocation of ltplso, to initialize the LTP database * (as necessary) and dynamic database. */ if (ltpInit(0) < 0) { putErrmsg("pmqlso can't initialize LTP.", NULL); return 1; } sdr = getIonsdr(); CHKERR(sdr_begin_xn(sdr)); /* Just to lock memory. */ findSpan(remoteEngineId, &vspan, &vspanElt); if (vspanElt == 0) { sdr_exit_xn(sdr); putErrmsg("No such engine in database.", itoa(remoteEngineId)); return 1; } if (vspan->lsoPid > 0 && vspan->lsoPid != sm_TaskIdSelf()) { sdr_exit_xn(sdr); putErrmsg("LSO task is already started for this span.", itoa(vspan->lsoPid)); return 1; } /* All command-line arguments are now validated. */ sdr_exit_xn(sdr); mq = mq_open(mqName, O_RDWR | O_CREAT, 0777, &mqAttributes); if (mq == (mqd_t) -1) { putSysErrmsg("pmqlso can't open message queue", mqName); return 1; } oK(_pmqlsoSemaphore(&vspan->segSemaphore)); isignal(SIGTERM, interruptThread); /* Can now begin transmitting to remote engine. */ writeMemo("[i] pmqlso is running."); running = 1; while (running && !(sm_SemEnded(_pmqlsoSemaphore(NULL)))) { segmentLength = ltpDequeueOutboundSegment(vspan, &segment); if (segmentLength < 0) { running = 0; /* Terminate LSO. */ continue; } if (segmentLength == 0) /* Interrupted. */ { continue; } if (segmentLength > PMQLSA_MSGSIZE) { putErrmsg("Segment is too big for PMQ LSO.", itoa(segmentLength)); running = 0; /* Terminate LSO. */ continue; } if (sendSegmentByPMQ(mq, segment, segmentLength) < 0) { putSysErrmsg("pmqlso failed sending segment", mqName); running = 0; /* Terminate LSO. */ continue; } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } mq_close(mq); writeErrmsgMemos(); writeMemo("[i] pmqlso duct has ended."); ionDetach(); return 0; }
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; }
static void *handleNotices(void *parm) { /* Main loop for LTP notice reception and handling. */ ReceiverThreadParms *rtp = (ReceiverThreadParms *) parm; AcqWorkArea *work; LtpNoticeType type; LtpSessionId sessionId; unsigned char reasonCode; unsigned char endOfBlock; unsigned long dataOffset; unsigned long dataLength; Object data; /* ZCO reference. */ Sdr sdr; snooze(1); /* Let main thread become interruptable. */ if (ltp_open(BpLtpClientId) < 0) { putErrmsg("ltpcli can't open client access.", itoa(BpLtpClientId)); pthread_kill(rtp->mainThread, SIGTERM); return NULL; } work = bpGetAcqArea(rtp->vduct); if (work == NULL) { ltp_close(BpLtpClientId); putErrmsg("ltpcli can't get acquisition work area", NULL); pthread_kill(rtp->mainThread, SIGTERM); 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); pthread_kill(rtp->mainThread, SIGTERM); rtp->running = 0; continue; } switch (type) { case LtpExportSessionCanceled: /* Xmit failure. */ if (data == 0) /* Ignore it. */ { break; /* Out of switch. */ } if (bpHandleXmitFailure(data) < 0) { putErrmsg("Crashed on xmit failure.", NULL); pthread_kill(rtp->mainThread, SIGTERM); rtp->running = 0; break; /* Out of switch. */ } sdr = getIonsdr(); sdr_begin_xn(sdr); zco_destroy_reference(sdr, data); if (sdr_end_xn(sdr) < 0) { putErrmsg("Crashed on data cleanup.", NULL); pthread_kill(rtp->mainThread, SIGTERM); rtp->running = 0; } break; /* Out of switch. */ case LtpImportSessionCanceled: break; /* Out of switch. */ case LtpRecvGreenSegment: case LtpRecvRedPart: if (acquireBundles(work, data, sessionId.sourceEngineId) < 0) { putErrmsg("Can't acquire bundle(s).", NULL); pthread_kill(rtp->mainThread, SIGTERM); 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. */ bpReleaseAcqArea(work); ltp_close(BpLtpClientId); return NULL; }
int udpclo(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 unsigned char *buffer; VOutduct *vduct; PsmAddress vductElt; Sdr sdr; Outduct outduct; ClProtocol protocol; Outflow outflows[3]; int i; char *hostName; unsigned short portNbr; unsigned int hostNbr; struct sockaddr socketName; struct sockaddr_in *inetName; Object bundleZco; BpExtendedCOS extendedCOS; char destDuctName[MAX_CL_DUCT_NAME_LEN + 1]; unsigned int bundleLength; int ductSocket = -1; int bytesSent; if (bpAttach() < 0) { putErrmsg("udpclo can't attach to BP.", NULL); return -1; } buffer = MTAKE(UDPCLA_BUFSZ); if (buffer == NULL) { putErrmsg("No memory for UDP buffer in udpclo.", NULL); return -1; } findOutduct("udp", "*", &vduct, &vductElt); if (vductElt == 0) { putErrmsg("No such udp duct.", "*"); MRELEASE(buffer); return -1; } if (vduct->cloPid > 0 && vduct->cloPid != sm_TaskIdSelf()) { putErrmsg("CLO task is already started for this duct.", itoa(vduct->cloPid)); MRELEASE(buffer); return -1; } /* All command-line arguments are now validated. */ sdr = getIonsdr(); sdr_read(sdr, (char *) &outduct, sdr_list_data(sdr, vduct->outductElt), sizeof(Outduct)); sdr_read(sdr, (char *) &protocol, outduct.protocol, sizeof(ClProtocol)); if (protocol.nominalRate <= 0) { vduct->xmitThrottle.nominalRate = DEFAULT_UDP_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; } /* Set up signal handling. SIGTERM is shutdown signal. */ oK(udpcloSemaphore(&(vduct->semaphore))); isignal(SIGTERM, shutDownClo); /* Can now begin transmitting to remote duct. */ writeMemo("[i] udpclo is running."); while (!(sm_SemEnded(vduct->semaphore))) { if (bpDequeue(vduct, outflows, &bundleZco, &extendedCOS, destDuctName) < 0) { sm_SemEnd(udpcloSemaphore(NULL));/* Stop. */ continue; } if (bundleZco == 0) /* Interrupted. */ { continue; } hostName = destDuctName; parseSocketSpec(destDuctName, &portNbr, &hostNbr); if (portNbr == 0) { portNbr = BpUdpDefaultPortNbr; } portNbr = htons(portNbr); if (hostNbr == 0) { writeMemoNote("[?] Can't get IP address for host", hostName); } hostNbr = htonl(hostNbr); memset((char *) &socketName, 0, sizeof socketName); inetName = (struct sockaddr_in *) &socketName; inetName->sin_family = AF_INET; inetName->sin_port = portNbr; memcpy((char *) &(inetName->sin_addr.s_addr), (char *) &hostNbr, 4); bundleLength = zco_length(sdr, bundleZco); bytesSent = sendBundleByUDP(&socketName, &ductSocket, bundleLength, bundleZco, buffer); if (bytesSent < bundleLength) { sm_SemEnd(udpcloSemaphore(NULL));/* Stop. */ continue; } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } if (ductSocket != -1) { close(ductSocket); } writeErrmsgMemos(); writeMemo("[i] udpclo duct has ended."); MRELEASE(buffer); ionDetach(); return 0; }