--- 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
}