Copied missing files from the subversion repository.
[collectd.git] / src / libping / sock.c
1 /**
2  * LIBPING socket library
3  *
4  * Copyright (C) 2000, 2001, 2002 by
5  * Jeffrey Fulmer - <jdfulmer@armstrong.com>
6  * This file is distributed as part of libping
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 #ifdef  HAVE_CONFIG_H
23 # include <config.h>
24 #endif/*HAVE_CONFIG_H*/
25
26 #include <stdio.h>
27 #include <sock.h>
28 #include <fcntl.h>
29
30 #ifdef  HAVE_ARPA_INET_H
31 # include <arpa/inet.h>
32 #endif/*HAVE_ARPA_INET_H*/
33  
34 #ifdef  HAVE_SYS_SOCKET_H
35 # include <sys/socket.h>
36 #endif/*HAVE_SYS_SOCKET_H*/ 
37
38 #ifdef  HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif/*HAVE_NETINET_IN_H*/
41  
42 #ifdef  HAVE_NETDB_H
43 # include <netdb.h>
44 #endif/*HAVE_NETDB_H*/
45
46 #ifdef  HAVE_SSL
47 # include <openssl/rand.h>
48 #endif/*HAVE_SSL */
49
50 #include <setup.h>
51 #include <errno.h>
52 #include <string.h>
53
54 /** 
55  * local prototypes 
56  */
57 int mknblock( int socket, int nonblock );
58 ssize_t socket_write( int sock, const void *vbuf, size_t len );  
59 ssize_t ssl_socket_write( CONN *C, const void *vbuf, size_t len );
60
61 /**
62  * JOEsocket
63  * returns int, socket handle
64  */
65 int
66 JOEsocket( CONN *C, const char *hn )
67 {
68   int conn;
69   struct timeval timeout;
70   int res;
71   int herrno;
72   int error;
73   socklen_t          len;
74   struct linger      ling;
75   struct sockaddr_in cli; 
76   struct hostent     *hp;
77   struct hostent     hent; 
78   char hbf[9000]; 
79
80 #if defined(_AIX)
81   char *aixbuf;
82   int  rc;
83 #endif/*_AIX*/ 
84
85 #ifdef  HAVE_SSL
86   int serr; 
87   char buf[1024]; 
88   C->ssl  = NULL;
89   C->ctx  = NULL;
90 #endif/*HAVE_SSL*/
91
92   C->sock = -1;
93   
94   if( C->prot == HTTPS ){
95     #ifdef HAVE_SSL
96       SSL_load_error_strings();
97       SSLeay_add_ssl_algorithms();
98       C->ctx = SSL_CTX_new( SSLv3_client_method());
99       if( C->ctx == NULL ){ perror( "SSL: ctx is NULL" ); }
100       /* http://www.openssl.org/support/faq.html#USER1
101        * Perhaps someday I'll learn to read the FAQ
102        * first and then code second, but probably not.
103        * Not all OSes have /dev/urandom, we must seed
104        * the PRNG
105        */
106       memset( buf, 0, sizeof( buf ));
107       RAND_seed( buf, sizeof( buf ));
108       C->ssl = SSL_new( C->ctx );
109       SSL_set_connect_state( C->ssl );
110     #else
111       return -1;
112     #endif /* HAVE_SSL */
113   }
114
115   /* create a socket, return -1 on failure */
116   if(( C->sock = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ){
117     return -1;
118   }
119  
120 #if defined(__GLIBC__)
121   /* for systems using GNU libc */
122   if(( gethostbyname_r( hn, &hent, hbf, sizeof(hbf), &hp, &herrno ) < 0 )){
123     hp = NULL;
124   }
125 #elif defined(sun)
126   /* Solaris 5++ */
127   hp = gethostbyname_r( hn, &hent, hbf, sizeof(hbf), &herrno );
128 #elif defined(_AIX)
129   aixbuf = (char*)xmalloc( 9000 );
130   rc  = gethostbyname_r(hn, (struct hostent *)aixbuf,
131                        (struct hostent_data *)(aixbuf + sizeof(struct hostent)));
132   hp = (struct hostent*)aixbuf;
133 #elif ( defined(hpux) || defined(__osf__) )
134   hp = gethostbyname( hn );
135   herrno = h_errno;
136 #else
137   /* simply hoping that gethostbyname is thread-safe */
138   hp = gethostbyname( hn );
139   herrno = h_errno;
140 #endif/*OS SPECIFICS*/ 
141
142   if( hp == NULL ) return -1;
143   bzero( &cli, sizeof( cli ));
144   bcopy( (char*)hp->h_addr, (char*)&cli.sin_addr, hp->h_length );
145   cli.sin_family = AF_INET;
146   cli.sin_port = htons( C->port );
147
148   ling.l_onoff  = 1;
149   ling.l_linger = 0;
150   if( setsockopt( C->sock, SOL_SOCKET, SO_LINGER, &ling, sizeof( ling )) < 0 ){ 
151     return -1;    
152   }
153
154   /**
155    * connect to the host 
156    * evaluate the server response and check for
157    * readability/writeability of the socket....
158    */ 
159   conn = connect( C->sock, (struct sockaddr *)&cli, sizeof(struct sockaddr_in));
160   if( conn < 0 ){
161     JOEclose( C );
162     return -1;
163   }
164   else if( conn == 0 ){
165     goto FINISH; /* immediate connection */
166   }
167   else{
168     /** 
169      * we have a connection, set the
170      * socket to non-blocking and test
171      * its integrity.
172      */
173     if(( mknblock( C->sock, TRUE )) < 0 ){
174       return -1;
175     }
176     FD_ZERO(&C->rset);
177     FD_ZERO(&C->wset);
178     FD_SET( C->sock, &C->rset );    
179     FD_SET( C->sock, &C->wset );    
180     memset((void *)&timeout, '\0', sizeof( struct timeval ));
181     /**
182      * the default timeout is set in init.c, it's
183      * value can be changed by the user in .siegerc,
184      * but we'll still use a ternary condition since
185      * you can't be too safe....
186      */ 
187     timeout.tv_sec  = (C->timeout > 0)?C->timeout:60;
188     timeout.tv_usec = 0;
189
190     if(( res = select( C->sock+1, &C->rset, &C->wset, NULL, &timeout )) < 1 ){
191       perror( "JOEsocket: connection timed out." );
192       close( C->sock );
193       return -1; 
194     }
195     if( FD_ISSET( C->sock, &C->rset) || FD_ISSET( C->sock, &C->wset )){
196       len = sizeof(error);
197       if( getsockopt( C->sock, SOL_SOCKET, SO_ERROR, &error, &len ) < 0 )
198         return(-1); 
199     }
200   } /* end of connect conditional */
201
202 FINISH:
203   /**
204    * make the socket blocking again.
205    */
206   if(( mknblock( C->sock, FALSE )) < 0 ){
207     perror( "JOEsocket: unable to set socket to non-blocking." );
208     return -1;
209   } 
210  
211   /* if requested, encrypt the transaction  */
212   if( C->prot == HTTPS ){
213     #ifdef HAVE_SSL
214       /* currently a fatal error, should it be? */
215       if(( SSL_set_fd( C->ssl, C->sock )) < 0 ){
216         perror( "unable to create secure socket!" );
217         exit( 0 );
218       }
219       if(( serr = SSL_connect( C->ssl )) < 0 ){
220         int problem = SSL_get_error( C->ssl, serr );
221         fprintf( stderr, "SSL_connect: want to %s more...\n",
222                ( problem == SSL_ERROR_WANT_READ) ? "read" : "write");
223         return -1;
224       }
225       SSL_get_cipher( C->ssl );
226     #else
227       return -1;
228     #endif /* HAVE_SSL */
229   }
230   
231   return((C->sock>0)?C->sock:-1);
232 }
233
234 /**
235  * makes the socket non-blocking,
236  * calls select with timeout and
237  * returns the socket to blocking.
238  */
239 int
240 JOEsocket_check( CONN *C, SDSET test )
241 {
242   int res;
243   struct timeval timeout;
244  
245   FD_ZERO(&C->rset);
246   FD_ZERO(&C->wset);
247   FD_SET( C->sock, &C->rset );
248   FD_SET( C->sock, &C->wset );
249   memset((void *)&timeout, '\0', sizeof( struct timeval ));
250
251   if(( mknblock( C->sock, TRUE )) < 0 ){
252     perror( "SIMBOTsocket: unable to set socket to non-blocking." );
253     return -1;
254   }
255  
256   timeout.tv_sec  = ( C->timeout > 0)?C->timeout:60;
257   timeout.tv_usec = 0;
258  
259   switch( test ){
260   case READ:
261     if(( res = select( C->sock+1, &C->rset, NULL, NULL, &timeout )) < 1 ){
262       close( C->sock );
263       return -1;
264     }
265     break;
266   case WRITE:
267     if(( res = select( C->sock+1, NULL, &C->wset, NULL, &timeout )) < 1 ){
268       close( C->sock );
269       return -1;
270     }
271     break;
272   case RDWR:
273     if(( res = select( C->sock+1, &C->rset, &C->wset, NULL, &timeout )) < 1 ){
274       close( C->sock );
275       return -1;
276     }
277     break;
278   }
279  
280   if(( mknblock( C->sock, FALSE )) < 0 ){
281     perror( "SIMBOTsocket: unable to set socket to non-blocking." );
282     return -1;
283   }
284   FD_CLR( C->sock, &C->rset );
285  
286   return 0;
287 }
288
289 /**
290  * local function
291  * set socket to non-blocking
292  */
293 int
294 mknblock( int sock, int nonblock )
295 {
296 #if HAVE_FCNTL_H 
297   int flags;
298   int retval;
299
300   flags = fcntl( sock, F_GETFL, 0 );
301   if( flags < 0 ){
302     perror("fcntl");
303     return -1;
304   }
305   if( nonblock ){ 
306     flags |=  O_NDELAY;
307   }
308   else{
309     flags &= ~O_NDELAY;
310   }
311   retval = fcntl( sock, F_SETFL, flags);
312   if( retval < 0 ){
313     perror("fcntl");
314     return -1;
315   } 
316   return retval;
317 #elif defined( FIONBIO )
318   ioctl_t status;
319  
320   status = nb ? 1 : 0;
321   return ioctl( sd, FIONBIO, &status );
322 #else
323   return -1;
324 #endif
325 }  
326
327 /**
328  * local function
329  * returns ssize_t
330  * writes vbuf to sock
331  */
332 ssize_t
333 socket_write( int sock, const void *vbuf, size_t len )
334 {
335   size_t      n;
336   ssize_t     w;
337   const char *buf;
338  
339   buf = vbuf;
340   n   = len;
341   while( n > 0 ){
342     if(( w = write( sock, buf, n )) <= 0 ){
343       if( errno == EINTR )
344         w = 0;
345       else
346         return( -1 );
347     }
348     n    -= w;
349     buf += n;
350   }
351   return( len );
352 }
353
354 /**
355  * local function
356  * returns ssize_t
357  * writes vbuf to sock
358  */
359 ssize_t
360 ssl_socket_write( CONN *C, const void *vbuf, size_t len )
361 {
362 #ifdef HAVE_SSL
363   size_t      n;
364   ssize_t     w;
365   const char *buf;
366
367   buf = vbuf;
368   n   = len;
369   while( n > 0 ){
370     if(( w = SSL_write( C->ssl, buf, n )) <= 0 ){
371       if( errno == EINTR )
372         w = 0;
373       else
374         return( -1 );
375     }
376     n    -= w;
377     buf += n;
378   }
379   return( len );
380 #else
381   perror( "protocol not supported" );
382   return -1;
383 #endif/*HAVE_SSL*/
384 }
385
386 ssize_t
387 JOEreadline( CONN *C, char *ptr, size_t len )
388 {
389   int n;
390  
391   do{
392     n = read( C->sock, ptr, 1 );
393   } while( n > 0 && *ptr++ != '\n' );
394  
395   *ptr++=0;
396   return( n > 0 );
397
398
399 ssize_t
400 JOEsocket_read( CONN *C, void *vbuf, size_t len )
401 {
402   size_t      n;
403   ssize_t     r;
404   char *buf;
405   
406   buf = vbuf;
407   n   = len;
408   
409   if( C->prot == HTTPS ){
410   #ifdef HAVE_SSL
411     while( n > 0 ){ 
412       if(( r = SSL_read( C->ssl, buf, n )) < 0 ){
413         if( errno == EINTR )
414           r = 0;
415         else
416           return( -1 );
417       }
418       else if( r == 0 ) break; 
419       n   -= r;
420       buf += r;
421     }   /* end of while    */
422   #endif/*HAVE_SSL*/
423   }  
424   else{
425     while( n > 0 ){
426       if(( r = read( C->sock, buf, n )) < 0 ){
427         if( errno == EINTR )
428           r = 0;
429         else
430           return( -1 );
431       }
432       else if( r == 0 ) break;
433       n   -= r;
434       buf += r;
435     } /* end of while */ 
436   }   /* end of else  */
437
438   return( len - n );  
439 }  
440
441 /**
442  * returns void
443  * socket_write wrapper function.
444  */
445 int
446 JOEsocket_write( CONN *C, const void *buf, size_t len )
447 {
448   int bytes;
449
450   if( C->prot == HTTPS ){
451     /* handle HTTPS protocol */
452     #ifdef HAVE_SSL
453     if(( bytes = ssl_socket_write( C, buf, len )) != len ){
454       perror( "JOEssl_socket_write: ERROR" );
455       return -1;
456     }
457     #else
458       perror( "JOEssl_socket_write: protocol NOT supported" );
459       return -1;
460     #endif/*HAVE_SSL*/
461   }
462   else{
463     /* assume HTTP */
464     if(( bytes = socket_write( C->sock, buf, len )) != len ){
465       perror( "JOEsocket_write: ERROR" );
466       return -1;
467     }
468   }
469
470   return 0;
471
472
473 /**
474  * returns void
475  * frees ssl resources if using ssl and
476  * closes the connection and the socket.
477  */
478 void
479 JOEclose( CONN *C )
480 {
481   #ifdef  HAVE_SSL
482     if( C->prot == HTTPS ){
483       SSL_shutdown( C->ssl );
484     }
485     SSL_free( C->ssl );
486     SSL_CTX_free( C->ctx );
487   #endif/*HAVE_SSL*/
488   close( C->sock ); 
489
490   return;
491
492
493