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 
00025 #ifdef HAVE_SYS_TYPES_H
00026 #include <sys/types.h>
00027 #endif
00028 
00029 #ifdef HAVE_SYS_SOCKET_H
00030 #include <sys/socket.h>
00031 #endif 
00032 
00033 #include <fcntl.h>
00034 
00035 #ifdef HAVE_ERRNO_H
00036 #include <errno.h>
00037 #endif 
00038 
00039 #include <stdarg.h>
00040 #include <signal.h>
00041 #include <net/if.h>
00042 #include <sys/un.h>
00043 
00044 #ifdef HAVE_NETDB_H
00045 #include <netdb.h>
00046 #endif
00047 
00048 #ifdef HAVE_NETINET_IN_H
00049 #include <netinet/in.h>
00050 #endif
00051 
00052 #ifdef HAVE_SYS_TIME_H
00053 #include <sys/time.h>
00054 #endif
00055 
00056 #ifdef HAVE_SYS_FILIO_H
00057 #include <sys/filio.h>
00058 #endif
00059 
00060 #ifdef HAVE_SYS_IOCTL_H
00061 #include <sys/ioctl.h>
00062 #endif
00063 
00064 #ifdef HAVE_SYS_FILIO_H
00065 #include <sys/filio.h>
00066 #endif
00067 
00068 #ifdef HAVE_STRING_H
00069 #include <string.h>
00070 #endif
00071 
00072 #ifdef HAVE_UNISTD_H
00073 #include <unistd.h>
00074 #endif
00075 
00076 #ifdef HAVE_SYS_STAT_H
00077 #include <sys/stat.h>
00078 #endif
00079 
00080 #ifdef HAVE_STROPTS_H
00081 #include <stropts.h>
00082 #endif
00083 
00084 #include "monitor.h"
00085 #include "net.h"
00086 #include "ssl.h"
00087 
00100 /* ------------------------------------------------------------------ Public */
00101 
00102 
00112 int check_connect(char *hostname, int port, int protocol) {
00113 
00114   int socket;
00115   int rv= TRUE;
00116 
00117   ASSERT(hostname);
00118   
00119   if ((socket= create_socket(hostname, port, protocol)) < 0) {
00120     
00121     rv= FALSE;
00122     
00123   } else if (! check_socket(socket)) {
00124 
00125     rv= FALSE;
00126 
00127   }
00128   
00129   close_socket(socket);
00130   
00131   return rv;
00132   
00133 }
00134 
00135 
00141 int check_host(char *hostname) {
00142   
00143   struct hostent *hp;
00144 
00145   ASSERT(hostname);
00146 
00147   if ((hp = gethostbyname(hostname)) == NULL) {
00148     
00149     return FALSE;
00150     
00151   }
00152   
00153   return TRUE;
00154   
00155 }
00156 
00157 
00166 int check_connection_io(Port_T p) {
00167 
00168   ASSERT(p);
00169 
00170   switch(p->type) {
00171    case SOCK_STREAM: return check_socket(p->socket);
00172    case SOCK_DGRAM:  return check_udp_socket(p->socket);
00173    default:          break;
00174   }
00175 
00176   return FALSE;
00177   
00178 }
00179 
00180 
00186 int check_socket(int socket) {
00187   
00188   fd_set rset, wset;
00189   struct timeval tv;
00190 
00191   FD_ZERO(&rset);
00192   FD_ZERO(&wset);
00193   FD_SET(socket, &rset);
00194   FD_SET(socket, &wset);
00195   tv.tv_sec= SELECT_TIMEOUT;
00196   tv.tv_usec= 0;
00197 
00198   return (select(socket+1, &rset, &wset, NULL, &tv) > 0);
00199 }
00200 
00201 
00212 int check_udp_socket(int socket) {
00213 
00214   int r;
00215   char buf[1]= {0};
00216 
00217   /*
00218    * R/W is asynchronous and we should probably loop and wait longer
00219    * for a possible ICMP error.
00220    */
00221   set_noblock(socket);
00222   write(socket, buf, 1);
00223   sleep(1);
00224   r= read(socket, buf, 1);
00225   set_block(socket);
00226   if(0>r) {
00227     switch(errno) {
00228     case ECONNREFUSED: return FALSE;
00229     default:           break;
00230     }
00231   }
00232   
00233   return TRUE;
00234 
00235 }
00236 
00237 
00246 int create_socket(char *hostname, int port, int protocol) {
00247 
00248   int s;
00249   struct hostent *hp;
00250   struct sockaddr_in sin;
00251   
00252   ASSERT(hostname);
00253 
00254   if ((hp= gethostbyname(hostname)) == NULL) {
00255     
00256     return -1;
00257     
00258   }
00259   
00260   if ((s= socket(AF_INET, protocol, 0)) < 0) {
00261     
00262     return -1;
00263     
00264   }
00265   
00266   sin.sin_family= AF_INET;
00267   sin.sin_port= htons(port);
00268   memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
00269 
00270   if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
00271 
00272     close_socket(s);
00273     return -1;
00274     
00275   }
00276 
00277   return s;
00278   
00279 }
00280 
00281 
00288 int create_generic_socket(Port_T pp) {
00289 
00290   int socket_fd= -1;
00291 
00292   ASSERT(pp);
00293 
00294   if(pp->family == AF_INET) {
00295 
00296     socket_fd= create_socket(pp->hostname, pp->port, pp->type);
00297 
00298   } else if(pp->family == AF_UNIX) {
00299 
00300     socket_fd= create_unix_socket(pp->pathname, pp->type);
00301 
00302   }
00303 
00304   return socket_fd;
00305   
00306 }
00307 
00308 
00316 int create_unix_socket(char *pathname, int protocol) {
00317 
00318   int s;
00319   struct sockaddr_un unixsocket;
00320   
00321   ASSERT(pathname);
00322 
00323   if ((s= socket(PF_UNIX, protocol, 0)) < 0) {
00324     
00325     return -1;
00326     
00327   }
00328   
00329   unixsocket.sun_family= AF_UNIX;
00330   snprintf(unixsocket.sun_path, sizeof(unixsocket.sun_path), "%s", pathname);
00331 
00332   if (connect(s, (struct sockaddr *)&unixsocket, sizeof(unixsocket)) < 0) {
00333 
00334     close_socket(s);
00335     return -1;
00336     
00337   }
00338 
00339   return s;
00340   
00341 }
00342 
00343 
00358 int create_server_socket(int port, int backlog, char *bindAddr) {
00359   
00360   int s;
00361   int flag= 1;
00362   struct sockaddr_in myaddr;
00363 
00364   if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0)
00365       return -1;
00366   
00367   memset(&myaddr, 0, sizeof(struct sockaddr_in));
00368   myaddr.sin_family= AF_INET;
00369   myaddr.sin_port= htons(port);
00370   
00371   if(bindAddr) {
00372     struct hostent *h= gethostbyname(bindAddr);
00373     endhostent();
00374     if(h==NULL) {
00375       errno= h_errno;
00376       goto error;
00377     }
00378     myaddr.sin_addr= *(struct in_addr*)h->h_addr_list[0];
00379   } else {
00380     myaddr.sin_addr.s_addr= htonl(INADDR_ANY);
00381   }
00382   
00383   if (setsockopt(s, SOL_SOCKET,
00384                   SO_REUSEADDR, (char *)&flag, sizeof(int)) < 0) 
00385       goto error;
00386 
00387   if (bind(s, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)) < 0)
00388       goto error;
00389   
00390   if (listen(s, backlog) < 0)
00391       goto error;
00392   
00393   if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1)
00394       goto error;
00395   
00396   return s;
00397 
00398   error:
00399   close(s);
00400 
00401   return -1;
00402 
00403 }
00404 
00405 
00411 int close_socket(int socket) {
00412 
00413   int rv= TRUE;
00414 
00415   if ((shutdown(socket, 2) < 0)) {
00416     
00417     rv= FALSE;
00418     
00419   }
00420   
00421   if (close(socket) < 0) {
00422     
00423     rv= FALSE;
00424     
00425   }
00426 
00427   return rv;
00428 
00429 }
00430 
00431 
00439 int set_sotimeout(int socket, int timeout) {
00440 
00441   struct timeval tv= {timeout, 0};
00442 
00443   return ((setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))==0) &&
00444           (setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv))==0));
00445 
00446 }
00447 
00448 
00454 int set_noblock(int socket) {
00455   
00456   int flag= 1;
00457 
00458   return (! ioctl(socket, FIONBIO, &flag));
00459 
00460 }
00461 
00462 
00468 int set_block(int socket) {
00469 
00470   int flag= 0;
00471 
00472   return (! ioctl(socket, FIONBIO, &flag));
00473 
00474 }
00475 
00485 int port_send(Port_T p, const char *msg, int len, int flags) {
00486 
00487   ASSERT(p);
00488   ASSERT(msg);
00489 
00490   if (p->ssl!=NULL) {
00491 
00492     return send_ssl_socket(p->ssl, (void *) msg, len);
00493 
00494   } else {
00495 
00496     return sock_send(p->socket, msg, len, flags);
00497 
00498   }
00499 
00500 }
00501 
00511 int port_recv(Port_T p, char *buf, int len, int flags) {
00512 
00513   ASSERT(p);
00514   ASSERT(buf);
00515 
00516   if (p->ssl!=NULL) {
00517     int error;
00518     error = recv_ssl_socket(p->ssl, buf, len);
00519 
00520     return error;
00521 
00522   } else {
00523 
00524     return sock_recv(p->socket, buf, len, flags);
00525 
00526   }
00527 }
00528 
00529 
00539 int sock_send(int sock, const char *msg, int len, int flags) {
00540 
00541   int rv;
00542   fd_set fdset;
00543   struct timeval t;
00544   int retry;
00545 
00546   ASSERT(msg);
00547 
00548   if (! set_noblock(sock)) {
00549     
00550     return -1;
00551     
00552   }
00553 
00554   rv= send(sock, msg, len, flags);
00555   if (rv <= 0) {
00556     
00557     if (errno == EWOULDBLOCK) 
00558     do {
00559       
00560       retry= FALSE;
00561       FD_ZERO(&fdset);
00562       FD_SET(sock, &fdset);
00563       t.tv_sec= SELECT_TIMEOUT;
00564       t.tv_usec= 0;
00565       rv = select(sock+1, NULL, &fdset, NULL, &t);
00566       if (rv <= 0) {
00567         
00568         rv= -1;
00569         
00570       }
00571       else {
00572         
00573         rv = send(sock, msg, len, flags);
00574         if (rv <= 0) {
00575           
00576           if(errno == EWOULDBLOCK) {
00577         
00578         retry= TRUE;
00579         sleep(1);
00580         
00581           }
00582           
00583         }
00584         
00585       }
00586       
00587     } while(retry);
00588     
00589   }
00590   
00591   set_block(sock);
00592 
00593   return rv;
00594   
00595 }
00596 
00597 
00607 int sock_recv(int sock, char *buf, int len, int flags) {
00608 
00609   int rv;
00610   fd_set fdset;
00611   struct timeval t;
00612 
00613   ASSERT(buf);
00614 
00615   if (! set_noblock(sock)) {
00616     
00617     return -1;
00618     
00619   }
00620   
00621   rv= recv(sock, buf, len, flags);
00622   if (rv <= 0) {
00623     
00624     if (errno == EWOULDBLOCK) {
00625       
00626       FD_ZERO(&fdset);
00627       FD_SET(sock, &fdset);
00628       t.tv_sec= SELECT_TIMEOUT;
00629       t.tv_usec = 0;
00630       rv = select(sock+1, &fdset, NULL, NULL, &t);
00631       if (rv <= 0) {
00632     
00633     rv= -1;
00634     
00635       }
00636       else {
00637     
00638     rv= recv(sock, buf, len, flags);
00639     
00640       }
00641       
00642     }
00643     
00644   }
00645 
00646   set_block(sock);
00647 
00648   return rv;
00649 
00650 }
00651 
00652 
00658 char *get_localhostname() {
00659 
00660   char hostname[256];
00661 
00662   if (gethostname(hostname, sizeof(hostname)) < 0) {
00663     
00664     return NULL;
00665     
00666   }
00667 
00668   return (strdup(hostname));
00669 
00670 }
00671 
00672 
00679 char *get_remote_host(int socket) {
00680 
00681   struct hostent *h;
00682   struct sockaddr_in r;
00683   int l= sizeof(struct sockaddr_in);
00684 
00685   if (getpeername(socket, (struct sockaddr*)&r, &l) < 0) {
00686     
00687     return NULL;
00688     
00689   } else {
00690     
00691     h=gethostbyaddr((char *)&r.sin_addr, sizeof(struct in_addr), AF_INET);
00692     if (h) {
00693       
00694       return strdup(h->h_name);
00695       
00696     }
00697     
00698   }
00699 
00700   return NULL;
00701 
00702 }
00703