![]() |
Icinga-core 1.4.0
next gen monitoring
|
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(¤t_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(¤t_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 }