File:  [ELWIX - Embedded LightWeight unIX -] / ansh / src / daemon3.c
Revision 1.1.1.1.2.1: download - view: text, annotated - select for diffs - revision graph
Fri Oct 7 13:41:26 2011 UTC (13 years, 8 months ago) by misho
Branches: ansh1_0
Diff to: branchpoint 1.1.1.1: preferred, unified
finish icmp service!!!

/*************************************************************************
 * (C) 2011 AITNET - Sofia/Bulgaria - <office@aitnet.org>
 *  by Michael Pounov <misho@elwix.org>
 *
 * $Author: misho $
 * $Id: daemon3.c,v 1.1.1.1.2.1 2011/10/07 13:41:26 misho Exp $
 *
 *************************************************************************/
#include "global.h"
#include "anshd.h"


void *
icmpTx(sched_task_t *task)
{
	struct tagProc *proc;
	int wlen;
	u_char *str;

	FTRACE(3);

	/* not found argument, drop data */
	if (!(proc = TASK_ARG(task)))
		return (void*) -1;

	if (Crypted) {
		str = cryptBuffer(proc->proc_buf_[FD2NET], proc->proc_rlen_[FD2NET], Crypted);
		if (str) {
			memcpy(proc->proc_buf_[FD2NET], str, proc->proc_rlen_[FD2NET]);
			free(str);
		}
	}

	if ((wlen = icmpSend(TASK_FD(task), proc->proc_id, proc->proc_flg, Crypted, proc->proc_buf_[FD2NET], 
			proc->proc_rlen_[FD2NET], &proc->proc_cli, sizeof proc->proc_cli)) != ANSH_FLG_ERR) {
		proc->proc_flg = ANSH_FLG_OK;
		proc->proc_rlen_[FD2NET] = 0;
	}
	VERB(5) LOG("Sended %d bytes", wlen);

	return NULL;
}

void *
icmpRx(sched_task_t *task)
{
	u_char *buf, *str;
	struct sockaddr sa;
	int rlen, n = 0, salen = sizeof sa;
	struct tagProc *proc = NULL;
	char ret;
	u_short id, *b;

	FTRACE(3);

	rlen = bpfLEN;
	if (!(buf = malloc(rlen)))
		goto end;

	if ((ret = icmpRecv(TASK_FD(task), &id, &Crypted, buf, &rlen, &sa, (socklen_t *) &salen)) == ANSH_FLG_ERR)
		goto end;
	VERB(5) LOG("Received %d bytes", rlen);
	if (!(ret & ANSH_FLG_CPOUT))
		goto end;

	/* packet is ok find active session */
	SLIST_FOREACH(proc, &pH, proc_next)
		if (proc->proc_id == id) {
			n = ANSH_CODE;
			break;
		}
	/* not found in sessions, drop packet */
	if (n != ANSH_CODE) {
		proc = NULL;
		goto end;
	}

	if (Crypted) {
		str = cryptBuffer(buf, rlen, Crypted);
		if (str) {
			memcpy(buf, str, rlen);
			free(str);
		}
	}

	switch (ret) {
		case ANSH_FLG_EOF:
		case ANSH_FLG_CPOUT:
			break;
		case ANSH_FLG_WINZ:
			b = (u_short*) buf;
			ioChgWinPTY(proc->proc_pty, ntohs(b[0]), ntohs(b[1]), ntohs(b[2]), ntohs(b[3]));
			/* if not started login, lets start & go! */
			if (!proc->proc_pid) {
				memcpy(&proc->proc_cli, &sa, sizeof sa);
				spawnLogin(task, proc);
			}
		default:
			goto end;
	}

	proc->proc_flg = ret;
	proc->proc_rlen_[NET2FD] = rlen;
	memset(proc->proc_buf_[NET2FD], 0, proc->proc_blen);
	memcpy(proc->proc_buf_[NET2FD], buf, proc->proc_rlen_[NET2FD]);
	schedWrite(TASK_ROOT(task), fdTx, proc, proc->proc_pty);
end:
	free(buf);
	schedRead(TASK_ROOT(task), icmpRx, NULL, proc ? proc->proc_sock : TASK_FD(task));
	return NULL;
}

void *
fdTx(sched_task_t *task)
{
	struct tagProc *proc;
	struct timeval tv = { 0 };
	int wlen;

	FTRACE(3);

	/* not found argument, drop data */
	if (!(proc = TASK_ARG(task)))
		return (void*) -1;

	/* if != ANSH_FLG_CPOUT isnt received from client */
	if (proc->proc_flg != ANSH_FLG_CPOUT || !proc->proc_pid)
		return NULL;

	if (waitpid(proc->proc_pid, &wlen, WNOHANG)) {
		ioFreePTY(TASK_FD(task), proc->proc_ttyname);
		schedCancelby(TASK_ROOT(task), NULL, CRITERIA_FD, (void*) TASK_FD(task), NULL);

		proc->proc_pid = 0;
		proc->proc_flg = ANSH_FLG_EOF;
		proc->proc_rlen_[FD2NET] = 0;

		schedWrite(TASK_ROOT(task), icmpTx, proc, proc->proc_sock);
		return NULL;
	}

	/* if Timeout defined, disarm timer */
	if (Timeout)
		schedCancelby(TASK_ROOT(task), &TASK_ROOT(task)->root_timer, CRITERIA_CALL, TOfunc, NULL);

	wlen = write(TASK_FD(task), proc->proc_buf_[NET2FD], proc->proc_rlen_[NET2FD]);
	switch (wlen) {
		case -1:
			ERR("write2tty #%d - %s", errno, strerror(errno));
			/* exit from shell and release tty */
			waitpid(proc->proc_pid, &wlen, 0);
			ioFreePTY(TASK_FD(task), proc->proc_ttyname);
			schedCancelby(TASK_ROOT(task), NULL, CRITERIA_FD, (void*) TASK_FD(task), NULL);

			proc->proc_pid = 0;
			proc->proc_flg = ANSH_FLG_EOF;
			proc->proc_rlen_[FD2NET] = 0;

			schedWrite(TASK_ROOT(task), icmpTx, proc, proc->proc_sock);
			return NULL;
		default:
			proc->proc_flg = ANSH_FLG_OK;
			proc->proc_rlen_[NET2FD] = 0;
	}
	VERB(3) LOG("Writed %d bytes - %s", wlen, proc->proc_buf_[NET2FD]);

	/* if Timeout defined, go arm timer */
	if (Timeout) {
		tv.tv_sec = Timeout;
		schedTimer(TASK_ROOT(task), TOfunc, proc, tv);
	}
	return NULL;
}

