/* file: client.c * author: Robert S. Laramee * class: cs720/820 * date started: 23 Apr 98 * date "finished": 04 May 98 * project: assignment 5 * description: The client program is interactive and continually * prompts the user for the operation to be performed * and the parameters for this operation. The client then packs this * information in the standard message format and sends it to the server. * When a response is received from the server, the status of the request and * the response are displayed on the output screen. Multiple client processes * can be running simultaneously. * * The main program is a menu-driven loop that interactively gets input data * from the user and calls the appropriate routines with their parameters. The * client program must create its message queue. Before exiting, the message * queue must be deleted. The client sends requests to the server queue * (standard predefined name). The server writes its response to the client * queue (the name of client's queue is sent to the server in the request * message). * * usage: [operation] [file name] [mode or offset] [# of bytes]\n" * * For a create operation (1) provide a 3 digit octal number as the mode. e.g. * operation and parameters : 1 file.txt 755 \n" * * For a read operation (2) provide the offset and number of bytes. e.g. * operation and parameters: 2 file.txt 10 1000 \n" * * To quit (3) type 3 or hit '^c' e.g. \n" * operation and parameters : 3 \n" * * Compile the program using the -lrt option on Christa or Alberti * e.g. % gcc -lrt -o client client.c */ #include/* for printf(), scanf(), fopen(), perror() etc. */ #include /* for EXIT_FAILURE */ #include /* for strlen(), strncopy() */ #include /* for strerror(), errno */ #include /* for open(), lseek() */ #include /* for open() */ #include /* for open() */ #include /* for read(), write(), lseek() */ #include /* for sigemptyset(), sigfillset() etc. */ #include /* for mq_open(), mq_send(), mq_recieve etc. */ #include "message.h" /* the header file with some data strctures */ /* signal handler for ctrl c (^c) */ void control_c() { char *clientQ_name = "client_queue"; sprintf(clientQ_name, "%d_queue", getpid()); /* delete the client queue when exiting */ unlink(clientQ_name); printf("\n exiting... \n"); exit(0); } /* This function converts the octal mode typed in by the user into a mode * that the create system call can use * Note the following rules for the octal number: * * 400 Permits read by owner. * 200 Permits write by owner. * 100 Permits execute or search by owner. * 040 Permits read by group. * 020 Permits write by group. * 010 Permits execute or search by group. * 004 Permits read by others. * 002 Permits write by others. * 001 Permits execute or search by others. */ mode_t convert_mode(int octal_number) { mode_t create_mode=0; if ((octal_number < 0) || (octal_number > 777)) { fprintf(stderr, "invalid octal number for create mode \n"); return -1; } if (octal_number/400 == 1) { create_mode = create_mode | S_IRUSR; /* assignment bitwise OR */ octal_number = octal_number % 400; } if (octal_number/200 == 1) { create_mode = create_mode | S_IWUSR; /* assignment bitwise OR */ octal_number = octal_number % 200; } if (octal_number/100 == 1) { create_mode = create_mode | S_IXUSR; /* assignment bitwise OR */ octal_number = octal_number % 100; } if (octal_number/40 == 1) { create_mode = create_mode | S_IRGRP; octal_number = octal_number % 40; } if (octal_number/20 == 1) { create_mode = create_mode | S_IWGRP; octal_number = octal_number % 20; } if (octal_number/10 == 1) { create_mode = create_mode | S_IXGRP; octal_number = octal_number % 10; } if (octal_number/4 == 1) { create_mode = create_mode | S_IROTH; octal_number = octal_number % 4; } if (octal_number/2 == 1) { create_mode = create_mode | S_IWOTH; octal_number = octal_number % 2; } if (octal_number/1 == 1) { create_mode = create_mode | S_IXOTH; octal_number = octal_number % 1; } return create_mode; } /* Generate a create request message for the client. Send the request across * to the server and process the response from the client. */ int client_create(REQUEST *request, mqd_t server_descriptor , mqd_t client_descriptor, int priority) { char clientQ_buffer[MAX_MSG]; /* client Q message buffer */ RESPONSE *response; /* pointer to server's response */ /* send the server a request message */ if(mq_send(server_descriptor,(char *)request, MAX_MSG, priority) != 0){ perror("error sending message to server : (errno) \n"); return -1; } /* receive server's response message */ if(mq_receive(client_descriptor, clientQ_buffer, MAX_MSG, &priority) == 0) { perror("error receiving message from server: (errno) \n"); return -1; } else { response = (RESPONSE *)clientQ_buffer; if (response->status == UNSUCCESS) { printf("%s", response->data); } else { printf("%s", response->data); } } /* end if (mq_receive...) */ return 0; } /* Generate the client's read request message. If the read request is larger * than MAX_MSG size, it should be broken into several requests of size not * exceeding MAX_MSG. Each request consists of the file-name, offset, and * number of bytes to be read. The client waits for the response from the * server before sending the next request. */ int client_read(REQUEST *request, mqd_t server_descriptor , mqd_t client_descriptor, int priority) { int i=0; int bytes_remaining=0; /* bytes remaining in read */ char clientQ_buffer[MAX_MSG]; /* client Q message buffer */ RESPONSE *response; /* pointer to server's response */ bytes_remaining = request->num_bytes; while (bytes_remaining > MAX_MSG) { request->num_bytes = MAX_MSG -5 ; /* leave room for end of line char */ /* send the server a request message */ if(mq_send(server_descriptor,(char *)request, MAX_MSG, priority) != 0){ perror("error sending message to server : (errno) \n"); return -1; } /* receive server's response message */ if(mq_receive(client_descriptor, clientQ_buffer, MAX_MSG, &priority) == 0) { perror("error receiving message from server: (errno) \n"); return -1; } else { response = (RESPONSE *)clientQ_buffer; if (response->status == UNSUCCESS) { printf("error reading data \n"); } else { for(i=0; i < MAX_MSG - 4; i++) { printf("%c", response->data[i]); } } } /* end if (mq_receive...) */ /* update the file offset and bytes remaining */ request->mode_or_offset = request->mode_or_offset + (MAX_MSG - 5); bytes_remaining = bytes_remaining - (MAX_MSG - 5); } /* end while() */ request->num_bytes = bytes_remaining; /* send the server a request message */ if(mq_send(server_descriptor,(char *)request, MAX_MSG, priority) != 0){ perror("error sending message to server : (errno) \n"); return -1; } /* receive server's response message */ if(mq_receive(client_descriptor, clientQ_buffer, MAX_MSG, &priority) == 0) { perror("error receiving message from server: (errno) \n"); return -1; } else { response = (RESPONSE *)clientQ_buffer; if (response->status == UNSUCCESS) { printf("error reading data \n"); } else { for(i=0; i < bytes_remaining; i++) { printf("%c", response->data[i]); } printf("\n"); } } /* end if (mq_receive... */ return 0; } int main (void) { int operation=0; /* operation MSG_CREATE = 1, MSG_READ = 2 */ int offset=0; /* IF read THEN offset */ int num_bytes=0; /* IF read THEN number of bytes to read */ int priority=0; /* priority of message */ int octal_number=0; /* create mode, (octal number) */ char input_buffer[4]; /* to put octal number in */ char file_name[MAX_NAME]; /* name of file to read or create */ char *serverQ_name = "server_queue"; /* server queue name */ char *clientQ_name = "client_queue"; /* client queue name */ struct mq_attr attribute; /* message queue attributes */ struct sigaction controlc_action; /* signal action structure */ REQUEST *request; /* pointer to REQUEST structure */ mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; mode_t create_mode=0; /* create mode used by creat() */ mqd_t server_descriptor; /* server Q descripitor */ mqd_t client_descriptor; /* client Q descripitor */ attribute.mq_maxmsg = 200; attribute.mq_msgsize = MAX_MSG; /* install SIGINT (control c) signal handler */ controlc_action.sa_handler = control_c; controlc_action.sa_flags = 0; sigemptyset(&controlc_action.sa_mask); if (sigaction(SIGINT, &controlc_action, NULL) == -1) perror("\n Could not set up SIGINT handler for control_c() action \n"); /* give the client message queue a unique name i.e. it's process ID * concatenated with the "_queue" extension. */ sprintf(clientQ_name, "%d_queue", getpid()); /* create client message queue */ client_descriptor = mq_open(clientQ_name, O_RDONLY|O_CREAT, mode, &attribute); if (client_descriptor == -1) { perror("Error opening client message queue: (errno) \n"); exit(EXIT_FAILURE); } /* open server's message queue */ server_descriptor = mq_open(serverQ_name, O_RDWR, mode, &attribute); if (server_descriptor == -1) { perror("error opening server message queue: (errno) \n"); exit(EXIT_FAILURE); } /* get a REQUEST structure */ if ((request = (REQUEST *)malloc(sizeof(REQUEST))) == NULL) { perror("error allocating memory for request : (errno) \n"); exit(EXIT_FAILURE); } printf("/** \n" " * usage: [operation] [file name] [mode or offset] [# of bytes]\n" " * \n" " * For a create operation (1) provide a 3 digit octal number as " "the mode. e.g. \n" " * operation and parameters : 1 file.txt 755 \n" " * \n" " * For a read operation (2) provide the offset and number of bytes." " e.g. \n" " * operation and parameters: 2 file.txt 10 1000 \n" " * \n" " * To quit (3) type 3 or hit '^c' e.g. \n" " * operation and parameters : 3 \n" " */ \n" ); while(1) { printf("operation and parameters : "); scanf("%d", &operation); if (operation == QUIT) { sprintf(clientQ_name, "%d_queue", getpid()); /* delete the client queue when exiting */ unlink(clientQ_name); printf(" exiting \n"); exit(0); } scanf("%s", file_name); /* fill the request structure */ strncpy(request->client_msgQ_name, clientQ_name, MAX_NAME); request->request_type = operation; strncpy(request->file_name, file_name, MAX_NAME); if (operation == MSG_CREATE) { gets(input_buffer); octal_number = atoi(input_buffer); create_mode = convert_mode(octal_number); if (create_mode == -1) { fprintf(stderr, "error converting mode for create \n"); } request->mode_or_offset = (int)create_mode; } else if (operation == MSG_READ) { scanf("%d %d", &offset, &num_bytes); request->mode_or_offset = offset; request->num_bytes = num_bytes; } if (request->request_type == MSG_CREATE) { if ((client_create(request, server_descriptor , client_descriptor, priority)) == -1) { fprintf(stderr, "error with client_create() \n"); } } else if (request->request_type == MSG_READ) { if ((client_read(request, server_descriptor , client_descriptor, priority)) == -1) { fprintf(stderr, "error with client_create() \n"); } } else { fprintf(stderr, "unrecognized mode \n"); } } /* end while(1) */ free(request); /* avoid memory leaks */ return 0; }