/***************************************************************************** * * STATUSWRL.C - Nagios 3-D (VRML) Network Status View * * Copyright (c) 1999-2007 Ethan Galstad (nagios@nagios.org) * Last Modified: 10-21-2007 * * Description: * * This CGI will dynamically create a 3-D VRML model of all hosts that are * being monitored on your network. * * License: * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************************************/ #include "../include/config.h" #include "../include/common.h" #include "../include/objects.h" #include "../include/statusdata.h" #include "../include/cgiutils.h" #include "../include/getcgi.h" #include "../include/cgiauth.h" extern char main_config_file[MAX_FILENAME_LENGTH]; extern char url_html_path[MAX_FILENAME_LENGTH]; extern char url_images_path[MAX_FILENAME_LENGTH]; extern char url_logo_images_path[MAX_FILENAME_LENGTH]; extern char *statuswrl_include; extern host *host_list; extern service *service_list; extern hostextinfo *hostextinfo_list; extern int default_statuswrl_layout_method; #define NAGIOS_VRML_IMAGE "nagiosvrml.png" #define DEFAULT_NODE_WIDTH 0.5 #define DEFAULT_HORIZONTAL_SPACING 1.0 #define DEFAULT_VERTICAL_SPACING 1.0 /* needed for auto-layout modes */ #define DEFAULT_NODE_HEIGHT 0.5 #define DEFAULT_NODE_HSPACING 1.0 #define DEFAULT_NODE_VSPACING 1.0 #define CIRCULAR_DRAWING_RADIUS 5.0 #define LAYOUT_USER_SUPPLIED 0 #define LAYOUT_COLLAPSED_TREE 2 #define LAYOUT_BALANCED_TREE 3 #define LAYOUT_CIRCULAR 4 void calculate_host_coords(void); void calculate_world_bounds(void); void display_world(void); void write_global_vrml_data(void); void draw_process_icon(void); void draw_host(hostextinfo *); void draw_host_links(void); void draw_host_link(host *,double,double,double,double,double,double); void document_header(void); int process_cgivars(void); int number_of_host_layer_members(host *,int); int max_child_host_layer_members(host *); int host_child_depth_separation(host *, host *); int max_child_host_drawing_width(host *); void calculate_balanced_tree_coords(host *,int,int); void calculate_circular_coords(void); void calculate_circular_layer_coords(host *,double,double,int,int); authdata current_authdata; float link_radius=0.016; float floor_width=0.0; float floor_depth=0.0; double min_z_coord=0.0; double min_x_coord=0.0; double min_y_coord=0.0; double max_z_coord=0.0; double max_x_coord=0.0; double max_y_coord=0.0; double max_world_size=0.0; double nagios_icon_x=0.0; double nagios_icon_y=0.0; int draw_nagios_icon=FALSE; double custom_viewpoint_x=0.0; double custom_viewpoint_y=0.0; double custom_viewpoint_z=0.0; int custom_viewpoint=FALSE; float vertical_spacing=DEFAULT_VERTICAL_SPACING; float horizontal_spacing=DEFAULT_HORIZONTAL_SPACING; float node_width=DEFAULT_NODE_WIDTH; float node_height=DEFAULT_NODE_WIDTH; /* should be the same as the node width */ char *host_name="all"; int show_all_hosts=TRUE; int use_textures=TRUE; int use_text=TRUE; int use_links=TRUE; int layout_method=LAYOUT_USER_SUPPLIED; int coordinates_were_specified=FALSE; /* were drawing coordinates specified with extended host info entries? */ int main(int argc, char **argv){ int result; /* reset internal variables */ reset_cgi_vars(); /* read the CGI configuration file */ result=read_cgi_config_file(get_cgi_config_location()); if(result==ERROR){ document_header(); return ERROR; } /* defaults from CGI config file */ layout_method=default_statuswrl_layout_method; /* get the arguments passed in the URL */ process_cgivars(); document_header(); /* read the main configuration file */ result=read_main_config_file(main_config_file); if(result==ERROR) return ERROR; /* read all object configuration data */ result=read_all_object_configuration_data(main_config_file,READ_ALL_OBJECT_DATA); if(result==ERROR) return ERROR; /* read all status data */ result=read_all_status_data(get_cgi_config_location(),READ_ALL_STATUS_DATA); if(result==ERROR){ free_memory(); return ERROR; } /* get authentication information */ get_authentication_information(¤t_authdata); /* display the 3-D VRML world... */ display_world(); /* free all allocated memory */ free_memory(); return OK; } void document_header(void){ char date_time[MAX_DATETIME_LENGTH]; time_t current_time; time_t expire_time; printf("Cache-Control: no-store\r\n"); printf("Pragma: no-cache\r\n"); time(¤t_time); get_time_string(¤t_time,date_time,sizeof(date_time),HTTP_DATE_TIME); printf("Last-Modified: %s\r\n",date_time); expire_time=0L; get_time_string(&expire_time,date_time,sizeof(date_time),HTTP_DATE_TIME); printf("Expires: %s\r\n",date_time); printf("Content-Type: x-world/x-vrml\r\n\r\n"); return; } int process_cgivars(void){ char **variables; int error=FALSE; int x; variables=getcgivars(); for(x=0;variables[x]!=NULL;x++){ /* do some basic length checking on the variable identifier to prevent buffer overflows */ if(strlen(variables[x])>=MAX_INPUT_BUFFER-1){ x++; continue; } /* we found the host argument */ else if(!strcmp(variables[x],"host")){ x++; if(variables[x]==NULL){ error=TRUE; break; } host_name=(char *)malloc(strlen(variables[x])+1); if(host_name==NULL) host_name="all"; else strcpy(host_name,variables[x]); strip_html_brackets(host_name); if(!strcmp(host_name,"all")) show_all_hosts=TRUE; else show_all_hosts=FALSE; } /* we found the no textures argument*/ else if(!strcmp(variables[x],"notextures")) use_textures=FALSE; /* we found the no text argument*/ else if(!strcmp(variables[x],"notext")) use_text=FALSE; /* we found the no links argument*/ else if(!strcmp(variables[x],"nolinks")) use_links=FALSE; /* we found the layout method option */ else if(!strcmp(variables[x],"layout")){ x++; if(variables[x]==NULL){ error=TRUE; break; } layout_method=atoi(variables[x]); } /* we found custom viewpoint coord */ else if(!strcmp(variables[x],"viewx")){ x++; if(variables[x]==NULL){ error=TRUE; break; } custom_viewpoint_x=strtod(variables[x],NULL); custom_viewpoint=TRUE; } else if(!strcmp(variables[x],"viewy")){ x++; if(variables[x]==NULL){ error=TRUE; break; } custom_viewpoint_y=strtod(variables[x],NULL); custom_viewpoint=TRUE; } else if(!strcmp(variables[x],"viewz")){ x++; if(variables[x]==NULL){ error=TRUE; break; } custom_viewpoint_z=strtod(variables[x],NULL); custom_viewpoint=TRUE; } } /* free memory allocated to the CGI variables */ free_cgivars(variables); return error; } /* top-level VRML world generation... */ void display_world(void){ hostextinfo *temp_hostextinfo; /* get the url we will use to grab the logo images... */ snprintf(url_logo_images_path,sizeof(url_logo_images_path),"%slogos/",url_images_path); url_logo_images_path[sizeof(url_logo_images_path)-1]='\x0'; /* calculate host drawing coordinates */ calculate_host_coords(); /* calculate world bounds */ calculate_world_bounds(); /* get the floor dimensions */ if(max_x_coord>0) floor_width=(float)(max_x_coord-min_x_coord)+(node_width*2); else floor_width=(float)(max_x_coord+min_x_coord)+(node_width*2); if(max_z_coord>0) floor_depth=(float)(max_z_coord-min_z_coord)+(node_height*2); else floor_depth=(float)(max_z_coord+min_z_coord)+(node_height*2); /* write global VRML data */ write_global_vrml_data(); /* no coordinates were specified, so display warning message */ if(coordinates_were_specified==FALSE){ printf("\n"); printf("Transform{\n"); printf("translation 0.0 0.0 0.0\n"); printf("children[\n"); printf("Billboard{\n"); printf("children[\n"); printf("Shape{\n"); printf("appearance Appearance {\n"); printf("material Material {\n"); printf("diffuseColor 1 0 0\n"); printf("}\n"); printf("}\n"); printf("geometry Text {\n"); printf("string [ \"Error: You have not supplied any 3-D drawing coordinates.\", \"Read the documentation for more information on supplying\", \"3-D drawing coordinates by defining\", \"extended host information entries in your config files.\" ]\n"); printf("fontStyle FontStyle {\n"); printf("family \"TYPEWRITER\"\n"); printf("size 0.3\n"); printf("justify \"MIDDLE\"\n"); printf("}\n"); printf("}\n"); printf("}\n"); printf("]\n"); printf("}\n"); printf("]\n"); printf("}\n"); } /* coordinates were specified... */ else{ /* draw Nagios icon */ if(layout_method!=LAYOUT_USER_SUPPLIED) draw_process_icon(); /* draw all hosts */ for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next) draw_host(temp_hostextinfo); /* draw host links */ draw_host_links(); } return; } /******************************************************************/ /************************ UTILITY FUNCTIONS ***********************/ /******************************************************************/ /* calculates how many "layers" separate parent and child - used by collapsed tree layout method */ int host_child_depth_separation(host *parent, host *child){ int this_depth=0; int min_depth=0; int have_min_depth=FALSE; host *temp_host; if(child==NULL) return -1; if(parent==child) return 0; if(is_host_immediate_child_of_host(parent,child)==TRUE) return 1; for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){ this_depth=host_child_depth_separation(temp_host,child); if(this_depth>=0 && (have_min_depth==FALSE || (have_min_depth==TRUE && (this_depthnext){ current_layer=host_child_depth_separation(parent,temp_host); if(current_layer==layer) layer_members++; } return layer_members; } /* calculate max number of members on all "layers" beneath and including parent host - used by collapsed tree layout method */ int max_child_host_layer_members(host *parent){ int current_layer; int max_members=1; int current_members=0; for(current_layer=1;;current_layer++){ current_members=number_of_host_layer_members(parent,current_layer); if(current_members<=0) break; if(current_members>max_members) max_members=current_members; } return max_members; } /* calculate max drawing width for host and children - used by balanced tree layout method */ int max_child_host_drawing_width(host *parent){ host *temp_host; int child_width=0; for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ if(is_host_immediate_child_of_host(parent,temp_host)==TRUE) child_width+=max_child_host_drawing_width(temp_host); } /* no children, so set width to 1 for this host */ if(child_width==0) return 1; else return child_width; } /******************************************************************/ /********************* CALCULATION FUNCTIONS **********************/ /******************************************************************/ /* calculates host drawing coordinates */ void calculate_host_coords(void){ hostextinfo *temp_hostextinfo; host *this_host; host *temp_host; int parent_hosts=0; int max_layer_width=1; int current_parent_host=0; int center_x=0; int offset_x=DEFAULT_NODE_WIDTH/2; int offset_y=DEFAULT_NODE_WIDTH/2; int current_layer=0; int layer_members=0; int current_layer_member=0; int max_drawing_width=0; /******************************/ /***** MANUAL LAYOUT MODE *****/ /******************************/ /* user-supplied coords */ if(layout_method==LAYOUT_USER_SUPPLIED){ /* see which hosts we should draw (only those with 3-D coords) */ for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){ if(temp_hostextinfo->have_3d_coords==TRUE) temp_hostextinfo->should_be_drawn=TRUE; else temp_hostextinfo->should_be_drawn=FALSE; } return; } /*****************************/ /***** AUTO-LAYOUT MODES *****/ /*****************************/ /* add empty extended host info entries for all hosts that don't have any */ for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ /* find the corresponding hostextinfo definition */ temp_hostextinfo=find_hostextinfo(temp_host->name); /* none was found, so add a blank one */ if(temp_hostextinfo==NULL) add_hostextinfo(temp_host->name,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0.0,0.0,0.0,0,0); /* default z coord should 0 for auto-layout modes unless overridden later */ else temp_hostextinfo->z_3d=0.0; } /***** COLLAPSED TREE MODE *****/ if(layout_method==LAYOUT_COLLAPSED_TREE){ /* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */ this_host=NULL; /* find total number of immediate parents for this host */ parent_hosts=number_of_immediate_parent_hosts(this_host); /* find the max layer width we have... */ max_layer_width=max_child_host_layer_members(this_host); if(parent_hosts>max_layer_width) max_layer_width=parent_hosts; /* calculate center x coord */ center_x=(((DEFAULT_NODE_WIDTH*max_layer_width)+(DEFAULT_NODE_HSPACING*(max_layer_width-1)))/2)+offset_x; /* coords for Nagios icon if necessary */ if(this_host==NULL || this_host->parent_hosts==NULL){ nagios_icon_x=center_x; nagios_icon_y=offset_y; draw_nagios_icon=TRUE; } /* do we need to draw a link to parent(s)? */ if(this_host!=NULL && is_host_immediate_child_of_host(NULL,this_host)==FALSE) offset_y+=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING; /* see which hosts we should draw and calculate drawing coords */ for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){ /* find the host that matches this entry */ temp_host=find_host(temp_hostextinfo->host_name); if(temp_host==NULL) continue; /* this is an immediate parent of the "main" host we're drawing */ else if(is_host_immediate_parent_of_host(this_host,temp_host)==TRUE){ temp_hostextinfo->should_be_drawn=TRUE; temp_hostextinfo->have_3d_coords=TRUE; temp_hostextinfo->x_3d=center_x-(((parent_hosts*DEFAULT_NODE_WIDTH)+((parent_hosts-1)*DEFAULT_NODE_HSPACING))/2)+(current_parent_host*(DEFAULT_NODE_WIDTH+DEFAULT_NODE_HSPACING))+(DEFAULT_NODE_WIDTH/2); temp_hostextinfo->y_3d=offset_y; current_parent_host++; } /* this is the "main" host we're drawing */ else if(this_host==temp_host){ temp_hostextinfo->should_be_drawn=TRUE; temp_hostextinfo->have_3d_coords=TRUE; temp_hostextinfo->x_3d=center_x; temp_hostextinfo->y_3d=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y; } /* else do not draw this host (we might if its a child - see below, but assume no for now) */ else{ temp_hostextinfo->should_be_drawn=FALSE; temp_hostextinfo->have_3d_coords=FALSE; } } /* TODO: REORDER CHILD LAYER MEMBERS SO THAT WE MINIMIZE LINK CROSSOVERS FROM PARENT HOSTS */ /* draw hosts in child "layers" */ for(current_layer=1;;current_layer++){ /* how many members in this layer? */ layer_members=number_of_host_layer_members(this_host,current_layer); if(layer_members==0) break; current_layer_member=0; /* see which hosts are members of this layer and calculate drawing coords */ for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){ /* find the host that matches this entry */ temp_host=find_host(temp_hostextinfo->host_name); if(temp_host==NULL) continue; /* is this host a member of the current child layer? */ if(host_child_depth_separation(this_host,temp_host)==current_layer){ temp_hostextinfo->should_be_drawn=TRUE; temp_hostextinfo->have_3d_coords=TRUE; temp_hostextinfo->x_3d=center_x-(((layer_members*DEFAULT_NODE_WIDTH)+((layer_members-1)*DEFAULT_NODE_HSPACING))/2)+(current_layer_member*(DEFAULT_NODE_WIDTH+DEFAULT_NODE_HSPACING))+(DEFAULT_NODE_WIDTH/2); if(this_host==NULL) temp_hostextinfo->y_3d=((DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)*current_layer)+offset_y; else temp_hostextinfo->y_3d=((DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING)*(current_layer+1))+offset_y; current_layer_member++; } } } } /***** "BALANCED" TREE MODE *****/ else if(layout_method==LAYOUT_BALANCED_TREE){ /* always use NULL as the "main" host, screen coords/dimensions are adjusted automatically */ this_host=NULL; /* find total number of immediate parents for this host */ parent_hosts=number_of_immediate_parent_hosts(this_host); /* find the max drawing width we have... */ max_drawing_width=max_child_host_drawing_width(this_host); if(parent_hosts>max_drawing_width) max_drawing_width=parent_hosts; /* calculate center x coord */ center_x=(((DEFAULT_NODE_WIDTH*max_drawing_width)+(DEFAULT_NODE_HSPACING*(max_drawing_width-1)))/2)+offset_x; /* coords for Nagios icon if necessary */ if(this_host==NULL || this_host->parent_hosts==NULL){ nagios_icon_x=center_x; nagios_icon_y=offset_y; draw_nagios_icon=TRUE; } /* do we need to draw a link to parent(s)? */ if(this_host!=NULL && is_host_immediate_child_of_host(NULL,this_host)==FALSE) offset_y+=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING; /* see which hosts we should draw and calculate drawing coords */ for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){ /* find the host that matches this entry */ temp_host=find_host(temp_hostextinfo->host_name); if(temp_host==NULL) continue; /* this is an immediate parent of the "main" host we're drawing */ else if(is_host_immediate_parent_of_host(this_host,temp_host)==TRUE){ temp_hostextinfo->should_be_drawn=TRUE; temp_hostextinfo->have_3d_coords=TRUE; temp_hostextinfo->x_3d=center_x-(((parent_hosts*DEFAULT_NODE_WIDTH)+((parent_hosts-1)*DEFAULT_NODE_HSPACING))/2)+(current_parent_host*(DEFAULT_NODE_WIDTH+DEFAULT_NODE_HSPACING))+(DEFAULT_NODE_WIDTH/2); temp_hostextinfo->y_3d=offset_y; current_parent_host++; } /* this is the "main" host we're drawing */ else if(this_host==temp_host){ temp_hostextinfo->should_be_drawn=TRUE; temp_hostextinfo->have_3d_coords=TRUE; temp_hostextinfo->x_3d=center_x; temp_hostextinfo->y_3d=DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y; } /* else do not draw this host (we might if its a child - see below, but assume no for now) */ else{ temp_hostextinfo->should_be_drawn=FALSE; temp_hostextinfo->have_3d_coords=FALSE; } } /* draw all children hosts */ calculate_balanced_tree_coords(this_host,center_x,DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING+offset_y); } /***** CIRCULAR LAYOUT MODE *****/ else if(layout_method==LAYOUT_CIRCULAR){ /* draw process icon */ nagios_icon_x=0; nagios_icon_y=0; draw_nagios_icon=TRUE; /* calculate coordinates for all hosts */ calculate_circular_coords(); } return; } /* calculate world dimensions */ void calculate_world_bounds(void){ hostextinfo *temp_hostextinfo; min_x_coord=0.0; min_y_coord=0.0; min_z_coord=0.0; max_x_coord=0.0; max_y_coord=0.0; max_z_coord=0.0; /* check all extended host entries */ for(temp_hostextinfo=hostextinfo_list;temp_hostextinfo!=NULL;temp_hostextinfo=temp_hostextinfo->next){ if(temp_hostextinfo->have_3d_coords==FALSE){ temp_hostextinfo->should_be_drawn=FALSE; continue; } if(temp_hostextinfo->should_be_drawn==FALSE) continue; if(temp_hostextinfo->x_3d < min_x_coord) min_x_coord=temp_hostextinfo->x_3d; else if(temp_hostextinfo->x_3d > max_x_coord) max_x_coord=temp_hostextinfo->x_3d; if(temp_hostextinfo->y_3d < min_y_coord) min_y_coord=temp_hostextinfo->y_3d; else if(temp_hostextinfo->y_3d > max_y_coord) max_y_coord=temp_hostextinfo->y_3d; if(temp_hostextinfo->z_3d < min_z_coord) min_z_coord=temp_hostextinfo->z_3d; else if(temp_hostextinfo->z_3d > max_z_coord) max_z_coord=temp_hostextinfo->z_3d; coordinates_were_specified=TRUE; } /* no drawing coordinates were specified */ if(coordinates_were_specified==FALSE){ min_x_coord=0.0; max_x_coord=0.0; min_y_coord=0.0; max_y_coord=0.0; min_z_coord=0.0; max_z_coord=6.0; } max_world_size=max_x_coord-min_x_coord; if(max_world_size<(max_y_coord-min_y_coord)) max_world_size=max_y_coord-min_y_coord; if(max_world_size<(max_z_coord-min_z_coord)) max_world_size=max_z_coord-min_z_coord; return; } /******************************************************************/ /*********************** DRAWING FUNCTIONS ************************/ /******************************************************************/ /* write global VRML data */ void write_global_vrml_data(void){ hostextinfo *temp_hostextinfo; float visibility_range=0.0; float viewpoint_z=0.0; /* write VRML code header */ printf("#VRML V2.0 utf8\n"); /* write world information */ printf("\n"); printf("WorldInfo{\n"); printf("title \"Nagios 3-D Network Status View\"\n"); printf("info [\"Copyright (c) 1999-2002 Ethan Galstad\"\n"); printf("\"nagios@nagios.org\"]\n"); printf("}\n"); /* background color */ printf("\n"); printf("Background{\n"); printf("skyColor 0.1 0.1 0.15\n"); printf("}\n"); /* calculate visibility range - don't let it get too low */ visibility_range=(max_world_size*2.0); if(visibility_range<25.0) visibility_range=25.0; /* write fog information */ printf("\n"); printf("Fog{\n"); printf("color 0.1 0.1 0.15\n"); printf("fogType \"EXPONENTIAL\"\n"); printf("visibilityRange %2.2f\n",visibility_range); printf("}\n"); /* custom viewpoint */ if(custom_viewpoint==TRUE){ printf("\n"); printf("Viewpoint{\n"); printf("position %2.2f %2.2f %2.2f\n",custom_viewpoint_x,custom_viewpoint_y,custom_viewpoint_z); printf("fieldOfView 0.78\n"); printf("description \"Entry Viewpoint\"\n"); printf("}\n"); } /* host close-up viewpoint */ if(show_all_hosts==FALSE){ temp_hostextinfo=find_hostextinfo(host_name); if(temp_hostextinfo!=NULL && temp_hostextinfo->have_3d_coords==TRUE){ printf("\n"); printf("Viewpoint{\n"); printf("position %2.3f %2.3f %2.3f\n",temp_hostextinfo->x_3d,temp_hostextinfo->y_3d,temp_hostextinfo->z_3d+5.0); printf("fieldOfView 0.78\n"); printf("description \"Host Close-Up Viewpoint\"\n"); printf("}\n"); } } /* calculate z coord for default viewpoint - don't get too close */ viewpoint_z=max_world_size; if(viewpoint_z<10.0) viewpoint_z=10.0; /* default viewpoint */ printf("\n"); printf("Viewpoint{\n"); printf("position %2.2f %2.2f %2.2f\n",min_x_coord+((max_x_coord-min_x_coord)/2.0),min_y_coord+((max_y_coord-min_y_coord)/2.0),viewpoint_z); printf("fieldOfView 0.78\n"); printf("description \"Default Viewpoint\"\n"); printf("}\n"); /* problem timer */ printf("DEF ProblemTimer TimeSensor{\n"); printf("loop TRUE\n"); printf("cycleInterval 5\n"); printf("}\n"); /* host text prototype */ printf("PROTO HostText[\n"); printf("field MFString the_text [\"\"]\n"); printf("field SFColor font_color 0.6 0.6 0.6"); printf("]\n"); printf("{\n"); printf("Billboard{\n"); printf("children[\n"); printf("Shape{\n"); printf("appearance Appearance {\n"); printf("material Material {\n"); printf("diffuseColor IS font_color\n"); printf("}\n"); printf("}\n"); printf("geometry Text {\n"); printf("string IS the_text\n"); printf("fontStyle FontStyle {\n"); printf("family \"TYPEWRITER\"\n"); printf("size 0.1\n"); printf("justify \"MIDDLE\"\n"); printf("}\n"); printf("}\n"); printf("}\n"); printf("]\n"); printf("}\n"); printf("}\n"); /* include user-defined world */ if(statuswrl_include!=NULL && coordinates_were_specified==TRUE && layout_method==LAYOUT_USER_SUPPLIED){ printf("\n"); printf("Inline{\n"); printf("url \"%s%s\"\n",url_html_path,statuswrl_include); printf("}\n"); } return; } /* draws a host */ void draw_host(hostextinfo *temp_hostextinfo){ host *temp_host; hoststatus *temp_hoststatus=NULL; char state_string[16]=""; double x, y, z; char *vrml_safe_hostname=NULL; int a, ch; if(temp_hostextinfo==NULL) return; /* make sure we have the coordinates */ if(temp_hostextinfo->have_3d_coords==FALSE) return; else{ x=temp_hostextinfo->x_3d; y=temp_hostextinfo->y_3d; z=temp_hostextinfo->z_3d; } /* find the config entry for this host */ temp_host=find_host(temp_hostextinfo->host_name); if(temp_host==NULL) return; /* make the host name safe for embedding in VRML */ vrml_safe_hostname=(char *)strdup(temp_host->name); if(vrml_safe_hostname==NULL) return; for(a=0;vrml_safe_hostname[a]!='\x0';a++){ ch=vrml_safe_hostname[a]; if((ch<'a' || ch>'z') && (ch<'A' || ch>'Z') && (ch<'0' || ch>'9')) vrml_safe_hostname[a]='_'; } /* see if user is authorized to view this host */ if(is_authorized_for_host(temp_host,¤t_authdata)==FALSE) return; /* get the status of the host */ temp_hoststatus=find_hoststatus(temp_host->name); printf("\n"); /* host object */ printf("Anchor{\n"); printf("children[\n"); printf("Transform {\n"); printf("translation %2.2f %2.2f %2.2f\n",x,y,z); printf("children [\n"); printf("DEF Host%s Shape{\n",vrml_safe_hostname); printf("appearance Appearance{\n"); printf("material DEF HostMat%s Material{\n",vrml_safe_hostname); if(temp_hoststatus==NULL) printf("emissiveColor 0.2 0.2 0.2\ndiffuseColor 0.2 0.2 0.2\n"); else if(temp_hoststatus->status==HOST_UP) printf("emissiveColor 0.2 1.0 0.2\ndiffuseColor 0.2 1.0 0.2\n"); else printf("emissiveColor 1.0 0.2 0.2\ndiffuseColor 1.0 0.2 0.2\n"); printf("transparency 0.4\n"); printf("}\n"); if(use_textures==TRUE && temp_hostextinfo->vrml_image!=NULL){ printf("texture ImageTexture{\n"); printf("url \"%s%s\"\n",url_logo_images_path,temp_hostextinfo->vrml_image); printf("}\n"); } printf("}\n"); printf("geometry Box{\n"); printf("size %2.2f %2.2f %2.2f\n",node_width,node_width,node_width); printf("}\n"); printf("}\n"); printf("]\n"); printf("}\n"); printf("]\n"); printf("description \"View status details for host '%s' (%s)\"\n",temp_host->name,temp_host->alias); printf("url \"%s?host=%s\"\n",STATUS_CGI,temp_host->name); printf("}\n"); /* draw status text */ if(use_text==TRUE){ printf("\n"); printf("Transform{\n"); printf("translation %2.3f %2.3f %2.3f\n",x,y+DEFAULT_NODE_WIDTH,z); printf("children[\n"); printf("HostText{\n"); if(temp_hoststatus!=NULL){ if(temp_hoststatus->status==HOST_UP) printf("font_color 0 1 0\n"); else if(temp_hoststatus->status==HOST_DOWN || temp_hoststatus->status==HOST_UNREACHABLE) printf("font_color 1 0 0\n"); } printf("the_text [\"%s\", \"%s\", ",temp_host->name,temp_host->alias); if(temp_hoststatus==NULL) strcpy(state_string,"UNKNOWN"); else{ if(temp_hoststatus->status==HOST_DOWN) strcpy(state_string,"DOWN"); else if(temp_hoststatus->status==HOST_UNREACHABLE) strcpy(state_string,"UNREACHABLE"); else if(temp_hoststatus->status==HOST_PENDING) strcpy(state_string,"PENDING"); else strcpy(state_string,"UP"); } printf("\"%s\"]\n",state_string); printf("}\n"); printf("]\n"); printf("}\n"); } /* host is down or unreachable, so make it fade in and out */ if(temp_hoststatus!=NULL && (temp_hoststatus->status==HOST_DOWN || temp_hoststatus->status==HOST_UNREACHABLE)) printf("ROUTE ProblemTimer.fraction_changed TO HostMat%s.set_transparency\n",vrml_safe_hostname); free(vrml_safe_hostname); return; } /* draw links between hosts */ void draw_host_links(void){ hostextinfo *child_hostextinfo; hostextinfo *parent_hostextinfo; host *parent_host; host *child_host; if(use_links==FALSE) return; for(child_hostextinfo=hostextinfo_list;child_hostextinfo!=NULL;child_hostextinfo=child_hostextinfo->next){ if(child_hostextinfo->have_3d_coords==FALSE) continue; child_host=find_host(child_hostextinfo->host_name); if(child_host==NULL) continue; /* check authorization */ if(is_authorized_for_host(child_host,¤t_authdata)==FALSE) continue; /* draw a link from this host to all of its parent hosts */ for(parent_host=host_list;parent_host!=NULL;parent_host=parent_host->next){ if(is_host_immediate_child_of_host(child_host,parent_host)==TRUE){ parent_hostextinfo=find_hostextinfo(parent_host->name); if(parent_hostextinfo==NULL) continue; if(parent_hostextinfo->have_3d_coords==FALSE) continue; /* check authorization */ if(is_authorized_for_host(parent_host,¤t_authdata)==FALSE) continue; /* draw the link between the child and parent hosts */ draw_host_link(parent_host,parent_hostextinfo->x_3d,parent_hostextinfo->y_3d,parent_hostextinfo->z_3d,child_hostextinfo->x_3d,child_hostextinfo->y_3d,child_hostextinfo->z_3d); } } } return; } /* draws a link from a parent host to a child host */ void draw_host_link(host *hst,double x0, double y0, double z0, double x1, double y1, double z1){ printf("\n"); if(hst!=NULL) printf("# Host '%s' LINK\n",hst->name); printf("Shape{\n"); printf("appearance DEF MATslategrey_0_ Appearance {\n"); printf("material Material {\n"); printf("diffuseColor 0.6 0.6 0.6\n"); printf("ambientIntensity 0.5\n"); printf("emissiveColor 0.6 0.6 0.6\n"); printf("}\n"); printf("}\n"); printf("geometry IndexedLineSet{\n"); printf("coord Coordinate{\n"); printf("point [ %2.3f %2.3f %2.3f, %2.3f %2.3f %2.3f ]\n",x0,y0,z0,x1,y1,z1); printf("}\n"); printf("coordIndex [ 0,1,-1 ]\n"); printf("}\n"); printf("}\n"); return; } /* draw process icon */ void draw_process_icon(void){ hostextinfo *child_hostextinfo; host *child_host; if(draw_nagios_icon==FALSE) return; /* draw process icon */ printf("\n"); printf("Anchor{\n"); printf("children[\n"); printf("Transform {\n"); printf("translation %2.2f %2.2f %2.2f\n",nagios_icon_x,nagios_icon_y,0.0); printf("children [\n"); printf("DEF ProcessNode Shape{\n"); printf("appearance Appearance{\n"); printf("material Material{\n"); printf("emissiveColor 0.5 0.5 0.5\n"); printf("diffuseColor 0.5 0.5 0.5\n"); printf("transparency 0.2\n"); printf("}\n"); if(use_textures==TRUE){ printf("texture ImageTexture{\n"); printf("url \"%s%s\"\n",url_logo_images_path,NAGIOS_VRML_IMAGE); printf("}\n"); } printf("}\n"); printf("geometry Box{\n"); printf("size %2.2f %2.2f %2.2f\n",node_width*3.0,node_width*3.0,node_width*3.0); printf("}\n"); printf("}\n"); printf("]\n"); printf("}\n"); printf("]\n"); printf("description \"View Nagios Process Information\"\n"); printf("url \"%s?type=%d\"\n",EXTINFO_CGI,DISPLAY_PROCESS_INFO); printf("}\n"); if(use_links==FALSE) return; /* draw links to immediate child hosts */ for(child_hostextinfo=hostextinfo_list;child_hostextinfo!=NULL;child_hostextinfo=child_hostextinfo->next){ if(child_hostextinfo->have_3d_coords==FALSE) continue; child_host=find_host(child_hostextinfo->host_name); if(child_host==NULL) continue; /* check authorization */ if(is_authorized_for_host(child_host,¤t_authdata)==FALSE) continue; /* draw a link to the host */ if(is_host_immediate_child_of_host(NULL,child_host)==TRUE) draw_host_link(NULL,nagios_icon_x,nagios_icon_y,0.0,child_hostextinfo->x_3d,child_hostextinfo->y_3d,child_hostextinfo->z_3d); } return; } /******************************************************************/ /***************** COORDINATE CALCULATION FUNCTIONS ***************/ /******************************************************************/ /* calculates coords of a host's children - used by balanced tree layout method */ void calculate_balanced_tree_coords(host *parent, int x, int y){ int parent_drawing_width; int start_drawing_x; int current_drawing_x; int this_drawing_width; host *temp_host; hostextinfo *temp_hostextinfo; /* calculate total drawing width of parent host */ parent_drawing_width=max_child_host_drawing_width(parent); /* calculate starting x coord */ start_drawing_x=x-(((DEFAULT_NODE_WIDTH*parent_drawing_width)+(DEFAULT_NODE_HSPACING*(parent_drawing_width-1)))/2); current_drawing_x=start_drawing_x; /* calculate coords for children */ for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ temp_hostextinfo=find_hostextinfo(temp_host->name); if(temp_hostextinfo==NULL) continue; if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){ /* get drawing width of child host */ this_drawing_width=max_child_host_drawing_width(temp_host); temp_hostextinfo->x_3d=current_drawing_x+(((DEFAULT_NODE_WIDTH*this_drawing_width)+(DEFAULT_NODE_HSPACING*(this_drawing_width-1)))/2); temp_hostextinfo->y_3d=y+DEFAULT_NODE_HEIGHT+DEFAULT_NODE_VSPACING; temp_hostextinfo->have_3d_coords=TRUE; temp_hostextinfo->should_be_drawn=TRUE; current_drawing_x+=(this_drawing_width*DEFAULT_NODE_WIDTH)+((this_drawing_width-1)*DEFAULT_NODE_HSPACING)+DEFAULT_NODE_HSPACING; /* recurse into child host ... */ calculate_balanced_tree_coords(temp_host,temp_hostextinfo->x_3d,temp_hostextinfo->y_3d); } } return; } /* calculate coords of all hosts in circular layout method */ void calculate_circular_coords(void){ /* calculate all host coords, starting with first layer */ calculate_circular_layer_coords(NULL,0.0,360.0,1,CIRCULAR_DRAWING_RADIUS); return; } /* calculates coords of all hosts in a particular "layer" in circular layout method */ void calculate_circular_layer_coords(host *parent, double start_angle, double useable_angle, int layer, int radius){ int parent_drawing_width=0; int this_drawing_width=0; int immediate_children=0; double current_drawing_angle=0.0; double this_drawing_angle=0.0; double available_angle=0.0; double clipped_available_angle=0.0; double average_child_angle=0.0; double x_coord=0.0; double y_coord=0.0; host *temp_host; hostextinfo *temp_hostextinfo; /* get the total number of immediate children to this host */ immediate_children=number_of_immediate_child_hosts(parent); /* bail out if we're done */ if(immediate_children==0) return; /* calculate total drawing "width" of parent host */ parent_drawing_width=max_child_host_drawing_width(parent); /* calculate average angle given to each child host */ average_child_angle=(double)(useable_angle/(double)immediate_children); /* calculate initial drawing angle */ current_drawing_angle=start_angle; /* calculate coords for children */ for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ temp_hostextinfo=find_hostextinfo(temp_host->name); if(temp_hostextinfo==NULL) continue; if(is_host_immediate_child_of_host(parent,temp_host)==TRUE){ /* get drawing width of child host */ this_drawing_width=max_child_host_drawing_width(temp_host); /* calculate angle this host gets for drawing */ available_angle=useable_angle*((double)this_drawing_width/(double)parent_drawing_width); /* clip available angle if necessary */ /* this isn't really necessary, but helps keep things looking a bit more sane with less potential connection crossover */ clipped_available_angle=360.0/layer; if(available_angle=360.0) this_drawing_angle-=360.0; while(this_drawing_angle<0.0) this_drawing_angle+=360.0; /* calculate drawing coords of this host using good ol' geometry... */ x_coord=-(sin(-this_drawing_angle*(M_PI/180.0))*radius); y_coord=-(sin((90+this_drawing_angle)*(M_PI/180.0))*radius); temp_hostextinfo->x_3d=(int)x_coord; temp_hostextinfo->y_3d=(int)y_coord; temp_hostextinfo->have_3d_coords=TRUE; temp_hostextinfo->should_be_drawn=TRUE; /* recurse into child host ... */ calculate_circular_layer_coords(temp_host,current_drawing_angle+((available_angle-clipped_available_angle)/2),clipped_available_angle,layer+1,radius+CIRCULAR_DRAWING_RADIUS); /* increment current drawing angle */ current_drawing_angle+=available_angle; } } return; }