You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
3.3 KiB

#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;
}