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