Icinga-core 1.4.0
next gen monitoring
module/idoutils/src/io.c
Go to the documentation of this file.
00001 /***************************************************************
00002  * IO.C - IDO I/O Functions
00003  *
00004  * Copyright (c) 2005-2006 Ethan Galstad
00005  * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org)
00006  * 
00007  *
00008  **************************************************************/
00009 
00010 #include "../../../include/config.h"
00011 #include "../include/common.h"
00012 #include "../include/io.h"
00013 
00014 #ifdef HAVE_SSL
00015 SSL_METHOD *meth;
00016 SSL_CTX *ctx;
00017 SSL *ssl;
00018 int use_ssl=IDO_FALSE;
00019 #else
00020 int use_ssl=IDO_FALSE;
00021 #endif
00022 
00023 
00024 
00025 /**************************************************************/
00026 /****** MMAP()'ED FILE FUNCTIONS ******************************/
00027 /**************************************************************/
00028 
00029 /* open a file read-only via mmap() */
00030 ido_mmapfile *ido_mmap_fopen(char *filename){
00031         ido_mmapfile *new_mmapfile;
00032         int fd;
00033         void *mmap_buf;
00034         struct stat statbuf;
00035         int mode=O_RDONLY;
00036 
00037         /* allocate memory */
00038         if((new_mmapfile=(ido_mmapfile *)malloc(sizeof(ido_mmapfile)))==NULL)
00039                 return NULL;
00040 
00041         /* open the file */
00042         if((fd=open(filename,mode))==-1){
00043                 free(new_mmapfile);
00044                 return NULL;
00045                 }
00046 
00047         /* get file info */
00048         if((fstat(fd,&statbuf))==-1){
00049                 close(fd);
00050                 free(new_mmapfile);
00051                 return NULL;
00052                 }
00053 
00054         /* mmap() the file */
00055         if((mmap_buf=(void *)mmap(0,statbuf.st_size,PROT_READ,MAP_PRIVATE,fd,0))==MAP_FAILED){
00056                 close(fd);
00057                 free(new_mmapfile);
00058                 return NULL;
00059                 }
00060 
00061         /* populate struct info for later use */
00062         /*new_mmapfile->path=strdup(filename);*/
00063         new_mmapfile->path=NULL;
00064         new_mmapfile->fd=fd;
00065         new_mmapfile->file_size=(unsigned long)(statbuf.st_size);
00066         new_mmapfile->current_position=0L;
00067         new_mmapfile->current_line=0L;
00068         new_mmapfile->mmap_buf=mmap_buf;
00069 
00070         return new_mmapfile;
00071         }
00072 
00073 
00074 /* close a file originally opened via mmap() */
00075 int ido_mmap_fclose(ido_mmapfile *temp_mmapfile){
00076 
00077         if(temp_mmapfile==NULL)
00078                 return IDO_ERROR;
00079 
00080         /* un-mmap() the file */
00081         munmap(temp_mmapfile->mmap_buf,temp_mmapfile->file_size);
00082 
00083         /* close the file */
00084         close(temp_mmapfile->fd);
00085 
00086         /* free memory */
00087         if(temp_mmapfile->path!=NULL)
00088                 free(temp_mmapfile->path);
00089         free(temp_mmapfile);
00090         
00091         return IDO_OK;
00092         }
00093 
00094 
00095 /* gets one line of input from an mmap()'ed file */
00096 char *ido_mmap_fgets(ido_mmapfile *temp_mmapfile){
00097         char *buf=NULL;
00098         unsigned long x=0L;
00099         int len=0;
00100 
00101         if(temp_mmapfile==NULL)
00102                 return NULL;
00103 
00104         /* we've reached the end of the file */
00105         if(temp_mmapfile->current_position>=temp_mmapfile->file_size)
00106                 return NULL;
00107 
00108         /* find the end of the string (or buffer) */
00109         for(x=temp_mmapfile->current_position;x<temp_mmapfile->file_size;x++){
00110                 if(*((char *)(temp_mmapfile->mmap_buf)+x)=='\n'){
00111                         x++;
00112                         break;
00113                         }
00114                 }
00115 
00116         /* calculate length of line we just read */
00117         len=(int)(x-temp_mmapfile->current_position);
00118 
00119         /* allocate memory for the new line */
00120         if((buf=(char *)malloc(len+1))==NULL)
00121                 return NULL;
00122 
00123         /* copy string to newly allocated memory and terminate the string */
00124         memcpy(buf,((char *)(temp_mmapfile->mmap_buf)+temp_mmapfile->current_position),len);
00125         buf[len]='\x0';
00126 
00127         /* update the current position */
00128         temp_mmapfile->current_position=x;
00129 
00130         /* increment the current line */
00131         temp_mmapfile->current_line++;
00132 
00133         return buf;
00134         }
00135 
00136 
00137 
00138 
00139 /**************************************************************/
00140 /****** SOCKET FUNCTIONS **************************************/
00141 /**************************************************************/
00142 
00143 
00144 /* opens data sink */
00145 int ido_sink_open(char *name, int fd, int type, int port, int flags, int *nfd){
00146         struct sockaddr_un server_address_u;
00147         struct sockaddr_in server_address_i;
00148         struct hostent *hp=NULL;
00149         mode_t mode=S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
00150         int newfd=0;
00151 #ifdef HAVE_SSL
00152         int rc=0;
00153 #endif
00154 
00155         /* use file */
00156         if(type==IDO_SINK_FILE){
00157                 if((newfd=open(name,flags,mode))==-1)
00158                         return IDO_ERROR;
00159                 }
00160 
00161         /* use existing file descriptor */
00162         else if(type==IDO_SINK_FD){
00163                 if(fd<0)
00164                         return IDO_ERROR;
00165                 else
00166                         newfd=fd;
00167                 }
00168 
00169         /* we are sending output to a unix domain socket */
00170         else if(type==IDO_SINK_UNIXSOCKET){
00171 
00172                 if(name==NULL)
00173                         return IDO_ERROR;
00174 
00175                 /* create a socket */
00176                 if(!(newfd=socket(PF_UNIX,SOCK_STREAM,0)))
00177                         return IDO_ERROR;
00178 
00179                 /* copy the socket address/path */
00180                 strncpy(server_address_u.sun_path,name,sizeof(server_address_u.sun_path)); 
00181                 server_address_u.sun_family=AF_UNIX; 
00182 
00183                 /* connect to the socket */
00184                 if((connect(newfd,(struct sockaddr *)&server_address_u,SUN_LEN(&server_address_u)))){
00185                         close(newfd);
00186                         return IDO_ERROR;
00187                         }
00188                 }
00189 
00190         /* we are sending output to a TCP socket */
00191         else if(type==IDO_SINK_TCPSOCKET){
00192 
00193                 if(name==NULL)
00194                         return IDO_ERROR;
00195                 
00196 #ifdef HAVE_SSL
00197                 if(use_ssl==IDO_TRUE){
00198                         SSL_library_init();
00199                         SSLeay_add_ssl_algorithms();
00200                         meth=SSLv23_client_method();
00201                         SSL_load_error_strings();
00202 
00203                         if((ctx=SSL_CTX_new(meth))==NULL){
00204                                         printf("IDOUtils: Error - could not create SSL context.\n");
00205                                         return IDO_ERROR;
00206                         }
00207                         /* ADDED 01/19/2004 */
00208                         /* use only TLSv1 protocol */
00209                         SSL_CTX_set_options(ctx,SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
00210                 }
00211 #endif
00212 
00213                 /* clear the address */
00214                 bzero((char *)&server_address_i,sizeof(server_address_i));
00215 
00216                 /* try to bypass using a DNS lookup if this is just an IP address */
00217                 if(!ido_inet_aton(name,&server_address_i.sin_addr)){
00218 
00219                         /* else do a DNS lookup */
00220                         if((hp=gethostbyname((const char *)name))==NULL)
00221                                 return IDO_ERROR;
00222 
00223                         memcpy(&server_address_i.sin_addr,hp->h_addr,hp->h_length);
00224                         }
00225 
00226                 /* create a socket */
00227                 if(!(newfd=socket(PF_INET,SOCK_STREAM,0)))
00228                         return IDO_ERROR;
00229 
00230                 /* copy the host/ip address and port */
00231                 server_address_i.sin_family=AF_INET; 
00232                 server_address_i.sin_port=htons(port);
00233 
00234                 /* connect to the socket */
00235                 if((connect(newfd,(struct sockaddr *)&server_address_i,sizeof(server_address_i)))){
00236                         close(newfd);
00237                         return IDO_ERROR;
00238                         }
00239 
00240 #ifdef HAVE_SSL
00241                 if(use_ssl==IDO_TRUE){
00242                         if((ssl=SSL_new(ctx))!=NULL){
00243                                 SSL_CTX_set_cipher_list(ctx,"ADH");
00244                                 SSL_set_fd(ssl,newfd);
00245                                 if((rc=SSL_connect(ssl))!=1){
00246                                         printf("Error - Could not complete SSL handshake.\n");
00247                                         SSL_CTX_free(ctx);
00248                                         close(newfd);
00249                                         return IDO_ERROR;
00250                                 }
00251                         } else {
00252                                 printf("IDOUtils: Error - Could not create SSL connection structure.\n");
00253                                 return IDO_ERROR;
00254                         }
00255                 }
00256 #endif
00257                 }
00258 
00259         /* unknown sink type */
00260         else
00261                 return IDO_ERROR;
00262 
00263         /* save the new file descriptor */
00264         *nfd=newfd;
00265 
00266         return IDO_OK;
00267         }
00268 
00269 
00270 /* writes to data sink */
00271 int ido_sink_write(int fd, char *buf, int buflen){
00272         int tbytes=0;
00273         int result=0;
00274 
00275         if(buf==NULL)
00276                 return IDO_ERROR;
00277         if(buflen<=0)
00278                 return 0;
00279 
00280         while(tbytes<buflen){
00281 
00282                 /* try to write everything we have left */
00283 #ifdef HAVE_SSL
00284                 if (use_ssl == IDO_TRUE)
00285                         result=SSL_write(ssl, buf+tbytes, buflen-tbytes);
00286                 else
00287 #endif
00288                         result=write(fd, buf+tbytes, buflen-tbytes);
00289 
00290                 /* some kind of error occurred */
00291                 if(result==-1){
00292 
00293                         /* unless we encountered a recoverable error, bail out */
00294                         if(errno!=EAGAIN && errno!=EINTR)
00295                                 return IDO_ERROR;
00296                         }
00297 
00298                 /* update the number of bytes we've written */
00299                 tbytes+=result;
00300                 }
00301 
00302         return tbytes;
00303         }
00304 
00305 
00306 /* writes a newline to data sink */
00307 int ido_sink_write_newline(int fd){
00308 
00309         return ido_sink_write(fd,"\n",1);
00310         }
00311 
00312 
00313 /* flushes data sink */
00314 int ido_sink_flush(int fd){
00315 
00316         /* flush sink */
00317         fsync(fd);
00318 
00319         return IDO_OK;
00320         }
00321 
00322 
00323 /* closes data sink */
00324 int ido_sink_close(int fd){
00325 
00326         /* no need to close STDOUT */
00327         if(fd==STDOUT_FILENO)
00328                 return IDO_OK;
00329 
00330         /* close the socket */
00331         shutdown(fd,2);
00332         close(fd);
00333 
00334         return IDO_OK;
00335         }
00336 
00337 
00338 /* This code was taken from Fyodor's nmap utility, which was originally taken from
00339    the GLIBC 2.0.6 libraries because Solaris doesn't contain the inet_aton() funtion. */
00340 int ido_inet_aton(register const char *cp, struct in_addr *addr){
00341         register unsigned int val;      /* changed from u_long --david */
00342         register int base, n;
00343         register char c;
00344         unsigned int parts[4];
00345         register unsigned int *pp = parts;
00346 
00347         c=*cp;
00348 
00349         for(;;){
00350 
00351                 /*
00352                  * Collect number up to ``.''.
00353                  * Values are specified as for C:
00354                  * 0x=hex, 0=octal, isdigit=decimal.
00355                  */
00356                 if (!isdigit((int)c))
00357                         return (0);
00358                 val=0;
00359                 base=10;
00360 
00361                 if(c=='0'){
00362                         c=*++cp;
00363                         if(c=='x'||c=='X')
00364                                 base=16,c=*++cp;
00365                         else
00366                                 base=8;
00367                         }
00368 
00369                 for(;;){
00370                         if(isascii((int)c) && isdigit((int)c)){
00371                                 val=(val*base)+(c -'0');
00372                                 c=*++cp;
00373                                 } 
00374                         else if(base==16 && isascii((int)c) && isxdigit((int)c)){
00375                                 val=(val<<4) | (c+10-(islower((int)c)?'a':'A'));
00376                                 c = *++cp;
00377                                 } 
00378                         else
00379                                 break;
00380                         }
00381 
00382                 if(c=='.'){
00383 
00384                         /*
00385                          * Internet format:
00386                          *      a.b.c.d
00387                          *      a.b.c   (with c treated as 16 bits)
00388                          *      a.b     (with b treated as 24 bits)
00389                          */
00390                         if(pp>=parts+3)
00391                                 return (0);
00392                         *pp++=val;
00393                         c=*++cp;
00394                         } 
00395                 else
00396                         break;
00397                 }
00398 
00399         /* Check for trailing characters */
00400         if(c!='\0' && (!isascii((int)c) || !isspace((int)c)))
00401                 return (0);
00402 
00403         /* Concoct the address according to the number of parts specified */
00404         n=pp-parts+1;
00405         switch(n){
00406 
00407         case 0:
00408                 return (0);             /* initial nondigit */
00409 
00410         case 1:                         /* a -- 32 bits */
00411                 break;
00412 
00413         case 2:                         /* a.b -- 8.24 bits */
00414                 if(val>0xffffff)
00415                         return (0);
00416                 val|=parts[0]<<24;
00417                 break;
00418 
00419         case 3:                         /* a.b.c -- 8.8.16 bits */
00420                 if(val>0xffff)
00421                         return (0);
00422                 val|=(parts[0]<< 24) | (parts[1]<<16);
00423                 break;
00424 
00425         case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
00426                 if(val>0xff)
00427                         return (0);
00428                 val|=(parts[0]<<24) | (parts[1]<<16) | (parts[2]<<8);
00429                 break;
00430                 }
00431 
00432         if(addr)
00433                 addr->s_addr=htonl(val);
00434 
00435         return (1);
00436         }
00437 
00438 
00439 /******************************************************************/
00440 /************************ STRING FUNCTIONS ************************/
00441 /******************************************************************/
00442 
00443 /* strip newline and carriage return characters from end of a string */
00444 void ido_strip_buffer(char *buffer){
00445         register int x;
00446         register int y;
00447 
00448         if(buffer==NULL || buffer[0]=='\x0')
00449                 return;
00450 
00451         /* strip end of string */
00452         y=(int)strlen(buffer);
00453         for(x=y-1;x>=0;x--){
00454                 if(buffer[x]=='\n' || buffer[x]=='\r' || buffer[x]==13)
00455                         buffer[x]='\x0';
00456                 else
00457                         break;
00458                 }
00459 
00460         return;
00461         }
00462 
00463 
00464 /* escape special characters in string */
00465 char *ido_escape_buffer(char *buffer){
00466         char *newbuf;
00467         register int x=0;
00468         register int y=0;
00469         register int len=0;
00470 
00471         if(buffer==NULL)
00472                 return NULL;
00473 
00474         /* allocate memory for escaped string */
00475         if((newbuf=(char *)malloc((strlen(buffer)*2)+1))==NULL)
00476                 return NULL;
00477 
00478         /* initialize string */
00479         newbuf[0]='\x0';
00480 
00481         len=(int)strlen(buffer);
00482         for(x=0;x<len;x++){
00483                 if(buffer[x]=='\t'){
00484                         newbuf[y++]='\\';
00485                         newbuf[y++]='t';
00486                         }
00487                 else if(buffer[x]=='\r'){
00488                         newbuf[y++]='\\';
00489                         newbuf[y++]='r';
00490                         }
00491                 else if(buffer[x]=='\n'){
00492                         newbuf[y++]='\\';
00493                         newbuf[y++]='n';
00494                         }
00495                 else if(buffer[x]=='\\'){
00496                         newbuf[y++]='\\';
00497                         newbuf[y++]='\\';
00498                         }
00499                 else
00500                         newbuf[y++]=buffer[x];
00501                 }
00502 
00503         /* terminate new string */
00504         newbuf[y++]='\x0';
00505 
00506         return newbuf;
00507         }
00508 
00509 
00510 /* unescape special characters in string */
00511 char *ido_unescape_buffer(char *buffer){
00512         register int x=0;
00513         register int y=0;
00514         register int len=0;
00515 
00516         if(buffer==NULL)
00517                 return NULL;
00518 
00519         len=(int)strlen(buffer);
00520         for(x=0;x<len;x++){
00521                 if(buffer[x]=='\\'){
00522                         if(buffer[x+1]=='\t')
00523                                 buffer[y++]='\t';
00524                         else if(buffer[x+1]=='r')
00525                                 buffer[y++]='\r';
00526                         else if(buffer[x+1]=='n')
00527                                 buffer[y++]='\n';
00528                         else if(buffer[x+1]=='\\')
00529                                 buffer[y++]='\\';
00530                         else
00531                                 buffer[y++]=buffer[x+1];
00532                         x++;
00533                         }
00534                 else
00535                         buffer[y++]=buffer[x];
00536                 }
00537 
00538         /* terminate string */
00539         buffer[y++]='\x0';
00540 
00541         return buffer;
00542         }
00543 
00544 
 All Data Structures Files Functions Variables Typedefs Defines