int main() { comm_channel comm[MAX_TAB]; //Router <-> URL-RENDERING process communication channel array //Controller <-> Router communication channel is now comm[0] pid_t contPid, tabspid[MAX_TAB]; //for forking the CONTROLLER and URL_RENDERING processes int controllerDead = 1; int r,n; //used for checking if the read returns anything useful int tab_count = 0; //total # of tabs int tab_index = 0; //current available index //pipes for bi-directions communication with the CONTROLLER process pipe(comm[0].parent_to_child_fd); pipe(comm[0].child_to_parent_fd); //make these pipes non-blocking int flags; flags = fcntl(comm[0].parent_to_child_fd[0], F_GETFL, 0); fcntl(comm[0].parent_to_child_fd[0] , F_SETFL, flags | O_NONBLOCK); flags = fcntl(comm[0].child_to_parent_fd[0], F_GETFL, 0); fcntl(comm[0].child_to_parent_fd[0] , F_SETFL, flags | O_NONBLOCK); //fork for the CONTROLLER contPid = fork(); controllerDead = 0; if(contPid == 0) { run_control(comm[0]); //uses callback functions to respond to reodr.quests from the ROUTER process_all_gtk_events(); //exits with the return status of 0 for success when the user closed the CONTROLLER window exit(0); } tab_count++; tab_index++; //tab 0 is the controller while(!controllerDead) // while the controller is still running { child_req_to_parent request; //do a non blocking read to check for messages from the children processes for(n = 0; n < tab_index; n++) { r = read(comm[n].child_to_parent_fd[0], &request, sizeof(child_req_to_parent)); if(r == -1) { //just keep going, ignore the error message } else //when the read returns some data { if(request.type == CREATE_TAB) // Create-tab req read { //creates non blocking pipes for Router <-> URL-RENDERING process communication if(tab_index >= MAX_TAB) { perror("Too many tabs"); break; } // Set the pipe pipe(comm[tab_index].parent_to_child_fd); pipe(comm[tab_index].child_to_parent_fd); // Set flags for non-blocking pipe reads flags = fcntl(comm[tab_index].parent_to_child_fd[0], F_GETFL, 0); fcntl(comm[tab_index].parent_to_child_fd[0] , F_SETFL, flags | O_NONBLOCK); flags = fcntl(comm[tab_index].child_to_parent_fd[0], F_GETFL, 0); fcntl(comm[tab_index].child_to_parent_fd[0] , F_SETFL, flags | O_NONBLOCK); //the ROUTER forks() a URL_RENDERING process (this happens when the user clicks the 'new tab' button in the controller window) tabspid[tab_index] = fork(); if(tabspid[tab_index] == -1) { perror("Fork failed :("); //fork failed } if(tabspid[tab_index] == 0) // Execute the browser { run_url_browser(tab_index, comm[tab_index]); exit(0); } // Increment the current tab and the max count tab_index++; tab_count++; } else if(request.type == NEW_URI_ENTERED) // URL rendering { int uri_index = request.req.uri_req.render_in_tab; // Request declarations child_req_to_parent new_uri_child; child_request c_req; new_uri_req new_uri; // Request field assignment new_uri.render_in_tab = uri_index; strcpy(new_uri.uri, request.req.uri_req.uri); c_req.uri_req = new_uri; new_uri_child.req = c_req; new_uri_child.type = NEW_URI_ENTERED; if(uri_index >= tab_index || uri_index < 0) //Error handling (is tab alive?) { perror("No such tab!"); } else { write(comm[uri_index].parent_to_child_fd[1], &new_uri_child, sizeof(child_req_to_parent)); // Write request to URL proc } } else if(request.type == TAB_KILLED) { //ROUTER closes the file descriptors of the correspoding pipe that was between the ROUTER and the tab that is now closed int killed_index = request.req.killed_req.tab_index; if( killed_index == 0) // Controller is killed { // Request declaration child_req_to_parent new_req; tab_killed_req killed_req; child_request child_req; // Request field assignment child_req.killed_req = killed_req; new_req.type = TAB_KILLED; new_req.req = child_req; int j; for(j = 0;j < tab_index; j++ ) // Handle children { new_req.req.killed_req.tab_index = j; write(comm[j].parent_to_child_fd[1], &new_req, sizeof(child_req_to_parent)); // Send tab-kill req to all children kill(tabspid[j], SIGKILL); //Euthanize children } controllerDead = 1; }else{ // } //Close the pipe & decrement tab count close(comm[killed_index].child_to_parent_fd[0]); close(comm[killed_index].parent_to_child_fd[0]); close(comm[killed_index].child_to_parent_fd[1]); close(comm[killed_index].parent_to_child_fd[1]); kill(tabspid[killed_index], SIGKILL); tab_count--; if( tab_count == 0 ) { return 0; } } } } //use usleep between reads so we dont slow down the CPU usleep(10000); } //ROUTER exits and returns 0 for success (when CONTROLLER and all URL_REDERING processes are finished kill(0, SIGKILL); exit(0); }
/* * Name: main * Input arguments: none * Output arguments: none * Function: This function creates the router and handles all child processes, * terminating when the controller is killed by the user. */ int main() { pid_t childpid; int i,j,k,l,newTabIndex,tailIndex = 0; size_t bytesWritten,bytesRead; comm = (comm_channel*)calloc (MAX_TAB, sizeof(comm_channel)); // Create pipes for controller and set to nonblocking read if(createPipesAndSetToNonBlock(0) < 0){ fprintf(stderr, "main@268: Failed to create pipes for controller\n"); exit(EXIT_FAILURE); } // Fork to create controller if((childpid = fork()) == 0){ run_control(); }else{ tailIndex++; child_req_to_parent request; while(1){ // Router polls for requests from children (controller + url browsers) for(i = 0; i < tailIndex; i++){ // only read from active processes (indicating pipe is open) if(!comm[i].isOpen) continue; usleep(1000); // Uses non-blocking read bytesRead = read(comm[i].child_to_parent_fd[0], &request, sizeof(child_req_to_parent)); // continue working with other tabs even if one of them had crashed if( bytesRead == -1 && errno != EAGAIN){ perror("main@293: Router fails to read tab's request"); continue; } // Router reads a request, act accordingly if( bytesRead!= -1){ switch(request.type){ case CREATE_TAB: // set the new tab index to an appropriate number newTabIndex = 0; for( l = 1; l < tailIndex; l++){ if(comm[l].isOpen == false){ newTabIndex = l; break; } } // didn't find an unused slot if(!newTabIndex){ if(tailIndex <= MAX_TAB) newTabIndex = tailIndex++; else{ fprintf(stderr, "main@315: Reached maximum number of tabs\n"); break; } } // set up pipes for the new tab if(createPipesAndSetToNonBlock(newTabIndex) < 0){ fprintf(stderr, "main@321: Failed to create pipes for new tab\n"); break; } // fork to create new tab if((childpid = fork()) == 0){ run_url_browser(newTabIndex); } break; case NEW_URI_ENTERED: if(!request.req.uri_req.render_in_tab){ fprintf(stderr, "main@331: Tab index unspecified\n"); break; } // No url rendering browser existd if(tailIndex <= 1){ fprintf(stderr, "main@336: Create an url window to render the page\n"); break; } if(!comm[request.req.uri_req.render_in_tab].isOpen){ fprintf(stderr, "main@340: The specified tab isn't open\n"); break; } if((bytesWritten = write(comm[request.req.uri_req.render_in_tab].parent_to_child_fd[1], &request, sizeof(child_req_to_parent))) == -1){ perror("main@344: Failed to write url"); } break; case TAB_KILLED: //Close file descriptors of corresponding tab's pipes. j = request.req.killed_req.tab_index; if (j > 0){ // close relevant pipes, kill the process if(comm[j].isOpen){ if(kill_process(j) < 0){ fprintf(stderr, "main@354: Failed to send kill process request\n"); fprintf(stderr, "main@354: Cannot kill tab %d process\n",j); break; } if(closePipes(j) < 0){ fprintf(stderr, "main@359: Tab %d process is killed successfully\n",j); fprintf(stderr, "main@359: But failed to close its pipes\n"); fprintf(stderr, "main@359: OS will close these pipes on program exit\n"); break; } if(j == tailIndex - 1) tailIndex--; }else{ fprintf(stderr, "main@368: Tab %d is invalid process to kill\n",j); break; } }else{ // Killing controller -> close all tabs for (k = tailIndex - 1; k > 0; k--){ if(!comm[k].isOpen) continue; if(kill_process(k) < 0){ fprintf(stderr, "main@377: Failed to send kill process request\n"); fprintf(stderr, "main@377: Cannot kill tab %d process\n",k); break; } if(closePipes(k) < 0){ fprintf(stderr, "main@382: Tab %d process is killed successfully\n",k); fprintf(stderr, "main@382: But failed to close its pipes\n"); fprintf(stderr, "main@382: OS will close these pipes on program exit\n"); break; } } closePipes(0); exit(EXIT_SUCCESS); } break; default: fprintf(stderr, "main@393: Controller received invalid request\n"); break; } } } } } return 0 ; }