Icinga-core 1.4.0
next gen monitoring
base/netutils.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * NETUTILS.C - Network connection  utility functions for Icinga
00004  *
00005  * Copyright (c) 1999,2008 Ethan Galstad (egalstad@nagios.org)
00006  * Portions Copyright (c) 1999-2008 Nagios Plugin development team
00007  * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org)
00008  *
00009  * License:
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License version 2 as
00013  * published by the Free Software Foundation.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00023  *
00024  *****************************************************************************/
00025 
00026 #include "../include/config.h"
00027 #include "../include/common.h"
00028 #include "../include/netutils.h"
00029 
00030 int dummy;      /* reduce compiler warnings */
00031 
00032 /* connect to a TCP socket in nonblocking fashion */
00033 int my_tcp_connect(char *host_name, int port, int *sd, int timeout){
00034         struct addrinfo hints;
00035         struct addrinfo *res;
00036         int result;
00037         char *port_str=NULL;
00038         int flags=0;
00039         fd_set rfds;
00040         fd_set wfds;
00041         struct timeval tv;
00042         int optval;
00043         socklen_t optlen;
00044 
00045         memset(&hints,0,sizeof(hints));
00046         hints.ai_family=PF_INET;
00047         hints.ai_socktype=SOCK_STREAM;
00048 
00049         dummy=asprintf(&port_str,"%d",port);
00050         result=getaddrinfo(host_name,port_str,&hints,&res);
00051         my_free(port_str);
00052         
00053         if(result!=0){
00054                 /*printf("GETADDRINFO: %s (%s) = %s\n",host_name,port_str,gai_strerror(result));*/
00055                 return ERROR;
00056                 }
00057 
00058         /* create a socket */
00059         *sd=socket(res->ai_family,SOCK_STREAM,res->ai_protocol);
00060         if(*sd<0){
00061                 freeaddrinfo(res);
00062                 return ERROR;
00063                 }
00064 
00065         /* make socket non-blocking */
00066         flags=fcntl(*sd,F_GETFL,0);
00067         fcntl(*sd,F_SETFL,flags|O_NONBLOCK);
00068 
00069         /* attempt to connect */
00070         result=connect(*sd,res->ai_addr,res->ai_addrlen);
00071 
00072         /* immediately successful connect */
00073         if(result==0){
00074                 result=OK;
00075                 /*printf("IMMEDIATE SUCCESS\n");*/
00076                 }
00077 
00078         /* connection error */
00079         else if(result<0 && errno!=EINPROGRESS){
00080                 result=ERROR;
00081                 }
00082 
00083         /* connection in progress - wait for it... */
00084         else{
00085 
00086                 do{
00087                         /* set connection timeout */
00088                         tv.tv_sec=timeout;
00089                         tv.tv_usec=0;
00090 
00091                         FD_ZERO(&wfds);
00092                         FD_SET(*sd,&wfds);
00093                         rfds=wfds;
00094 
00095                         /* wait for readiness */
00096                         result=select((*sd)+1,&rfds,&wfds,NULL,&tv);
00097 
00098                         /*printf("SELECT RESULT: %d\n",result);*/
00099 
00100                         /* timeout */
00101                         if(result==0){
00102                                 /*printf("TIMEOUT\n");*/
00103                                 result=ERROR;
00104                                 break;
00105                                 }
00106 
00107                         /* an error occurred */
00108                         if(result<0 && errno!=EINTR){
00109                                 result=ERROR;
00110                                 break;
00111                                 }
00112 
00113                         /* got something - check it */
00114                         else if(result>0){
00115 
00116                                 /* get socket options to check for errors */
00117                                 optlen=sizeof(int);
00118                                 if(getsockopt(*sd,SOL_SOCKET,SO_ERROR,(void *)(&optval),&optlen) < 0){ 
00119                                         result=ERROR;
00120                                         break;
00121                                         }
00122                                 
00123                                 /* an error occurred in the connection */
00124                                 if(optval!=0){
00125                                         result=ERROR;
00126                                         break;
00127                                         }
00128 
00129                                 /* the connection was good! */
00130                                 /*
00131                                 printf("CONNECT SELECT: ERRNO=%s\n",strerror(errno));
00132                                 printf("CONNECT SELECT: OPTVAL=%s\n",strerror(optval));
00133                                 */
00134                                 result=OK;
00135                                 break;
00136                                 }
00137 
00138                         /* some other error occurred */
00139                         else{
00140                                 result=ERROR;
00141                                 break;
00142                                 }
00143                         
00144                         }while(1);
00145                 }
00146 
00147 
00148         freeaddrinfo(res);
00149 
00150         return result;
00151         }
00152 
00153 
00154 /* based on Beej's sendall - thanks Beej! */
00155 int my_sendall(int s, char *buf, int *len, int timeout){
00156         int total_sent=0;
00157         int bytes_left=0;
00158         int n;
00159         fd_set wfds;
00160         struct timeval tv;
00161         int result=OK;
00162         time_t start_time;
00163         time_t current_time;
00164 
00165         time(&start_time);
00166 
00167         bytes_left=*len;
00168         while(total_sent < *len){
00169 
00170                 /* set send timeout */
00171                 tv.tv_sec=timeout;
00172                 tv.tv_usec=0;
00173 
00174                 FD_ZERO(&wfds);
00175                 FD_SET(s,&wfds);
00176 
00177                 /* wait for readiness */
00178                 result=select(s+1,NULL,&wfds,NULL,&tv);
00179 
00180                 /* timeout */
00181                 if(result==0){
00182                         /*printf("RECV SELECT TIMEOUT\n");*/
00183                         result=ERROR;
00184                         break;
00185                         }
00186                 /* error */
00187                 else if(result<0){
00188                         /*printf("RECV SELECT ERROR: %s\n",strerror(errno));*/
00189                         result=ERROR;
00190                         break;
00191                         }
00192 
00193                 /* we're ready to write some data */
00194                 result=OK;
00195 
00196                 /* send the data */
00197                 n=send(s,buf+total_sent,bytes_left,0);
00198                 if(n==-1){
00199                         /*printf("SEND ERROR: (%d) %s\n",s,strerror(errno));*/
00200                         break;
00201                         }
00202 
00203                 total_sent+=n;
00204                 bytes_left-=n;
00205 
00206                 /* make sure we haven't overrun the timeout */
00207                 time(&current_time);
00208                 if(current_time-start_time>timeout){
00209                         result=ERROR;
00210                         break;
00211                         }
00212                 }
00213 
00214         *len=total_sent;
00215 
00216         return result;
00217         }
00218 
00219 
00220 /* receives all data in non-blocking mode with a timeout  - modelled after sendall() */
00221 int my_recvall(int s, char *buf, int *len, int timeout){
00222         int total_received=0;
00223         int bytes_left=*len;
00224         int n=0;
00225         time_t start_time;
00226         time_t current_time;
00227         fd_set rfds;
00228         struct timeval tv;
00229         int result=OK;
00230 
00231         /* clear the receive buffer */
00232         bzero(buf,*len);
00233 
00234         time(&start_time);
00235 
00236         /* receive all data */
00237         while(total_received<*len){
00238 
00239                 /* set receive timeout */
00240                 tv.tv_sec=timeout;
00241                 tv.tv_usec=0;
00242 
00243                 FD_ZERO(&rfds);
00244                 FD_SET(s,&rfds);
00245 
00246                 /* wait for readiness */
00247                 result=select(s+1,&rfds,NULL,NULL,&tv);
00248 
00249                 /* timeout */
00250                 if(result==0){
00251                         /*printf("RECV SELECT TIMEOUT\n");*/
00252                         result=ERROR;
00253                         break;
00254                         }
00255                 /* error */
00256                 else if(result<0){
00257                         /*printf("RECV SELECT ERROR: %s\n",strerror(errno));*/
00258                         result=ERROR;
00259                         break;
00260                         }
00261 
00262                 /* we're ready to read some data */
00263                 result=OK;
00264 
00265                 /* receive some data */
00266                 n=recv(s,buf+total_received,bytes_left,0);
00267 
00268                 /* server disconnected */
00269                 if(n==0){
00270                         /*printf("SERVER DISCONNECT\n");*/
00271                         break;
00272                         }
00273 
00274                 /* apply bytes we received */
00275                 total_received+=n;
00276                 bytes_left-=n;
00277 
00278                 /* make sure we haven't overrun the timeout */
00279                 time(&current_time);
00280                 if(current_time-start_time>timeout){
00281                         result=ERROR;
00282                         break;
00283                         }
00284                 }
00285 
00286         /* return number of bytes actually received here */
00287         *len=total_received;
00288 
00289         return result;
00290         }
 All Data Structures Files Functions Variables Typedefs Defines