/** * \file utils.cpp * This file contains the implementations of some helper methods for ApMon. */ /* * ApMon - Application Monitoring Tool * Version: 2.2.0 * * Copyright (C) 2006 California Institute of Technology * * Permission is hereby granted, free of charge, to use, copy and modify * this software and its documentation (the "Software") for any * purpose, provided that existing copyright notices are retained in * all copies and that this notice is included verbatim in any distributions * or substantial portions of the Software. * This software is a part of the MonALISA framework (http://monalisa.cacr.caltech.edu). * Users of the Software are asked to feed back problems, benefits, * and/or suggestions about the software to the MonALISA Development Team * (developers@monalisa.cern.ch). Support for this software - fixing of bugs, * incorporation of new features - is done on a best effort basis. All bug * fixes and enhancements will be made available under the same terms and * conditions as the original software, * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, * EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS * PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR * MODIFICATIONS. */ #include "utils.h" #include "ApMon.h" #ifdef __ICC // disable icc remark #2259: non-pointer conversion from "X" to "Y" may lose significant bits #pragma warning(disable:2259) #endif bool apmon_utils::urlModified(char *url, char *lastModified) throw(runtime_error) { char temp_filename[300]; FILE *tmp_file; bool lineFound; char line[MAX_STRING_LEN1]; #ifndef WIN32 long mypid = getpid(); #else long mypid = _getpid(); #endif char str1[100], str2[100]; #ifndef WIN32 sprintf(temp_filename, "/tmp/apmon_http%ld", mypid); #else char *tmp = getenv("TEMP"); if(tmp == NULL) tmp = getenv("TMP"); if(tmp == NULL) tmp = "c:"; sprintf(temp_filename, "%s\\apmon_http%ld", tmp, mypid); #endif /* get the HTTP header and put it in a temporary file */ httpRequest(url, (char*)"HEAD", temp_filename); /* read the header from the temporary file */ tmp_file = fopen(temp_filename, "rt"); if (tmp_file == NULL) throw runtime_error("[ urlModified() ] Error getting the configuration web page"); //line = (char*)malloc(MAX_STRING_LEN * sizeof(char)); //check if we got the page correctly fgets(line, MAX_STRING_LEN, tmp_file); sscanf(line, "%s %s", str1, str2); if (atoi(str2) != 200) { fclose(tmp_file); unlink(temp_filename); throw runtime_error("[ urlModified() ] Error getting the configuration web page"); } // look for the "Last-Modified" line lineFound = false; while (fgets(line, MAX_STRING_LEN, tmp_file) != NULL) { if (strstr(line, "Last-Modified") == line) { lineFound = true; break; } } fclose(tmp_file); unlink(temp_filename); if (lineFound) { if (strcmp(line, lastModified) != 0) { return true; } else return false; } else // if the line was not found we must assume the page was modified return true; } int apmon_utils::httpRequest(char *url, char *reqType, char *temp_filename) throw(runtime_error) { // the server from which we get the configuration file char hostname[MAX_STRING_LEN]; // the name of the remote file char filename[MAX_STRING_LEN]; // the port on which the server listens (by default 80) int port; char msg[MAX_STRING_LEN]; int sd, rc; // struct sockaddr_in localAddr; struct sockaddr_in servAddr; struct hostent *h; struct timeval optval; char *request; // the HTTP request char buffer[MAX_STRING_LEN]; // for reading from the socket int totalSize; // the size of the remote file FILE *tmp_file; parse_URL(url, hostname, &port, filename); sprintf(msg, "Sending HTTP %s request to: \n Hostname: %s , Port: %d , Filename: %s", reqType, hostname, port, filename); logger(INFO, msg); request = (char *)malloc(MAX_STRING_LEN * sizeof(char)); strcpy(request, reqType); strcat(request, " "); request = (char *)strcat( request, filename); request = (char *)strcat( request, " HTTP/1.0\r\nHOST: "); request = (char *)strcat( request, hostname); request = (char *)strcat( request, "\r\n\r\n"); h = gethostbyname(hostname); if(h==NULL) { free(request); sprintf(msg,"[ httpRequest() ] Unknown host: %s ", hostname); throw runtime_error(msg); } servAddr.sin_family = h->h_addrtype; memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length); servAddr.sin_port = htons(port);//(LOCAL_SERVER_PORT); sd = socket(AF_INET, SOCK_STREAM, 0); if(sd<0) { free(request); throw runtime_error(" [ httpRequest() ] Cannot open socket "); } /* set connection timeout */ optval.tv_sec = 10; optval.tv_usec = 0; //setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, (char *) &optval, // sizeof(optval)); setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char *) &optval, sizeof(optval)); /* localAddr.sin_family = AF_INET; localAddr.sin_addr.s_addr = htonl(INADDR_ANY); localAddr.sin_port = htons(0); rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr)); if(rc<0) { free(request); close(sd); sprintf(msg, "%s: cannot bind port TCP %u", url,port); throw runtime_error(msg); } */ // connect to the server rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr)); if(rc<0) { free(request); #ifndef WIN32 close(sd); #else closesocket(sd); #endif throw runtime_error("[ httpRequest() ] Cannot connect to http server"); } // send the request rc = send(sd, request, strlen(request), 0); if(rc<0) { #ifndef WIN32 close(sd); #else closesocket(sd); #endif free(request); throw runtime_error("[ httpRequest() ] Cannot send the request to the http server"); } free(request); /* read the response and put it in a temporary file */ tmp_file = fopen(temp_filename, "wb"); if (tmp_file == NULL) { #ifndef WIN32 close(sd); #else closesocket(sd); #endif throw runtime_error("[ httpRequest() ] Unable to open for writing temporary file"); } rc = 0, totalSize = 0; do { memset(buffer,0x0,MAX_STRING_LEN); // init line rc = recv(sd, buffer, MAX_STRING_LEN, 0); if( rc > 0) { fwrite(buffer, rc, 1, tmp_file); totalSize +=rc; } }while(rc>0); sprintf(msg, "Received response from %s, response size is %d bytes", hostname, totalSize); logger(INFO, msg); #ifndef WIN32 close(sd); #else closesocket(sd); #endif fclose(tmp_file); return totalSize; } char *apmon_utils::findIP(char *address) throw(runtime_error) { int isIP = 1; char *destIP, *s; struct in_addr addr; unsigned int j; bool ipFound; for (j = 0; j < strlen(address); j++) if (isalpha(address[j])) { // if we found a letter, this is not an IP address isIP = 0; break; } if (!isIP) { // the user provided a hostname, find the IP struct hostent *he = gethostbyname(address); if (he == NULL) { char tmp_msg[40]; sprintf(tmp_msg, "[ findIP() ] Invalid destination address %s", address); throw runtime_error(tmp_msg); } j = 0; /* get from the list the first IP address (which is not a loopback one) */ ipFound = false; while ((he -> h_addr_list)[j] != NULL) { memcpy(&(addr.s_addr), (he -> h_addr_list)[j], 4); s = inet_ntoa(addr); if (strcmp(s, "127.0.0.1") != 0) { destIP = strdup(s); ipFound = true; break; } j++; } if (!ipFound) { destIP = strdup("127.0.0.1"); fprintf(stderr, "The destination for datagrams is localhost\n"); } } else // the string was an IP address destIP = strdup(address); return destIP; } void apmon_utils::parse_URL(char *url, char *hostname, int *port, char *identifier) throw(runtime_error) { char protocol[MAX_STRING_LEN], scratch[MAX_STRING_LEN], *ptr=0, *nptr=0; char msg[MAX_STRING_LEN]; strcpy(scratch, url); ptr = (char *)strchr(scratch, ':'); if (!ptr) throw runtime_error("[ parse_URL() ] Wrong url: no protocol specified"); strcpy(ptr, "\0"); strcpy(protocol, scratch); if (strcmp(protocol, "http")) { sprintf(msg, "[ parse_URL() ] Wrong protocol in URL: %s", protocol); throw runtime_error(msg); } strcpy(scratch, url); ptr = (char *)strstr(scratch, "//"); if (!ptr) { throw runtime_error("[ parse_URL() ] Wrong url: no server specified"); } ptr += 2; strcpy(hostname, ptr); nptr = (char *)strchr(ptr, ':'); if (!nptr) { *port = 80; /* use the default HTTP port number */ nptr = (char *)strchr(hostname, '/'); } else { sscanf(nptr, ":%d", port); nptr = (char *)strchr(hostname, ':'); } if (nptr) *nptr = '\0'; nptr = (char *)strchr(ptr, '/'); if (!nptr) { throw runtime_error("[ parse_URL() ] Wrong url: no file specified"); } strcpy(identifier, nptr); } void apmon_utils::freeMat(char **mat, int nRows) { int i; for (i = 0; i < nRows; i++) free(mat[i]); free(mat); } char *apmon_utils::trimString(char *s) { unsigned int i, j, firstpos, lastpos; char *ret = (char *)malloc((strlen(s) + 1) * sizeof(char)); j = 0; // find the position of the first non-space character in the string for (i = 0; i < strlen(s); i++) if (!isspace(s[i])) break; firstpos = i; if (firstpos == strlen(s)) { ret[0] = 0; return ret; } // find the position of the last non-space character in the string for (i = strlen(s) ; i > 0; i--) if (!isspace(s[i-1])) break; lastpos = i; for (i = firstpos; i <= lastpos; i++) ret[j++] = s[i]; ret[j++] = 0; return ret; } int apmon_utils::xdrSize(int type, char *value) { int size; switch (type) { // case XDR_INT16: (not supported) case XDR_INT32: case XDR_REAL32: return 4; // case XDR_INT64: (not supported) case XDR_REAL64: return 8; case XDR_STRING: /* XDR adds 4 bytes to hold the length of the string */ //size = (strlen(value) + 1) + 4; if (value == NULL) { logger(WARNING, "[ xdrSize() ] null string argument"); size = 4; } else { size = strlen(value) + 4; /* the length of the XDR representation must be a multiple of 4, so there might be some extra bytes added*/ if (size % 4 != 0) size += (4 - size % 4); return size; } } return RET_ERROR; } int apmon_utils::sizeEval(int type, char *value) { switch (type) { // case XDR_INT16: case XDR_INT32: case XDR_REAL32: return 4; // case XDR_INT64: case XDR_REAL64: return 8; case XDR_STRING: return (strlen(value) + 1); } return RET_ERROR; } void apmon_utils::logParameters(int level, int nParams, char **paramNames, int *valueTypes, char **paramValues) { int i; char typeNames[][15] = {"XDR_STRING", "", "XDR_INT32", "", "XDR_REAL32", "XDR_REAL64"}; char logmsg[200], val[100]; for (i = 0; i < nParams; i++) { if (paramNames[i] == NULL || (valueTypes[i] == XDR_STRING && paramValues[i] == NULL)) continue; sprintf(logmsg, "%s (%s) ", paramNames[i], typeNames[valueTypes[i]]); //printf("%s () ", paramNames[i]); switch(valueTypes[i]) { case XDR_STRING: sprintf(val, "%s", paramValues[i]); break; case XDR_INT32: sprintf(val, "%d", *(int *)paramValues[i]); break; case XDR_REAL32: sprintf(val, "%f", *(float *)paramValues[i]); break; case XDR_REAL64: sprintf(val, "%f", *(double *)(paramValues[i])); break; } strcat(logmsg, val); logger(level, logmsg); } } bool apmon_utils::isPrivateAddress(char *addr) { char *s1, *s2; int n1, n2; char tmp[MAX_STRING_LEN]; // char buf[MAX_STRING_LEN]; // char *pbuf = buf; strcpy(tmp, addr); s1 = strtok/*_r*/(tmp,".");//, &pbuf); n1 = atoi(s1); s2 = strtok/*_r*/(NULL, ".");//, &pbuf); n2 = atoi(s2); if (n1 == 10) return true; if (n1 == 172 && n2 >= 16 && n2 <= 31) return true; if (n1 == 192 && n2 == 168) return true; return false; } int apmon_utils::getVectIndex(char *item, char **vect, int vectDim) { int i; for (i = 0; i < vectDim; i++) if (strcmp(item, vect[i]) == 0) return i; return -1; } void apmon_utils::logger(int msgLevel, const char *msg, int newLevel) { char time_s[30]; int len; time_t crtTime = time(NULL); char *levels[5] = {(char*)"FATAL", (char*)"WARNING", (char*)"INFO", (char*)"FINE", (char*)"DEBUG"}; static int loglevel = INFO; #ifndef WIN32 static pthread_mutex_t logger_mutex; #else static HANDLE logger_mutex; #endif static bool firstTime = true; if (firstTime) { #ifndef WIN32 pthread_mutex_init(&logger_mutex, NULL); #else logger_mutex = CreateMutex(NULL, FALSE, NULL); #endif firstTime = false; } pthread_mutex_lock(&logger_mutex); #ifndef WIN32 char cbuf[50]; strcpy(time_s, ctime_r(&crtTime, cbuf)); #else strcpy(time_s, ctime(&crtTime)); #endif len = strlen(time_s); time_s[len - 1] = 0; if (newLevel >= 0 && newLevel <=4) { loglevel = newLevel; if (loglevel>=2) printf("[TIME: %s] Changed the logging level to %s\n", time_s, levels[newLevel]); } else { if (msgLevel >= 0 && msgLevel <= 4) { if (msgLevel <= loglevel) printf("[TIME: %s] [%s] %s\n",time_s, levels[msgLevel], msg); } else printf("[WARNING] Invalid logging level %d!\n", msgLevel); } pthread_mutex_unlock(&logger_mutex); }