ecen5273

ECEN5273 Coursework
git clone https://git.pngu.org/ecen5273
Log | Files | Refs | README

uftp_server.c (6776B)


// File Transfer (Server)
// Jack Sangdahl
// 07 September 2024
#include <arpa/inet.h>
#include <dirent.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#define DATA_SIZE 1024

int main(int argc, char **argv) {
  if (argc != 2) {
    fprintf(stderr, "usage: %s <port_num>\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  int port = atoi(argv[1]), sock;
  if (port > 65535 || port < 5000) {
    fprintf(stderr, "%s: port must be in range 5000-65535\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    fprintf(stderr, "%s: error opening socket\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  struct sockaddr_in server_addr, client_addr;
  memset(&server_addr, 0, sizeof(server_addr));
  memset(&client_addr, 0, sizeof(client_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = INADDR_ANY;
  server_addr.sin_port = htons((short)port);
  if (bind(sock, (const struct sockaddr *)&server_addr, sizeof(server_addr)) <
      0) {
    fprintf(stderr, "%s: error binding socket to port\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  printf("ready to receive client connections\n");
  socklen_t client_size = sizeof(client_addr);
  char data[DATA_SIZE], command[DATA_SIZE], filename[DATA_SIZE];
  while (1) {
    memset(data, 0, strlen(data));
    ssize_t n = recvfrom(sock, data, DATA_SIZE, 0,
                         (struct sockaddr *)&client_addr, &client_size);
    if (n < 0)
      fprintf(stderr, "%s: error receiving datagram from client\n", argv[0]);
    struct hostent *host_info =
        gethostbyaddr((const char *)&client_addr.sin_addr.s_addr,
                      sizeof(client_addr.sin_addr.s_addr), AF_INET);
    if (!host_info)
      fprintf(stderr, "%s: error determining host info\n", argv[0]);
    char *host_addr = inet_ntoa(client_addr.sin_addr);
    printf("%s: received datagram from %s (%s)\n", argv[0], host_info->h_name,
           host_addr);
    printf("received %d/%d bytes: %s\n", (int)strlen(data), (int)n, data);
    sscanf(data, "%s %s", command, filename);
    if (!strncmp(command, "get", 3)) {
      printf("sending file %s to client...\n", filename);
      int send_data, f = open(filename, O_RDONLY);
      if (f < 0) {
        send_data = -1;
        fprintf(stderr, "error: file %s does not exist in directory\n",
                filename);
      } else
        send_data = 1;
      if (sendto(sock, &send_data, sizeof(send_data), 0,
                 (struct sockaddr *)&client_addr, client_size) < 0) {
        fprintf(stderr, "%s: error sending status to client\n", argv[0]);
        if (f >= 0)
          close(f);
        continue;
      }
      if (f < 0)
        continue;
      off_t file_size = lseek(f, 0, SEEK_END);
      if (file_size < 0) {
        fprintf(stderr, "error: determine file size of file %s\n", filename);
        close(f);
        continue;
      }
      lseek(f, 0, SEEK_SET);
      sprintf(data, "%ld", file_size);
      if (sendto(sock, data, strlen(data), 0, (struct sockaddr *)&client_addr,
                 client_size) < 0) {
        fprintf(stderr, "%s: error sending file size to client\n", argv[0]);
        close(f);
        continue;
      }
      memset(data, 0, sizeof(data));
      ssize_t bytes_read;
      while ((bytes_read = read(f, data, sizeof(data)))) {
        if (sendto(sock, data, bytes_read, 0, (struct sockaddr *)&client_addr,
                   client_size) < 0) {
          fprintf(stderr, "%s: error sending data to client\n", argv[0]);
          break;
        }
        memset(data, 0, sizeof(data));
      }
      if (bytes_read < 0)
        fprintf(stderr, "%s: error reading from file %s\n", argv[0], filename);
      close(f);
    } else if (!strncmp(command, "put", 3)) {
      printf("receiving file %s from client...\n", filename);
      if (recvfrom(sock, data, DATA_SIZE, 0, (struct sockaddr *)&client_addr,
                   &client_size) < 0)
        fprintf(stderr, "%s: error receiving data from client\n", argv[0]);
      int file_size = atoi(data),
          f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
      if (f < 0)
        fprintf(stderr, "%s: error opening file %s\n", argv[0], filename);
      int bytes_transferred = 0;
      ssize_t bytes_received;
      while (bytes_transferred < file_size) {
        memset(data, 0, sizeof(data));
        int transfer_size = (file_size - bytes_transferred < DATA_SIZE)
                                ? (file_size - bytes_transferred)
                                : DATA_SIZE;
        bytes_received =
            recvfrom(sock, data, transfer_size, 0,
                     (struct sockaddr *)&client_addr, &client_size);
        if (bytes_received < 0) {
          fprintf(stderr, "%s: error receiving data from client\n", argv[0]);
          close(f);
        }
        if (write(f, data, bytes_received) != bytes_received) {
          fprintf(stderr, "%s: error writing data to file %s\n", argv[0],
                  filename);
          close(f);
        }
        bytes_transferred += bytes_received;
        printf("received %d/%d bytes\n", bytes_transferred, file_size);
      }
      close(f);
      printf("file %s transferred successfully\n", filename);
    } else if (!strncmp(command, "delete", 6)) {
      int send_data, f = open(filename, O_RDWR);
      if (f < 0) {
        send_data = 1;
        if (sendto(sock, &send_data, sizeof(int), 0,
                   (struct sockaddr *)&client_addr, client_size) < 0)
          fprintf(stderr, "%s: error sending data to client\n", argv[0]);
      }
      close(f);
      if (remove(filename) < 0) {
        send_data = 2;
        fprintf(stderr, "%s: error removing file %s\n", argv[0], filename);
      } else
        send_data = 0;
      if (sendto(sock, &send_data, sizeof(int), 0,
                 (struct sockaddr *)&client_addr, client_size) < 0)
        fprintf(stderr, "%s: error sending data to client\n", argv[0]);
    } else if (!strncmp(command, "ls", 2)) {
      char send_data[DATA_SIZE] = {0};
      DIR *d = opendir(".");
      int data_len = 0;
      struct dirent *curr;
      while ((curr = readdir(d))) {
        int name_len = strlen(curr->d_name);
        memcpy(send_data + data_len, curr->d_name, name_len);
        data_len += name_len;
        send_data[data_len] = '\n';
        data_len++;
      }
      closedir(d);
      if (data_len)
        if (sendto(sock, send_data, strlen(send_data), 0,
                   (struct sockaddr *)&client_addr, client_size) < 0)
          fprintf(stderr, "%s: error sending data to client\n", argv[0]);
    } else if (!strncmp(command, "exit", 4))
      printf("received exit signal from client\n");
  }
  return EXIT_SUCCESS;
}