|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <strings.h>
|
|
#include <fcntl.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/event.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
|
|
|
|
#define PORT 8001
|
|
#define CPORT 8002
|
|
#define PATH "/tmp/sendfile"
|
|
#define H_SIZE 1000
|
|
#define T_SIZE 4096
|
|
#define N_SEC 50000000
|
|
|
|
|
|
int main() {
|
|
int s, sc, fd, kq;
|
|
|
|
off_t size;
|
|
|
|
struct sockaddr_in addr;
|
|
struct sockaddr_in copy;
|
|
struct timespec req, actual;
|
|
struct sf_hdtr header;
|
|
bzero(&header, sizeof(struct sf_hdtr));
|
|
bzero(&req, sizeof(struct timespec));
|
|
bzero(&actual, sizeof(struct timespec));
|
|
req.tv_nsec = N_SEC;
|
|
#if 0
|
|
struct iovec vec;
|
|
|
|
vec.iov_base = malloc(H_SIZE);
|
|
vec.iov_len= H_SIZE;
|
|
|
|
fd = open("/dev/urandom", O_RDONLY);
|
|
read(fd, vec.iov_base, H_SIZE);
|
|
close(fd);
|
|
|
|
header.headers = &vec;
|
|
header.hdr_cnt = 1;
|
|
#endif
|
|
|
|
s = socket(PF_INET, SOCK_STREAM, 0);
|
|
if (s < 0)
|
|
err(errno, "Cannot create socket");
|
|
|
|
bzero(&addr, sizeof(struct sockaddr_in));
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(PORT);
|
|
inet_aton("127.0.0.1", &addr.sin_addr);
|
|
|
|
if (bind(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) {
|
|
close(s);
|
|
err(errno, "Cannot bind to 127.0.0.1 %d", (int) PORT);
|
|
}
|
|
|
|
if (listen(s, 0)) {
|
|
close(s);
|
|
err(errno, "Cannot listen to socket");
|
|
}
|
|
|
|
kq = kqueue();
|
|
if (kq < 0) {
|
|
close(s);
|
|
err(errno, "Cannot create kqueue");
|
|
}
|
|
|
|
addr.sin_port = htons(CPORT);
|
|
char *buf = malloc(T_SIZE);
|
|
|
|
while ((sc = accept(s, NULL, 0)) > 0) {
|
|
off_t sbytes;
|
|
off_t off;
|
|
off_t ssize;
|
|
int nevt, ss;
|
|
struct kevent evt;
|
|
|
|
fd = open(PATH, O_RDWR | O_CREAT);
|
|
if (fd < 0) {
|
|
close(s);
|
|
err(errno, "Cannot open file to send");
|
|
}
|
|
ftruncate(fd, 0);
|
|
unlink(PATH);
|
|
fcntl(sc, F_SETFL, O_NONBLOCK);
|
|
|
|
EV_SET(&evt, sc, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
|
nevt = 1;
|
|
size = 0;
|
|
do {
|
|
kevent(kq, &evt, nevt, &evt, 1, NULL);
|
|
nevt = 0;
|
|
ssize = evt.data;
|
|
do {
|
|
sbytes = ((ssize > T_SIZE) ? T_SIZE : ssize);
|
|
off = read(sc, buf, sbytes);
|
|
if (off != sbytes) {
|
|
err(errno, "something went wrong during read");
|
|
}
|
|
off = write(fd, buf, sbytes);
|
|
if (sbytes != off) {
|
|
err(errno, "something went wrong during write");
|
|
}
|
|
ssize -= sbytes;
|
|
size += sbytes;
|
|
} while(ssize > 0);
|
|
} while((evt.flags & EV_EOF) == 0);
|
|
|
|
|
|
retry:
|
|
ss = socket(PF_INET, SOCK_STREAM, 0);
|
|
if (ss < 0) {
|
|
close(sc);
|
|
close(fd);
|
|
close(s);
|
|
err(errno, "Cannot create proxy socket");
|
|
}
|
|
bcopy(&addr, ©, sizeof(struct sockaddr_in));
|
|
if(connect(ss, (struct sockaddr *)©, sizeof(struct sockaddr_in))) {
|
|
close(ss);
|
|
if (errno == ECONNREFUSED) {
|
|
nanosleep(&req, &actual);
|
|
goto retry;
|
|
}
|
|
close(sc);
|
|
close(fd);
|
|
close(s);
|
|
err(errno, "Cannot connect to proxy");
|
|
}
|
|
|
|
sbytes = 0;
|
|
off = 0;
|
|
ssize = size;
|
|
while (sendfile(fd, ss, off, ssize, &header, &sbytes, 0) == -1) {
|
|
if (errno != EAGAIN) {
|
|
close(sc);
|
|
close(s);
|
|
close(fd);
|
|
close(ss);
|
|
err(errno, "Cannot send file");
|
|
}
|
|
|
|
off += sbytes;
|
|
ssize -= sbytes;
|
|
if (ssize <= 0)
|
|
break;
|
|
sbytes = 0;
|
|
}
|
|
EV_SET(&evt, sc, EVFILT_READ, EV_DELETE, 0, 0, NULL);
|
|
kevent(kq, &evt, 1, NULL, 0, NULL);
|
|
close(sc);
|
|
close(ss);
|
|
close(fd);
|
|
|
|
}
|
|
}
|
|
|
|
|