static void *sendKeepalives(void *parm) { KeepaliveThreadParms *parms = (KeepaliveThreadParms *) parm; int count = KEEPALIVE_PERIOD; int bytesSent; iblock(SIGTERM); while (*(parms->cloRunning)) { snooze(1); count++; if (count < KEEPALIVE_PERIOD) { continue; } /* Time to send a keepalive. Note that the * interval between keepalive attempts will be * KEEPALIVE_PERIOD plus (if the remote induct * is not reachable) the length of time taken * by TCP to determine that the connection * attempt will not succeed (e.g., 3 seconds). */ count = 0; pthread_mutex_lock(parms->mutex); bytesSent = sendBundleByTCP(parms->socketName, parms->ductSocket, 0, 0, NULL); pthread_mutex_unlock(parms->mutex); if (bytesSent < 0) { shutDownClo(); break; } } 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; }
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); }