|
|
| version 1.1.2.7, 2009/11/15 21:33:17 | version 1.3.2.1, 2012/07/22 22:54:53 |
|---|---|
| Line 1 | Line 1 |
| /************************************************************************* | |
| * (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com> | |
| * by Michael Pounov <misho@aitbg.com> | |
| * | |
| * $Author$ | |
| * $Id$ | |
| * | |
| ************************************************************************* | |
| The ELWIX and AITNET software is distributed under the following | |
| terms: | |
| All of the documentation and software included in the ELWIX and AITNET | |
| Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org> | |
| Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 | |
| by Michael Pounov <misho@elwix.org>. All rights reserved. | |
| Redistribution and use in source and binary forms, with or without | |
| modification, are permitted provided that the following conditions | |
| are met: | |
| 1. Redistributions of source code must retain the above copyright | |
| notice, this list of conditions and the following disclaimer. | |
| 2. Redistributions in binary form must reproduce the above copyright | |
| notice, this list of conditions and the following disclaimer in the | |
| documentation and/or other materials provided with the distribution. | |
| 3. All advertising materials mentioning features or use of this software | |
| must display the following acknowledgement: | |
| This product includes software developed by Michael Pounov <misho@elwix.org> | |
| ELWIX - Embedded LightWeight unIX and its contributors. | |
| 4. Neither the name of AITNET nor the names of its contributors | |
| may be used to endorse or promote products derived from this software | |
| without specific prior written permission. | |
| THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND | |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| SUCH DAMAGE. | |
| */ | |
| #include "global.h" | #include "global.h" |
| #include "upd.h" | #include "upd.h" |
| Line 350 static void Signal(int sig) | Line 395 static void Signal(int sig) |
| int stat; | int stat; |
| switch (sig) { | switch (sig) { |
| case SIGHUP: | |
| VERB(5) printf("Info(5):: Signal arrived #%d\n", sig); | |
| break; | |
| case SIGCHLD: | case SIGCHLD: |
| while (waitpid(-1, &stat, WNOHANG) > 0); | while (waitpid(-1, &stat, WNOHANG) > 0); |
| break; | break; |
| Line 365 int Daemonize(struct sockaddr_in sin, const char *csTF | Line 413 int Daemonize(struct sockaddr_in sin, const char *csTF |
| int s, n = 1; | int s, n = 1; |
| pid_t pid; | pid_t pid; |
| fd_set rfd; | fd_set rfd; |
| int clilen, len; | u_short seq = 0xffff; |
| struct sockaddr_in cli; | int clilen, len, f, retry; |
| struct sockaddr_in cli, rcv; | |
| struct sigaction sa; | struct sigaction sa; |
| struct tftphdr *tftp; | u_char buf[TFTP_BUF], *pos; |
| u_char buf[TFTP_BUF]; | char szFName[STRSIZ]; |
| struct tftphdr *tftp = (struct tftphdr*) buf; | |
| struct timeval tv = { TFTP_TIMEOUT, 0 }; | |
| VERB(3) printf("Daemonize procedure for %s:%d to %s\n", | VERB(3) printf("Daemonize procedure for %s:%d to %s\n", |
| inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), csTFTP); | inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), csTFTP); |
| Line 379 int Daemonize(struct sockaddr_in sin, const char *csTF | Line 430 int Daemonize(struct sockaddr_in sin, const char *csTF |
| sa.sa_handler = Signal; | sa.sa_handler = Signal; |
| sigaction(SIGCHLD, &sa, NULL); | sigaction(SIGCHLD, &sa, NULL); |
| sigaction(SIGTERM, &sa, NULL); | sigaction(SIGTERM, &sa, NULL); |
| sigaction(SIGHUP, &sa, NULL); | |
| s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); | s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| if (s == -1) { | if (s == -1) { |
| Line 410 int Daemonize(struct sockaddr_in sin, const char *csTF | Line 462 int Daemonize(struct sockaddr_in sin, const char *csTF |
| if (select(s + 1, &rfd, NULL, NULL, NULL) == -1) | if (select(s + 1, &rfd, NULL, NULL, NULL) == -1) |
| continue; | continue; |
| memset(buf, 0, TFTP_BUF); | |
| clilen = sizeof cli; | clilen = sizeof cli; |
| len = recvfrom(s, buf, TFTP_BUF, 0, (struct sockaddr*) &cli, | len = recvfrom(s, buf, TFTP_BUF, 0, (struct sockaddr*) &cli, |
| (socklen_t*) &clilen); | (socklen_t*) &clilen); |
| if (len == -1) | if (len == -1) { |
| VERB(5) printf("Error:: in recvfrom #%d - %s\n", | |
| errno, strerror(errno)); | |
| continue; | continue; |
| } | |
| tftp = (struct tftphdr*) (pos = buf); | |
| VERB(5) printf("Info(5):: Received packet from %s len %d with opcode=%hd\n", | |
| inet_ntoa(cli.sin_addr), len, ntohs(tftp->th_opcode)); | |
| switch (ntohs(tftp->th_opcode)) { | |
| case WRQ: | |
| len -= 2; | |
| pos += 2; | |
| strlcpy(szFName, (char*) pos, sizeof szFName); | |
| VERB(5) printf("Info(5):: Get filename %s\n", szFName); | |
| len -= strlen((char*) pos) + 1; | |
| pos += strlen((char*) pos) + 1; | |
| VERB(5) printf("Info(5):: Get mode %s len=%d\n", pos, len); | |
| if (strncmp((char*) pos, "octet", len)) { | |
| memset(buf, 0, TFTP_BUF); | |
| tftp->th_opcode = htons(ERROR); | |
| tftp->th_code = htons(EBADOP); | |
| strncpy(tftp->th_data, "Error:: mode not supported", 27); | |
| sendto(s, buf, 31, 0, (struct sockaddr*) &cli, sizeof cli); | |
| continue; | |
| } | |
| VERB(2) printf("Info(2):: Receive file %s from %s\n", | |
| szFName, inet_ntoa(cli.sin_addr)); | |
| f = open(szFName, O_WRONLY | O_CREAT | O_EXCL, 0644); | |
| if (f == -1) { | |
| memset(buf, 0, TFTP_BUF); | |
| tftp->th_opcode = htons(ERROR); | |
| switch (errno) { | |
| case EACCES: | |
| case EPERM: | |
| tftp->th_code = htons(EACCESS); | |
| break; | |
| case EEXIST: | |
| tftp->th_code = htons(EEXISTS); | |
| break; | |
| default: | |
| tftp->th_code = htons(ENOSPACE); | |
| } | |
| snprintf(tftp->th_data, STRSIZ, "Error:: in file %s", | |
| strerror(errno)); | |
| sendto(s, buf, strlen(tftp->th_data) + 4, 0, | |
| (struct sockaddr*) &cli, sizeof cli); | |
| continue; | |
| } | |
| memset(buf, 0, TFTP_BUF); | |
| tftp->th_opcode = htons(ACK); | |
| tftp->th_block = seq = 0; | |
| sendto(s, tftp, 4, 0, (struct sockaddr*) &cli, sizeof cli); | |
| for (retry = TFTP_RETRY; retry;) { | |
| FD_ZERO(&rfd); | |
| FD_SET(s, &rfd); | |
| if (select(s + 1, &rfd, NULL, NULL, &tv) < 1) { | |
| retry--; | |
| continue; | |
| } | |
| memset(buf, 0, TFTP_BUF); | |
| clilen = sizeof sin; | |
| if ((len = recvfrom(s, buf, TFTP_BUF, 0, | |
| (struct sockaddr*) &rcv, | |
| (socklen_t*) &clilen)) == -1) { | |
| VERB(5) printf("Error:: in recvfrom #%d - %s\n", | |
| errno, strerror(errno)); | |
| retry--; | |
| continue; | |
| } else | |
| if (cli.sin_addr.s_addr != rcv.sin_addr.s_addr) | |
| continue; | |
| VERB(5) printf("Info(5):: received opcode=%d block=%d seq=%d\n", | |
| ntohs(tftp->th_opcode), ntohs(tftp->th_block), seq); | |
| if (ERROR == ntohs(tftp->th_opcode)) { | |
| syslog(LOG_ERR, "Error:: in tftp receiving #%d - %s", | |
| tftp->th_code, tftp->th_data); | |
| close(f); | |
| unlink(szFName); | |
| break; | |
| } | |
| if (DATA == ntohs(tftp->th_opcode) && | |
| ++seq == ntohs(tftp->th_block)) { | |
| if (write(f, tftp->th_data, len - 4) == -1) { | |
| syslog(LOG_ERR, "Error:: Can`t write to file %s\n", | |
| szFName); | |
| close(f); | |
| unlink(szFName); | |
| break; | |
| } | |
| memset(buf, 0, TFTP_BUF); | |
| tftp->th_opcode = htons(ACK); | |
| tftp->th_block = htons(seq); | |
| sendto(s, tftp, 4, 0, (struct sockaddr*) &rcv, sizeof rcv); | |
| VERB(5) printf("Info(5):: Send ACK for %s block=%d\n", | |
| inet_ntoa(cli.sin_addr), seq); | |
| if (SEGSIZE > len - 4) { | |
| close(f); | |
| syslog(LOG_INFO, "TFTP transfer complete to %s", | |
| szFName); | |
| break; | |
| } | |
| } else { | |
| memset(buf, 0, TFTP_BUF); | |
| tftp->th_opcode = htons(ERROR); | |
| tftp->th_code = htons(EBADID); | |
| snprintf(tftp->th_data, STRSIZ, "Error:: in transfer #%d", | |
| seq); | |
| sendto(s, buf, strlen(tftp->th_data) + 4, 0, | |
| (struct sockaddr*) &cli, sizeof cli); | |
| retry--; | |
| } | |
| } | |
| if (!retry) { | |
| close(f); | |
| unlink(szFName); | |
| syslog(LOG_ERR, "Error:: transfer aborted - timeout!"); | |
| } | |
| break; | |
| case RRQ: | |
| len -= 2; | |
| pos += 2; | |
| strlcpy(szFName, (char*) pos, sizeof szFName); | |
| VERB(5) printf("Info(5):: Get filename %s\n", szFName); | |
| len -= strlen((char*) pos) + 1; | |
| pos += strlen((char*) pos) + 1; | |
| VERB(5) printf("Info(5):: Get mode %s len=%d\n", pos, len); | |
| if (strncmp((char*) pos, "octet", len)) { | |
| memset(buf, 0, TFTP_BUF); | |
| tftp->th_opcode = htons(ERROR); | |
| tftp->th_code = htons(EBADOP); | |
| strncpy(tftp->th_data, "Error:: mode not supported", 27); | |
| sendto(s, buf, 31, 0, (struct sockaddr*) &cli, sizeof cli); | |
| continue; | |
| } | |
| VERB(2) printf("Info(2):: Send file %s to %s\n", | |
| szFName, inet_ntoa(cli.sin_addr)); | |
| f = open(szFName, O_RDONLY); | |
| if (f == -1) { | |
| memset(buf, 0, TFTP_BUF); | |
| tftp->th_opcode = htons(ERROR); | |
| switch (errno) { | |
| case EACCES: | |
| case EPERM: | |
| tftp->th_code = htons(EACCESS); | |
| break; | |
| case ENOENT: | |
| tftp->th_code = htons(ENOTFOUND); | |
| break; | |
| default: | |
| tftp->th_code = htons(ENOSPACE); | |
| } | |
| snprintf(tftp->th_data, STRSIZ, "Error:: in file %s", | |
| strerror(errno)); | |
| sendto(s, buf, strlen(tftp->th_data) + 4, 0, | |
| (struct sockaddr*) &cli, sizeof cli); | |
| continue; | |
| } else | |
| seq = 1; | |
| for (retry = TFTP_RETRY; retry;) { | |
| tftp->th_opcode = htons(DATA); | |
| tftp->th_block = htons(seq); | |
| if ((len = read(f, tftp->th_data, SEGSIZE)) == -1) { | |
| syslog(LOG_ERR, "Error:: Can`t read from file %s\n", | |
| szFName); | |
| close(f); | |
| break; | |
| } else | |
| sendto(s, buf, len + 4, 0, | |
| (struct sockaddr*) &cli, sizeof cli); | |
| FD_ZERO(&rfd); | |
| FD_SET(s, &rfd); | |
| if (select(s + 1, &rfd, NULL, NULL, &tv) < 1) { | |
| retry--; | |
| continue; | |
| } | |
| memset(buf, 0, TFTP_BUF); | |
| clilen = sizeof sin; | |
| if (recvfrom(s, buf, TFTP_BUF, 0, (struct sockaddr*) &rcv, | |
| (socklen_t*) &clilen) == -1) { | |
| VERB(5) printf("Error:: in recvfrom #%d - %s\n", | |
| errno, strerror(errno)); | |
| retry--; | |
| continue; | |
| } else | |
| if (cli.sin_addr.s_addr != rcv.sin_addr.s_addr) | |
| continue; | |
| VERB(5) printf("Info(5):: received opcode=%d block=%d seq=%d\n", | |
| ntohs(tftp->th_opcode), ntohs(tftp->th_block), seq); | |
| if (ERROR == ntohs(tftp->th_opcode)) { | |
| syslog(LOG_ERR, "Error:: in tftp sending #%d - %s", | |
| tftp->th_code, tftp->th_data); | |
| if (lseek(f, len * -1, SEEK_CUR) == -1) { | |
| syslog(LOG_ERR, "Error:: revert sending #%d - %s", | |
| errno, strerror(errno)); | |
| close(f); | |
| break; | |
| } | |
| retry--; | |
| continue; | |
| } | |
| if (ACK == ntohs(tftp->th_opcode) && | |
| seq == ntohs(tftp->th_block)) { | |
| seq++; | |
| if (SEGSIZE > len) { | |
| close(f); | |
| syslog(LOG_INFO, "TFTP transfer complete to %s", | |
| szFName); | |
| break; | |
| } | |
| } else { | |
| memset(buf, 0, TFTP_BUF); | |
| tftp->th_opcode = htons(ERROR); | |
| tftp->th_code = htons(EBADID); | |
| snprintf(tftp->th_data, STRSIZ, "Error:: in transfer #%d", | |
| seq); | |
| sendto(s, buf, strlen(tftp->th_data) + 4, 0, | |
| (struct sockaddr*) &cli, sizeof cli); | |
| retry--; | |
| } | |
| } | |
| if (!retry) { | |
| close(f); | |
| syslog(LOG_ERR, "Error:: transfer aborted - timeout!"); | |
| } | |
| break; | |
| case DATA: | |
| if (seq == 0xffff) | |
| VERB(5) printf("Error:: not specified operation!\n"); | |
| break; | |
| } | |
| } | } |
| break; | break; |