Return to srv.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / tftpd / src |
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: {
1.2.2.2 misho 122: char *opt, *val;
123: int len;
124:
125: do {
126: /* option */
127: len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
128: if (len == -1)
129: return -1;
130: opt = (char*) rpack_rnext(pkt, len);
131: if (!opt)
132: return -1;
133: /* value */
134: len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
135: if (len == -1)
136: return -1;
137: val = (char*) rpack_rnext(pkt, len);
138: if (!val)
139: return -1;
140:
141: if (!strcasecmp(opt, TFTP_OPT_BLKSIZE)) {
142: len = strtol(val, NULL, 10);
143: if (len > TFTP_LOAD_MAX)
144: cli.siz = len;
145: } else if (!strcasecmp(opt, TFTP_OPT_TSIZE))
146: cli.tsiz = strtoll(val, NULL, 10);
147: else if (!strcasecmp(opt, TFTP_OPT_TIMEOUT))
148: cli.tout = strtol(val, NULL, 10);
149: else
150: return -1;
151: } while (!RPACK_ISEND(pkt));
152:
1.2.2.3 ! misho 153: EVERBOSE(4, "blksize=%u tsize=%llu timeout=%u", cli.siz, cli.tsiz, cli.tout);
1.2.2.1 misho 154: return 0;
155: }
156:
157: static void *
158: txOack(sched_task_t *task)
159: {
160: rpack_t *pkt = TASK_DATA(task);
161: u_short n = htons(TFTP_OPC_OACK);
162: struct stat sb;
163: char szStr[STRSIZ];
164:
165: ETRACE();
166:
167: RPACK_REWIND(pkt);
168: rpack_uint16(pkt, &n, 0);
169:
170: /* if opcode is RRQ and tsize is 0 then we must return file size to client */
171: if (cli.opc == TFTP_OPC_RRQ && !cli.tsiz && stat(cli.file, &sb) != -1)
172: cli.tsiz = sb.st_size;
173:
174: if (cli.siz > TFTP_LOAD_MAX) {
175: memset(szStr, 0, sizeof szStr);
176: snprintf(szStr, sizeof szStr, "%u", cli.siz);
177: rpack_rdata(pkt, TFTP_OPT_BLKSIZE, strlen(TFTP_OPT_BLKSIZE) + 1);
178: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
179: }
180: if (cli.tsiz) {
181: memset(szStr, 0, sizeof szStr);
182: snprintf(szStr, sizeof szStr, "%llu", cli.tsiz);
183: rpack_rdata(pkt, TFTP_OPT_TSIZE, strlen(TFTP_OPT_TSIZE) + 1);
184: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
185: }
186: if (cli.tout) {
187: memset(szStr, 0, sizeof szStr);
188: snprintf(szStr, sizeof szStr, "%u", cli.tout);
189: rpack_rdata(pkt, TFTP_OPT_TIMEOUT, strlen(TFTP_OPT_TIMEOUT) + 1);
190: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
191: }
192:
193: schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task),
194: TASK_DATA(task), RPACK_OFF(pkt));
195: taskExit(task, NULL);
196: }
197:
1.1 misho 198: static void *
199: RQ(sched_task_t *task)
200: {
201: rpack_t *pkt = TASK_DATA(task);
202: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
203: int len, rlen = TASK_DATLEN(task) - 2;
204: char *str;
205: u_short code = 0;
206:
207: ETRACE();
208:
209: cli.siz = TFTP_LOAD_MAX;
210: len = str_getString(tftp->tftp_data, rlen, &str);
211: if (len == -1)
212: goto end;
213: else {
214: rlen -= len;
215: strlcpy(cli.file, (char*) tftp->tftp_data, sizeof cli.file);
216: }
217: len = str_getString((const u_char*) str, rlen, NULL);
218: if (len == -1)
219: goto end;
220: else {
221: rlen -= len;
222: if (!strcasecmp(str, TFTP_MODE_ASCII))
223: strlcpy(cli.mode, TFTP_MODE_ASCII, sizeof cli.mode);
224: else if (!strcasecmp(str, TFTP_MODE_OCTET))
225: strlcpy(cli.mode, TFTP_MODE_OCTET, sizeof cli.mode);
226: else if (!strcasecmp(str, TFTP_MODE_MAIL)) {
227: strlcpy(cli.mode, TFTP_MODE_MAIL, sizeof cli.mode);
228: code = htole16(4);
229: goto end;
230: } else {
231: code = htole16(1);
232: goto end;
233: }
234: }
235:
236: cli.opc = ntohs(tftp->tftp_opc);
237: switch (cli.opc) {
238: case TFTP_OPC_RRQ:
239: code = O_RDONLY;
240: EVERBOSE(2, "RRQ:: file=%s mode=%s\n", cli.file, cli.mode);
241: break;
242: case TFTP_OPC_WRQ:
243: code = O_WRONLY | O_CREAT;
244: str = (char*) cfg_getAttribute(&cfg, "tftpd", "override");
245: if (!str || tolower(*str) != 'y')
246: code |= O_EXCL;
247: EVERBOSE(2, "WRQ:: file=%s mode=%s\n", cli.file, cli.mode);
248: break;
249: }
1.2.2.1 misho 250:
251: if (!RPACK_ISEND(pkt) && !getOpts(pkt))
252: schedEvent(TASK_ROOT(task), txOack, NULL, TASK_FD(task),
253: TASK_DATA(task), 0);
254:
1.1 misho 255: cli.fd = open(cli.file, code, 0644);
256: if (cli.fd == -1) {
257: if (errno == EACCES)
258: code = htole16(2);
259: else if (errno == ENFILE)
260: code = htole16(3);
261: else if (errno == EEXIST)
262: code = htole16(6);
263: else
264: code = htole16(0);
265: ESYSERR(0);
266: goto end;
267: } else
268: cli.seq = 0;
269:
1.2 misho 270: schedEvent(TASK_ROOT(task), execProg, "request", 0, NULL, cli.opc);
271:
1.1 misho 272: if (cli.opc == TFTP_OPC_WRQ) {
273: /* ack */
274: tftp->tftp_opc = htons(TFTP_OPC_ACK);
275: RPACK_REWIND(pkt);
276: rpack_uint16(pkt, NULL, 0);
277: rpack_uint16(pkt, &cli.seq, 0);
278:
279: schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task),
280: TASK_DATA(task), RPACK_OFF(pkt));
281: } else
282: schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task),
283: TASK_DATA(task), 0);
284:
285: cli.seq = 1; /* 1st ack */
286: taskExit(task, NULL);
287: end:
288: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
289: RPACK_REWIND(pkt);
290: rpack_uint16(pkt, NULL, 0);
291: rpack_uint16(pkt, &code, 0);
292: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
293:
294: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
295: TASK_DATA(task), RPACK_OFF(pkt));
296: taskExit(task, NULL);
297: }
298:
299: static void *
300: ACK(sched_task_t *task)
301: {
302: rpack_t *pkt = TASK_DATA(task);
303: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
304: u_short code;
305:
306: ETRACE();
307:
308: RPACK_REWIND(pkt);
309: code = rpack_uint16(pkt, NULL, 0);
310: if (ntohs(code) != TFTP_OPC_ACK) {
311: code = htole16(5);
312: goto end;
313: }
314:
315: code = rpack_uint16(pkt, NULL, 0);
316: if (ntohs(code) > cli.seq || (ntohs(code) < (cli.seq - 1))) {
317: code = htole16(5);
318: goto end;
319: } else if (ntohs(code) == cli.seq)
320: cli.seq++;
321:
322: EVERBOSE(3, "ACK:: seq=%hu; my new seq=%hu;", ntohs(code), cli.seq);
323:
324: if (!cli.close)
325: schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task),
326: TASK_DATA(task), 0);
327: else {
1.2 misho 328: schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_RRQ);
1.1 misho 329: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
330: schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
331: EVERBOSE(2, "Finish RRQ request");
332: }
333: taskExit(task, NULL);
334: end:
335: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
336: RPACK_REWIND(pkt);
337: rpack_uint16(pkt, NULL, 0);
338: rpack_uint16(pkt, &code, 0);
339: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
340:
341: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
342: TASK_DATA(task), RPACK_OFF(pkt));
343: taskExit(task, NULL);
344: }
345:
346: static void *
347: DATA(sched_task_t *task)
348: {
349: rpack_t *pkt = TASK_DATA(task);
350: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
351: u_short code;
352: int len;
353:
354: ETRACE();
355:
356: RPACK_REWIND(pkt);
357: code = rpack_uint16(pkt, NULL, 0);
358: if (ntohs(code) != TFTP_OPC_DATA) {
359: code = htole16(5);
360: goto end;
361: }
362:
363: code = rpack_uint16(pkt, NULL, 0);
364: if (ntohs(code) < cli.seq || ntohs(code) > cli.seq + 1) {
365: code = htole16(5);
366: goto end;
367: } else
368: cli.seq = ntohs(code);
369:
370: len = TASK_DATLEN(task) - RPACK_OFF(pkt);
371: if (len < cli.siz)
372: cli.close = 42; /* last received packet, should be close! */
373:
374: EVERBOSE(3, "DATA:: seq=%hu; len=%d", cli.seq, len);
375:
376: len = pwrite(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
377: if (len == -1) {
378: ESYSERR(0);
379: code = htole16(3);
380: goto end;
381: } else {
382: rpack_rnext(pkt, len);
383: EVERBOSE(3, "Written to file %s %d bytes", cli.file, len);
384: }
385:
386: schedEvent(TASK_ROOT(task), txAck, NULL, TASK_FD(task), TASK_DATA(task), 0);
387: taskExit(task, NULL);
388: end:
389: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
390: RPACK_REWIND(pkt);
391: rpack_uint16(pkt, NULL, 0);
392: rpack_uint16(pkt, &code, 0);
393: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
394:
395: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
396: TASK_DATA(task), RPACK_OFF(pkt));
397: taskExit(task, NULL);
398: }
399:
400: void *
401: rxPkt(sched_task_t *task)
402: {
403: sockaddr_t sa;
404: socklen_t salen = sizeof sa;
405: int rlen;
406: rpack_t *pkt = TASK_DATA(task);
407: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
408: u_short code;
409:
410: ETRACE();
411:
412: memset(RPACK_BUF(pkt), 0, RPACK_LEN(pkt));
413: rlen = recvfrom(TASK_FD(task), RPACK_BUF(pkt), RPACK_LEN(pkt), 0, &sa.sa, &salen);
414: if (rlen == -1) {
415: ESYSERR(0);
416: goto end;
417: } else if (!cli.addr.sa.sa_len) {
418: cli.addr = sa;
419: switch (ntohs(tftp->tftp_opc)) {
420: case TFTP_OPC_RRQ:
421: case TFTP_OPC_WRQ:
422: schedEvent(TASK_ROOT(task), RQ, NULL, TASK_FD(task),
423: TASK_DATA(task), rlen);
424: break;
425: case TFTP_OPC_ERROR:
426: default:
427: RPACK_REWIND(pkt);
428: code = htons(TFTP_OPC_ERROR);
429: rpack_uint16(pkt, &code, 0);
430: code = htole16(4);
431: rpack_uint16(pkt, &code, 0);
432: rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
433:
434: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
435: TASK_DATA(task), RPACK_OFF(pkt));
436: goto end;
437: }
438: } else if (memcmp(&cli.addr, &sa, salen)) {
439: EERROR(LOG_WARNING, "Packet dropped!!!\n"
440: "Get frame from different address for this session");
441: goto end;
442: } else
443: switch (ntohs(tftp->tftp_opc)) {
444: case TFTP_OPC_ACK:
445: schedEvent(TASK_ROOT(task), ACK, NULL, TASK_FD(task),
446: TASK_DATA(task), rlen);
447: break;
448: case TFTP_OPC_DATA:
449: schedEvent(TASK_ROOT(task), DATA, NULL, TASK_FD(task),
450: TASK_DATA(task), rlen);
451: break;
452: case TFTP_OPC_OACK:
453: ELOGGER(LOG_WARNING, "oack");
454: /*
455: schedEvent(TASK_ROOT(task), OACK, NULL, TASK_FD(task),
456: TASK_DATA(task), rlen);
457: */
458: break;
459: case TFTP_OPC_ERROR:
460: default:
461: RPACK_REWIND(pkt);
462: code = htons(TFTP_OPC_ERROR);
463: rpack_uint16(pkt, &code, 0);
464: code = htole16(4);
465: rpack_uint16(pkt, &code, 0);
466: rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
467:
468: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
469: TASK_DATA(task), RPACK_OFF(pkt));
470: goto end;
471: }
472:
473: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
474: schedTimer(TASK_ROOT(task), timeoutSession, NULL, timeout, NULL, 0);
475: end:
476: schedReadSelf(task);
477: taskExit(task, NULL);
478: }