/* server.c
   A simple stateless file server
   Solution to programming exercise
   Verteilte Systeme II, WS 99/00
   Uebungsblatt 4, 10/1999
   Joerg Hakenberg <joerg.hakenberg@student.uni-ulm.de>
*/

/* Aufruf : server <Server-Port> */
 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>

#define DEFPORT 4000

char ausgabe[16384] = "";

char filename[50] = "";
char destname[50] = "";


/* creates the file specified in filename */
char* fs_create (char *filename) {
  creat(filename, O_CREAT);
  chmod(filename, S_IRUSR | S_IWUSR);
  strcpy(ausgabe, "file was created\n");
  return ausgabe;
}

/* deletes the file specified in filename */
char* fs_delete (char *filename) {
  unlink(filename);
  strcpy(ausgabe, "file was deleted\n");
  return ausgabe;
}

/* reads the contents of the specified file and puts them to the stream */
char* fs_read (char *filename, int offset, int length) {
  FILE *inputfile;
  int i;
  char input[16384];
  strcpy(ausgabe, ""); strcpy(input, "");

  inputfile = fopen(filename, "r");
  if (inputfile == NULL) {
    return "error opening file\n";
  }
  
  fseek(inputfile, offset-1, SEEK_SET);
  for (i = 1; i <= length; i++) {
  	input[i-1] = fgetc(inputfile);
	if (input[i-1] == EOF) {
	        input[i-1] = 0;
		strncpy(ausgabe, input, i);
		fclose(inputfile);
		return ausgabe;
	}	
  }
  input[i] = 0;
  strncpy(ausgabe, input, length);
  fclose(inputfile);
  
  return ausgabe;
}

char* fs_append (char* filename, char* data) {
	FILE *outputfile;
	int fd;
	
	fd = open(filename, O_RDWR | O_APPEND);
	lockf(fd, F_LOCK, 0);
	
	write(fd, data, strlen(data));	
	
	lockf(fd, F_ULOCK, 0);
	close(fd);
	
	strcpy(ausgabe, "text was appended\n");
	return ausgabe;
}

char* fs_status (char* filename) {
	int fd;
	struct stat buf;
	
	fd = open(filename, O_RDWR | O_APPEND);
	fstat(fd, (struct stat*) &buf);
	close(fd);
	
	while (strlen(filename) < 12) {
		strcat(filename, " ");
	}
	
	sprintf(ausgabe, "%s : size=%d mode=%d uid=%d gid=%d", filename, buf.st_size, buf.st_mode, buf.st_uid, buf.st_gid);
	return ausgabe;
}

void usage(char* name) {
	printf("%s - a stateless fileserver\n", name);
	printf("Usage: %s <port> (default port = %d)\n", name, DEFPORT);
	exit(1);
}

int main(int argc, char* argv[]){

	int list_socket;
        int cli_socket;
        int socklen;
        int ret;
        struct sockaddr_in servaddr;
        struct sockaddr_in cliaddr;
	int port = DEFPORT;
	
        char buffer[128];
	char st[100], st1[100], st2[100];
	char command[1], commandline[50];
        int i, j, lines;
	
	int offset, length;
	
        time_t utime;                       /* UTC time */
        char* timeptr;                      /* buffer for timestring */
	
        /* check for port */
        if (argc == 2) {
            port = atoi(argv[1]);
        } else if (argc != 1) {
            usage(argv[0]);
        }
	
	/* open listen socket */
        list_socket = socket(AF_INET, SOCK_STREAM, 0);
        if (list_socket == -1) {
                perror("socket() error");
                exit(1);
        }

        /* bin dsocket to port */
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(port);
        ret = bind(list_socket,
                   (struct sockaddr *) &servaddr,
		   sizeof(servaddr));
        if (ret == -1) {
                perror("Can't bind listen socket");
                exit(1);
        }
	
	/* listen to socket */
	ret = listen(list_socket, 5);
        if (ret == -1) {
                perror("Can't listen to listen socket");
                exit(1);
        }


        /* iterative server loop */
        while(1) {
	
                /* accept connection from client */
                socklen = sizeof(cliaddr);
                cli_socket = accept(list_socket,
                                    (struct sockaddr *) &cliaddr,
				    &socklen);
                if (ret == -1) {
                        perror("Can't accept on listen socket");
                        exit(1);
                }

                /* log the connection */
                printf("connection from %s, port %d",
                                inet_ntoa(cliaddr.sin_addr),
				ntohs(cliaddr.sin_port));
		/* get timestring */
        	utime = time(NULL);
        	timeptr = ctime(&utime);
		printf(" at %s", timeptr);

                /* read command from client*/
		strcpy(buffer, "");
                ret = read(cli_socket, (void *) &buffer, sizeof(buffer));
                buffer[ret] = '\0';

		strcpy(commandline, "");
		strcpy(commandline, buffer);
		printf("Commandline: %s", commandline);

		/* extract command and params from commandline */
		ret = sscanf(commandline, "%s%s", command, st);
		printf("Params : %s...\n", st);
		printf("Command: %s...\n", command);

		switch (command[0]) {
		  case 'r' : printf("Request was the read command ...\n");
		  	     ret = sscanf(commandline, "%s%s%s%s", command, 
			     filename, st1, st2);
			     printf("        file to read : %s...\n", filename);
			     offset = atoi(st1);
			     length = atoi(st2);
			     printf("              offset : %d...\n", offset);
			     printf("              length : %d...\n", length);
			     strcpy(ausgabe, fs_read(filename, offset, length));
		             break;
		  case 'a' : printf("Request was the append command ...\n");
		  	     ret = sscanf(commandline, "%s%s%s", command, filename, st1);
			     printf("        file to append to : %s\n", filename);
			     printf("        text to append : %s\n", st1);
			     strcpy(ausgabe, fs_append(filename, st1));
		  	     break;
		  case 'c' : printf("Request was the create command ...\n");
		  	     ret = sscanf(commandline, "%s%s%s", command, filename);
			     printf("        file to create : %s\n", filename);
			     strcpy(ausgabe, fs_create(filename));
			     printf("        file was created ...\n");
		             break;
		  case 'd' : printf("Request was the delete command ...\n");
		  	     ret = sscanf(commandline, "%s%s", command, filename);
			     printf("        file to delete : %s\n", filename);
			     strcpy(ausgabe, fs_delete(filename));
			     printf("        file was deleted ...\n");
			     break;
		  case 's' : printf("Request was the status command ...\n");
		  	     ret = sscanf(commandline, "%s%s%s", command, filename);
			     printf("        file to view status from : %s\n", filename);
			     strcpy(ausgabe, fs_status(filename));
			     break;
	          default  : printf("Request was an unrecognized command ...\n");
		}

                /* Ausgabe auf den Socket legen */
                ret = write(cli_socket, ausgabe, strlen(ausgabe));

		/* print status message */
		printf("        wrote %d bytes to stream ...\n\n", ret);
		/*printf("%s\n\n", ausgabe);*/

		strcpy(ausgabe, "");
		strcpy(st, ""); strcpy(st1, ""); strcpy(st2, "");
		strcpy(filename, ""); strcpy(destname, "");

		/* close socket */
                close(cli_socket);

        }

}