Example #1
0
static int	run_sdatest(uvast destEngineId)
{
	SenderThreadParms	parms;
	pthread_t		senderThread;

	isignal(SIGTERM, interruptThread);
	if (destEngineId)
	{
		/*	Must start sender thread.			*/

		parms.destEngineId = destEngineId;
		parms.running = 1;
		if (pthread_begin(&senderThread, NULL, sendItems, &parms))
		{
			putSysErrmsg("sdatest can't create send thread", NULL);
			return 1;
		}
	}

	if (sda_run(getLengthOfItem, handleItem) < 0)
	{
		putErrmsg("sdatest sda_run failed.", NULL);
	}

	if (destEngineId)
	{
		parms.running = 0;
		pthread_join(senderThread, NULL);
	}

	writeErrmsgMemos();
	writeMemo("[i] sdatest main thread has ended.");
	ionDetach();
	return 0;
}
Example #2
0
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;
}
Example #3
0
int	udplsi(int a1, int a2, int a3, int a4, int a5,
		int a6, int a7, int a8, int a9, int a10)
{
	char	*endpointSpec = (char *) a1;
#else
int	main(int argc, char *argv[])
{
	char	*endpointSpec = (argc > 1 ? argv[1] : NULL);
#endif
	LtpVdb			*vdb;
	unsigned short		portNbr = 0;
	unsigned int		ipAddress = INADDR_ANY;
	struct sockaddr		socketName;
	struct sockaddr_in	*inetName;
	ReceiverThreadParms	rtp;
	socklen_t		nameLength;
	pthread_t		receiverThread;
	int			fd;
	char			quit = '\0';

	/*	Note that ltpadmin must be run before the first
	 *	invocation of ltplsi, to initialize the LTP database
	 *	(as necessary) and dynamic database.			*/ 

	if (ltpInit(0) < 0)
	{
		putErrmsg("udplsi can't initialize LTP.", NULL);
		return 1;
	}

	vdb = getLtpVdb();
	if (vdb->lsiPid != ERROR && vdb->lsiPid != sm_TaskIdSelf())
	{
		putErrmsg("LSI task is already started.", itoa(vdb->lsiPid));
		return 1;
	}

	/*	All command-line arguments are now validated.		*/

	if (endpointSpec)
	{
		if(parseSocketSpec(endpointSpec, &portNbr, &ipAddress) != 0)
		{
			putErrmsg("Can't get IP/port for endpointSpec.",
					endpointSpec);
			return -1;
		}
	}

	if (portNbr == 0)
	{
		portNbr = LtpUdpDefaultPortNbr;
	}

	portNbr = htons(portNbr);
	ipAddress = htonl(ipAddress);
	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 *) &ipAddress, 4);
	rtp.linkSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (rtp.linkSocket < 0)
	{
		putSysErrmsg("LSI can't open UDP socket", NULL);
		return -1;
	}

	nameLength = sizeof(struct sockaddr);
	if (reUseAddress(rtp.linkSocket)
	|| bind(rtp.linkSocket, &socketName, nameLength) < 0
	|| getsockname(rtp.linkSocket, &socketName, &nameLength) < 0)
	{
		closesocket(rtp.linkSocket);
		putSysErrmsg("Can't initialize socket", NULL);
		return 1;
	}

	/*	Set up signal handling; SIGTERM is shutdown signal.	*/

	ionNoteMainThread("udplsi");
	isignal(SIGTERM, interruptThread);

	/*	Start the receiver thread.				*/

	rtp.running = 1;
	if (pthread_begin(&receiverThread, NULL, handleDatagrams, &rtp))
	{
		closesocket(rtp.linkSocket);
		putSysErrmsg("udplsi can't create receiver thread", NULL);
		return 1;
	}

	/*	Now sleep until interrupted by SIGTERM, at which point
	 *	it's time to stop the link service.			*/

	{
		char	txt[500];

		isprintf(txt, sizeof(txt),
			"[i] udplsi is running, spec=[%s:%d].", 
			inet_ntoa(inetName->sin_addr), ntohs(portNbr));
		writeMemo(txt);
	}

	ionPauseMainThread(-1);

	/*	Time to shut down.					*/

	rtp.running = 0;

	/*	Wake up the receiver thread by sending it a 1-byte
	 *	datagram.						*/

	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fd >= 0)
	{
		isendto(fd, &quit, 1, 0, &socketName, sizeof(struct sockaddr));
		closesocket(fd);
	}

	pthread_join(receiverThread, NULL);
	closesocket(rtp.linkSocket);
	writeErrmsgMemos();
	writeMemo("[i] udplsi has ended.");
	ionDetach();
	return 0;
}
Example #4
0
int	ltpcli(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
	VInduct			*vduct;
	PsmAddress		vductElt;
	ReceiverThreadParms	rtp;
	pthread_t		receiverThread;

	if (ductName == NULL)
	{
		PUTS("Usage: ltpcli <local engine number>]");
		return 0;
	}

	if (bpAttach() < 0)
	{
		putErrmsg("ltpcli can't attach to BP.", NULL);
		return -1;
	}

	findInduct("ltp", ductName, &vduct, &vductElt);
	if (vductElt == 0)
	{
		putErrmsg("No such ltp duct.", ductName);
		return -1;
	}

	if (vduct->cliPid != ERROR && vduct->cliPid != sm_TaskIdSelf())
	{
		putErrmsg("CLI task is already started for this duct.",
				itoa(vduct->cliPid));
		return -1;
	}

	/*	All command-line arguments are now validated.		*/

	if (ltp_attach() < 0)
	{
		putErrmsg("ltpcli can't initialize LTP.", NULL);
		return -1;
	}

	/*	Set up signal handling; SIGTERM is shutdown signal.	*/

	ionNoteMainThread("ltpcli");
	isignal(SIGTERM, interruptThread);

	/*	Start the receiver thread.				*/

	rtp.vduct = vduct;
	rtp.running = 1;
	if (pthread_begin(&receiverThread, NULL, handleNotices, &rtp))
	{
		putSysErrmsg("ltpcli can't create receiver thread", NULL);
		return 1;
	}

	/*	Now sleep until interrupted by SIGTERM, at which point
	 *	it's time to stop the induct.				*/

	writeMemo("[i] ltpcli is running.");
	ionPauseMainThread(-1);

	/*	Time to shut down.					*/

	rtp.running = 0;

	/*	Stop the receiver thread by interrupting client access.	*/

	ltp_interrupt(BpLtpClientId);
	pthread_join(receiverThread, NULL);
	writeErrmsgMemos();
	writeMemo("[i] ltpcli duct has ended.");
	ionDetach();
	return 0;
}
Example #5
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();
    }
