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