1 /*
2 * The Spread Toolkit.
3 *
4 * The contents of this file are subject to the Spread Open-Source
5 * License, Version 1.0 (the ``License''); you may not use
6 * this file except in compliance with the License. You may obtain a
7 * copy of the License at:
8 *
9 * http://www.spread.org/license/
10 *
11 * or in the file ``license.txt'' found in this distribution.
12 *
13 * Software distributed under the License is distributed on an AS IS basis,
14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15 * for the specific language governing rights and limitations under the
16 * License.
17 *
18 * The Creators of Spread are:
19 * Yair Amir, Michal Miskin-Amir, Jonathan Stanton.
20 *
21 * Copyright (C) 1993-2004 Spread Concepts LLC <spread@spreadconcepts.com>
22 *
23 * All Rights Reserved.
24 *
25 * Major Contributor(s):
26 * ---------------
27 * Cristina Nita-Rotaru crisn@cs.purdue.edu - group communication security.
28 * Theo Schlossnagle jesus@omniti.com - Perl, skiplists, autoconf.
29 * Dan Schoenblum dansch@cnds.jhu.edu - Java interface.
30 * John Schultz jschultz@cnds.jhu.edu - contribution to process group membership.
31 *
32 */
33
34
35 /*
36 // example for a file:
37 // 4
38 // 3 132.27.1.0 [4803]
39 // harpo [132.28.33.22]
40 // hazard
41 // hal
42 // 4 132.28.3.0 3377
43 // bih
44 // binoc
45 // bbl
46 // bbc
47 // 2 125.32.0.0 3355
48 // rb
49 // rc
50 // 2 132.27.1.0
51 // harry
52 // harmony
53 */
54
55 #include "arch.h"
56
57 #ifndef ARCH_PC_WIN95
58
59 #include <netdb.h>
60 #include <sys/param.h>
61 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <unistd.h>
64
65 #else /* ARCH_PC_WIN95 */
66
67 #include <winsock.h>
68
69 #endif /* ARCH_PC_WIN95 */
70
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <assert.h>
75
76 #include "configuration.h"
77
78 #define ext_conf_body
79 #include "conf_body.h"
80 #undef ext_conf_body
81
82 #include "alarm.h"
83 #include "memory.h"
84 #include "spread_params.h"
85
86 static proc My;
87
88 /* True means allow dangerous monitor commands like partition and flow control
89 * to be handled.
90 * False means to ignore requests for those actions. THIS IS THE SAFE SETTING
91 */
92 static bool EnableDangerousMonitor = FALSE;
93
94 static port_reuse SocketPortReuse = port_reuse_auto;
95
96 static char *RuntimeDir = NULL;
97
98 static char *User = NULL;
99
100 static char *Group = NULL;
101
102 static int Link_Protocol;
103
Conf_init(char * file_name,char * my_name)104 int Conf_init( char *file_name, char *my_name )
105 {
106 struct hostent *host_ptr;
107 char machine_name[256];
108 char ip[16];
109 int i,j;
110 unsigned int name_len;
111 char configfile_location[MAXPATHLEN];
112 #if 0
113 int s;
114 char line[132];
115 char buf[132];
116 int full;
117 char optional_id[20];
118 int iret;
119 char *ret;
120 int p;
121 int32 i1,i2,i3,i4;
122 #endif
123 Num_procs = 0;
124 /* init Config, Config_procs from file
125 init My from host
126 */
127 configfile_location[0] = '\0';
128 strcat(configfile_location, SPREAD_ETCDIR);
129 strcat(configfile_location, "/spread.conf");
130
131 if (NULL != (yyin = fopen(file_name,"r")) )
132 Alarm( PRINT, "Conf_init: using file: %s\n", file_name);
133 if (yyin == NULL)
134 if (NULL != (yyin = fopen(configfile_location, "r")) )
135 Alarm( PRINT, "Conf_init: using file: %s\n", configfile_location);
136 if (yyin == NULL)
137 Alarm( EXIT, "Conf_init: error opening config file %s\n",
138 file_name);
139
140 yyparse();
141 #if 0
142 do{
143 ret = fgets(line,132,fp);
144 if (ret == NULL)
145 Alarm( EXIT, "Conf_init: no number of segments \n");
146 full = sscanf( line, "%s", buf );
147 }while( line[0] == '#' || full <= 0 );
148
149 sscanf(line,"%d",&Config.num_segments);
150 Alarm( CONF, "Conf_init: %d segments\n", Config.num_segments );
151 for ( s=0; s < Config.num_segments; s++ )
152 {
153 do{
154 ret = fgets(line,132,fp);
155 if (ret == NULL)
156 Alarm( EXIT, "Conf_init: no segment data line \n");
157 full = sscanf( line, "%s", buf );
158 }while( line[0] == '#' || full <= 0 );
159
160 for(i=0; i< 3; i++)
161 {
162 ret = strchr(line, '.' );
163 if ( ret == NULL)
164 Alarm( EXIT, "Conf_init: error in bcast addr\n");
165 *ret = ' ';
166 }
167 iret = sscanf(line,"%d%d%d%d%d%hd",
168 &Config.segments[s].num_procs,
169 &i1,&i2,&i3,&i4,
170 &Config.segments[s].port);
171 if( iret == 5 ) Config.segments[s].port = 4803;
172 else if( iret < 6 )
173 Alarm( EXIT, "Conf_init: not a valid segment line: %s\n",
174 line);
175
176 Alarm( CONF, "Conf_init: segment %d: with %d procs, (%d.%d.%d.%d, %hd)\n",
177 s, Config.segments[s].num_procs,
178 i1,i2,i3,i4,
179 Config.segments[s].port );
180
181 Config.segments[s].bcast_address =
182 ( (i1 << 24 ) | (i2 << 16) | (i3 << 8) | i4 );
183
184 for ( p=0; p < Config.segments[s].num_procs; p++ )
185 {
186 do{
187 ret = fgets(line,132,fp);
188 if (ret == NULL)
189 Alarm( EXIT, "Conf_init: no proc line\n");
190 full = sscanf( line, "%s", buf );
191 }while( line[0] == '#' || full <= 0 );
192
193 /* %19 is MAX_PROC_NAME-1 for the null */
194
195 iret = sscanf(line,"%19s%s",Config_procs[Num_procs].name,
196 optional_id);
197 if( iret == 1 )
198 {
199 host_ptr = gethostbyname(Config_procs[Num_procs].name);
200
201 if ( host_ptr == 0)
202 Alarm( EXIT, "Conf_init: no such host %s\n",
203 Config_procs[Num_procs].name);
204
205 memcpy(&Config_procs[Num_procs].id, host_ptr->h_addr_list[0],
206 sizeof(int32) );
207 Config_procs[Num_procs].id =
208 htonl( Config_procs[Num_procs].id );
209 i1= ( Config_procs[Num_procs].id & 0xff000000 ) >> 24;
210 i2= ( Config_procs[Num_procs].id & 0x00ff0000 ) >> 16;
211 i3= ( Config_procs[Num_procs].id & 0x0000ff00 ) >> 8;
212 i4= Config_procs[Num_procs].id & 0x000000ff;
213 }else if( iret == 2 ){
214 for(i=0; i< 3; i++)
215 {
216 ret = strchr(optional_id, '.' );
217 if ( ret == NULL)
218 Alarm( EXIT,
219 "Conf_init: error in id or not a valid host line: %s\n",line);
220 *ret = ' ';
221 }
222 sscanf(optional_id,"%d%d%d%d",&i1,&i2,&i3,&i4);
223 Config_procs[Num_procs].id =
224 ( (i1 << 24 ) | (i2 << 16) | (i3 << 8) | i4 );
225 }else Alarm( EXIT, "Conf_init: not a valid host line: %s\n",
226 line);
227
228 Config_procs[Num_procs].port = Config.segments[s].port;
229 Config_procs[Num_procs].seg_index = s;
230 Config_procs[Num_procs].index_in_seg = p;
231 Config.segments[s].proc_ids[p] =
232 Config_procs[Num_procs].id;
233
234 Alarm( CONF, "Conf_init: \t\t%-20s\t%d.%d.%d.%d\n",
235 Config_procs[Num_procs].name, i1,i2,i3,i4 );
236
237 Num_procs++;
238 }
239 }
240 #endif
241
242 fclose(yyin);
243
244 /* Test for localhost segemnt defined with other non-localhost segments.
245 * That is an invalid configuration
246 */
247 if ( Config.num_segments > 1 ) {
248 int found_localhost = 0;
249 int found_nonlocal = 0;
250 for ( i=0; i < Config.num_segments; i++) {
251 if ( ((Config.segments[i].bcast_address & 0xff000000) >> 24) == 127 ) {
252 found_localhost = 1;
253 } else {
254 found_nonlocal = 1;
255 }
256 }
257 if (found_nonlocal && found_localhost) {
258 /* Both localhost and non-localhost segments exist. This is a non-functional config.*/
259 Alarmp( SPLOG_PRINT, PRINT, "Conf_init: Invalid configuration:\n");
260 Conf_print( &Config );
261 Alarmp( SPLOG_PRINT, PRINT, "\n");
262 Alarmp( SPLOG_FATAL, CONF, "Conf_init: Localhost segments can not be used along with regular network address segments.\nMost likely you need to remove or comment out the \nSpread_Segment 127.0.0.255 {...}\n section of your configuration file.\n");
263 }
264 }
265
266 if( my_name == NULL ){
267 gethostname(machine_name,sizeof(machine_name));
268 host_ptr = gethostbyname(machine_name);
269 if( host_ptr == 0 )
270 Alarm( EXIT, "Conf_init: could not get my ip address (my name is %s)\n",
271 machine_name );
272 if (host_ptr->h_addrtype != AF_INET)
273 Alarm(EXIT, "Conf_init: Sorry, cannot handle addr types other than IPv4\n");
274 if (host_ptr->h_length != 4)
275 Alarm(EXIT, "Conf_init: Bad IPv4 address length\n");
276
277 i = -1; /* in case host_ptr->h_length == 0 */
278 for (j = 0; host_ptr->h_addr_list[j] != NULL; j++) {
279 memcpy(&My.id, host_ptr->h_addr_list[j], sizeof(struct in_addr));
280 My.id = ntohl( My.id );
281 i = Conf_proc_by_id( My.id, &My );
282 if( i >= 0 ) break;
283 }
284 if( i < 0 ) Alarm( EXIT,
285 "Conf_init: My proc id (%d.%d.%d.%d) is not in configuration\n", IP1(My.id),IP2(My.id),IP3(My.id),IP4(My.id) );
286
287 }else if( ! strcmp( my_name, "Monitor" ) ){
288 gethostname(machine_name,sizeof(machine_name));
289 host_ptr = gethostbyname(machine_name);
290
291 if( host_ptr == 0 )
292 Alarm( EXIT, "Conf_init: no such monitor host %s\n",
293 machine_name );
294
295 memcpy(&My.id, host_ptr->h_addr_list[0],
296 sizeof(int32) );
297 My.id = ntohl( My.id );
298
299 name_len = strlen( machine_name );
300 if( name_len > sizeof(My.name) ) name_len = sizeof(My.name);
301 memcpy(My.name, machine_name, name_len );
302 Alarm( CONF, "Conf_init: My name: %s, id: %d\n",
303 My.name, My.id );
304 return( 1 );
305 }else{
306 name_len = strlen( my_name );
307 if( name_len > sizeof(My.name) ) name_len = sizeof(My.name);
308 memcpy(My.name, my_name, name_len );
309 i = Conf_proc_by_name( My.name, &My );
310 if( i < 0 ) Alarm( EXIT,
311 "Conf_init: My proc %s is not in configuration \n",
312 My.name);
313
314 }
315
316 Conf_id_to_str( My.id, ip );
317 Alarm( CONF, "Conf_init: My name: %s, id: %s, port: %hd\n",
318 My.name, ip, My.port );
319
320 return( 0 );
321 }
322
Conf()323 configuration Conf()
324 {
325 return Config;
326 }
327
Conf_my()328 proc Conf_my()
329 {
330 return My;
331 }
332
Conf_set_link_protocol(int protocol)333 void Conf_set_link_protocol(int protocol)
334 {
335 if (protocol < 0 || protocol >= MAX_PROTOCOLS) {
336 Alarm(PRINT, "Conf_set_link_protocol: Illegal protocol type %d\n", protocol);
337 return;
338 }
339 Link_Protocol = protocol;
340 }
341
Conf_get_link_protocol(void)342 int Conf_get_link_protocol(void)
343 {
344 return(Link_Protocol);
345 }
346
347
Conf_proc_by_id(int32u id,proc * p)348 int Conf_proc_by_id( int32u id, proc *p )
349 {
350 int i,j;
351
352 for ( i=0; i < Num_procs; i++ )
353 {
354 for ( j=0; j < Config_procs[i].num_if; j++)
355 {
356 if ( Config_procs[i].ifc[j].ip == id )
357 {
358 *p = Config_procs[i] ;
359 return( i );
360 }
361 }
362 }
363 return( -1 );
364 }
365
Conf_proc_by_name(char * name,proc * p)366 int Conf_proc_by_name( char *name, proc *p )
367 {
368 int i;
369
370 for ( i=0; i < Num_procs; i++ )
371 {
372 if ( strcmp( Config_procs[i].name, name ) == 0 )
373 {
374 *p = Config_procs[i];
375 return( i );
376 }
377 }
378 return( -1 );
379 }
380
Conf_id_in_seg(segment * seg,int32u id)381 int Conf_id_in_seg( segment *seg, int32u id )
382 {
383 int i,j;
384
385 for ( j=0; j < seg->num_procs; j++ )
386 {
387 for ( i=0; i < seg->procs[j]->num_if; i++)
388 {
389 if ( seg->procs[j]->ifc[i].ip == id )
390 return( j );
391 }
392 }
393 return( -1 );
394 }
Conf_proc_ref_by_id(int32u id,proc ** p)395 static int Conf_proc_ref_by_id( int32u id, proc **p )
396 {
397 int i,j;
398
399 for ( i=0; i < Num_procs; i++ )
400 {
401 for ( j=0; j < Config_procs[i].num_if; j++)
402 {
403 if ( Config_procs[i].ifc[j].ip == id )
404 {
405 *p = &Config_procs[i];
406 return( i );
407 }
408 }
409 }
410 return( -1 );
411 }
412
Conf_append_id_to_seg(segment * seg,int32u id)413 int Conf_append_id_to_seg( segment *seg, int32u id)
414 {
415 proc *p;
416 if (Conf_proc_ref_by_id(id, &p) != -1)
417 {
418 seg->procs[seg->num_procs] = p;
419 seg->num_procs++;
420 return( 0 );
421 }
422 return( -1 );
423 }
Conf_id_in_conf(configuration * config,int32u id)424 int Conf_id_in_conf( configuration *config, int32u id )
425 {
426 int i;
427
428 for ( i=0; i < config->num_segments; i++ )
429 if ( Conf_id_in_seg(&(config->segments[i]), id) >= 0 )
430 return( i );
431 return( -1 );
432 }
433
Conf_num_procs(configuration * config)434 int Conf_num_procs( configuration *config )
435 {
436 int i,ret;
437
438 ret = 0;
439 for ( i=0; i < config->num_segments; i++ )
440 ret += config->segments[i].num_procs;
441
442 return( ret );
443 }
444
Conf_leader(configuration * config)445 int32u Conf_leader( configuration *config )
446 {
447 int i;
448
449 for( i=0; i < config->num_segments; i++ )
450 {
451 if( config->segments[i].num_procs > 0 )
452 return( config->segments[i].procs[0]->id );
453 }
454 Alarm( EXIT, "Conf_leader: Empty configuration %c",Conf_print(config));
455 return( -1 );
456 }
457
Conf_last(configuration * config)458 int32u Conf_last( configuration *config )
459 {
460 int i,j;
461
462 for( i = config->num_segments-1; i >= 0; i-- )
463 {
464 if( config->segments[i].num_procs > 0 )
465 {
466 j = config->segments[i].num_procs-1;
467 return( config->segments[i].procs[j]->id );
468 }
469 }
470 Alarm( EXIT, "Conf_last: Empty configuration %c",Conf_print(config));
471 return( -1 );
472 }
473
Conf_seg_leader(configuration * config,int16 seg_index)474 int32u Conf_seg_leader( configuration *config, int16 seg_index )
475 {
476 if( config->segments[seg_index].num_procs > 0 )
477 {
478 return( config->segments[seg_index].procs[0]->id );
479 }
480 Alarm( EXIT, "Conf_seg_leader: Empty segment %d in Conf %c",
481 seg_index, Conf_print(config));
482 return( -1 );
483 }
484
Conf_seg_last(configuration * config,int16 seg_index)485 int32u Conf_seg_last( configuration *config, int16 seg_index )
486 {
487 int j;
488
489 if( config->segments[seg_index].num_procs > 0 )
490 {
491 j = config->segments[seg_index].num_procs-1;
492 return( config->segments[seg_index].procs[j]->id );
493 }
494 Alarm( EXIT, "Conf_seg_leader: Empty segment %d in Conf %c",
495 seg_index, Conf_print(config));
496 return(-1);
497 }
498
Conf_num_procs_in_seg(configuration * config,int16 seg_index)499 int Conf_num_procs_in_seg( configuration *config, int16 seg_index )
500 {
501 return( config->segments[seg_index].num_procs );
502 }
503
Conf_id_to_str(int32u id,char * str)504 void Conf_id_to_str( int32u id, char *str )
505 {
506 int32u i1,i2,i3,i4;
507
508 i1 = (id & 0xff000000) >> 24;
509 i2 = (id & 0x00ff0000) >> 16;
510 i3 = (id & 0x0000ff00) >> 8;
511 i4 = (id & 0x000000ff);
512 sprintf( str, "%u.%u.%u.%u", i1, i2, i3, i4 );
513 }
514
Conf_print(configuration * config)515 char Conf_print(configuration *config)
516 {
517 int s,p,ret;
518 char ip[16];
519 proc pr;
520
521 Alarm( PRINT, "--------------------\n" );
522 Alarm( PRINT, "Configuration at %s is:\n", My.name );
523 Alarm( PRINT, "Num Segments %d\n",config->num_segments );
524 for ( s=0; s < config->num_segments; s++ )
525 {
526 Conf_id_to_str( config->segments[s].bcast_address, ip );
527 Alarm( PRINT, "\t%d\t%-16s %hd\n",
528 config->segments[s].num_procs, ip,
529 config->segments[s].port );
530 for( p=0; p < config->segments[s].num_procs; p++)
531 {
532 ret = Conf_proc_by_id( config->segments[s].procs[p]->id,
533 &pr );
534 Conf_id_to_str( pr.id, ip );
535 Alarm( PRINT, "\t\t%-20s\t%-16s\n", pr.name, ip );
536 }
537 }
538 Alarm( PRINT, "====================" );
539 return( '\n' );
540 }
541
Conf_get_dangerous_monitor_state(void)542 bool Conf_get_dangerous_monitor_state(void)
543 {
544 return(EnableDangerousMonitor);
545 }
546
Conf_set_dangerous_monitor_state(bool new_state)547 void Conf_set_dangerous_monitor_state(bool new_state)
548 {
549 if (new_state == FALSE) {
550 Alarm(PRINT, "disabling Dangerous Monitor Commands!\n");
551 } else if (new_state == TRUE) {
552 Alarm(PRINT, "ENABLING Dangerous Monitor Commands! Make sure Spread network is secured\n");
553 } else {
554 /* invalid setting */
555 return;
556 }
557 EnableDangerousMonitor = new_state;
558 }
559
Conf_get_port_reuse_type(void)560 port_reuse Conf_get_port_reuse_type(void)
561 {
562 return(SocketPortReuse);
563 }
564
Conf_set_port_reuse_type(port_reuse state)565 void Conf_set_port_reuse_type(port_reuse state)
566 {
567 switch (state)
568 {
569 case port_reuse_auto:
570 Alarm(PRINT, "Setting SO_REUSEADDR to auto\n");
571 break;
572 case port_reuse_on:
573 Alarm(PRINT, "Setting SO_REUSEADDR to always on -- make sure Spread daemon host is secured!\n");
574 break;
575 case port_reuse_off:
576 Alarm(PRINT, "Setting SO_REUSEADDR to always off\n");
577 break;
578 default:
579 /* Inavlid type -- ignored */
580 return;
581 }
582 SocketPortReuse = state;
583 }
584
set_param_if_valid(char ** param,char * value,char * description,unsigned int max_value_len)585 static void set_param_if_valid(char **param, char *value, char *description, unsigned int max_value_len)
586 {
587 if (value != NULL && *value != '\0')
588 {
589 unsigned int len = strlen(value);
590 char *old_value = *param;
591 char *buf;
592 if (len > max_value_len)
593 {
594 Alarm(EXIT, "set_param_if_valid: value string too long\n");
595 }
596 buf = Mem_alloc(len + 1);
597 if (buf == NULL)
598 {
599 Alarm(EXIT, "set_param_if_valid: Out of memory\n");
600 }
601 strncpy(buf, value, len);
602 buf[len] = '\0';
603
604 *param = buf;
605 if (old_value != NULL)
606 {
607 dispose(old_value);
608 }
609 Alarm(PRINT, "Set %s to '%s'\n", description, value);
610 }
611 else
612 {
613 Alarm(DEBUG, "Ignored invalid %s\n", description);
614 }
615 }
616
Conf_get_runtime_dir(void)617 char *Conf_get_runtime_dir(void)
618 {
619 return (RuntimeDir != NULL ? RuntimeDir : SP_RUNTIME_DIR);
620 }
621
Conf_set_runtime_dir(char * dir)622 void Conf_set_runtime_dir(char *dir)
623 {
624 set_param_if_valid(&RuntimeDir, dir, "runtime directory", MAXPATHLEN);
625 }
626
Conf_get_user(void)627 char *Conf_get_user(void)
628 {
629 return (User != NULL ? User : SP_USER);
630 }
631
Conf_set_user(char * user)632 void Conf_set_user(char *user)
633 {
634 set_param_if_valid(&User, user, "user name", 32);
635 }
636
Conf_get_group(void)637 char *Conf_get_group(void)
638 {
639 return (Group != NULL ? Group : SP_GROUP);
640 }
641
Conf_set_group(char * group)642 void Conf_set_group(char *group)
643 {
644 set_param_if_valid(&Group, group, "group name", 32);
645 }
646