File:  [ELWIX - Embedded LightWeight unIX -] / tftpd / src / srv.c
Revision 1.8: download - view: text, annotated - select for diffs - revision graph
Mon Feb 24 22:28:54 2014 UTC (10 years, 3 months ago) by misho
Branches: MAIN
CVS tags: tftp1_3, TFTP1_2, HEAD
version 1.2

    1: /*************************************************************************
    2: * (C) 2014 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
    3: *  by Michael Pounov <misho@elwix.org>
    4: *
    5: * $Author: misho $
    6: * $Id: srv.c,v 1.8 2014/02/24 22:28:54 misho Exp $
    7: *
    8: **************************************************************************
    9: The ELWIX and AITNET software is distributed under the following
   10: terms:
   11: 
   12: All of the documentation and software included in the ELWIX and AITNET
   13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
   14: 
   15: Copyright 2004 - 2014
   16: 	by Michael Pounov <misho@elwix.org>.  All rights reserved.
   17: 
   18: Redistribution and use in source and binary forms, with or without
   19: modification, are permitted provided that the following conditions
   20: are met:
   21: 1. Redistributions of source code must retain the above copyright
   22:    notice, this list of conditions and the following disclaimer.
   23: 2. Redistributions in binary form must reproduce the above copyright
   24:    notice, this list of conditions and the following disclaimer in the
   25:    documentation and/or other materials provided with the distribution.
   26: 3. All advertising materials mentioning features or use of this software
   27:    must display the following acknowledgement:
   28: This product includes software developed by Michael Pounov <misho@elwix.org>
   29: ELWIX - Embedded LightWeight unIX and its contributors.
   30: 4. Neither the name of AITNET nor the names of its contributors
   31:    may be used to endorse or promote products derived from this software
   32:    without specific prior written permission.
   33: 
   34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
   35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   44: SUCH DAMAGE.
   45: */
   46: #include "global.h"
   47: #include "exec.h"
   48: #include "buf.h"
   49: #include "srv.h"
   50: 
   51: 
   52: static void *
   53: timeoutSession(sched_task_t *task)
   54: {
   55: 	rpack_t *pkt = TASK_DATA(task);
   56: 
   57: 	ETRACE();
   58: 
   59: 	if (bf)
   60: 		flushBuffer(cli.fd);
   61: 
   62: 	/* drop session */
   63: 	if (cli.fd > 2)
   64: 		close(cli.fd);
   65: 	rpack_resize(pkt, TFTP_PKT_MAX);
   66: 	memset(&cli, 0, sizeof cli);
   67: 
   68: 	taskExit(task, NULL);
   69: }
   70: 
   71: static void *
   72: txPkt(sched_task_t *task)
   73: {
   74: 	int wlen;
   75: 	rpack_t *pkt = TASK_DATA(task);
   76: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
   77: 
   78: 	ETRACE();
   79: 
   80: 	wlen = sendto(TASK_FD(task), RPACK_BUF(pkt), TASK_DATLEN(task), 
   81: 			0, &cli.addr.sa, cli.addr.sa.sa_len);
   82: 	if (wlen == -1)
   83: 		ESYSERR(0);
   84: 	else if (wlen != TASK_DATLEN(task)) {
   85: 		EERROR(EIO, "Sended %d bytes != packet %d bytes", 
   86: 				wlen, TASK_DATLEN(task));
   87: 		schedEvent(TASK_ROOT(task), execProg, "error", 0, NULL, TFTP_OPC_ERROR);
   88: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
   89: 				timeoutSession, NULL);
   90: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, TASK_DATA(task), 0);
   91: 	} else
   92: 		EVERBOSE(2, "Sended %d bytes", wlen);
   93: 	/* on error or argument, drop session */
   94: 	if (TASK_ARG(task) == (void*) -1 || ntohs(tftp->tftp_opc) == TFTP_OPC_ERROR) {
   95: 		schedEvent(TASK_ROOT(task), execProg, "error", 0, NULL, TFTP_OPC_ERROR);
   96: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
   97: 				timeoutSession, NULL);
   98: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, TASK_DATA(task), 0);
   99: 	}
  100: 
  101: 	taskExit(task, NULL);
  102: }
  103: 
  104: static void *
  105: txData(sched_task_t *task)
  106: {
  107: 	rpack_t *pkt = TASK_DATA(task);
  108: 	u_short code = 0, n = htons(TFTP_OPC_DATA);
  109: 	int len;
  110: 
  111: 	ETRACE();
  112: 
  113: 	RPACK_REWIND(pkt);
  114: 	rpack_uint16(pkt, &n, 0);
  115: 	n = htons(cli.seq);
  116: 	rpack_uint16(pkt, &n, 0);
  117: 
  118: 	/* max file size check */
  119: 	if (cli.tsiz && cli.tsiz < cli.seq * cli.siz) {
  120: 		len = cli.tsiz - (cli.seq - 1) * cli.siz;
  121: 		cli.close = 42;	/* last sended packet, should be close! */
  122: 	} else
  123: 		len = cli.siz;
  124: 
  125: 	len = pread(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
  126: 	if (len == -1) {
  127: 		ESYSERR(0);
  128: 		code = htons(3);
  129: 		goto end;
  130: 	} else {
  131: 		rpack_rnext(pkt, len);
  132: 		EVERBOSE(3, "Read from file %s %d bytes", cli.file, len);
  133: 	}
  134: 
  135: 	if (cli.siz - len)
  136: 		cli.close = 42;	/* last sended packet, should be close! */
  137: 
  138: 	schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  139: 			TASK_DATA(task), RPACK_OFF(pkt));
  140: 	taskExit(task, NULL);
  141: end:
  142: 	RPACK_REWIND(pkt);
  143: 	n = htons(TFTP_OPC_ERROR);
  144: 	rpack_uint16(pkt, &n, 0);
  145: 	rpack_uint16(pkt, &code, 0);
  146: 	rpack_rdata(pkt, errs[ntohs(code)].err_msg, strlen(errs[ntohs(code)].err_msg) + 1);
  147: 
  148: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  149: 			TASK_DATA(task), RPACK_OFF(pkt));
  150: 	taskExit(task, NULL);
  151: }
  152: 
  153: static void *
  154: txAck(sched_task_t *task)
  155: {
  156: 	rpack_t *pkt = TASK_DATA(task);
  157: 	u_short n = htons(TFTP_OPC_ACK);
  158: 
  159: 	ETRACE();
  160: 
  161: 	RPACK_REWIND(pkt);
  162: 	rpack_uint16(pkt, &n, 0);
  163: 	n = htons(cli.seq);
  164: 	rpack_uint16(pkt, &n, 0);
  165: 
  166: 	schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  167: 			TASK_DATA(task), RPACK_OFF(pkt));
  168: 
  169: 	if (cli.close) {
  170: 		schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_WRQ);
  171: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  172: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, TASK_DATA(task), 0);
  173: 		EVERBOSE(2, "Finish WRQ request");
  174: 		schedResumeby(TASK_ROOT(task), CRITERIA_ID, 0);
  175: 	}
  176: 	taskExit(task, NULL);
  177: }
  178: 
  179: static int
  180: getOpts(rpack_t * __restrict pkt, int rlen)
  181: {
  182: 	char *opt, *val;
  183: 	int len;
  184: 
  185: 	if (!rlen)
  186: 		return -1;
  187: 
  188: 	do {
  189: 		/* option */
  190: 		len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
  191: 		if (len == -1)
  192: 			return -1;
  193: 		else
  194: 			rlen -= len;
  195: 		opt = (char*) rpack_rnext(pkt, len);
  196: 		if (!opt)
  197: 			return -1;
  198: 		EVERBOSE(7, "opt=%s rlen=%d", opt, rlen);
  199: 		/* value */
  200: 		len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
  201: 		if (len == -1)
  202: 			return -1;
  203: 		else
  204: 			rlen -= len;
  205: 		val = (char*) rpack_rnext(pkt, len);
  206: 		if (!val)
  207: 			return -1;
  208: 		EVERBOSE(7, "val=%s rlen=%d", val, rlen);
  209: 
  210: 		if (!strcasecmp(opt, TFTP_OPT_BLKSIZE))
  211: 			cli.tmp = strtol(val, NULL, 10);
  212: 		else if (!strcasecmp(opt, TFTP_OPT_TSIZE))
  213: 			cli.tsiz = strtoll(val, NULL, 10);
  214: 		else if (!strcasecmp(opt, TFTP_OPT_TIMEOUT))
  215: 			cli.tout.tv_sec = strtol(val, NULL, 10);
  216: 		else if (!strcasecmp(opt, TFTP_OPT_ROLLOVER)) {
  217: 			cli.roll = strtol(val, NULL, 10);
  218: 			cli.roll++;
  219: 		}
  220: 	} while (rlen > 0);
  221: 
  222: 	EVERBOSE(4, "blksize=%u tsize=%llu timeout=%d rollover=%u", 
  223: 			cli.siz, cli.tsiz, (int) cli.tout.tv_sec, cli.roll - 1);
  224: 	return 0;
  225: }
  226: 
  227: static void *
  228: txOack(sched_task_t *task)
  229: {
  230: 	rpack_t *pkt = TASK_DATA(task);
  231: 	u_short n = htons(TFTP_OPC_OACK);
  232: 	struct stat sb;
  233: 	char szStr[STRSIZ];
  234: 
  235: 	ETRACE();
  236: 
  237: 	RPACK_REWIND(pkt);
  238: 	rpack_uint16(pkt, &n, 0);
  239: 
  240: 	/* if opcode is RRQ and tsize is 0 then we must return file size to client */
  241: 	if (cli.opc == TFTP_OPC_RRQ && !cli.tsiz && stat(cli.file, &sb) != -1)
  242: 		cli.tsiz = sb.st_size;
  243: 
  244: 	if (cli.siz > TFTP_LOAD_MAX) {
  245: 		memset(szStr, 0, sizeof szStr);
  246: 		snprintf(szStr, sizeof szStr, "%u", cli.siz);
  247: 		rpack_rdata(pkt, TFTP_OPT_BLKSIZE, strlen(TFTP_OPT_BLKSIZE) + 1);
  248: 		rpack_rdata(pkt, szStr, strlen(szStr) + 1);
  249: 	}
  250: 	if (cli.tsiz) {
  251: 		memset(szStr, 0, sizeof szStr);
  252: 		snprintf(szStr, sizeof szStr, "%llu", cli.tsiz);
  253: 		rpack_rdata(pkt, TFTP_OPT_TSIZE, strlen(TFTP_OPT_TSIZE) + 1);
  254: 		rpack_rdata(pkt, szStr, strlen(szStr) + 1);
  255: 	}
  256: 	if (cli.tout.tv_sec) {
  257: 		memset(szStr, 0, sizeof szStr);
  258: 		snprintf(szStr, sizeof szStr, "%d", (int) cli.tout.tv_sec);
  259: 		rpack_rdata(pkt, TFTP_OPT_TIMEOUT, strlen(TFTP_OPT_TIMEOUT) + 1);
  260: 		rpack_rdata(pkt, szStr, strlen(szStr) + 1);
  261: 	}
  262: 	if (cli.roll) {
  263: 		memset(szStr, 0, sizeof szStr);
  264: 		snprintf(szStr, sizeof szStr, "%u", cli.roll - 1);
  265: 		rpack_rdata(pkt, TFTP_OPT_ROLLOVER, strlen(TFTP_OPT_ROLLOVER) + 1);
  266: 		rpack_rdata(pkt, szStr, strlen(szStr) + 1);
  267: 	}
  268: 
  269: 	EVERBOSE(4, "blksize=%u tsize=%llu timeout=%d rollover=%u", 
  270: 			cli.siz, cli.tsiz, (int) cli.tout.tv_sec, cli.roll - 1);
  271: 	schedCallOnce(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  272: 			TASK_DATA(task), RPACK_OFF(pkt));
  273: 	taskExit(task, NULL);
  274: }
  275: 
  276: static void *
  277: RQ(sched_task_t *task)
  278: {
  279: 	rpack_t *pkt = TASK_DATA(task);
  280: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  281: 	int len, rlen = TASK_DATLEN(task) - 2;
  282: 	char *str;
  283: 	u_short code = 0;
  284: 
  285: 	ETRACE();
  286: 
  287: 	cli.siz = TFTP_LOAD_MAX;
  288: 	cli.opc = ntohs(rpack_uint16(pkt, NULL, 0));
  289: 	if (!RW && cli.opc == TFTP_OPC_WRQ) {
  290: 		code = htons(2);
  291: 		goto end;
  292: 	}
  293: 	len = str_getString(RPACK_NEXT(pkt), rlen, &str);
  294: 	if (len == -1)
  295: 		goto end;
  296: 	else {
  297: 		strlcpy(cli.file, (char*) RPACK_NEXT(pkt), sizeof cli.file);
  298: 		rlen -= len;
  299: 		rpack_rnext(pkt, len);
  300: 	}
  301: 	len = str_getString((const u_char*) str, rlen, NULL);
  302: 	if (len == -1)
  303: 		goto end;
  304: 	else {
  305: 		rlen -= len;
  306: 		rpack_rnext(pkt, len);
  307: 		if (!strcasecmp(str, TFTP_MODE_ASCII))
  308: 			strlcpy(cli.mode, TFTP_MODE_ASCII, sizeof cli.mode);
  309: 		else if (!strcasecmp(str, TFTP_MODE_OCTET))
  310: 			strlcpy(cli.mode, TFTP_MODE_OCTET, sizeof cli.mode);
  311: 		else if (!strcasecmp(str, TFTP_MODE_MAIL)) {
  312: 			strlcpy(cli.mode, TFTP_MODE_MAIL, sizeof cli.mode);
  313: 			code = htons(4);
  314: 			goto end;
  315: 		} else {
  316: 			code = htons(1);
  317: 			goto end;
  318: 		}
  319: 	}
  320: 
  321: 	switch (cli.opc) {
  322: 		case TFTP_OPC_RRQ:
  323: 			code = O_RDONLY;
  324: 			EVERBOSE(2, "RRQ:: file=%s mode=%s\n", cli.file, cli.mode);
  325: 			break;
  326: 		case TFTP_OPC_WRQ:
  327: 			code = O_WRONLY | O_CREAT;
  328: 			str = (char*) cfg_getAttribute(&cfg, "tftpd", "override");
  329: 			if (!str || tolower(*str) != 'y')
  330: 				code |= O_EXCL;
  331: 			EVERBOSE(2, "WRQ:: file=%s mode=%s\n", cli.file, cli.mode);
  332: 			break;
  333: 	}
  334: 
  335: 	cli.fd = open(cli.file, code, 0644);
  336: 	if (cli.fd == -1) {
  337: 		if (errno == EACCES)
  338: 			code = htons(2);
  339: 		else if (errno == ENFILE)
  340: 			code = htons(3);
  341: 		else if (errno == EEXIST)
  342: 			code = htons(6);
  343: 		else if (errno == ENOENT)
  344: 			code = htons(1);
  345: 		else
  346: 			code = htons(0);
  347: 		ESYSERR(0);
  348: 		goto end;
  349: 	} else
  350: 		cli.seq = 0;
  351: 
  352: 	schedEvent(TASK_ROOT(task), execProg, "request", 0, NULL, cli.opc);
  353: 
  354: 	if (!getOpts(pkt, rlen)) {
  355: 		if (cli.tmp > TFTP_LOAD_MAX) {
  356: 			if (rpack_resize(pkt, cli.tmp + 4))
  357: 				ELIBERR(elwix);
  358: 			else
  359: 				cli.siz = cli.tmp;
  360: 		}
  361: 		if (cli.tout.tv_sec) {
  362: 			schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
  363: 					timeoutSession, NULL);
  364: 			schedTimer(TASK_ROOT(task), timeoutSession, NULL, 
  365: 					cli.tout, TASK_DATA(task), 0);
  366: 		}
  367: 		schedEvent(TASK_ROOT(task), txOack, NULL, TASK_FD(task), 
  368: 				TASK_DATA(task), 0);
  369: 	} else if (cli.opc == TFTP_OPC_WRQ) {
  370: 		/* ack */
  371: 		tftp->tftp_opc = htons(TFTP_OPC_ACK);
  372: 		RPACK_REWIND(pkt);
  373: 		rpack_uint16(pkt, NULL, 0);
  374: 		rpack_uint16(pkt, &cli.seq, 0);
  375: 
  376: 		schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  377: 				TASK_DATA(task), RPACK_OFF(pkt));
  378: 	} else
  379: 		schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task), 
  380: 				TASK_DATA(task), 0);
  381: 
  382: 	cli.seq = 1;	/* 1st ack */
  383: 	taskExit(task, NULL);
  384: end:
  385: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  386: 	RPACK_REWIND(pkt);
  387: 	rpack_uint16(pkt, NULL, 0);
  388: 	rpack_uint16(pkt, &code, 0);
  389: 	rpack_rdata(pkt, errs[ntohs(code)].err_msg, strlen(errs[ntohs(code)].err_msg) + 1);
  390: 
  391: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  392: 			TASK_DATA(task), RPACK_OFF(pkt));
  393: 	taskExit(task, NULL);
  394: }
  395: 
  396: static void *
  397: ACK(sched_task_t *task)
  398: {
  399: 	rpack_t *pkt = TASK_DATA(task);
  400: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  401: 	u_short code;
  402: 
  403: 	ETRACE();
  404: 
  405: 	RPACK_REWIND(pkt);
  406: 	code = rpack_uint16(pkt, NULL, 0);
  407: 	if (ntohs(code) != TFTP_OPC_ACK) {
  408: 		code = htons(5);
  409: 		goto end;
  410: 	}
  411: 
  412: 	code = rpack_uint16(pkt, NULL, 0);
  413: 	if (ntohs(code) > cli.seq || (ntohs(code) < (cli.seq - 1))) {
  414: 		code = htons(5);
  415: 		goto end;
  416: 	} else if (ntohs(code) == cli.seq) {
  417: 		/* check for rollover seq id */
  418: 		if (cli.roll && cli.seq == USHRT_MAX)
  419: 			cli.seq = cli.roll - 1;
  420: 		else
  421: 			cli.seq++;
  422: 	}
  423: 
  424: 	EVERBOSE(3, "ACK:: seq=%hu; my new seq=%hu;", ntohs(code), cli.seq);
  425: 
  426: 	if (!cli.close)
  427: 		schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task), 
  428: 				TASK_DATA(task), 0);
  429: 	else {
  430: 		schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_RRQ);
  431: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  432: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, TASK_DATA(task), 0);
  433: 		EVERBOSE(2, "Finish RRQ request");
  434: 	}
  435: 	taskExit(task, NULL);
  436: end:
  437: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  438: 	RPACK_REWIND(pkt);
  439: 	rpack_uint16(pkt, NULL, 0);
  440: 	rpack_uint16(pkt, &code, 0);
  441: 	rpack_rdata(pkt, errs[ntohs(code)].err_msg, strlen(errs[ntohs(code)].err_msg) + 1);
  442: 
  443: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  444: 			TASK_DATA(task), RPACK_OFF(pkt));
  445: 	taskExit(task, NULL);
  446: }
  447: 
  448: static void *
  449: DATA(sched_task_t *task)
  450: {
  451: 	rpack_t *pkt = TASK_DATA(task);
  452: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  453: 	u_short code;
  454: 	int len;
  455: 
  456: 	ETRACE();
  457: 
  458: 	RPACK_REWIND(pkt);
  459: 	code = rpack_uint16(pkt, NULL, 0);
  460: 	if (ntohs(code) != TFTP_OPC_DATA) {
  461: 		code = htons(5);
  462: 		goto end;
  463: 	}
  464: 
  465: 	code = rpack_uint16(pkt, NULL, 0);
  466: 	if (ntohs(code) < cli.seq || ntohs(code) > cli.seq + 1) {
  467: 		code = htons(5);
  468: 		goto end;
  469: 	} else
  470: 		cli.seq = ntohs(code);
  471: 
  472: 	/* max file size check */
  473: 	len = TASK_DATLEN(task) - RPACK_OFF(pkt);
  474: 	if (cli.tsiz && cli.tsiz < cli.seq * cli.siz)
  475: 		len = MIN(len, cli.tsiz - (cli.seq - 1) * cli.siz);
  476: 	if (len < cli.siz)
  477: 		cli.close = 42;	/* last received packet, should be close! */
  478: 
  479: 	EVERBOSE(3, "DATA:: seq=%hu; len=%d", cli.seq, len);
  480: 
  481: 	if (len > 0) {
  482: 		if (!bf)
  483: 			len = pwrite(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
  484: 		else
  485: 			len = bfwrite(cli.fd, RPACK_NEXT(pkt), len);
  486: 		if (len == -1) {
  487: 			ESYSERR(0);
  488: 			code = htons(3);
  489: 			goto end;
  490: 		} else
  491: 			rpack_rnext(pkt, len);
  492: 	}
  493: 	EVERBOSE(3, "Written to file %s %d bytes", cli.file, len);
  494: 
  495: 	schedEvent(TASK_ROOT(task), txAck, NULL, TASK_FD(task), TASK_DATA(task), 0);
  496: 	taskExit(task, NULL);
  497: end:
  498: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  499: 	RPACK_REWIND(pkt);
  500: 	rpack_uint16(pkt, NULL, 0);
  501: 	rpack_uint16(pkt, &code, 0);
  502: 	rpack_rdata(pkt, errs[ntohs(code)].err_msg, strlen(errs[ntohs(code)].err_msg) + 1);
  503: 
  504: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  505: 			TASK_DATA(task), RPACK_OFF(pkt));
  506: 	taskExit(task, NULL);
  507: }
  508: 
  509: void *
  510: rxPkt(sched_task_t *task)
  511: {
  512: 	sockaddr_t sa;
  513: 	socklen_t salen = sizeof sa;
  514: 	int rlen;
  515: 	rpack_t *pkt = TASK_DATA(task);
  516: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  517: 	u_short code;
  518: 
  519: 	ETRACE();
  520: 
  521: 	memset(RPACK_BUF(pkt), 0, RPACK_LEN(pkt));
  522: 	rlen = recvfrom(TASK_FD(task), RPACK_BUF(pkt), RPACK_LEN(pkt), 0, &sa.sa, &salen);
  523: 	if (rlen == -1) {
  524: 		ESYSERR(0);
  525: 		goto end;
  526: 	} else if (!cli.addr.sa.sa_len) {
  527: 		cli.addr = sa;
  528: 		RPACK_REWIND(pkt);
  529: 		switch (ntohs(tftp->tftp_opc)) {
  530: 			case TFTP_OPC_RRQ:
  531: 			case TFTP_OPC_WRQ:
  532: 				schedEvent(TASK_ROOT(task), RQ, NULL, TASK_FD(task), 
  533: 						TASK_DATA(task), rlen);
  534: 				break;
  535: 			case TFTP_OPC_ERROR:
  536: 			default:
  537: 				RPACK_REWIND(pkt);
  538: 				code = htons(TFTP_OPC_ERROR);
  539: 				rpack_uint16(pkt, &code, 0);
  540: 				code = htons(4);
  541: 				rpack_uint16(pkt, &code, 0);
  542: 				rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
  543: 
  544: 				schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  545: 						TASK_DATA(task), RPACK_OFF(pkt));
  546: 				goto end;
  547: 		}
  548: 	} else if (memcmp(&cli.addr, &sa, salen)) {
  549: 		EERROR(LOG_WARNING, "Packet dropped!!!\n"
  550: 				"Get frame from different address for this session");
  551: 		goto end;
  552: 	} else
  553: 		switch (ntohs(tftp->tftp_opc)) {
  554: 			case TFTP_OPC_ACK:
  555: 				schedEvent(TASK_ROOT(task), ACK, NULL, TASK_FD(task), 
  556: 						TASK_DATA(task), rlen);
  557: 				break;
  558: 			case TFTP_OPC_DATA:
  559: 				schedEvent(TASK_ROOT(task), DATA, NULL, TASK_FD(task), 
  560: 						TASK_DATA(task), rlen);
  561: 				break;
  562: 			case TFTP_OPC_OACK:
  563: 			case TFTP_OPC_ERROR:
  564: 			default:
  565: 				RPACK_REWIND(pkt);
  566: 				code = htons(TFTP_OPC_ERROR);
  567: 				rpack_uint16(pkt, &code, 0);
  568: 				code = htons(4);
  569: 				rpack_uint16(pkt, &code, 0);
  570: 				rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
  571: 
  572: 				schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  573: 						TASK_DATA(task), RPACK_OFF(pkt));
  574: 				goto end;
  575: 		}
  576: 
  577: 	schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  578: 	schedTimer(TASK_ROOT(task), timeoutSession, NULL, 
  579: 			cli.tout.tv_sec ? cli.tout : timeout, TASK_DATA(task), 0);
  580: end:
  581: 	schedReadSelf(task);
  582: 	taskExit(task, NULL);
  583: }

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