#include #include #include #include #include #include #include #include #include #include "eblapp.h" #define PORT 1069 #define MAX_PACKET_SIZE 1024 #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 ACK"); } wtf = 1; } } else { wtf = 0; printf("got %d\n", current_offset); 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; }