|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <netdb.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include "eblapp.h"
|
|
|
|
|
|
|
|
|
|
#define PORT 1069
|
|
|
|
|
#define MAX_PACKET_SIZE 1400
|
|
|
|
|
#define TIMEOUT 5
|
|
|
|
|
|
|
|
|
|
void error(const char *msg) {
|
|
|
|
|
perror(msg);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
|
if (argc < 3) {
|
|
|
|
|
fprintf(stderr, "Usage: %s hostname filename\n", argv[0]);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char buffer[MAX_PACKET_SIZE];
|
|
|
|
|
uint32_t current_offset = 0;
|
|
|
|
|
int sockfd;
|
|
|
|
|
struct sockaddr_in serv_addr;
|
|
|
|
|
struct hostent *server;
|
|
|
|
|
|
|
|
|
|
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
|
if (sockfd < 0)
|
|
|
|
|
error("ERROR opening socket");
|
|
|
|
|
|
|
|
|
|
server = gethostbyname(argv[1]);
|
|
|
|
|
if (server == NULL) {
|
|
|
|
|
fprintf(stderr, "ERROR, no such host\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset((char *)&serv_addr, 0, sizeof(serv_addr));
|
|
|
|
|
serv_addr.sin_family = AF_INET;
|
|
|
|
|
memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr,
|
|
|
|
|
server->h_length);
|
|
|
|
|
serv_addr.sin_port = htons(PORT);
|
|
|
|
|
|
|
|
|
|
struct Eblapp_request *request = (struct Eblapp_request *)buffer;
|
|
|
|
|
request->opcode = EBLAPP_REQUEST_FILE;
|
|
|
|
|
request->filename_size = strlen(argv[2]);
|
|
|
|
|
memcpy(request + 1, argv[2], request->filename_size);
|
|
|
|
|
|
|
|
|
|
int packet_len = strlen(argv[2]) + sizeof(*request);
|
|
|
|
|
|
|
|
|
|
if (sendto(sockfd, buffer, packet_len, 0, (struct sockaddr *)&serv_addr,
|
|
|
|
|
sizeof(serv_addr)) < 0) {
|
|
|
|
|
error("ERROR sending RRQ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("Requesting file: %s\n", argv[2]);
|
|
|
|
|
|
|
|
|
|
// Open output file
|
|
|
|
|
int fd = open(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
error("ERROR creating file");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int wtf = 0;
|
|
|
|
|
while (1) {
|
|
|
|
|
fd_set readfds;
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
struct Eblapp_transfer_data *data = (struct Eblapp_transfer_data *)buffer;
|
|
|
|
|
|
|
|
|
|
FD_ZERO(&readfds);
|
|
|
|
|
FD_SET(sockfd, &readfds);
|
|
|
|
|
tv.tv_sec = TIMEOUT;
|
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
|
|
|
|
|
|
int rv = select(sockfd + 1, &readfds, NULL, NULL, &tv);
|
|
|
|
|
if (rv > 0) {
|
|
|
|
|
socklen_t serv_len = sizeof(serv_addr);
|
|
|
|
|
int n = recvfrom(sockfd, buffer, MAX_PACKET_SIZE, 0,
|
|
|
|
|
(struct sockaddr *)&serv_addr, &serv_len);
|
|
|
|
|
if (n < 4)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// printf("opcode %d\n", data->opcode);
|
|
|
|
|
if (data->opcode == EBLAPP_TRANSFER_DATA) { // DATA
|
|
|
|
|
struct Eblapp_ack ack = {0};
|
|
|
|
|
if (data->block_start != current_offset) {
|
|
|
|
|
if (!wtf) {
|
|
|
|
|
printf("Invalid order (%d/%d)\n", data->block_start,
|
|
|
|
|
current_offset);
|
|
|
|
|
ack.opcode = EBLAPP_WTF;
|
|
|
|
|
ack.ack_byte = current_offset;
|
|
|
|
|
if (sendto(sockfd, &ack, sizeof(ack), 0,
|
|
|
|
|
(struct sockaddr *)&serv_addr, serv_len) < 0) {
|
|
|
|
|
error("ERROR sending WTF");
|
|
|
|
|
}
|
|
|
|
|
wtf = 1;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
wtf = 0;
|
|
|
|
|
printf("got %d (%d)\n", current_offset, n - 8);
|
|
|
|
|
current_offset += (n - 8);
|
|
|
|
|
ack.opcode = EBLAPP_ACK;
|
|
|
|
|
ack.ack_byte = current_offset;
|
|
|
|
|
if (sendto(sockfd, &ack, sizeof(ack), 0,
|
|
|
|
|
(struct sockaddr *)&serv_addr, serv_len) < 0) {
|
|
|
|
|
error("ERROR sending ACK");
|
|
|
|
|
}
|
|
|
|
|
write(fd, buffer + 8, (n - 8));
|
|
|
|
|
}
|
|
|
|
|
} else if (data->opcode == EBLAPP_TRANSFER_END) {
|
|
|
|
|
printf("got transfer end\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
close(sockfd);
|
|
|
|
|
close(fd);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|