pupes-backup/src/main.c
2025-10-11 19:54:47 +02:00

138 lines
4.5 KiB
C

#include <asm-generic/errno-base.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <math.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include "color.h"
#define ALLOWED_IP "192.168.1.213"
#define MAX_FILE_SIZE_G 100
#define MAX_FILE_SIZE (size_t)MAX_FILE_SIZE_G*1073741824
#define READ_BUFFER_SIZE 32768 // 256K
const char* filename_base = "backup";
int sockfd;
int main(int argc, char* argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage:\n%s [BACKUP DIRECTORY]\n", argv[0]);
return EINVAL;
}
int client_fd;
struct sockaddr_in servaddr, client_addr;
socklen_t client_len = sizeof(client_addr);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
printf("Socket created successfully\n");
int opt = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
perror("setsockopt failed");
close(sockfd);
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(15531);
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) {
perror("socket bind failed");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("Socket bound to port 15531\n");
if (listen(sockfd, 1) != 0) {
perror("listen failed");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("Listening on port 15531\n");
while (1) {
client_fd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
if (client_fd < 0) {
perror("accept failed");
continue;
}
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
if (strcmp(client_ip, ALLOWED_IP) == 0) {
printf("Accepted connection from %s\n", client_ip);
const time_t unix_time = time(NULL);
const uint8_t time_lenght = floor(log10(unix_time)) + 1;
const size_t path_with_filename_lenght = strlen(argv[1]) + 1 /*'/'*/ + strlen(filename_base) + 1 /*'-'*/ + time_lenght + 1 /*NULL BYTE*/;
char* full_filename_path = malloc(path_with_filename_lenght);
char* moved_ptr;
moved_ptr = stpcpy(full_filename_path,argv[1]); //copy directory path
moved_ptr[0] = '/';
moved_ptr = stpcpy(&moved_ptr[1], filename_base);
moved_ptr[0] = '-';
sprintf(&moved_ptr[1], "%lu", unix_time); // time + NULL terminator
int savefile_fd = open(full_filename_path, O_WRONLY | O_CREAT, 0644);
ssize_t bytes_transferred;
size_t receved_this_read_cicle = SIZE_MAX;
size_t total_received = 0;
char* read_buffer = malloc(READ_BUFFER_SIZE);
while (receved_this_read_cicle != 0 && total_received < MAX_FILE_SIZE){
receved_this_read_cicle = 0;
while ((bytes_transferred = read(client_fd, read_buffer, READ_BUFFER_SIZE - receved_this_read_cicle)) > 0) {
if (bytes_transferred == -1) {
fprintf(stderr, YELLOW"["RED"CRITICAL"YELLOW"]"RESET" Error: %s, when receving file: %s failed file may be corupted\n", strerror(errno) ,full_filename_path);
goto client_cleanup;
}
receved_this_read_cicle += bytes_transferred;
}
if (receved_this_read_cicle == 0) {break;}
total_received += receved_this_read_cicle;
if (write(savefile_fd, read_buffer, receved_this_read_cicle) == -1) {
fprintf(stderr, YELLOW"["RED"CRITICAL"YELLOW"]"RESET" Error: %s, when writing file: %s failed file may be corupted\n", strerror(errno) ,full_filename_path);
}}
client_cleanup:
printf("finished handling: %s\n",full_filename_path);
free(read_buffer);
free(full_filename_path);
close(savefile_fd);
close(client_fd);
} else {
printf("Rejected connection from %s\n", client_ip);
close(client_fd);
}
}
return 0;
}
[[gnu::destructor]]
void program_exit() {
shutdown(sockfd, SHUT_RDWR);
close(sockfd);
}