-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.c
323 lines (291 loc) · 8.99 KB
/
server.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#include <assert.h>
/* FreeBSD */
#define _WITH_GETLINE
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "window.h"
#include "db.h"
#include "words.h"
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
/* the encapsulation of a client thread, i.e., the thread that handles
* commands from clients */
typedef struct Client {
pthread_t thread;
window_t *win;
} client_t;
typedef struct ClientNode{
struct ClientNode *next;
client_t *client;
}clientNode_t;
int started;
clientNode_t* top;
pthread_mutex_t perm_mutex;
pthread_cond_t perm_given_cv;
int permission;
/* Interface with a client: get requests, carry them out and report results */
void *client_run(void *);
/* Interface to the db routines. Pass a command, get a result */
int handle_command(char *, char *, int len);
/*
* Create an interactive client - one with its own window. This routine
* creates the window (which starts the xterm and a process under it. The
* window is labelled with the ID passsed in. On error, a NULL pointer is
* returned and no process started. The client data structure returned must be
* destroyed using client_destroy()
*/
client_t *client_create(int ID) {
client_t *new_Client = (client_t *) malloc(sizeof(client_t));
char title[16];
if (!new_Client) return NULL;
sprintf(title, "Client %d", ID);
/* Creates a window and set up a communication channel with it */
if ((new_Client->win = window_create(title))) return new_Client;
else {
free(new_Client);
return NULL;
}
}
/*
* Create a client that reads cmmands from a file and writes output to a file.
* in and out are the filenames. If out is NULL then /dev/stdout (the main
* process's standard output) is used. On error a NULL pointer is returned.
* The returned client must be disposed of using client_destroy.
*/
client_t *client_create_no_window(char *in, char *out) {
char *outf = (out) ? out : "/dev/stdout";
client_t *new_Client = (client_t *) malloc(sizeof(client_t));
if (!new_Client) return NULL;
/* Creates a window and set up a communication channel with it */
if( (new_Client->win = nowindow_create(in, outf))) return new_Client;
else {
free(new_Client);
return NULL;
}
}
/*
* Destroy a client created with either client_create or
* client_create_no_window. The cient data structure, the underlying window
* (if any) and process (if any) are all destroyed and freed, and any open
* files are closed. Do not access client after calling this function.
*/
void client_destroy(client_t *client) {
/* Remove the window */
window_destroy(client->win);
free(client);
}
/* Code executed by the client */
void *client_run(void *arg)
{
pthread_mutex_lock(&perm_mutex);
if(!permission)
pthread_cond_wait(&perm_given_cv, &perm_mutex);
pthread_mutex_unlock(&perm_mutex);
client_t *client = (client_t *) arg;
/* main loop of the client: fetch commands from window, interpret
* and handle them, return results to window. */
char *command = 0;
size_t clen = 0;
/* response must be empty for the first call to serve */
char response[256] = { 0 };
/* Serve until the other side closes the pipe */
while (serve(client->win, response, &command, &clen) != -1) {
pthread_mutex_lock(&perm_mutex);
if(!permission)
pthread_cond_wait(&perm_given_cv,&perm_mutex);
pthread_mutex_unlock(&perm_mutex);
handle_command(command, response, sizeof(response));
}
started--;
pthread_exit(NULL);
}
void *client_run_dbInit(void *arg)
{
client_t *client = (client_t *) arg;
/* main loop of the client: fetch commands from window, interpret
* and handle them, return results to window. */
char *command = 0;
size_t clen = 0;
/* response must be empty for the first call to serve */
char response[256] = { 0 };
/* Serve until the other side closes the pipe */
while (serve(client->win, response, &command, &clen) != -1) {
handle_command(command, response, sizeof(response));
}
return;
}
int handle_command(char *command, char *response, int len) {
if (command[0] == EOF) {
strncpy(response, "all done", len - 1);
return 0;
}
interpret_command(command, response, len);
return 1;
}
void stackInsert(client_t *arg){
clientNode_t * newClient = (clientNode_t *) malloc(sizeof(clientNode_t));
newClient->client = arg;
if(top == NULL){
newClient->next = NULL;
top = newClient;
}else{
newClient->next = top;
top = newClient;
}
return;
}
void deleteStack(){
clientNode_t * current = top;
while(current!=NULL){
current = current->next;
free(top);
top = current;
}
return;
}
void client_init(char type, char* inputfile, char* outputfile){
client_t *c = NULL; /* A client to serve */
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int rc;
if(type == 'e'){
//no need to lock started because it is not being used for any conditions
c = client_create(started++);
}else if(type == 'E'){
started++;
c = client_create_no_window(inputfile, outputfile);
}
if(c == NULL) {
fprintf(stderr,"ERROR: client could not be created");
return;
}
rc = pthread_create(&(c->thread),&attr, client_run,(void *)c);
if (rc) {
fprintf(stderr,"ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
if(type == 'e'){
fprintf(stdout, "Created a new interactive client \n");
}else if(type == 'E'){
fprintf(stdout, "Created a new automated client \n");
}
stackInsert(c);
pthread_attr_destroy(&attr);
return;
}
void stop_all_clients(){
pthread_mutex_lock(&perm_mutex);
if(permission){
permission = 0;
fprintf(stdout, "Stopped all clients\n");
}else{
fprintf(stdout, "Clients were already stopped. This command had no effect\n");
}
pthread_mutex_unlock(&perm_mutex);
return;
}
void allow_all_clients(){
pthread_mutex_unlock(&perm_mutex);
if(!permission){
fprintf(stdout, "Clients have now started\n");
permission = 1;
}else
fprintf(stdout, "Clients are already executing\n");
pthread_cond_broadcast(&perm_given_cv);
pthread_mutex_unlock(&perm_mutex);
return;
}
void server_wait_for_clients(){
clientNode_t * current = top;
void * status;
while(current!=NULL){
int rc;
rc= pthread_join(current->client->thread, &status);
if (rc) {
fprintf(stderr,"ERROR: return code from pthread_join() is %d\n", rc);
exit(-1);
}
client_destroy(current->client);
current = current->next;
}
deleteStack();
fprintf(stdout,"Main: All threads have finished executing\n");
return;
}
int main(int argc, char *argv[]) {
started = 0; /* Number of clients started */
pthread_mutex_init(&perm_mutex, NULL);
pthread_cond_init (&perm_given_cv, NULL);
permission = 0;// denied by default
time_t startTime;
time_t endTime;
char* timeFile;
timeFile = argv[1];
char c;
for(;;){
printf(">");
scanf("%c",&c);
if(c == 'i'){
int temp_perm = permission;
permission = 0;
char input[4096];
char output[4096];
scanf("%s",input);
scanf("%s",output);
client_t* c = client_create_no_window(input, output);
if(c == NULL){
printf( "INVALID FILENAMEs, db could not be initialized");
}else{
printf("DB initialized");
client_run_dbInit(c);
client_destroy(c);
}
permission = temp_perm;
}else if(c == 'e'){
client_init(c,NULL,NULL);
}else if(c == 'E'){
char input[4096];
char output[4096];
scanf("%s",input);
scanf("%s",output);
client_init(c,input,output);
}else if(c == 's'){
stop_all_clients();
}else if(c == 'g'){
allow_all_clients();
}else if(c == 'w'){
allow_all_clients();
fprintf(stdout, "Wrapping up. No more commands will be taken now\n");
time(&startTime);
break;
}else{
printf("WRONG INPUT. PLEASE CHOOSE FROM e E s g w");
}
getchar();
}
server_wait_for_clients();
fprintf(stderr, "Terminating.\n");
time(&endTime);
double seconds = difftime(endTime,startTime);
printf("Finished Executing in %f\n",seconds);
if(timeFile){
FILE* fp;
fp = fopen(timeFile,"a");
fprintf(fp, "%f\n",seconds);
}
/* Clean up the window data */
window_cleanup();
destroyDBMutex();
pthread_mutex_destroy(&perm_mutex);
pthread_cond_destroy(&perm_given_cv);
pthread_exit(NULL);
}