I would prefer, if you have time, that you rewrite your code to make it neat. However, if you don't have time, I understand.
The grading on these questions will be roughly 12 points for question 1, 10 for question 2, 12 for question 3, and 24 for question 4.
typedef struct { char *host; int port; int qtime; FILE *fin; FILE *fout; int socket; } Ripoff_Info; | void establish(Ripoff_Info *r, int cl) { if (cl) { fclose(r->fin); fclose(r->fout); close(r->socket); } r->socket = request_connection(r->host, r->port); r->fin = fdopen(r->socket, "r"); r->fout = fdopen(r->socket, "w"); } | void read_quotes(Ripoff_Info *r) { establish(r, 0); while (1) { sleep(r->qtime); fprintf(r->fout, "GET-QUOTES\n"); fflush(r->fout) != 0) if (read_and_display_quotes(r->fin) == 0) { establish(r, 1); } } } |
The procedure read_and_display_quote() reads quotes from their server and displays them using sophisticated graphics. It returns 1 when it's done. If the connection to the server dies during read_and_display_quote(), then it returns zero, and as you can see, the program re-establishes a connection to the server, and continues.
Part A: Your boss only received a precompiled executable for his $100,000. He was told to run it with the following command line arguments:
UNIX> ripoff server.ripoff.com 5555 1The problem is that the program keeps dying after 10 minutes. Your boss asks you to figure out why, and when you call customer service, they tell you, "server.ripoff.com never keeps its connections open for more than 10 minutes to prevent denial of service attacks. It's ok, because the program re-establishes lost connections." Customer service is wrong, and it has nothing to do with denial of service attacks. Tell me why your program is dying -- give me the exact situation: tell me when and where the program is dying.
Part B: If you had the source code, you could fix this problem very easily. Go ahead and fix it. The "answer sheet for Question 1" has the above code in it -- go ahead and modify it so that it fixes the problem and re-establishes the connection rather than dying.
You may not add any global variables to this program. Fix it in the way that was advocated in class.
Write a program with two threads, A and B. Have thread A call execl("./ripoff", "ripoff", "server.ripoff.com", "5555", "1", NULL) and have thread B call pthread_join() on thread A. When the server drops the connection and ripoff dies, thread A will die too, and thread B can fork off a new thread A to reestablish the connection.
Part A: While tact may not be your strong suit, you need to tell your boss that what he is proposing is impossible. Please explain to me why the boss's plan is impossible. Be specific. You don't have to be tactful.
Part B: You can use fork(), execl() and wait() to do pretty much the same thing that your boss wants you to do, without bothering with pthreads. Write the program that does this. The only system calls that you are allowed to make, implicitly or explicitly, are fork(), execl() and wait().
You've been offered a raise if you can figure out a way to fix this problem, and since you've taken CS360, you're in good shape. You need to write a proxy server, which will run on the same machine as ripoff: dumbboss.investers.com. It will serve a socket on port 6000, and you will call ripoff as follows:
UNIX> ripoff dumbboss.inverstors.com 6000 1Your proxy will make sure that ripoff never dies, by re-establishing its own connection to server.ripoff.com when it detects that the connection has gone away. In that way, the connection between ripoff and the proxy never goes away. Your job is to write the proxy as a pthreads program with two threads. One thread reads from ripoff and writes to the server, and one reads from the server and writes to ripoff.
I have written a lot of this program for you on the next page -- your job is to simply write the procedures for the two threads: ripoff_to_server() and server_to_ripoff(). As you can see, they both get the same information. You can add to Thread_Info, but you will lose two points if you do so.
You may assume that output from server.ripoff.com is line buffered (in other words, it always comes as full lines with a newline, which means that you can use fdopen()/fgets()/fputs()). Moreover, lines are never more than 500 characters long.
Also, read Part C before you start implementing.
Part B (2 points, probably): Why do I call pthread_exit() in the main thread rather than just letting it exit naturally?
Part C: There are four ways that connections can die:
#include <pthread.h> #include <stdio.h> #include <stdlib.h> typedef struct { FILE *fin_server; FILE *fout_server; int fd_server; FILE *fin_ripoff; FILE *fout_ripoff; int fd_ripoff; pthread_mutex_t *lock; pthread_cond_t *cond; } Thread_Info; void *ripoff_to_server(void *arg) { Thread_Info *ti; ti = (Thread_Info *) arg; /* You write this. */ } void *server_to_ripoff(void *arg) { Thread_Info *ti; ti = (Thread_Info *) arg; /* You write this. */ } main() { int s; Thread_Info TI; pthread_t rts, str; pthread_mutex_t lock; pthread_cond_t cond; s = serve_socket(6000); TI.fd_ripoff = accept_connection(s); close(s); TI.fin_ripoff = fdopen(TI.fd_ripoff, "r"); TI.fout_ripoff = fdopen(TI.fd_ripoff, "w"); pthread_mutex_init(&lock, NULL); TI.lock = &lock; pthread_cond_init(&cond, NULL); TI.cond = &cond; TI.fd_server = request_connection("server.ripoff.com", 5555); TI.fin_server = fdopen(TI.fd_server, "r"); TI.fout_server = fdopen(TI.fd_server, "w"); pthread_create(&rts, NULL, ripoff_to_server, &TI); pthread_create(&str, NULL, server_to_ripoff, &TI); pthread_exit(NULL); } |