version 1.1.2.6, 2009/11/15 17:55:15
|
version 1.2, 2011/06/08 12:45:41
|
Line 1
|
Line 1
|
|
/************************************************************************* |
|
* (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com> |
|
* by Michael Pounov <misho@aitbg.com> |
|
* |
|
* $Author$ |
|
* $Id$ |
|
* |
|
*************************************************************************/ |
#include "global.h" |
#include "global.h" |
#include "upd.h" |
#include "upd.h" |
|
|
|
|
|
int Kill; |
|
|
|
|
static inline int ChkImg(const char *csImg, char *psDir) |
static inline int ChkImg(const char *csImg, char *psDir) |
{ |
{ |
int res = 0; |
int res = 0; |
Line 340 int Clean(const char *csImg)
|
Line 351 int Clean(const char *csImg)
|
return 0; |
return 0; |
} |
} |
|
|
|
// ---------------------------------- |
|
|
|
static void Signal(int sig) |
|
{ |
|
int stat; |
|
|
|
switch (sig) { |
|
case SIGHUP: |
|
VERB(5) printf("Info(5):: Signal arrived #%d\n", sig); |
|
break; |
|
case SIGCHLD: |
|
while (waitpid(-1, &stat, WNOHANG) > 0); |
|
break; |
|
case SIGTERM: |
|
Kill = 1; |
|
VERB(5) printf("Info(5):: Signal arrived #%d\n", sig); |
|
break; |
|
} |
|
} |
|
|
int Daemonize(struct sockaddr_in sin, const char *csTFTP) |
int Daemonize(struct sockaddr_in sin, const char *csTFTP) |
{ |
{ |
|
int s, n = 1; |
|
pid_t pid; |
|
fd_set rfd; |
|
u_short seq = 0xffff; |
|
int clilen, len, f, retry; |
|
struct sockaddr_in cli, rcv; |
|
struct sigaction sa; |
|
u_char buf[TFTP_BUF], *pos; |
|
char szFName[MAX_STR]; |
|
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); |
|
|
|
memset(&sa, 0, sizeof sa); |
|
sigemptyset(&sa.sa_mask); |
|
sa.sa_handler = Signal; |
|
sigaction(SIGCHLD, &sa, NULL); |
|
sigaction(SIGTERM, &sa, NULL); |
|
sigaction(SIGHUP, &sa, NULL); |
|
|
|
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
|
if (s == -1) { |
|
printf("Error:: in create socket #%d - %s\n", errno, strerror(errno)); |
|
return -1; |
|
} |
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) == -1) { |
|
printf("Error:: in socket options #%d - %s\n", errno, strerror(errno)); |
|
close(s); |
|
return -1; |
|
} |
|
if (bind(s, (struct sockaddr*) &sin, sizeof sin) == -1) { |
|
printf("Error:: in bind #%d - %s\n", errno, strerror(errno)); |
|
close(s); |
|
return -1; |
|
} |
|
|
|
switch ((pid = fork())) { |
|
case -1: |
|
printf("Error:: in socket options #%d - %s\n", errno, strerror(errno)); |
|
close(s); |
|
return -1; |
|
case 0: |
|
setsid(); |
|
|
|
while (!Kill) { |
|
FD_ZERO(&rfd); |
|
FD_SET(s, &rfd); |
|
if (select(s + 1, &rfd, NULL, NULL, NULL) == -1) |
|
continue; |
|
|
|
memset(buf, 0, TFTP_BUF); |
|
clilen = sizeof cli; |
|
len = recvfrom(s, buf, TFTP_BUF, 0, (struct sockaddr*) &cli, |
|
(socklen_t*) &clilen); |
|
if (len == -1) { |
|
VERB(5) printf("Error:: in recvfrom #%d - %s\n", |
|
errno, strerror(errno)); |
|
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, MAX_STR); |
|
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, MAX_STR); |
|
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; |
|
} |
|
|
|
|
|
close(s); |
return 0; |
return 0; |
} |
} |