--- projects/cms/source/ihost/ihost.c 2004/05/31 13:52:27 1.52 +++ projects/cms/source/ihost/ihost.c 2005/09/24 13:30:40 1.53 @@ -27,11 +27,16 @@ #include #include #include -#include #include #include +#ifndef WIN32 +#include #include #include +#else +#include +#include +#endif #include #include @@ -42,6 +47,28 @@ #define LOG_INFO 2 #define LOG_DEBUG 3 +#define SERVICENAME "ihost" + +/* Windows printf does not understand %lld, so we have to use %I64d */ +#ifdef WIN32 +#define LLD "%I64d" +#define OPTSTRING "vVn:i:s:p:w:h" +#define SLEEP 10000 +#else +#define LLD "%lld" +#define OPTSTRING "vfVn:i:s:p:h" +#define SLEEP 10 +#endif + +/* The "socket" */ +#ifdef WIN32 +#define IHOST_SOCKET SOCKET +#define CLOSESOCKET(socket) closesocket(socket) +#else +#define IHOST_SOCKET FILE * +#define CLOSESOCKET(socket) fclose(socket) +#endif + typedef struct{ int filtermanager_port; char *filtermanager_host; @@ -77,9 +104,17 @@ typedef struct{ }udp_sockinfo_t; ihost_config_t ihost_config; +ihost_state_t ihost_state; extern int errno; +#ifdef WIN32 +int run_server = 1; +int run_as_service = 0; +SERVICE_STATUS service_status; +SERVICE_STATUS_HANDLE hstatus; +#endif + /* Taken from the OpenSSH code. Its licence included in function.*/ #ifndef HAVE_STRLCAT @@ -194,8 +229,12 @@ int create_udp_sockinfo(udp_sockinfo_t *udp_sockinfo, return 0; } -FILE *create_tcp_connection(char *hostname, int port){ +IHOST_SOCKET create_tcp_connection(char *hostname, int port){ +#ifdef WIN32 + SOCKET sock; +#else int sock; +#endif struct sockaddr_in addr; struct in_addr haddr; FILE *f; @@ -203,13 +242,13 @@ FILE *create_tcp_connection(char *hostname, int port){ log_msg(LOG_DEBUG, "Creating tcp socket"); if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0){ log_msg(LOG_CRIT, "Failed to make TCP Socket"); - return NULL; + goto out; } if((get_host_addr(hostname, &haddr))!=0){ log_msg(LOG_CRIT, "Failed to lookup name for %s", hostname); close(sock); - return NULL; + goto out; } memset(&addr, 0, sizeof(addr)); @@ -221,9 +260,11 @@ FILE *create_tcp_connection(char *hostname, int port){ if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) !=0){ log_msg(LOG_CRIT, "Failed to connect to hostname %s on port %d", hostname, port); close(sock); - return NULL; + goto out; } +#ifndef WIN32 +/* Windows does not treat sockets like this :( */ if((f=fdopen(sock, "r+"))==NULL){ log_msg(LOG_CRIT, "Failed to connect to open filedescriptor on tcp connection"); close(sock); @@ -231,8 +272,19 @@ FILE *create_tcp_connection(char *hostname, int port){ } return f; +#else + return sock; +#endif + +out: +#ifdef WIN32 + return 0; +#else + return NULL; +#endif } +#ifndef WIN32 int tcp_comm(FILE *f, char *send, char **response, char *expected){ log_msg(LOG_DEBUG, "Sending %s", send); @@ -252,8 +304,50 @@ int tcp_comm(FILE *f, char *send, char **response, cha log_msg(LOG_DEBUG, "Did not get expected response"); return -1; } +#else +int tcp_comm(SOCKET soc, char *sendstr, char **response, char *expected) { + static char *rec = NULL; + char sendbuf[128]; + char recbuf[128]; + int bytesRecv; + char *tmp; + + sprintf(sendbuf, "%s\n", sendstr); -int tcp_comm_strdup(FILE *f, char *send, char **response, char *expected){ + log_msg(LOG_DEBUG, "Sending %s", sendstr); + send(soc, sendbuf, strlen(sendbuf), 0); + bytesRecv = recv(soc, recbuf, 128, 0); + + if(bytesRecv != 0 && bytesRecv != SOCKET_ERROR) { + /* remove \n and copy to a string */ + recbuf[bytesRecv-1] = '\0'; + tmp = realloc(rec, bytesRecv); + if(tmp == NULL) { + free(rec); + rec = NULL; + log_msg(LOG_CRIT, "out of memory"); + return -1; + } + rec = tmp; + rec = strcpy(rec, recbuf); + *response = rec; + log_msg(LOG_DEBUG, "Received %s", *response); + } else { + return -1; + } + if(strcmp(*response, "ERROR")==0) return -1; + + if(expected==NULL) return 0; + + if((strcmp(expected, *response))==0) return 0; + + log_msg(LOG_DEBUG, "Did not get expected response"); + return -1; +} +#endif /* WIN32 */ + +int tcp_comm_strdup(IHOST_SOCKET f, char *send, char **response, char *expected) +{ if((tcp_comm(f, send, response, expected))!=0){ return -1; } @@ -265,8 +359,7 @@ int tcp_comm_strdup(FILE *f, char *send, char **respon } int ihost_getconfig(ihost_state_t *ihost_state){ - - FILE *tcp_con; + IHOST_SOCKET tcp_con; char *response; char *response_ptr; @@ -280,12 +373,23 @@ int ihost_getconfig(ihost_state_t *ihost_state){ int server_udp_port=0; time_t config_ttl=0; - if((tcp_con=create_tcp_connection(ihost_state->filtermanager_host, ihost_state->filtermanager_port))==NULL){ + if((tcp_con=create_tcp_connection(ihost_state->filtermanager_host, ihost_state->filtermanager_port)) +#ifndef WIN32 + ==NULL +#else + ==0 +#endif + ) { return -1; } if(ihost_state->file_list!=NULL || ihost_state->last_modified!=NULL){ - if(tcp_con==NULL){ +#ifndef WIN32 + if(tcp_con==NULL) +#else + if(tcp_con==0) +#endif + { goto error; } @@ -301,7 +405,7 @@ int ihost_getconfig(ihost_state_t *ihost_state){ if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){ goto error; } - fclose(tcp_con); + CLOSESOCKET(tcp_con); return 0; }else{ if((strcmp(response, "EXPIRED"))!=0){ @@ -381,7 +485,7 @@ int ihost_getconfig(ihost_state_t *ihost_state){ goto error; } - fclose(tcp_con); + CLOSESOCKET(tcp_con); /* We have the data we need, and its all been read correctly */ @@ -425,7 +529,7 @@ error: if(host_fqdn!=NULL) free(host_fqdn); if(server_fqdn!=NULL) free(server_fqdn); if(host_ip!=NULL) free(host_ip); - fclose(tcp_con); + CLOSESOCKET(tcp_con); return -1; } @@ -473,12 +577,13 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ /*Get mem stats, and fill in xml */ + if((mem_stats=sg_get_mem_stats())==NULL){ log_msg(LOG_CRIT, "Failed to get memory statistics: %s (%s)", sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ snprintf(tmp, size, \ - "%lld%lld%lld%lld", \ + ""LLD""LLD""LLD""LLD"", \ mem_stats->total, \ mem_stats->free, \ mem_stats->used, \ @@ -489,6 +594,7 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ /* Get load stats */ + if((load_stats=sg_get_load_stats())==NULL){ log_msg(LOG_CRIT, "Failed to get load statistics: %s (%s)", sg_str_error(sg_get_error()), sg_get_error_arg()); @@ -519,12 +625,13 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ /* swap stats */ + if((swap_stats=sg_get_swap_stats())==NULL){ log_msg(LOG_CRIT, "Failed to get swap statistics: %s (%s)", sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ snprintf(tmp, size, \ - "%lld%lld%lld",\ + ""LLD""LLD""LLD"",\ swap_stats->total, \ swap_stats->used, \ swap_stats->free); @@ -554,6 +661,7 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ /* process stats */ + if((process_stats=sg_get_process_count())==NULL){ log_msg(LOG_CRIT, "Failed to get process statistics: %s (%s)", sg_str_error(sg_get_error()), sg_get_error_arg()); @@ -572,6 +680,7 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ /* Get paging stats */ + if((page_stats=sg_get_page_stats_diff())==NULL){ log_msg(LOG_CRIT, "Failed to get paging statistics: %s (%s)", sg_str_error(sg_get_error()), sg_get_error_arg()); @@ -584,7 +693,7 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ y=page_stats->pages_pageout; } snprintf(tmp, size, \ - "%lld%lld", \ + ""LLD""LLD"", \ x, \ y); @@ -610,7 +719,7 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ } snprintf(tmp, size, \ - "", \ + "", \ counter, \ diskio_stats->disk_name, \ x, \ @@ -643,7 +752,7 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ } snprintf(tmp, size, \ - "", \ + "", \ counter, \ network_stats->interface_name, \ x, \ @@ -668,7 +777,7 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ strlcat(xml, "", size); for(counter=0;counter", \ + "", \ counter, \ disk_stats->device_name, \ disk_stats->mnt_point, \ @@ -703,10 +812,183 @@ too_big_error: +/* WIN32 NT service stuff */ +#ifdef WIN32 +void service_stopped() { + if(run_as_service) { + service_status.dwCurrentState = SERVICE_STOPPED; + service_status.dwWin32ExitCode = errno; + service_status.dwServiceSpecificExitCode = 0; + + SetServiceStatus(hstatus, &service_status); + } +} + +void control_handler(DWORD request) { + switch(request) { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + service_status.dwWin32ExitCode = 0; + service_status.dwCurrentState = SERVICE_STOP_PENDING; + break; + default: + break; + } + + SetServiceStatus (hstatus, &service_status); +} + +/* attempt to tell service manager to start our service. + * return 0 on error, 1 on ok + */ +int start_service() { + SC_HANDLE scm; + SC_HANDLE service; + + // Open SCM + if((scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL) { + log_msg(LOG_CRIT, "Failed to open Service Control Manager"); + return 0; + } + // Locate the service + if((service = OpenService(scm, SERVICENAME, SERVICE_START)) == NULL) { + log_msg(LOG_CRIT, "Unable to open the service"); + return 0; + } + // Start the service + if(StartService(service, 0, NULL) == 0) { + log_msg(LOG_CRIT, "Unable to start the service"); + return 0; + } + return 1; +} + +int stop_service() { + SC_HANDLE scm; + SC_HANDLE service; + SERVICE_STATUS status; + + // Open SCM + if((scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL) { + log_msg(LOG_CRIT, "Failed to open Service Control Manager"); + return 0; + } + // Locate service + if((service = OpenService(scm, SERVICENAME, SERVICE_STOP)) == NULL) { + log_msg(LOG_CRIT, "Unable to open the service"); + return 0; + } + // Stop the service + if(!ControlService(service, SERVICE_CONTROL_STOP, &status)) { + log_msg(LOG_CRIT, "Unable to stop the service"); + return 0; + } + return 1; +} + +int register_service(int argc, char **argv) { + char path[MAX_PATH]; + int cmdline_len; + int i; + char *cmdline; + char *tmp; + SC_HANDLE scm; + + if(!GetModuleFileName(NULL, path, MAX_PATH)) { + log_msg(LOG_CRIT, "GetModuleFileName failed"); + return 0; + } + + // Calculate command line length + // 14 = 10 for " -w service", 2x quote around path and ending \0 + cmdline_len = strlen(path) + 14; + for (i=0; i=udp_time){ + if(sg_snapshot()) { + log_msg(LOG_ERR, "sg_snapshot failed: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); + continue; /* Could this get ugly? */ + } if((get_system_stats(packet_num++, &ihost_state, packet, MAX_UDP_PACKET_SIZE))!=0){ log_msg(LOG_ERR, "Failed to get system stats"); } @@ -906,7 +1192,7 @@ int main(int argc, char **argv){ while((create_udp_sockinfo(&udp_sockinfo, ihost_state.server_fqdn, ihost_state.server_udp_port))!=0){ log_msg(LOG_CRIT, "Failed to create udp socket"); - sleep(10); + sleep(SLEEP); } config_time=time(NULL)+ihost_state.config_ttl; @@ -917,8 +1203,196 @@ int main(int argc, char **argv){ sleep_delay=udp_time-time(NULL); log_msg(LOG_DEBUG, "Sleeping for %d", sleep_delay); +#ifdef WIN32 + /* convert to millisecs */ + sleep_delay *= 1000; +#endif if(sleep_delay>0) sleep(sleep_delay); } + if(sg_shutdown()) { + log_msg(LOG_ERR, "sg_shutdown failed: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); + } + +#ifdef WIN32 + WSACleanup(); + if(run_as_service) { + service_status.dwWin32ExitCode = 0; + service_status.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(hstatus, &service_status); + } +#endif + log_msg(LOG_ERR, "ihost shutdown successfully"); + fclose(ihost_config.log); + return(0); + +out: +#ifdef WIN32 + WSACleanup(); + service_stopped(); +#endif + exit(1); +} + +#ifdef WIN32 +int service_main(int argc, char **argv) { + int error; + + service_status.dwServiceType = SERVICE_WIN32; + service_status.dwCurrentState = SERVICE_START_PENDING; + service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_SHUTDOWN; + service_status.dwWin32ExitCode = 0; + service_status.dwServiceSpecificExitCode = 0; + service_status.dwCheckPoint = 0; + service_status.dwWaitHint = 0; + + hstatus = RegisterServiceCtrlHandler(SERVICENAME, + (LPHANDLER_FUNCTION)control_handler); + if(hstatus == (SERVICE_STATUS_HANDLE)0) { + log_msg(LOG_CRIT, "RegisterServiceCtrlHandle failed"); + return -1; + } + + return run_ihost(); +} + + +void parse_w(int argc, char **argv) { + if (strcasecmp(optarg, "start") == 0) { + log_msg(LOG_ERR, "Attempting to start service..."); + run_server = 0; + if(start_service()) + log_msg(LOG_ERR, "Service started"); + } else if (strcasecmp(optarg, "stop") == 0) { + log_msg(LOG_ERR, "Attempting to stop service..."); + run_server = 0; + if(stop_service()) + log_msg(LOG_ERR, "Service stopped"); + } else if (strcasecmp(optarg, "service") == 0) { + run_as_service = 1; + } else if (strcasecmp(optarg, "register") == 0) { + log_msg(LOG_ERR, "Attempting to register service..."); + run_server = 0; + int i = optind; + optind = argc; + /* Grab the remaining arguments and use each time the service + * is started */ + if (register_service(argc-i, &argv[i])) + log_msg(LOG_ERR, "Registered service successfully"); + } else if (strcasecmp(optarg, "unregister") == 0) { + log_msg(LOG_ERR, "Attempting to unregister service..."); + run_server = 0; + if(unregister_service()) + log_msg(LOG_ERR, "Unregistered service successfully"); + } else { + fprintf(stderr, "Unknown -w option\n"); + usage(argv[0]); + exit(1); + } +} +#endif + + +int main(int argc, char **argv){ + int cmdopt; + extern int optind; + + /* Set default settings */ + ihost_config.verbose=1; + ihost_config.daemon=1; + /* Set all errors to go down stderr until told otherwise */ + ihost_config.log=stderr; + + /* Blank ihost_state to default settings */ + ihost_state.filtermanager_host=DEF_SERVER_NAME; + ihost_state.filtermanager_port=DEF_SERVER_PORT; + ihost_state.host_fqdn=NULL; + ihost_state.host_ip=NULL; + ihost_state.preset_fqdn = 0; + ihost_state.preset_ip = 0; + ihost_state.server_fqdn=NULL; + ihost_state.file_list=NULL; + ihost_state.last_modified=NULL; + + while((cmdopt=getopt(argc, argv, OPTSTRING)) != -1){ + switch(cmdopt){ + case 'v': + ihost_config.verbose++; + break; + +#ifndef WIN32 + case 'f': + /* Force syslog logging since stderr will be closed in this case */ + ihost_config.daemon=0; + break; +#endif + + case 'V': + fprintf(stderr, "%s version %s\n", argv[0], VERSION); + break; + case 'n': + ihost_state.preset_fqdn = 1; + ihost_state.host_fqdn = strdup(optarg); + if(ihost_state.host_fqdn == NULL){ + fprintf(stderr, "Missing hostname\n"); + usage(argv[0]); + } + break; + case 'i': + /* Hmm.. Someone could set any string to be the IP, and it will let it */ + ihost_state.preset_ip = 1; + ihost_state.host_ip = strdup(optarg); + if(ihost_state.host_ip == NULL){ + fprintf(stderr, "Missing ip\n"); + usage(argv[0]); + } + break; + + case 's': + ihost_state.filtermanager_host=strdup(optarg); + break; + + case 'p': + ihost_state.filtermanager_port=atoi(optarg); + break; + +#ifdef WIN32 + case 'w': + parse_w(argc, argv); + break; +#endif + + case 'h': + default: + usage(argv[0]); + exit(1); + } + } + +#ifdef WIN32 + if (run_server) { + if(run_as_service) { + if((ihost_config.log=fopen(LOG_FILE, "a"))==NULL){ + ihost_config.log=stderr; + log_msg(LOG_CRIT, "Failed to open Logfiles %s for writing", LOG_FILE); + exit(1); + } + log_msg(LOG_ERR, "Starting Service-Mode i-host"); + SERVICE_TABLE_ENTRY service_table[2]; + service_table[0].lpServiceName = SERVICENAME; + service_table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)service_main; + service_table[1].lpServiceName = NULL; + service_table[1].lpServiceProc = NULL; + return StartServiceCtrlDispatcher(service_table); + } else { + log_msg(LOG_ERR, "Starting User-Mode i-host"); + return run_ihost(); + } + } +#else + return run_ihost(); +#endif }