File:  [ELWIX - Embedded LightWeight unIX -] / tftpd / src / srv.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Fri Feb 14 15:38:37 2014 UTC (10 years, 4 months ago) by misho
Branches: MAIN
CVS tags: HEAD
Initial revision

    1: #include "global.h"
    2: 
    3: 
    4: static void *
    5: timeoutSession(sched_task_t *task)
    6: {
    7: 	ETRACE();
    8: 
    9: 	/* drop session */
   10: 	if (cli.fd > 2)
   11: 		close(cli.fd);
   12: 	memset(&cli, 0, sizeof cli);
   13: 
   14: 	taskExit(task, NULL);
   15: }
   16: 
   17: static void *
   18: txPkt(sched_task_t *task)
   19: {
   20: 	int wlen;
   21: 	rpack_t *pkt = TASK_DATA(task);
   22: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
   23: 
   24: 	ETRACE();
   25: 
   26: 	wlen = sendto(TASK_FD(task), RPACK_BUF(pkt), TASK_DATLEN(task), 
   27: 			0, &cli.addr.sa, cli.addr.sa.sa_len);
   28: 	if (wlen == -1)
   29: 		ESYSERR(0);
   30: 	else if (wlen != TASK_DATLEN(task)) {
   31: 		EERROR(EIO, "Sended %d bytes != packet %d bytes", 
   32: 				wlen, TASK_DATLEN(task));
   33: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
   34: 				timeoutSession, NULL);
   35: 		memset(&cli, 0, sizeof(sockaddr_t));
   36: 	} else
   37: 		EVERBOSE(2, "Sended %d bytes", wlen);
   38: 	/* on error or argument, drop session */
   39: 	if (TASK_ARG(task) == (void*) -1 || ntohs(tftp->tftp_opc) == TFTP_OPC_ERROR) {
   40: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
   41: 				timeoutSession, NULL);
   42: 		memset(&cli, 0, sizeof cli);
   43: 	}
   44: 
   45: 	taskExit(task, NULL);
   46: }
   47: 
   48: static void *
   49: txData(sched_task_t *task)
   50: {
   51: 	rpack_t *pkt = TASK_DATA(task);
   52: 	u_short code = 0, n = htons(TFTP_OPC_DATA);
   53: 	int len;
   54: 
   55: 	ETRACE();
   56: 
   57: 	RPACK_REWIND(pkt);
   58: 	rpack_uint16(pkt, &n, 0);
   59: 	n = htons(cli.seq);
   60: 	rpack_uint16(pkt, &n, 0);
   61: 
   62: 	len = pread(cli.fd, RPACK_NEXT(pkt), cli.siz, (cli.seq - 1) * cli.siz);
   63: 	if (len == -1) {
   64: 		ESYSERR(0);
   65: 		code = htole16(3);
   66: 		goto end;
   67: 	} else {
   68: 		rpack_rnext(pkt, len);
   69: 		EVERBOSE(3, "Read from file %s %d bytes", cli.file, len);
   70: 	}
   71: 
   72: 	if (cli.siz - len)
   73: 		cli.close = 42;	/* last sended packet, should be close! */
   74: 
   75: 	schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
   76: 			TASK_DATA(task), RPACK_OFF(pkt));
   77: 	taskExit(task, NULL);
   78: end:
   79: 	RPACK_REWIND(pkt);
   80: 	n = htons(TFTP_OPC_ERROR);
   81: 	rpack_uint16(pkt, &n, 0);
   82: 	rpack_uint16(pkt, &code, 0);
   83: 	rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
   84: 
   85: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
   86: 			TASK_DATA(task), RPACK_OFF(pkt));
   87: 	taskExit(task, NULL);
   88: }
   89: 
   90: static void *
   91: txAck(sched_task_t *task)
   92: {
   93: 	rpack_t *pkt = TASK_DATA(task);
   94: 	u_short n = htons(TFTP_OPC_ACK);
   95: 
   96: 	ETRACE();
   97: 
   98: 	RPACK_REWIND(pkt);
   99: 	rpack_uint16(pkt, &n, 0);
  100: 	n = htons(cli.seq);
  101: 	rpack_uint16(pkt, &n, 0);
  102: 
  103: 	schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  104: 			TASK_DATA(task), RPACK_OFF(pkt));
  105: 
  106: 	if (cli.close) {
  107: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  108: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
  109: 		EVERBOSE(2, "Finish WRQ request");
  110: 	}
  111: 	taskExit(task, NULL);
  112: }
  113: 
  114: static void *
  115: RQ(sched_task_t *task)
  116: {
  117: 	rpack_t *pkt = TASK_DATA(task);
  118: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  119: 	int len, rlen = TASK_DATLEN(task) - 2;
  120: 	char *str;
  121: 	u_short code = 0;
  122: 
  123: 	ETRACE();
  124: 
  125: 	cli.siz = TFTP_LOAD_MAX;
  126: 	len = str_getString(tftp->tftp_data, rlen, &str);
  127: 	if (len == -1)
  128: 		goto end;
  129: 	else {
  130: 		rlen -= len;
  131: 		strlcpy(cli.file, (char*) tftp->tftp_data, sizeof cli.file);
  132: 	}
  133: 	len = str_getString((const u_char*) str, rlen, NULL);
  134: 	if (len == -1)
  135: 		goto end;
  136: 	else {
  137: 		rlen -= len;
  138: 		if (!strcasecmp(str, TFTP_MODE_ASCII))
  139: 			strlcpy(cli.mode, TFTP_MODE_ASCII, sizeof cli.mode);
  140: 		else if (!strcasecmp(str, TFTP_MODE_OCTET))
  141: 			strlcpy(cli.mode, TFTP_MODE_OCTET, sizeof cli.mode);
  142: 		else if (!strcasecmp(str, TFTP_MODE_MAIL)) {
  143: 			strlcpy(cli.mode, TFTP_MODE_MAIL, sizeof cli.mode);
  144: 			code = htole16(4);
  145: 			goto end;
  146: 		} else {
  147: 			code = htole16(1);
  148: 			goto end;
  149: 		}
  150: 	}
  151: 
  152: 	cli.opc = ntohs(tftp->tftp_opc);
  153: 	switch (cli.opc) {
  154: 		case TFTP_OPC_RRQ:
  155: 			code = O_RDONLY;
  156: 			EVERBOSE(2, "RRQ:: file=%s mode=%s\n", cli.file, cli.mode);
  157: 			break;
  158: 		case TFTP_OPC_WRQ:
  159: 			code = O_WRONLY | O_CREAT;
  160: 			str = (char*) cfg_getAttribute(&cfg, "tftpd", "override");
  161: 			if (!str || tolower(*str) != 'y')
  162: 				code |= O_EXCL;
  163: 			EVERBOSE(2, "WRQ:: file=%s mode=%s\n", cli.file, cli.mode);
  164: 			break;
  165: 	}
  166: 	cli.fd = open(cli.file, code, 0644);
  167: 	if (cli.fd == -1) {
  168: 		if (errno == EACCES)
  169: 			code = htole16(2);
  170: 		else if (errno == ENFILE)
  171: 			code = htole16(3);
  172: 		else if (errno == EEXIST)
  173: 			code = htole16(6);
  174: 		else
  175: 			code = htole16(0);
  176: 		ESYSERR(0);
  177: 		goto end;
  178: 	} else
  179: 		cli.seq = 0;
  180: 
  181: 	if (cli.opc == TFTP_OPC_WRQ) {
  182: 		/* ack */
  183: 		tftp->tftp_opc = htons(TFTP_OPC_ACK);
  184: 		RPACK_REWIND(pkt);
  185: 		rpack_uint16(pkt, NULL, 0);
  186: 		rpack_uint16(pkt, &cli.seq, 0);
  187: 
  188: 		schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  189: 				TASK_DATA(task), RPACK_OFF(pkt));
  190: 	} else
  191: 		schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task), 
  192: 				TASK_DATA(task), 0);
  193: 
  194: 	cli.seq = 1;	/* 1st ack */
  195: 	taskExit(task, NULL);
  196: end:
  197: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  198: 	RPACK_REWIND(pkt);
  199: 	rpack_uint16(pkt, NULL, 0);
  200: 	rpack_uint16(pkt, &code, 0);
  201: 	rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
  202: 
  203: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  204: 			TASK_DATA(task), RPACK_OFF(pkt));
  205: 	taskExit(task, NULL);
  206: }
  207: 
  208: static void *
  209: ACK(sched_task_t *task)
  210: {
  211: 	rpack_t *pkt = TASK_DATA(task);
  212: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  213: 	u_short code;
  214: 
  215: 	ETRACE();
  216: 
  217: 	RPACK_REWIND(pkt);
  218: 	code = rpack_uint16(pkt, NULL, 0);
  219: 	if (ntohs(code) != TFTP_OPC_ACK) {
  220: 		code = htole16(5);
  221: 		goto end;
  222: 	}
  223: 
  224: 	code = rpack_uint16(pkt, NULL, 0);
  225: 	if (ntohs(code) > cli.seq || (ntohs(code) < (cli.seq - 1))) {
  226: 		code = htole16(5);
  227: 		goto end;
  228: 	} else if (ntohs(code) == cli.seq)
  229: 		cli.seq++;
  230: 
  231: 	EVERBOSE(3, "ACK:: seq=%hu; my new seq=%hu;", ntohs(code), cli.seq);
  232: 
  233: 	if (!cli.close)
  234: 		schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task), 
  235: 				TASK_DATA(task), 0);
  236: 	else {
  237: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  238: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
  239: 		EVERBOSE(2, "Finish RRQ request");
  240: 	}
  241: 	taskExit(task, NULL);
  242: end:
  243: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  244: 	RPACK_REWIND(pkt);
  245: 	rpack_uint16(pkt, NULL, 0);
  246: 	rpack_uint16(pkt, &code, 0);
  247: 	rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
  248: 
  249: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  250: 			TASK_DATA(task), RPACK_OFF(pkt));
  251: 	taskExit(task, NULL);
  252: }
  253: 
  254: static void *
  255: DATA(sched_task_t *task)
  256: {
  257: 	rpack_t *pkt = TASK_DATA(task);
  258: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  259: 	u_short code;
  260: 	int len;
  261: 
  262: 	ETRACE();
  263: 
  264: 	RPACK_REWIND(pkt);
  265: 	code = rpack_uint16(pkt, NULL, 0);
  266: 	if (ntohs(code) != TFTP_OPC_DATA) {
  267: 		code = htole16(5);
  268: 		goto end;
  269: 	}
  270: 
  271: 	code = rpack_uint16(pkt, NULL, 0);
  272: 	if (ntohs(code) < cli.seq || ntohs(code) > cli.seq + 1) {
  273: 		code = htole16(5);
  274: 		goto end;
  275: 	} else
  276: 		cli.seq = ntohs(code);
  277: 
  278: 	len = TASK_DATLEN(task) - RPACK_OFF(pkt);
  279: 	if (len < cli.siz)
  280: 		cli.close = 42;	/* last received packet, should be close! */
  281: 
  282: 	EVERBOSE(3, "DATA:: seq=%hu; len=%d", cli.seq, len);
  283: 
  284: 	len = pwrite(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
  285: 	if (len == -1) {
  286: 		ESYSERR(0);
  287: 		code = htole16(3);
  288: 		goto end;
  289: 	} else {
  290: 		rpack_rnext(pkt, len);
  291: 		EVERBOSE(3, "Written to file %s %d bytes", cli.file, len);
  292: 	}
  293: 
  294: 	schedEvent(TASK_ROOT(task), txAck, NULL, TASK_FD(task), TASK_DATA(task), 0);
  295: 	taskExit(task, NULL);
  296: end:
  297: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  298: 	RPACK_REWIND(pkt);
  299: 	rpack_uint16(pkt, NULL, 0);
  300: 	rpack_uint16(pkt, &code, 0);
  301: 	rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
  302: 
  303: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  304: 			TASK_DATA(task), RPACK_OFF(pkt));
  305: 	taskExit(task, NULL);
  306: }
  307: 
  308: void *
  309: rxPkt(sched_task_t *task)
  310: {
  311: 	sockaddr_t sa;
  312: 	socklen_t salen = sizeof sa;
  313: 	int rlen;
  314: 	rpack_t *pkt = TASK_DATA(task);
  315: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  316: 	u_short code;
  317: 
  318: 	ETRACE();
  319: 
  320: 	memset(RPACK_BUF(pkt), 0, RPACK_LEN(pkt));
  321: 	rlen = recvfrom(TASK_FD(task), RPACK_BUF(pkt), RPACK_LEN(pkt), 0, &sa.sa, &salen);
  322: 	if (rlen == -1) {
  323: 		ESYSERR(0);
  324: 		goto end;
  325: 	} else if (!cli.addr.sa.sa_len) {
  326: 		cli.addr = sa;
  327: 		switch (ntohs(tftp->tftp_opc)) {
  328: 			case TFTP_OPC_RRQ:
  329: 			case TFTP_OPC_WRQ:
  330: 				schedEvent(TASK_ROOT(task), RQ, NULL, TASK_FD(task), 
  331: 						TASK_DATA(task), rlen);
  332: 				break;
  333: 			case TFTP_OPC_ERROR:
  334: 			default:
  335: 				RPACK_REWIND(pkt);
  336: 				code = htons(TFTP_OPC_ERROR);
  337: 				rpack_uint16(pkt, &code, 0);
  338: 				code = htole16(4);
  339: 				rpack_uint16(pkt, &code, 0);
  340: 				rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
  341: 
  342: 				schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  343: 						TASK_DATA(task), RPACK_OFF(pkt));
  344: 				goto end;
  345: 		}
  346: 	} else if (memcmp(&cli.addr, &sa, salen)) {
  347: 		EERROR(LOG_WARNING, "Packet dropped!!!\n"
  348: 				"Get frame from different address for this session");
  349: 		goto end;
  350: 	} else
  351: 		switch (ntohs(tftp->tftp_opc)) {
  352: 			case TFTP_OPC_ACK:
  353: 				schedEvent(TASK_ROOT(task), ACK, NULL, TASK_FD(task), 
  354: 						TASK_DATA(task), rlen);
  355: 				break;
  356: 			case TFTP_OPC_DATA:
  357: 				schedEvent(TASK_ROOT(task), DATA, NULL, TASK_FD(task), 
  358: 						TASK_DATA(task), rlen);
  359: 				break;
  360: 			case TFTP_OPC_OACK:
  361: 				ELOGGER(LOG_WARNING, "oack");
  362: 				/*
  363: 				schedEvent(TASK_ROOT(task), OACK, NULL, TASK_FD(task), 
  364: 						TASK_DATA(task), rlen);
  365: 						*/
  366: 				break;
  367: 			case TFTP_OPC_ERROR:
  368: 			default:
  369: 				RPACK_REWIND(pkt);
  370: 				code = htons(TFTP_OPC_ERROR);
  371: 				rpack_uint16(pkt, &code, 0);
  372: 				code = htole16(4);
  373: 				rpack_uint16(pkt, &code, 0);
  374: 				rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
  375: 
  376: 				schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  377: 						TASK_DATA(task), RPACK_OFF(pkt));
  378: 				goto end;
  379: 		}
  380: 
  381: 	schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  382: 	schedTimer(TASK_ROOT(task), timeoutSession, NULL, timeout, NULL, 0);
  383: end:
  384: 	schedReadSelf(task);
  385: 	taskExit(task, NULL);
  386: }

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