9adc6f83025fdf040bb7ff30cd83805ef7cbd934
[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   t_job *j;
133
134   j=(t_job *)priv.job.current->data;
135
136   printf("receiving data from client (#cells=%d)\n",j->size);
137
138   network_receive_chan(&(priv.net),gi,(unsigned char *)&d3l,
139                        sizeof(d3_lattice));
140   network_receive_chan(&(priv.net),gi,(unsigned char *)&info,sizeof(info));
141   network_receive_chan(&(priv.net),gi,j->ac,j->size*sizeof(unsigned char));
142   network_receive_chan(&(priv.net),gi,(unsigned char *)j->cc,
143                        j->size*sizeof(int));
144   network_receive_chan(&(priv.net),gi,(unsigned char *)&(j->step),sizeof(int));
145
146   if(dc!=DC_QUIT) {
147     snprintf(filename,128,"./data/nlsop_b%f_c%f_s%f_ds%d_dr%f_-_%d_of_%d.save",
148              j->info.b,j->info.c,j->info.s,
149              j->info.diff_rate,j->info.dr_ac,
150              j->step,j->info.steps);
151     if((fd=open(filename,O_WRONLY|O_CREAT))<0) {
152       printf("FATAL: unable to open file %s\n",filename);
153       return -1;
154     }
155
156     if(write(fd,&d3l,sizeof(d3_lattice))<sizeof(d3_lattice)) {
157       printf("FATAL: write of d3_lattice failed\n");
158       return -1;
159     }
160
161     if(write(fd,&info,sizeof(info))<sizeof(info)) {
162       printf("FATAL: write of info failed\n");
163       return -1;
164     }
165
166     ret=write(fd,j->ac,j->size*sizeof(unsigned char));
167     if(ret<j->size*sizeof(unsigned char)) {
168       printf("FATAL: write of a/c states failed\n");
169       return -1;
170     }
171    
172     ret=write(fd,j->cc,j->size*sizeof(int));
173     if(ret<j->size*sizeof(int)) {
174       printf("FATAL: write of c.-conc. failed\n");
175       return -1;
176     }
177
178     close(fd);
179     
180   }
181
182   return 1;
183 }
184
185 int add_job(void) {
186
187   t_job job;
188
189   job.channel=-1;
190   job.status=IN_QUEUE;
191   job.progress=0;
192
193   network_receive_chan(&(priv.net),gi,(unsigned char *)&(job.x),sizeof(int));
194   network_receive_chan(&(priv.net),gi,(unsigned char *)&(job.y),sizeof(int));
195   network_receive_chan(&(priv.net),gi,(unsigned char *)&(job.z),sizeof(int));
196   network_receive_chan(&(priv.net),gi,(unsigned char *)&(job.info),
197                        sizeof(info));
198
199   job.size=job.x*job.y*job.z;
200
201   job.ac=(unsigned char *)malloc(job.size*sizeof(unsigned char));
202   if(job.ac==NULL) {
203     printf("unable to malloc a/c memory\n");
204     return -1;
205   }
206
207   job.cc=(int *)malloc(job.size*sizeof(int));
208   if(job.cc==NULL) {
209     printf("unable to malloc cc memory\n");
210     return -1;
211   }
212
213   job.step=0;
214
215   list_add_element(&(priv.job),&job,sizeof(t_job));
216   
217   printf("job added: b=%f | c=%f | s=%f ...\n",
218          job.info.b,job.info.c,job.info.s);
219
220   return 1;
221 }
222
223 int send_status(void) {
224
225   unsigned char data;
226   int count;
227   int i;
228
229   data=GUI_INFO;
230
231   network_send_chan(&(priv.net),gi,&data,sizeof(unsigned char));
232   printf("sending job + client list ...\n");
233
234   count=list_count(&(priv.job));
235   network_send_chan(&(priv.net),gi,(unsigned char *)&count,sizeof(int));
236   list_reset(&(priv.job));
237   for(i=0;i<count;i++) {
238     network_send_chan(&(priv.net),gi,priv.job.current->data,sizeof(t_job));
239     list_next(&(priv.job));
240   }
241
242   count=list_count(&(priv.client));
243   network_send_chan(&(priv.net),gi,(unsigned char *)&count,sizeof(int));
244   list_reset(&(priv.client));
245   for(i=0;i<count;i++) {
246     network_send_chan(&(priv.net),gi,priv.client.current->data,
247                       sizeof(t_client));
248     list_next(&(priv.client));
249   }
250
251   return 1;
252 }
253
254 int handle_node(void) {
255
256   unsigned char data;
257   t_client *c;
258   t_job *j;
259
260   for(gi=0;gi<MAX_CONNECTIONS;gi++) {
261     if(FD_ISSET(priv.net.connection[gi].fd,&(priv.event.rfds))) {
262
263       alert=0;
264       alarm(1);
265       network_receive_chan(&(priv.net),gi,&data,1);
266       alarm(0);
267
268       if(alert==1) return -1;
269
270       if(list_search_data(&(priv.client),&gi,sizeof(int))==L_SUCCESS) {
271         /* it's a client */
272         list_search_data(&(priv.job),&gi,sizeof(int));
273         j=(t_job *)priv.job.current->data;
274         c=(t_client *)priv.client.current->data;
275
276         if(data==DC_END) {
277           save_job(DC_END);
278           /* reset client */
279           c->status=IDLE;
280           /* free job memory */
281           free(j->ac);
282           free(j->cc);
283           /* delete job entry */
284           list_del_current(&(priv.job));
285           printf("job ended, saved and removed from list.\n");
286         }
287
288         if(data==DC_OK) {
289           save_job(DC_OK);
290           /* inc progress state */
291           j->progress+=1;
292           printf("job at next level, saved.\n");
293         }
294
295         if(data==DC_QUIT) {
296           save_job(DC_QUIT);
297           /* network disconnect */
298           event_math(priv.net.connection[gi].fd,&(priv.event),READ,REMOVE);
299           network_close(&(priv.net),gi);
300           /* del from client list */
301           list_del_current(&(priv.client));
302           /* change job state */
303           j->status=IN_QUEUE;
304           printf("client terminating, job queued, client removed.\n");
305         }
306       }
307
308       else if(list_search_data(&(priv.gui),&gi,sizeof(int))==L_SUCCESS) {
309         /* its a gui */
310         if(data==GUI_ADDJOB) add_job();
311
312         else if(data==GUI_INFO) send_status();
313
314         else if(data==GUI_QUIT) {
315           printf("disconnecting gui on channel %d\n",gi);
316           event_math(priv.net.connection[gi].fd,&(priv.event),READ,REMOVE);
317           network_close(&(priv.net),gi);
318           list_del_current(&(priv.gui));
319         }
320
321         else {
322           printf("unknown gui command\n");
323           return -1;
324         }
325       }
326
327       else {
328         printf("this chan is not in client or gui list! i disconnect now!\n");
329         event_math(priv.net.connection[gi].fd,&(priv.event),READ,REMOVE);
330         network_close(&(priv.net),gi);
331       }
332     }
333   }
334
335   printf("\n");
336    
337   return 1;
338 }
339
340 int distribute_jobs(t_event *event,void *allineed) {
341
342   int count_j,count_c,min;
343   t_job *j;
344   t_client *c;
345   unsigned char data;
346   d3_lattice d3l;
347
348   list_reset(&(priv.job));
349   list_reset(&(priv.client));
350
351   count_j=0;
352   count_c=0;
353
354   if((priv.client.current==NULL)||(priv.job.current==NULL)) return 2;
355
356   j=(t_job *)priv.job.current->data;
357   c=(t_client *)priv.client.current->data;
358   if(j->status==IN_QUEUE) count_j++;
359   if(c->status==IDLE) count_c++;
360
361   while(list_next(&(priv.job))!=L_NO_NEXT_ELEMENT) {
362     j=(t_job *)priv.job.current->data;
363     if(j->status==IN_QUEUE) count_j++;
364   }
365   while(list_next(&(priv.client))!=L_NO_NEXT_ELEMENT) {
366     c=(t_client *)priv.client.current->data;
367     if(c->status==IDLE) count_c++;
368   }
369  
370   min=(count_c<count_j)?count_c:count_j;
371
372   if(min!=0) {
373     printf("d: distributing jobs ...\n");
374     printf("%d queued jobs, %d idle clients\n\n",count_j,count_c);
375   }
376
377   list_reset(&(priv.job));
378   list_reset(&(priv.client));
379
380   while(min) {
381     j=(t_job *)priv.job.current->data;
382     c=(t_client *)priv.client.current->data;
383     while(c->status!=IDLE) {
384       list_next(&(priv.client));
385       c=(t_client *)priv.client.current->data;
386     }
387     while(j->status!=IN_QUEUE) {
388       list_next(&(priv.job));
389       j=(t_job *)priv.job.current->data;
390     }
391
392     /* direct current job to current client */
393     if(j->step==0) data=NLSOP_NJOB;
394     else data=NLSOP_CJOB;
395
396     c->status=WORK;
397     j->channel=c->channel;
398     j->status=IN_WORK;
399
400     d3l.max_x=j->x;
401     d3l.max_y=j->y;
402     d3l.max_z=j->z;
403
404     network_send_chan(&(priv.net),c->channel,&data,sizeof(unsigned char));
405     network_send_chan(&(priv.net),c->channel,(unsigned char *)&d3l,
406                       sizeof(d3_lattice));
407     network_send_chan(&(priv.net),c->channel,(unsigned char *)&(j->info),
408                       sizeof(info));
409
410     if(data==NLSOP_CJOB) {
411       network_send_chan(&(priv.net),c->channel,j->ac,
412                         j->size*sizeof(unsigned char));
413       network_receive_chan(&(priv.net),c->channel,&data,sizeof(unsigned char));
414       network_send_chan(&(priv.net),c->channel,(unsigned char *)&(j->cc),
415                         j->size*sizeof(int));
416       network_receive_chan(&(priv.net),c->channel,&data,sizeof(unsigned char));
417       network_send_chan(&(priv.net),c->channel,(unsigned char *)&(j->step),
418                         sizeof(int));
419       network_receive_chan(&(priv.net),c->channel,&data,sizeof(unsigned char));
420     }
421
422     --min;
423     list_next(&(priv.client));
424     list_next(&(priv.job));
425   }
426
427   return 1;
428 }
429
430 int parse_incoming(t_event *event,void *allineed) {
431
432   /* decide what to do */
433   if(FD_ISSET(priv.net.l_fd,&(priv.event.rfds))) {
434     /* new node */
435     printf("new node ...\n");
436     add_node();
437   }
438   else {
439     /* client/gui interaction */
440     printf("node interaction ...\n");
441     handle_node();
442   }
443     
444   return 1;
445 }
446
447 void destroy_it(int signum) {
448
449   t_job *j;
450
451   printf("connection to client (ch %d) fucked up!\n",gi);
452   event_math(priv.net.connection[gi].fd,&(priv.event),READ,REMOVE);
453   network_close(&(priv.net),gi);
454   if(list_search_data(&(priv.client),&gi,sizeof(int))==L_SUCCESS) {
455     list_del_current(&(priv.client));
456     printf("removed client from list\n");
457   }
458   if(list_search_data(&(priv.job),&gi,sizeof(int))==L_SUCCESS) {
459     printf("associated job found. resetting & queueing job.\n");
460     j=(t_job *)priv.job.current->data;
461     j->channel=-1;
462     j->status=IN_QUEUE;
463     j->progress=0;
464   }
465   if(list_search_data(&(priv.gui),&gi,sizeof(int))==L_SUCCESS) {
466     list_del_current(&(priv.gui));
467     printf("removed gui from list\n");
468   }
469
470   alert=1;
471   alarm(0);
472
473 }
474
475 /*
476  * main program
477  */
478
479 int main(int argc,char **argv)
480 {
481
482   int port;
483
484   /* default values */
485   port=1025;
486
487   /* parse argv */
488   if(argc==2) port=atoi(argv[1]);
489
490   /* event init */
491   event_init(&(priv.event),1);
492   /* 10 sec event timeout - distributing jobs */
493   event_set_timeout(&(priv.event),10,0);
494
495   /* list init */
496   list_init(&(priv.client),1);
497   list_init(&(priv.gui),1);
498   list_init(&(priv.job),1);
499
500   /* connect to server */
501   network_init(&(priv.net),1);
502   network_set_listen_port(&(priv.net),port);
503   if(network_listen(&(priv.net))!=N_SUCCESS) {
504     printf("unable to listen on port %d, aborting!\n",port);
505     return -1;
506   }
507
508   /* install sighandler */
509   signal(SIGALRM,destroy_it);
510
511   /* wait for events :) */
512   event_math(priv.net.l_fd,&(priv.event),READ,ADD);
513   printf("\nNLSOP_SERVER started!\n\n");
514   event_start(&(priv.event),NULL,parse_incoming,distribute_jobs);
515
516   return 1;
517 }
518