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.
126 lines
3.3 KiB
126 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; |
|
}
|
|
|