Annotation of tftpd/src/srv.c, revision 1.3
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.3 ! misho 119: static int
! 120: getOpts(const char *opts, int rlen)
! 121: {
! 122: if (!opts)
! 123: return -1;
! 124:
! 125: return 0;
! 126: }
! 127:
1.1 misho 128: static void *
129: RQ(sched_task_t *task)
130: {
131: rpack_t *pkt = TASK_DATA(task);
132: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
133: int len, rlen = TASK_DATLEN(task) - 2;
1.3 ! misho 134: char *str, *opts;
1.1 misho 135: u_short code = 0;
136:
137: ETRACE();
138:
139: cli.siz = TFTP_LOAD_MAX;
140: len = str_getString(tftp->tftp_data, rlen, &str);
141: if (len == -1)
142: goto end;
143: else {
144: rlen -= len;
145: strlcpy(cli.file, (char*) tftp->tftp_data, sizeof cli.file);
146: }
1.3 ! misho 147: len = str_getString((const u_char*) str, rlen, &opts);
1.1 misho 148: if (len == -1)
149: goto end;
150: else {
151: rlen -= len;
152: if (!strcasecmp(str, TFTP_MODE_ASCII))
153: strlcpy(cli.mode, TFTP_MODE_ASCII, sizeof cli.mode);
154: else if (!strcasecmp(str, TFTP_MODE_OCTET))
155: strlcpy(cli.mode, TFTP_MODE_OCTET, sizeof cli.mode);
156: else if (!strcasecmp(str, TFTP_MODE_MAIL)) {
157: strlcpy(cli.mode, TFTP_MODE_MAIL, sizeof cli.mode);
158: code = htole16(4);
159: goto end;
160: } else {
161: code = htole16(1);
162: goto end;
163: }
164: }
165:
1.3 ! misho 166: /* tftp extended options */
! 167: if (!RPACK_ISEND(pkt) && !getOpts(opts, rlen))
! 168: cli.opts = 42; /* we have options */
! 169:
1.1 misho 170: cli.opc = ntohs(tftp->tftp_opc);
171: switch (cli.opc) {
172: case TFTP_OPC_RRQ:
173: code = O_RDONLY;
174: EVERBOSE(2, "RRQ:: file=%s mode=%s\n", cli.file, cli.mode);
175: break;
176: case TFTP_OPC_WRQ:
177: code = O_WRONLY | O_CREAT;
178: str = (char*) cfg_getAttribute(&cfg, "tftpd", "override");
179: if (!str || tolower(*str) != 'y')
180: code |= O_EXCL;
181: EVERBOSE(2, "WRQ:: file=%s mode=%s\n", cli.file, cli.mode);
182: break;
183: }
184: cli.fd = open(cli.file, code, 0644);
185: if (cli.fd == -1) {
186: if (errno == EACCES)
187: code = htole16(2);
188: else if (errno == ENFILE)
189: code = htole16(3);
190: else if (errno == EEXIST)
191: code = htole16(6);
192: else
193: code = htole16(0);
194: ESYSERR(0);
195: goto end;
196: } else
197: cli.seq = 0;
198:
1.2 misho 199: schedEvent(TASK_ROOT(task), execProg, "request", 0, NULL, cli.opc);
200:
1.1 misho 201: if (cli.opc == TFTP_OPC_WRQ) {
202: /* ack */
203: tftp->tftp_opc = htons(TFTP_OPC_ACK);
204: RPACK_REWIND(pkt);
205: rpack_uint16(pkt, NULL, 0);
206: rpack_uint16(pkt, &cli.seq, 0);
207:
208: schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task),
209: TASK_DATA(task), RPACK_OFF(pkt));
210: } else
211: schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task),
212: TASK_DATA(task), 0);
213:
214: cli.seq = 1; /* 1st ack */
215: taskExit(task, NULL);
216: end:
217: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
218: RPACK_REWIND(pkt);
219: rpack_uint16(pkt, NULL, 0);
220: rpack_uint16(pkt, &code, 0);
221: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
222:
223: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
224: TASK_DATA(task), RPACK_OFF(pkt));
225: taskExit(task, NULL);
226: }
227:
228: static void *
229: ACK(sched_task_t *task)
230: {
231: rpack_t *pkt = TASK_DATA(task);
232: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
233: u_short code;
234:
235: ETRACE();
236:
237: RPACK_REWIND(pkt);
238: code = rpack_uint16(pkt, NULL, 0);
239: if (ntohs(code) != TFTP_OPC_ACK) {
240: code = htole16(5);
241: goto end;
242: }
243:
244: code = rpack_uint16(pkt, NULL, 0);
245: if (ntohs(code) > cli.seq || (ntohs(code) < (cli.seq - 1))) {
246: code = htole16(5);
247: goto end;
248: } else if (ntohs(code) == cli.seq)
249: cli.seq++;
250:
251: EVERBOSE(3, "ACK:: seq=%hu; my new seq=%hu;", ntohs(code), cli.seq);
252:
253: if (!cli.close)
254: schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task),
255: TASK_DATA(task), 0);
256: else {
1.2 misho 257: schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_RRQ);
1.1 misho 258: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
259: schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
260: EVERBOSE(2, "Finish RRQ request");
261: }
262: taskExit(task, NULL);
263: end:
264: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
265: RPACK_REWIND(pkt);
266: rpack_uint16(pkt, NULL, 0);
267: rpack_uint16(pkt, &code, 0);
268: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
269:
270: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
271: TASK_DATA(task), RPACK_OFF(pkt));
272: taskExit(task, NULL);
273: }
274:
275: static void *
276: DATA(sched_task_t *task)
277: {
278: rpack_t *pkt = TASK_DATA(task);
279: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
280: u_short code;
281: int len;
282:
283: ETRACE();
284:
285: RPACK_REWIND(pkt);
286: code = rpack_uint16(pkt, NULL, 0);
287: if (ntohs(code) != TFTP_OPC_DATA) {
288: code = htole16(5);
289: goto end;
290: }
291:
292: code = rpack_uint16(pkt, NULL, 0);
293: if (ntohs(code) < cli.seq || ntohs(code) > cli.seq + 1) {
294: code = htole16(5);
295: goto end;
296: } else
297: cli.seq = ntohs(code);
298:
299: len = TASK_DATLEN(task) - RPACK_OFF(pkt);
300: if (len < cli.siz)
301: cli.close = 42; /* last received packet, should be close! */
302:
303: EVERBOSE(3, "DATA:: seq=%hu; len=%d", cli.seq, len);
304:
305: len = pwrite(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
306: if (len == -1) {
307: ESYSERR(0);
308: code = htole16(3);
309: goto end;
310: } else {
311: rpack_rnext(pkt, len);
312: EVERBOSE(3, "Written to file %s %d bytes", cli.file, len);
313: }
314:
315: schedEvent(TASK_ROOT(task), txAck, NULL, TASK_FD(task), TASK_DATA(task), 0);
316: taskExit(task, NULL);
317: end:
318: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
319: RPACK_REWIND(pkt);
320: rpack_uint16(pkt, NULL, 0);
321: rpack_uint16(pkt, &code, 0);
322: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
323:
324: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
325: TASK_DATA(task), RPACK_OFF(pkt));
326: taskExit(task, NULL);
327: }
328:
329: void *
330: rxPkt(sched_task_t *task)
331: {
332: sockaddr_t sa;
333: socklen_t salen = sizeof sa;
334: int rlen;
335: rpack_t *pkt = TASK_DATA(task);
336: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
337: u_short code;
338:
339: ETRACE();
340:
341: memset(RPACK_BUF(pkt), 0, RPACK_LEN(pkt));
342: rlen = recvfrom(TASK_FD(task), RPACK_BUF(pkt), RPACK_LEN(pkt), 0, &sa.sa, &salen);
343: if (rlen == -1) {
344: ESYSERR(0);
345: goto end;
346: } else if (!cli.addr.sa.sa_len) {
347: cli.addr = sa;
348: switch (ntohs(tftp->tftp_opc)) {
349: case TFTP_OPC_RRQ:
350: case TFTP_OPC_WRQ:
351: schedEvent(TASK_ROOT(task), RQ, NULL, TASK_FD(task),
352: TASK_DATA(task), rlen);
353: break;
354: case TFTP_OPC_ERROR:
355: default:
356: RPACK_REWIND(pkt);
357: code = htons(TFTP_OPC_ERROR);
358: rpack_uint16(pkt, &code, 0);
359: code = htole16(4);
360: rpack_uint16(pkt, &code, 0);
361: rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
362:
363: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
364: TASK_DATA(task), RPACK_OFF(pkt));
365: goto end;
366: }
367: } else if (memcmp(&cli.addr, &sa, salen)) {
368: EERROR(LOG_WARNING, "Packet dropped!!!\n"
369: "Get frame from different address for this session");
370: goto end;
371: } else
372: switch (ntohs(tftp->tftp_opc)) {
373: case TFTP_OPC_ACK:
374: schedEvent(TASK_ROOT(task), ACK, NULL, TASK_FD(task),
375: TASK_DATA(task), rlen);
376: break;
377: case TFTP_OPC_DATA:
378: schedEvent(TASK_ROOT(task), DATA, NULL, TASK_FD(task),
379: TASK_DATA(task), rlen);
380: break;
381: case TFTP_OPC_OACK:
382: ELOGGER(LOG_WARNING, "oack");
383: /*
384: schedEvent(TASK_ROOT(task), OACK, NULL, TASK_FD(task),
385: TASK_DATA(task), rlen);
386: */
387: break;
388: case TFTP_OPC_ERROR:
389: default:
390: RPACK_REWIND(pkt);
391: code = htons(TFTP_OPC_ERROR);
392: rpack_uint16(pkt, &code, 0);
393: code = htole16(4);
394: rpack_uint16(pkt, &code, 0);
395: rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
396:
397: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
398: TASK_DATA(task), RPACK_OFF(pkt));
399: goto end;
400: }
401:
402: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
403: schedTimer(TASK_ROOT(task), timeoutSession, NULL, timeout, NULL, 0);
404: end:
405: schedReadSelf(task);
406: taskExit(task, NULL);
407: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>