void *
fdRx(sched_task_t *task)
{
	struct tagProc *proc;
	struct timeval tv = { 0 };
	int rlen;

	FTRACE(3);

	/* not found argument, drop data */
	if (!(proc = TASK_ARG(task)))
		return (void*) -1;
	if (!proc->proc_pid)
		return NULL;

	if (waitpid(proc->proc_pid, &rlen, WNOHANG)) {
		ioFreePTY(TASK_FD(task), proc->proc_ttyname);
		schedCancelby(TASK_ROOT(task), NULL, CRITERIA_FD, (void*) TASK_FD(task), NULL);

		proc->proc_pid = 0;
		proc->proc_flg = ANSH_FLG_EOF;
		proc->proc_rlen_[FD2NET] = 0;

		schedWrite(TASK_ROOT(task), icmpTx, proc, proc->proc_sock);
		return NULL;
	}

	/* if Timeout defined, disarm timer */
	if (Timeout)
		schedCancelby(TASK_ROOT(task), &TASK_ROOT(task)->root_timer, CRITERIA_CALL, TOfunc, NULL);

	memset(proc->proc_buf_[FD2NET], 0, proc->proc_blen);
	rlen = read(TASK_FD(task), proc->proc_buf_[FD2NET], proc->proc_blen);
	switch (rlen) {
		case -1:
			ERR("readtty #%d - %s", errno, strerror(errno));
		case 0:
			/* exit from shell and release tty */
			waitpid(proc->proc_pid, &rlen, 0);
			ioFreePTY(TASK_FD(task), proc->proc_ttyname);
			schedCancelby(TASK_ROOT(task), NULL, CRITERIA_FD, (void*) TASK_FD(task), NULL);
			VERB(3) LOG("EOF process status %d", rlen);

			proc->proc_pid = 0;
			proc->proc_flg = ANSH_FLG_EOF;
			proc->proc_rlen_[FD2NET] = 0;

			schedWrite(TASK_ROOT(task), icmpTx, proc, proc->proc_sock);
			return NULL;
		default:
			proc->proc_flg = ANSH_FLG_OK;
			proc->proc_rlen_[FD2NET] = rlen;
	}
	VERB(3) LOG("Readed %d bytes - %s", rlen, proc->proc_buf_[FD2NET]);

	schedWrite(TASK_ROOT(task), icmpTx, proc, proc->proc_sock);
	schedRead(TASK_ROOT(task), fdRx, proc, proc->proc_pty);

	/* if Timeout defined, go arm timer */
	if (Timeout) {
		tv.tv_sec = Timeout;
		schedTimer(TASK_ROOT(task), TOfunc, proc, tv);
	}
	return NULL;
}

int
spawnLogin(sched_task_t *task, struct tagProc *proc)
{
	int flg;
	struct timeval tv = { 0 };
	char str[STRSIZ] = { 0 };
	struct sockaddr_in *sin;
	struct sockaddr_in6 *sin6;

	FTRACE(3);

	assert(proc);

	switch ((proc->proc_pid = ioForkPTY(&proc->proc_pty, proc->proc_ttyname, 
					sizeof proc->proc_ttyname, NULL, NULL, NULL))) {
		case -1:
			ERR("ioForkPTY() #%d - %s", io_GetErrno(), io_GetError());
			return -1;
		case 0:
			printf("ansh3d ELWIX remote management system over ICMP (%s)\n\n", 
					proc->proc_ttyname);
			strlcpy(str, "-hansh3@", sizeof str);
			if (proc->proc_cli.sa_family == AF_INET) {
				sin = (struct sockaddr_in*) &proc->proc_cli;
				inet_ntop(AF_INET, &sin->sin_addr, str + 8, INET_ADDRSTRLEN);
			} else if (proc->proc_cli.sa_family == AF_INET) {
				sin6 = (struct sockaddr_in6*) &proc->proc_cli;
				inet_ntop(AF_INET6, &sin6->sin6_addr, str + 8, INET6_ADDRSTRLEN);
			}
			execl("/usr/bin/login", "login", str, NULL);
			/* never reached */
			return -1;
		default:
			flg = fcntl(proc->proc_pty, F_GETFL);
			fcntl(proc->proc_pty, F_SETFL, flg | O_NONBLOCK);

			VERB(3) LOG("Parent know child pid %d", proc->proc_pid);
			schedRead(TASK_ROOT(task), fdRx, proc, proc->proc_pty);

			/* if Timeout defined, go arm timer */
			if (Timeout) {
				tv.tv_sec = Timeout;
				schedTimer(TASK_ROOT(task), TOfunc, proc, tv);
			}
			break;
	}

	return 0;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>