cleaned up dirty pointer handling -> global priv struct
[physik/nlsop.git] / nlsop_server.c
1 /*
2  * nlsop server code
3  *
4  * author: frank zirkelbach (frank.zirkelbach@physik.uni-augsburg.de)
5  *
6  * this program tries helping to understand the amorphous depuration
7  * and recrystallization of SiCx while ion implantation at temperatures
8  * below 400 degree celsius.
9  * hopefully the program will simulate the stabilization of the
10  * selforganizing lamella structure in the observed behaviour.
11  *
12  * refs: 
13  *  - J. K. N. Lindner. Habil.Schrift, Universitaet Augsburg.
14  *  - Maik Haeberlen. Diplomarbeit, Universitaet Augsburg.
15  *
16  * Copyright (C) 2004 Frank Zirkelbach
17  *
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 2 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31  *
32  */
33
34 #define _GNU_SOURCE
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <signal.h>
43
44 #include "nlsop.h"
45 #include "dfbapi.h"
46 #include "random.h"
47
48 #include "network.h"
49 #include "event.h"
50 #include "list.h"
51
52 #include "nlsop_general.h"
53
54 typedef struct s_priv {
55   t_event event;
56   t_net net;
57   t_list client;
58   t_list gui;
59   t_list job;
60 } t_priv;
61
62 /* global */
63 int alert;
64 int gi;
65 t_priv priv;
66
67 /*
68  * server specific stuff
69  */
70
71 int usage(char *prog)
72 {
73  puts("usage:");
74  printf("%s <listen port>\n",prog);
75  return 1;
76 }
77
78 int add_node(void) {
79
80   int channel;
81   unsigned char data;
82   t_client client;
83   int gui_chan;
84
85   channel=network_manage_incoming(&(priv.net));
86   if(channel==N_E_ACCEPT) {
87     printf("accept failed!\n");
88     return -1;
89   }
90   if(channel==N_E_MAXC) {
91     printf("maximum connections reached!\n");
92     return -1;
93   }
94   printf("connection from %s port %d (ch: %d)\n",
95          priv.net.connection[channel].ip,priv.net.connection[channel].port,
96          channel);
97
98   /* are you client or gui? */
99   network_receive_chan(&(priv.net),channel,&data,1);
100   if(data==NLSOP_GUI) {
101     gui_chan=channel;
102     list_add_element(&(priv.gui),&gui_chan,sizeof(int));
103     printf("node is a gui\n");
104   }
105   else if(data==NLSOP_CLIENT) {
106     client.status=IDLE;
107     client.channel=channel;
108     list_add_element(&(priv.client),&client,sizeof(t_client));
109     printf("node is a client\n");
110   }
111   else {
112     printf("not a client or gui - lets kick that ass out of here!\n");
113     network_close(&(priv.net),channel);
114     return -1;
115   }
116
117   /* if we have a new node - care for it! */
118   event_math(priv.net.connection[channel].fd,&(priv.event),READ,ADD);
119
120   printf("\n");
121
122   return 1;
123 }
124
125 int save_job(unsigned char dc) {
126
127   char filename[128];
128   int fd;
129   int ret;
130   d3_lattice d3l;
131   info info;
132   unsigned char data;
133   t_job *j;
134
135   j=(t_job *)priv.job.current->data;
136
137   printf("receiving data from client (%d)\n",j->size);
138   data=DATA_OK;
139
140   /* initial data_ok to start transmit on client */
141   network_send_chan(&(priv.net),gi,&data,sizeof(unsigned char));
142
143   network_receive_chan(&(priv.net),gi,(unsigned char *)&d3l,
144                        sizeof(d3_lattice));
145   network_send_chan(&(priv.net),gi,&data,sizeof(unsigned char));
146   printf("debug: got d3_lattice\n");
147
148   network_receive_chan(&(priv.net),gi,(unsigned char *)&info,sizeof(info));
149   network_send_chan(&(priv.net),gi,&data,sizeof(unsigned char));
150   printf("debug: got info\n");
151
152   network_receive_chan(&(priv.net),gi,j->ac,j->size*sizeof(unsigned char));
153   network_send_chan(&(priv.net),gi,&data,sizeof(unsigned char));
154   printf("debug: got ac\n");
155
156   network_receive_chan(&(priv.net),gi,(unsigned char *)j->cc,
157                        j->size*sizeof(int));
158   network_send_chan(&(priv.net),gi,&data,sizeof(unsigned char));
159   printf("debug: got cc\n");
160
161   network_receive_chan(&(priv.net),gi,(unsigned char *)&(j->step),sizeof(int));
162   network_send_chan(&(priv.net),gi,&data,sizeof(unsigned char));
163   printf("debug: got steps\n");
164
165   if(dc!=DC_QUIT) {
166     snprintf(filename,128,"./data/nlsop_b%f_c%f_s%f_ds%d_dr%f_-_%d_of_%d.save",
167              j->info.b,j->info.c,j->info.s,
168              j->info.diff_rate,j->info.dr_ac,
169              j->step,j->info.steps);
170     if((fd=open(filename,O_WRONLY|O_CREAT))<0) {
171       printf("FATAL: unable to open file %s\n",filename);
172       return -1;
173     }
174
175     if(write(fd,&d3l,sizeof(d3_lattice))<sizeof(d3_lattice)) {
176       printf("FATAL: write of d3_lattice failed\n");
177       return -1;
178     }
179
180     if(write(fd,&info,sizeof(info))<sizeof(info)) {
181       printf("FATAL: write of info failed\n");
182       return -1;
183     }
184
185     ret=write(fd,j->ac,j->size*sizeof(unsigned char));
186     if(ret<j->size*sizeof(unsigned char)) {
187       printf("FATAL: write of a/c states failed\n");
188       return -1;
189     }
190    
191     ret=write(fd,j->cc,j->size*sizeof(int));
192     if(ret<j->size*sizeof(int)) {
193       printf("FATAL: write of c.-conc. failed\n");
194       return -1;
195     }
196
197     close(fd);
198     
199   }
200
201   return 1;
202 }
203
204 int add_job(void) {
205
206   t_job job;
207
208   job.channel=-1;
209   job.status=IN_QUEUE;
210   job.progress=0;
211
212   network_receive_chan(&(priv.net),gi,(unsigned char *)&(job.x),sizeof(int));
213   network_receive_chan(&(priv.net),gi,(unsigned char *)&(job.y),sizeof(int));
214   network_receive_chan(&(priv.net),gi,(unsigned char *)&(job.z),sizeof(int));
215   network_receive_chan(&(priv.net),gi,(unsigned char *)&(job.info),
216                        sizeof(info));
217
218   job.size=job.x*job.y*job.z;
219
220   job.ac=(unsigned char *)malloc(job.size*sizeof(unsigned char));
221   if(job.ac==NULL) {
222     printf("unable to malloc a/c memory\n");
223     return -1;
224   }
225
226   job.cc=(int *)malloc(job.size*sizeof(int));
227   if(job.cc==NULL) {
228     printf("unable to malloc cc memory\n");
229     return -1;
230   }
231
232   job.step=0;
233
234   list_add_element(&(priv.job),&job,sizeof(t_job));
235   
236   printf("job added: b=%f | c=%f | s=%f ...\n",
237          job.info.b,job.info.c,job.info.s);
238
239   return 1;
240 }
241
242 int send_status(void) {
243
244   unsigned char data;
245   int count;
246   int i;
247
248   data=GUI_INFO;
249
250   count=list_count(&(priv.job));
251
252   printf("sending job info\n");
253
254   network_send_chan(&(priv.net),gi,&data,sizeof(unsigned char));
255   network_send_chan(&(priv.net),gi,(unsigned char *)&count,sizeof(int));
256
257   list_reset(&(priv.job));
258   for(i=0;i<count;i++) {
259     network_send_chan(&(priv.net),gi,priv.job.current->data,sizeof(t_job));
260     list_next(&(priv.job));
261   }
262
263   return 1;
264 }
265
266 int handle_node(void) {
267
268   unsigned char data;
269   t_client *c;
270   t_job *j;
271
272   for(gi=0;gi<MAX_CONNECTIONS;gi++) {
273     if(FD_ISSET(priv.net.connection[gi].fd,&(priv.event.rfds))) {
274
275       alert=0;
276       alarm(1);
277       network_receive_chan(&(priv.net),gi,&data,1);
278       alarm(0);
279
280       if(alert==1) return -1;
281
282       if(list_search_data(&(priv.client),&gi,sizeof(int))==L_SUCCESS) {
283         /* it's a client */
284         list_search_data(&(priv.job),&gi,sizeof(int));
285         j=(t_job *)priv.job.current->data;
286         c=(t_client *)priv.client.current->data;
287
288         if(data==DC_END) {
289           save_job(DC_END);
290           /* reset client */
291           c->status=IDLE;
292           /* free job memory */
293           free(j->ac);
294           free(j->cc);
295           /* delete job entry */
296           list_del_current(&(priv.job));
297           printf("job ended, saved and removed from list.\n");
298         }
299
300         if(data==DC_OK) {
301           save_job(DC_OK);
302           /* inc progress state */
303           j->progress+=1;
304           printf("job at next level, saved.\n");
305         }
306
307         if(data==DC_QUIT) {
308           save_job(DC_QUIT);
309           /* network disconnect */
310           event_math(priv.net.connection[gi].fd,&(priv.event),READ,REMOVE);
311           network_close(&(priv.net),gi);
312           /* del from client list */
313           list_del_current(&(priv.client));
314           /* change job state */
315           j->status=IN_QUEUE;
316           printf("client terminating, job queued, client removed.\n");
317         }
318       }
319
320       else if(list_search_data(&(priv.gui),&gi,sizeof(int))==L_SUCCESS) {
321         /* its a gui */
322         if(data==GUI_ADDJOB) add_job();
323
324         else if(data==GUI_INFO) send_status();
325
326         else if(data==GUI_QUIT) {
327           printf("disconnecting gui on channel %d\n",gi);
328           event_math(priv.net.connection[gi].fd,&(priv.event),READ,REMOVE);
329           network_close(&(priv.net),gi);
330           list_del_current(&(priv.gui));
331         }
332
333         else {
334           printf("unknown gui command\n");
335           return -1;
336         }
337       }
338
339       else {
340         printf("this chan is not in client or gui list! i disconnect now!\n");
341         event_math(priv.net.connection[gi].fd,&(priv.event),READ,REMOVE);
342         network_close(&(priv.net),gi);
343       }
344     }
345   }
346
347   printf("\n");
348    
349   return 1;
350 }
351
352 int distribute_jobs(t_event *event,void *allineed) {
353
354   int count_j,count_c,min;
355   t_job *j;
356   t_client *c;
357   unsigned char data;
358   d3_lattice d3l;
359
360   list_reset(&(priv.job));
361   list_reset(&(priv.client));
362
363   count_j=0;
364   count_c=0;
365
366   if((priv.client.current==NULL)||(priv.job.current==NULL)) return 2;
367
368   j=(t_job *)priv.job.current->data;
369   c=(t_client *)priv.client.current->data;
370   if(j->status==IN_QUEUE) count_j++;
371   if(c->status==IDLE) count_c++;
372
373   while(list_next(&(priv.job))!=L_NO_NEXT_ELEMENT) {
374     j=(t_job *)priv.job.current->data;
375     if(j->status==IN_QUEUE) count_j++;
376   }
377   while(list_next(&(priv.client))!=L_NO_NEXT_ELEMENT) {
378     c=(t_client *)priv.client.current->data;
379     if(c->status==IDLE) count_c++;
380   }
381  
382   min=(count_c<count_j)?count_c:count_j;
383
384   if(min!=0) {
385     printf("d: distributing jobs ...\n");
386     printf("%d queued jobs, %d idle clients\n\n",count_j,count_c);
387   }
388
389   list_reset(&(priv.job));
390   list_reset(&(priv.client));
391
392   while(min) {
393     j=(t_job *)priv.job.current->data;
394     c=(t_client *)priv.client.current->data;
395     while(c->status!=IDLE) {
396       list_next(&(priv.client));
397       c=(t_client *)priv.client.current->data;
398     }
399     while(j->status!=IN_QUEUE) {
400       list_next(&(priv.job));
401       j=(t_job *)priv.job.current->data;
402     }
403
404     /* direct current job to current client */
405     if(j->step==0) data=NLSOP_NJOB;
406     else data=NLSOP_CJOB;
407
408     c->status=WORK;
409     j->channel=c->channel;
410     j->status=IN_WORK;
411
412     d3l.max_x=j->x;
413     d3l.max_y=j->y;
414     d3l.max_z=j->z;
415
416     network_send_chan(&(priv.net),c->channel,&data,sizeof(unsigned char));
417     network_send_chan(&(priv.net),c->channel,(unsigned char *)&d3l,
418                       sizeof(d3_lattice));
419     network_send_chan(&(priv.net),c->channel,(unsigned char *)&(j->info),
420                       sizeof(info));
421
422     if(data==NLSOP_CJOB) {
423       network_send_chan(&(priv.net),c->channel,j->ac,
424                         j->size*sizeof(unsigned char));
425       network_receive_chan(&(priv.net),c->channel,&data,sizeof(unsigned char));
426       network_send_chan(&(priv.net),c->channel,(unsigned char *)&(j->cc),
427                         j->size*sizeof(int));
428       network_receive_chan(&(priv.net),c->channel,&data,sizeof(unsigned char));
429       network_send_chan(&(priv.net),c->channel,(unsigned char *)&(j->step),
430                         sizeof(int));
431       network_receive_chan(&(priv.net),c->channel,&data,sizeof(unsigned char));
432     }
433
434     --min;
435     list_next(&(priv.client));
436     list_next(&(priv.job));
437   }
438
439   return 1;
440 }
441
442 int parse_incoming(t_event *event,void *allineed) {
443
444   /* decide what to do */
445   if(FD_ISSET(priv.net.l_fd,&(priv.event.rfds))) {
446     /* new node */
447     printf("new node ...\n");
448     add_node();
449   }
450   else {
451     /* client/gui interaction */
452     printf("node interaction ...\n");
453     handle_node();
454   }
455     
456   return 1;
457 }
458
459 void destroy_it(int signum) {
460
461   printf("connection to client (ch %d) fucked up!\n",gi);
462   event_math(priv.net.connection[gi].fd,&(priv.event),READ,REMOVE);
463   network_close(&(priv.net),gi);
464   if(list_search_data(&(priv.client),&gi,sizeof(int))==L_SUCCESS) {
465     list_del_current(&(priv.client));
466     printf("removed client from list\n");
467   }
468   if(list_search_data(&(priv.gui),&gi,sizeof(int))==L_SUCCESS) {
469     list_del_current(&(priv.gui));
470     printf("removed gui from list\n");
471   }
472
473   alert=1;
474   alarm(0);
475
476 }
477
478 /*
479  * main program
480  */
481
482 int main(int argc,char **argv)
483 {
484
485   int port;
486
487   /* default values */
488   port=1025;
489
490   /* parse argv */
491   if(argc==2) port=atoi(argv[1]);
492
493   /* event init */
494   event_init(&(priv.event),1);
495   /* 10 sec event timeout - distributing jobs */
496   event_set_timeout(&(priv.event),10,0);
497
498   /* list init */
499   list_init(&(priv.client),1);
500   list_init(&(priv.gui),1);
501   list_init(&(priv.job),1);
502
503   /* connect to server */
504   network_init(&(priv.net),1);
505   network_set_listen_port(&(priv.net),port);
506   if(network_listen(&(priv.net))!=N_SUCCESS) {
507     printf("unable to listen on port %d, aborting!\n",port);
508     return -1;
509   }
510
511   /* install sighandler */
512   signal(SIGALRM,destroy_it);
513
514   /* wait for events :) */
515   event_math(priv.net.l_fd,&(priv.event),READ,ADD);
516   printf("\nNLSOP_SERVER started!\n\n");
517   event_start(&(priv.event),NULL,parse_incoming,distribute_jobs);
518
519   return 1;
520 }
521