/* file:                server.c
 * author:              Robert S. Laramee
 * class:               cs720/820
 * date started:        25 Apr 98
 * date "finished":     04 May 98
 * project:             assignment 5
 * description:         This process runs in the background. The server first 
 *                      creates the server message Q (standard name that is 
 * known to all clients). The server continually waits to read messages from 
 * its server queue. Once the message is read, it is serviced and the request 
 * is written to the specific client's message queue (name of this queue is 
 * sent in the request).
 *
 * Compile the program using the -lrt option on Christa or Alberti
 * e.g. % gcc -lrt -o server server.c
 */

#include       /* for printf(), scanf(), fopen(), perror() etc. */
#include      /* for EXIT_FAILURE                              */
#include      /* for strlen(), strncopy()                      */
#include       /* for strerror(), errno                         */
#include   /* for open(), lseek(), creat()                  */
#include    /* for open(), creat()                           */
#include       /* for open(), creat()                           */
#include      /* for read(), write(), lseek()                  */
#include      /* for mq_open(), mq_send(), mq_recieve etc.     */
#include "message.h"    /* the header file with some data strctures      */

/* Process the client's request to create a file. If the creat call fails, 
 * return suitable error message to the client. 
 */
int server_create(REQUEST *request, RESPONSE *response) {

    mode_t create_mode=0;

    create_mode = (mode_t)request->mode_or_offset;

   /* The umask command sets the file mode creation mask of the current 
    * shell execution environment to the value specified  by the mask operand.
    * This mask affects the initial value of the file permission bits of 
    * subsequently created files.
    */

    umask(0);                       
    if ((creat(request->file_name, create_mode)) == -1) {

        perror("error creating file: ");
        return -1;
    }
    return 0;
}
/* Process the client's read request. If any system call fails, return 
 * suitable error message to the client. 
 */
int server_read(REQUEST *request, RESPONSE *response) {

    int from_fd;

   /* read bytes from disk */
    if((from_fd = open(request->file_name, O_RDONLY)) == -1) {
        fprintf(stderr, "error cannot open %s: %s \n"
                      , request->file_name, strerror(errno));
        return -1;;
    }
    if (lseek(from_fd, request->mode_or_offset, SEEK_SET)
	                                     != (request->mode_or_offset)) {

        fprintf(stderr, "error with offset in file %s: %s \n"
                      , request->file_name, strerror(errno));
        return -1; 
    }
    if (read(from_fd, response->data, request->num_bytes) 
	                                             != request->num_bytes) {
        fprintf(stderr, "error reading file %s: %s \n"
		      , request->file_name, strerror(errno));
        return -1;
    }
    close(from_fd);
    return 0;
}

int main (void) {

    int i=0;
    int operation=0;             /* operation MSG_CREATE = 1, MSG_READ = 2  */
    int mode_or_offset=0;        /* IF read THEN offset IF create THEN mode */
    int priority=0;                      /* priority of message             */

    char serverQ_buffer[MAX_MSG];        /* server Q message buffer         */
    char clientQ_buffer[MAX_MSG];        /* client Q message buffer         */
    char *serverQ_name = "server_queue"; /* server Q name                   */
    struct mq_attr attribute;            /* message Q attributes            */
    REQUEST *request;                    /* pointer to client's request     */
    RESPONSE *response;                  /* pointer to server's response    */

    mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
    mqd_t server_descriptor;             /* server message Q descripitor    */
    mqd_t client_descriptor;             /* client message Q descripitor    */
    attribute.mq_maxmsg = 200;
    attribute.mq_msgsize = MAX_MSG;

    /* create server message queue */
 server_descriptor = mq_open(serverQ_name, O_RDONLY|O_CREAT, mode, &attribute);

     if (server_descriptor == -1) {

	 perror("Error opening server message queue: (errno) \n");
         exit(EXIT_FAILURE);
     }

    /* allocate memory for a RESPONSE structure */
     if ((response = (RESPONSE *)malloc(sizeof(RESPONSE))) == NULL) {
	 perror("error allocating memory for response : (errno) \n");
     }

    while(1) {

       /* receive client's  message */
        if(mq_receive(server_descriptor, serverQ_buffer, MAX_MSG, &priority) 
                                                                      == 0) {
            perror("error receiving message from client: (errno) \n");
            exit(EXIT_FAILURE);

        } else {

           /* check the request type */
            request = (REQUEST *)serverQ_buffer;

            if (request->request_type == MSG_CREATE) {

		if (server_create(request, response) != 0) {

                    response->status = UNSUCCESS;
                    strncpy(response->data, "error creating file\n", MAX_NAME);
                } else {

                    response->status = SUCCESS;
                    strncpy(response->data, " ok \n", MAX_NAME);

		} /* end if(server_create()) */

            } else if (request->request_type == MSG_READ) {

	        if (server_read(request, response) != 0) {

                    response->status = UNSUCCESS;
                    strncpy(response->data, "no data from read()", MAX_NAME);

                } else {

                    response->status = SUCCESS;

                } /* end if(server_read()) */
	    } else {

		fprintf(stderr, "unidentified client request type \n");
            }
	} /* end if (mq_receive ...) */

       /* open clients's message queue */
        client_descriptor = mq_open(request->client_msgQ_name, O_RDWR, mode, 
 	      		                                   &attribute);
        if (client_descriptor == -1) {

            perror("Error opening client message queue: (errno) \n");
            exit(EXIT_FAILURE);
        }

       /* send the client the response */
       if(mq_send(client_descriptor,(char*)response, MAX_MSG, priority) != 0){

	    perror("Error sending reply message to client: (errno) \n");
            exit(EXIT_FAILURE);
	}

        free(response);      /* avoid memory leaks in server */
     } /* end while(1) */
}