net.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C), 2000-2002 by Contributors to the monit codebase. 
00003  * All Rights Reserved.
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License as
00007  * published by the Free Software Foundation; either version 2 of the
00008  * License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #ifdef HAVE_SYS_TYPES_H
00025 #include <sys/types.h>
00026 #endif
00027 #include <sys/socket.h>
00028 #include <fcntl.h>
00029 #include <errno.h>
00030 #include <stdarg.h>
00031 #include <signal.h>
00032 #include <net/if.h>
00033 #include <sys/un.h>
00034 
00035 #ifdef HAVE_NETDB_H
00036 #include <netdb.h>
00037 #endif
00038 
00039 #ifdef HAVE_NETINET_IN_H
00040 #include <netinet/in.h>
00041 #endif
00042 
00043 #ifdef HAVE_SYS_TIME_H
00044 #include <sys/time.h>
00045 #endif
00046 
00047 #ifdef HAVE_SYS_FILIO_H
00048 #include <sys/filio.h>
00049 #endif
00050 
00051 #ifdef HAVE_SYS_IOCTL_H
00052 #include <sys/ioctl.h>
00053 #endif
00054 
00055 #ifdef HAVE_SYS_FILIO_H
00056 #include <sys/filio.h>
00057 #endif
00058 
00059 #ifdef HAVE_STRING_H
00060 #include <string.h>
00061 #endif
00062 
00063 #ifdef HAVE_UNISTD_H
00064 #include <unistd.h>
00065 #endif
00066 
00067 #ifdef HAVE_SYS_STAT_H
00068 #include <sys/stat.h>
00069 #endif
00070 
00071 #ifdef HAVE_STROPTS_H
00072 #include <stropts.h>
00073 #endif
00074 
00075 #include "monitor.h"
00076 #include "net.h"
00077 
00090 /* ------------------------------------------------------------------ Public */
00091 
00092 
00102 int check_connect(char *hostname, int port, int protocol) {
00103 
00104   int socket;
00105   int rv= TRUE;
00106 
00107   if ((socket= create_socket(hostname, port, protocol)) < 0) {
00108     
00109     rv= FALSE;
00110     
00111   } else if (! check_socket(socket)) {
00112 
00113     rv= FALSE;
00114 
00115   }
00116   
00117   close_socket(socket);
00118   
00119   return rv;
00120   
00121 }
00122 
00123 
00129 int check_host(char *hostname) {
00130   
00131   struct hostent *hp;
00132 
00133   if ((hp = gethostbyname(hostname)) == NULL) {
00134     
00135     return FALSE;
00136     
00137   }
00138   
00139   return TRUE;
00140   
00141 }
00142 
00143 
00152 int check_connection_io(Port_T p) {
00153 
00154   switch(p->type) {
00155    case SOCK_STREAM: return check_socket(p->socket);
00156    case SOCK_DGRAM:  return check_udp_socket(p->socket);
00157    default:          break;
00158   }
00159 
00160   return FALSE;
00161   
00162 }
00163 
00164 
00170 int check_socket(int socket) {
00171   
00172   fd_set rset, wset;
00173   struct timeval tv;
00174 
00175   FD_ZERO(&rset);
00176   FD_ZERO(&wset);
00177   FD_SET(socket, &rset);
00178   FD_SET(socket, &wset);
00179   tv.tv_sec= SELECT_TIMEOUT;
00180   tv.tv_usec= 0;
00181 
00182   return (select(socket+1, &rset, &wset, NULL, &tv) > 0);
00183 }
00184 
00185 
00192 int check_udp_socket(int socket) {
00193 
00194   int r;
00195   char buf[1]= {0};
00196 
00197   /*
00198    * R/W is asynchronous and we should probably loop and wait longer
00199    * for a possible ICMP error.
00200    */
00201   set_noblock(socket);
00202   write(socket, buf, 1);
00203   sleep(1);
00204   r= read(socket, buf, 1);
00205   set_block(socket);
00206   if(0>r) {
00207     switch(errno) {
00208     case ECONNREFUSED: return FALSE;
00209     default:           break;
00210     }
00211   }
00212   
00213   return TRUE;
00214 
00215 }
00216 
00217 
00226 int create_socket(char *hostname, int port, int protocol) {
00227 
00228   int s;
00229   struct hostent *hp;
00230   struct sockaddr_in sin;
00231   
00232   if ((hp= gethostbyname(hostname)) == NULL) {
00233     
00234     return -1;
00235     
00236   }
00237   
00238   if ((s= socket(AF_INET, protocol, 0)) < 0) {
00239     
00240     return -1;
00241     
00242   }
00243   
00244   sin.sin_family= AF_INET;
00245   sin.sin_port= htons(port);
00246   memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
00247 
00248   if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
00249 
00250     close_socket(s);
00251     return -1;
00252     
00253   }
00254 
00255   return s;
00256   
00257 }
00258 
00259 
00266 int create_generic_socket(Port_T pp) {
00267 
00268   int socket_fd= -1;
00269 
00270   if(pp->family == AF_INET) {
00271 
00272     socket_fd= create_socket(pp->hostname, pp->port, pp->type);
00273 
00274   } else if(pp->family == AF_UNIX) {
00275 
00276     socket_fd= create_unix_socket(pp->pathname, pp->type);
00277 
00278   }
00279 
00280   return socket_fd;
00281   
00282 }
00283 
00284 
00292 int create_unix_socket(char *pathname, int protocol) {
00293 
00294   int s;
00295   struct sockaddr_un unixsocket;
00296   
00297   if ((s= socket(PF_UNIX, protocol, 0)) < 0) {
00298     
00299     return -1;
00300     
00301   }
00302   
00303   unixsocket.sun_family= AF_UNIX;
00304   snprintf(unixsocket.sun_path, sizeof(unixsocket.sun_path), "%s", pathname);
00305 
00306   if (connect(s, (struct sockaddr *)&unixsocket, sizeof(unixsocket)) < 0) {
00307 
00308     close_socket(s);
00309     return -1;
00310     
00311   }
00312 
00313   return s;
00314   
00315 }
00316 
00317 
00332 int create_server_socket(int port, int backlog, char *bindAddr) {
00333   
00334   int s;
00335   int flag= 1;
00336   struct sockaddr_in myaddr;
00337 
00338   if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0)
00339       return -1;
00340   
00341   memset(&myaddr, 0, sizeof(struct sockaddr_in));
00342   myaddr.sin_family= AF_INET;
00343   myaddr.sin_port= htons(port);
00344   
00345   if(bindAddr) {
00346     struct hostent *h= gethostbyname(bindAddr);
00347     endhostent();
00348     if(h==NULL) {
00349       errno= h_errno;
00350       goto error;
00351     }
00352     myaddr.sin_addr= *(struct in_addr*)h->h_addr_list[0];
00353   } else {
00354     myaddr.sin_addr.s_addr= htonl(INADDR_ANY);
00355   }
00356   
00357   if (setsockopt(s, SOL_SOCKET,
00358                   SO_REUSEADDR, (char *)&flag, sizeof(int)) < 0) 
00359       goto error;
00360 
00361   if (bind(s, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)) < 0)
00362       goto error;
00363   
00364   if (listen(s, backlog) < 0)
00365       goto error;
00366   
00367   if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1)
00368       goto error;
00369   
00370   return s;
00371 
00372   error:
00373   close(s);
00374 
00375   return -1;
00376 
00377 }
00378 
00379 
00385 int close_socket(int socket) {
00386 
00387   int rv= TRUE;
00388 
00389   if ((shutdown(socket, 2) < 0)) {
00390     
00391     rv= FALSE;
00392     
00393   }
00394   
00395   if (close(socket) < 0) {
00396     
00397     rv= FALSE;
00398     
00399   }
00400 
00401   return rv;
00402 
00403 }
00404 
00405 
00413 int set_sotimeout(int socket, int timeout) {
00414 
00415   struct timeval tv= {timeout, 0};
00416 
00417   return ((setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))==0) &&
00418           (setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv))==0));
00419 
00420 }
00421 
00422 
00428 int set_noblock(int socket) {
00429   
00430   int flag= 1;
00431 
00432   return (! ioctl(socket, FIONBIO, &flag));
00433 
00434 }
00435 
00436 
00442 int set_block(int socket) {
00443 
00444   int flag= 0;
00445 
00446   return (! ioctl(socket, FIONBIO, &flag));
00447 
00448 }
00449 
00450 
00460 int sock_send(int sock, const char *msg, int len, int flags) {
00461 
00462   int rv;
00463   fd_set fdset;
00464   struct timeval t;
00465   int retry;
00466 
00467   if (! set_noblock(sock)) {
00468     
00469     return -1;
00470     
00471   }
00472 
00473   rv= send(sock, msg, len, flags);
00474   if (rv <= 0) {
00475     
00476     if (errno == EWOULDBLOCK) 
00477     do {
00478       
00479       retry= FALSE;
00480       FD_ZERO(&fdset);
00481       FD_SET(sock, &fdset);
00482       t.tv_sec= SELECT_TIMEOUT;
00483       t.tv_usec= 0;
00484       rv = select(sock+1, NULL, &fdset, NULL, &t);
00485       if (rv <= 0) {
00486         
00487         rv= -1;
00488         
00489       }
00490       else {
00491         
00492         rv = send(sock, msg, len, flags);
00493         if (rv <= 0) {
00494           
00495           if(errno == EWOULDBLOCK) {
00496         
00497         retry= TRUE;
00498         sleep(1);
00499         
00500           }
00501           
00502         }
00503         
00504       }
00505       
00506     } while(retry);
00507     
00508   }
00509   
00510   set_block(sock);
00511 
00512   return rv;
00513   
00514 }
00515 
00516 
00526 int sock_recv(int sock, char *buf, int len, int flags) {
00527 
00528   int rv;
00529   fd_set fdset;
00530   struct timeval t;
00531 
00532   if (! set_noblock(sock)) {
00533     
00534     return -1;
00535     
00536   }
00537   
00538   rv= recv(sock, buf, len, flags);
00539   if (rv <= 0) {
00540     
00541     if (errno == EWOULDBLOCK) {
00542       
00543       FD_ZERO(&fdset);
00544       FD_SET(sock, &fdset);
00545       t.tv_sec= SELECT_TIMEOUT;
00546       t.tv_usec = 0;
00547       rv = select(sock+1, &fdset, NULL, NULL, &t);
00548       if (rv <= 0) {
00549     
00550     rv= -1;
00551     
00552       }
00553       else {
00554     
00555     rv= recv(sock, buf, len, flags);
00556     
00557       }
00558       
00559     }
00560     
00561   }
00562 
00563   set_block(sock);
00564 
00565   return rv;
00566 
00567 }
00568 
00569 
00575 char *get_localhostname() {
00576 
00577   char hostname[256];
00578 
00579   if (gethostname(hostname, sizeof(hostname)) < 0) {
00580     
00581     return NULL;
00582     
00583   }
00584 
00585   return (strdup(hostname));
00586 
00587 }
00588 
00589 
00596 char *get_remote_host(int socket) {
00597 
00598   struct hostent *h;
00599   struct sockaddr_in r;
00600   int l= sizeof(struct sockaddr_in);
00601 
00602   if (getpeername(socket, (struct sockaddr*)&r, &l) < 0) {
00603     
00604     return NULL;
00605     
00606   } else {
00607     
00608     h=gethostbyaddr((char *)&r.sin_addr, sizeof(struct in_addr), AF_INET);
00609     if (h) {
00610       
00611       return strdup(h->h_name);
00612       
00613     }
00614     
00615   }
00616 
00617   return NULL;
00618 
00619 }
00620