Example #6
0
int	bpcp(int a1, int a2, int a3, int a4, int a5,
		int a6, int a7, int a8, int a9, int a10)
{
	int t;
	char* argv[5];
	int		argc;

	/*Initialize CFDP*/
	ion_cfdp_init();

	/*Recursive flag is a1*/
	iamrecursive = atoi((char*)a1);
	if(iamrecursive!=0 && iamrecursive!=1)
	{
		iamrecursive=0;
	}

	/*Pretty progress meter always disabled*/
	showprogress=0;

	/*Lifetime is a2. a2=0 results in default lifetime.*/
	t=strtol((char*)a2, NULL, 10);
	if (t > 0)
	{
		parms.utParms.lifespan=t;
	}

	/*Custody Switch is a3. 1=ON, 0=OFF*/
	t = atoi((char*)a3);
	if(t==1)
	{
		parms.utParms.custodySwitch = SourceCustodyRequired;
	}
	else
	{
		if(t==0)
		{
			parms.utParms.custodySwitch = NoCustodyRequested;
		}
	}

	/*Class of Service is a4.*/
	t=strtol((char*)a4, NULL, 10);
	if (t>=0 && t <= 2)
	{
		parms.utParms.classOfService=t;
	}

	/*Debug flag is a5.*/
	debug=atoi((char*)a5);
	if(debug>0)
	{
		version();
	}

	/*a6-a10 are files to copy/destinations*/
	argc=0;
	if((char*)a6!=NULL)
	{
		argv[argc]=(char*)a6;
		argc++;
	}
	if((char*)a7!=NULL)
	{
		argv[argc]=(char*)a7;
		argc++;
	}
	if((char*)a8!=NULL)
	{
		argv[argc]=(char*)a8;
		argc++;
	}
	if((char*)a9!=NULL)
	{
		argv[argc]=(char*)a9;
		argc++;
	}
	if((char*)a10!=NULL)
	{
		argv[argc]=(char*)a10;
		argc++;
	}

#else
int main(int argc, char **argv)
{
	int ch;
	extern char *optarg;
	extern int optind;
	int tmpoption;

	/*Initialize CFDP*/
	ion_cfdp_init();

	/*Parse commandline options*/
	while ((ch = getopt(argc, argv, "dqrL:C:S:v")) != -1)
	{
		switch (ch)
		{
			case 'r':
				/*Recursive*/
				iamrecursive = 1;
				break;
			case 'd':
				/*Debug*/
				debug++;
				break;
			case 'v':
				/*Print Version info*/
				version();
				break;
			case 'q':
				/*Quiet*/
				showprogress = 0;
				break;
			case 'L':
				/*Lifetime*/
				tmpoption=-1;
				tmpoption=strtol(optarg, NULL, 10);
				if (tmpoption > 0)
				{
					parms.utParms.lifespan=tmpoption;
				}
				else
				{
					dbgprintf(0, "Error: Invalid BP Lifetime\n");
					exit_nicely(1);
				}
				break;
			case 'C':
				/*Custody Transfer*/
				if (strcmp(optarg, "Yes")==0 ||
					strcmp(optarg, "YES")==0 ||
					strcmp(optarg, "yes")==0 ||
					strcmp(optarg, "y")==0 ||
					strcmp(optarg, "On")==0 ||
					strcmp(optarg, "ON")==0 ||
					strcmp(optarg, "on")==0 ||
					strcmp(optarg, "1")==0)
				{
						parms.utParms.custodySwitch = SourceCustodyRequired;
				}
				else
				{
						if (strcmp(optarg, "No")==0 ||
							strcmp(optarg, "NO")==0 ||
							strcmp(optarg, "yes")==0 ||
							strcmp(optarg, "n")==0 ||
							strcmp(optarg, "Off")==0 ||
							strcmp(optarg, "OFF")==0 ||
							strcmp(optarg, "off")==0 ||
							strcmp(optarg, "0")==0)
						{
							parms.utParms.custodySwitch = NoCustodyRequested;
						}
						else
						{
							dbgprintf(0, "Error: Invalid Custody Transfer Setting\n");
						}
					}
				break;
			case 'S':
				/*Class of Service*/
				tmpoption=-1;
				tmpoption=strtol(optarg, NULL, 10);
				if (tmpoption>=0 && tmpoption <= 2)
				{
					parms.utParms.classOfService=tmpoption;
				} else {
					dbgprintf(0, "Error: Invalid BP Class of Service\n");
					exit_nicely(1);
				}
				break;
			default:
				usage();
		}
	}
	argc -= optind;
	argv += optind;
#endif
	char *targ;

	/*Initialize tmp file array*/
	memset(tmp_files,0, NUM_TMP_FILES*255);

#ifdef SIG_HANDLER
	/*Set SIGTERM and SIGINT handlers*/
	isignal(SIGTERM, handle_sigterm);
	isignal(SIGINT, handle_sigterm);
#endif

	/*Additional argument checks*/
	if (!isatty(STDOUT_FILENO))
	{
		showprogress = 0;
	}

	if (argc < 2)
	{
		usage();
	}
	if (argc > 2)
	{
		/*We are moving multiple files, destination must be a directory*/
		targetshouldbedirectory = 1;
	}

	/*Connect to CFDP*/
	if (cfdp_attach() < 0)
	{
		dbgprintf(0, "Error: Can't initialize CFDP. Is ION running?\n");
		exit(1);
	}

	/*Create receiver thread*/
	events_sem=sm_SemCreate(SM_NO_KEY, SM_SEM_FIFO);
	if (events_sem==SM_SEM_NONE || sm_SemTake(events_sem)<0)
	{
		dbgprintf(0, "Error: Can't create semaphore\n");
		exit(1);
	}
	recv_running=1;
	if (pthread_begin(&rcv_thread, NULL, &rcv_msg_thread, (void*)&recv_running))
	{
		dbgprintf(0, "Error: Can't start message thread\n");
		sm_SemDelete(events_sem);
		exit(1);
	}

	/*Parse Paths*/
	if ((targ = remote_path(argv[argc - 1])))
	{
		/* Last path is remote path
		 * Destination is remote host*/
		toremote(targ, argc, argv);
	}
	else
	{
		/*Destination is localhost*/
		if (targetshouldbedirectory)
		{
			/*If we are moving multiple files, check that destination
			 * is directory*/
			if (is_dir(argv[argc - 1]))
			{
				tolocal(argc, argv);
			}
			else
			{
				dbgprintf(0, "Error: Destination is not a directory\n");
				exit_nicely(1);
			}
		}
		else
		{
			/*Single file copy*/
			tolocal(argc, argv);
		}
	}


	exit_nicely(0);
	return 0;
}