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