int main (int argc, char *const *argv) { char command; /* FIXME: Localisation is meaningless, unless --help and --version are locally used. Localisation would be best accomplished by the calling tar, on messages found within error packets. */ #if DOSWIN program_name = get_program_base_name (argv[0]); #else program_name = argv[0]; #endif setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); /* FIXME: Implement --help and --version as per GNU standards. */ argc--, argv++; if (argc > 0) { debug_file = fopen (*argv, "w"); if (debug_file == 0) { return_numbered_error (errno); exit (EXIT_FAILURE); } setbuf (debug_file, NULL); } while (full_read (INPUT, &command, 1) == 1) { errno = 0; /* FIXME: errno should be read-only */ switch (command) { /* FIXME: Maybe 'H' and 'V' for --help and --version output? */ case 'O': { char device_string[STRING_SIZE]; char mode_string[STRING_SIZE]; get_string (device_string); get_string (mode_string); DEBUG2 ("rmtd: O %s %s\n", device_string, mode_string); if (tape >= 0) close (tape); #if defined (i386) && defined (AIX) /* This is alleged to fix a byte ordering problem. I'm quite suspicious if it's right. -- mib. */ { mode_t old_mode = atoi (mode_string); mode_t new_mode = 0; if ((old_mode & 3) == 0) new_mode |= O_RDONLY; if (old_mode & 1) new_mode |= O_WRONLY; if (old_mode & 2) new_mode |= O_RDWR; if (old_mode & 0x0008) new_mode |= O_APPEND; if (old_mode & 0x0200) new_mode |= O_CREAT; if (old_mode & 0x0400) new_mode |= O_TRUNC; if (old_mode & 0x0800) new_mode |= O_EXCL; tape = open (device_string, new_mode, 0666); } #else tape = open (device_string, atoi (mode_string), 0666); #endif if (tape < 0) return_numbered_error (errno); else return_response (0); break; } case 'C': { char device_string[STRING_SIZE]; get_string (device_string); /* discard */ DEBUG ("rmtd: C\n"); if (close (tape) < 0) return_numbered_error (errno); else { tape = -1; return_response (0); } break; } case 'L': { int status = 0; char count_string[STRING_SIZE]; char position_string[STRING_SIZE]; get_string (count_string); get_string (position_string); DEBUG2 ("rmtd: L %s %s\n", count_string, position_string); status = lseek (tape, (off_t) atol (count_string), atoi (position_string)); if (status < 0) return_numbered_error (errno); else return_response (status); break; } case 'W': { char count_string[STRING_SIZE]; ssize_t size_read = 0; ssize_t size_written; size_t counter; int size; get_string (count_string); size = atoi (count_string); DEBUG1 ("rmtd: W %s\n", count_string); prepare_record_buffer (size); for (counter = 0; counter < size; counter += size_read) { size_read = full_read (INPUT, record_buffer + counter, size - counter); if (size_read <= 0) { return_error_message (N_("Premature end of file")); /* Exit status used to be 2. */ exit (EXIT_FAILURE); } } size_written = full_write (tape, record_buffer, size); if (size_written < 0) return_numbered_error (errno); else return_response (size_written); break; } case 'R': { char count_string[STRING_SIZE]; size_t size; ssize_t read_size; get_string (count_string); DEBUG1 ("rmtd: R %s\n", count_string); size = atoi (count_string); prepare_record_buffer (size); read_size = full_read (tape, record_buffer, size); if (read_size < 0) return_numbered_error (errno); else { sprintf (reply_buffer, "A%d\n", read_size); full_write (OUTPUT, reply_buffer, strlen (reply_buffer)); full_write (OUTPUT, record_buffer, read_size); } break; } case 'I': { int status = 0; char operation_string[STRING_SIZE]; char count_string[STRING_SIZE]; get_string (operation_string); get_string (count_string); DEBUG2 ("rmtd: I %s %s\n", operation_string, count_string); #ifdef MTIOCTOP { struct mtop mtop; mtop.mt_op = atoi (operation_string); mtop.mt_count = atoi (count_string); if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0) { return_numbered_error (errno); break; } status = mtop.mt_count; } #endif return_response (status); break; } case 'S': { int status = 0; DEBUG ("rmtd: S\n"); #ifdef MTIOCGET { struct mtget operation; if (ioctl (tape, MTIOCGET, (char *) &operation) < 0) { return_numbered_error (errno); break; } status = sizeof (operation); sprintf (reply_buffer, "A%d\n", status); full_write (OUTPUT, reply_buffer, strlen (reply_buffer)); full_write (OUTPUT, (char *) &operation, sizeof (operation)); } #endif /* FIXME: No reply at all, here? */ break; } default: DEBUG1 (_("rmtd: Garbage command %c\n"), command); return_error_message (N_("Garbage command")); /* Exit status used to be 3. */ exit (EXIT_FAILURE); } } exit (EXIT_SUCCESS); }
/** * handle_client: Main application layer thread for each client * @author ndemarinis (Basic implementation) */ void *handle_client(void *data){ struct client_handler_data *clnt = (struct client_handler_data *)data; int pipes[2]; // Make a pipe to connect to the layer stack uint16_t cur_seq_num = 0; pid_t clnt_pid; // PID we receive from the client before startup struct layer_stack *stack; // Work data for layer stack implementation // Grab the client's identifier if((recv(clnt->sock, &clnt_pid, sizeof(pid_t), 0) != sizeof(pid_t))) die_with_error("Error receiving PID from client!"); stack = create_layer_stack(clnt->sock, clnt_pid, pipes); // Initialize all of our layer threads sleep(1); // Wait a second for the thread creation to settle int bytes_read; struct packet client_p; struct packet response_p; while(1){ //Wait for a packet to come in bytes_read = read(pipe_read(pipes), &client_p, sizeof(struct packet)); if(!bytes_read) // If we read nothing, it's time to terminate. { dprintf(DID_INFO, "APP: Read 0 bytes from layer stack. Terminating!\n"); break; } int opcode = client_p.opcode; //login if (opcode == __LOGIN_CODE){ //payload is just the username for this opcode if(login(client_p.payload) == 0){ //response code for SUCCESS response_p.opcode = 0x05; response_p.seq_num = cur_seq_num; cur_seq_num++; //no payload basic success response! response_p.length = 0; send_packet(pipes, response_p); } else { //basic response packet signaling invailed login response_p.opcode = __NOT_AUTHORIZED_CODE; response_p.seq_num = cur_seq_num; cur_seq_num++; response_p.length = 0; send_packet(pipes, response_p); } //create record } else if (opcode == __CREATE_CODE){ //payload syntax "<firstName>,<lastName>,<location>" char *firstName = strtok(client_p.payload, ","); char *lastName = strtok(NULL, ","); char *location = strtok(NULL, ""); //replace null with proper response once I determine what its for! char *response = malloc(10*sizeof(response)); int resp = createRecord(firstName, lastName, location, response); //if a 0 was not returned an error occured if (resp) { //send an error back! return_error(pipes, resp, &cur_seq_num); } else { //send back the data return_response(pipes, response, &cur_seq_num); } //query record } else if (opcode == __QUERY_CODE){ //payload syntax "NAME:<firstName>,<lastName>" // "LOCATION:<location>" char *queryType = strtok(client_p.payload, ":"); bodyEntry *responses; int resp; //two types of query name and location if (strcmp(queryType, "NAME") == 0){ //handle queries by name char *firstName = strtok(NULL, ","); char *lastName = strtok(NULL, ""); int respCount; //get the query response from the database resp = queryRecordByName(firstName, lastName, &responses, &respCount); //if resp is not 0 then an error occured if (resp){ //send an error back! return_error(pipes, resp, &cur_seq_num); } else { //send the information back to the client! char response[respCount*(16+20+36+3)]; memset(response,0,sizeof(response)); int i, rID; char recordID[10]; for (i = 0; i < respCount; i++){ rID = responses[i].id; sprintf(recordID, "%09d", rID); strcat(response, recordID); strcat(response, ","); strcat(response, responses[i].location); strcat(response, ","); } return_response(pipes, response, &cur_seq_num); } } else if (strcmp(queryType, "LOCATION") == 0){ //handle queries by location char *location = strtok(NULL, ""); int respCount; //get the query response from the database resp = queryRecordByLocation(location, &responses, &respCount); //if resp is not 0 then an error occured if (resp){ //send an error back! return_error(pipes, resp, &cur_seq_num); } else { //send the information back to the client! char response[respCount*(16+20+36+3)]; memset(response,0,sizeof(response)); int i, rID; char recordID[10]; for (i = 0; i < respCount; i++){ rID = responses[i].id; sprintf(recordID, "%09d", rID); strcat(response, recordID); strcat(response, ","); strcat(response, responses[i].firstName); strcat(response, ","); strcat(response, responses[i].lastName); strcat(response, ","); } return_response(pipes, response, &cur_seq_num); } } //update record } else if (opcode == __UPDATE_CODE){ //payload syntax "<recordId>,<firstName>,<lastName>" char *recordId = strtok(client_p.payload, ","); char *firstName = strtok(NULL, ","); char *lastName = strtok(NULL, ""); //convert recordID into an integer int rId = atoi(recordId); int resp = updateRecordName(rId, firstName, lastName); //if resp is not 0 then an error occured if (resp){ //send an error back! return_error(pipes, resp, &cur_seq_num); } else { //send the information back to the client! //basic success packet so an empty string is given for the payload return_response(pipes, "", &cur_seq_num); } //add picture } else if (opcode == __ADD_PIC_CODE){ /*payload syntax 1st packet: "<firstName>,<lastName>,<imageSize>" 2nd+ packets: "<pictureData>" These picture data packets will continue until the entirety of the picture has been transmitted The file is complete once the server has recieved a packet ending with an EOF character */ //get the name information from the first packet transmitted char *firstName = strtok(client_p.payload, ","); char *lastName = strtok(NULL, ","); char *imageSize = strtok(NULL, ""); unsigned long size = atol(imageSize); //create an array capable of holding the entire image char pictureData[size]; int i = 0; // DEBUG: Write out the file as we read it FILE *out = fopen("server_output.png", "w+"); //start recieving the picture data, continue until this entire picture has been recieved while(i < size - 1){ //read in a new packet of data bytes_read = read(pipe_read(pipes), &client_p, sizeof(struct packet)); dprintf(DID_APP_INFO, "APP: Received packet of %d bytes with payload of %d bytes.\n", bytes_read, client_p.length); //store the picture data into the array memcpy(pictureData + i, client_p.payload, client_p.length); //increment i by the length of the payload i += client_p.length; } // DEBUG: Write out that whole array to the test file printf("Received picture of %d total bytes.\n", i); write(fileno(out), pictureData, i); // DEBUG: Close that file fflush(out); fclose(out); char add_response[10]; int resp = addPicture(firstName, lastName, pictureData, add_response); if (resp){ //send an error back! return_error(pipes, resp, &cur_seq_num); } else { //send the information back to the client! return_response(pipes, add_response, &cur_seq_num); } //connect picture } else if (opcode == __CONNECT_PIC_CODE){ //payload syntax "<pictureID>,<recordID>" char *pictureID = strtok(client_p.payload, ","); char *recordID = strtok(NULL, ""); int pID = atoi(pictureID); int rID = atoi(recordID); int resp = connectPictureToRecord(pID, rID); if (resp){ //send and error back! return_error(pipes, resp, &cur_seq_num); } else { //send the success packet back! return_response(pipes, "", &cur_seq_num); } //logout! } else if (opcode == __LOGOUT_CODE){ //payload syntax NONE //break out of the while loop containin this and allow the thread processing this client to exit logout(); break; //download picture } else if (opcode == __QUERY_PIC_CODE){ //payload syntax "<pictureID>" char *pictureID = strtok(client_p.payload, ""); int pID = atoi(pictureID); char pictureData[__MAX_IMAGE_SIZE]; int resp = queryPicture(pID, pictureData); if (resp){ //send an error back! return_error(pipes, resp, &cur_seq_num); } else { //break the image into packets and send it back to the client! //write the data into a tempory file handle for simple reading when breaking into packets //base the temporary file off of the pid to ensure uniqueness char filename[MAX_FILENAME_SIZE]; int pid = getpid(); char cpid[10]; sprintf(cpid, "%d", pid); strcpy(filename, "temp_"); strcat(filename, cpid); strcat(filename, ".jpg"); //open the temp file for writing FILE *picture = fopen(filename, "w"); //write the entire image to the file! fwrite(pictureData, 1, sizeof(pictureData), picture); //send a simple packet informing the client of the size of the image that it is going to recieve response_p.opcode = 5; response_p.seq_num = cur_seq_num; cur_seq_num++; sprintf(response_p.payload, "%lu", sizeof(pictureData)); response_p.length = strlen(response_p.payload); send_packet(pipes, response_p); //read into packets and send them until the end of file is reached //note this uses the same packet pointer the entire time so the opcode does not need to be set again response_p.opcode = 5; while(!feof(picture)){ //read at most 251 bytes of the picture into the packets payload int readSize = fread(response_p.payload, 1, MAX_PAYLOAD, picture); //if there was no error then add the sequence number and the length to the packet then send it //DO NOT SET THE SEND FLAG, this will handle it on its own since there could be multiple sends if (!ferror(picture)){ response_p.seq_num = cur_seq_num; cur_seq_num++; response_p.length = (uint8_t)readSize; //send this packet down to the data link layer send_packet(pipes, response_p); } else { //an error occured return an error code so that the client can stop processing the image and drop the corrupt data return_error(pipes, 1, &cur_seq_num); break; } } //close the picture that was being read fclose(picture); //delete the temporary file remove(filename); } } // Send it straight back //printf("APP: Sending string of %d bytes: %s\n", to_read, read_buffer); //write(pipe_write(pipes), read_buffer, to_read); } curr_clients--; pthread_exit(NULL); }