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