/* * Copyright (c) 2003 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_ZLIB #include #endif /* HAVE_ZLIB */ #include #include "applefile.h" #include "cksum.h" #include "connect.h" #include "argcargv.h" extern void (*logger)( char * ); extern int verbose; struct timeval timeout = { 60, 0 }; extern int errno; extern SSL_CTX *ctx; #ifdef HAVE_ZLIB int zlib_level = 0; #endif void v_logger( char *line ) { printf( "<<< %s\n", line ); return; } static SNET * connectsn2( struct sockaddr_in *sin ) { int s; int one = 1; SNET *sn = NULL; struct protoent *proto; if (( s = socket( PF_INET, SOCK_STREAM, 0 )) < 0 ) { perror( "socket" ); exit( 2 ); } if (( proto = getprotobyname( "tcp" )) == NULL ) { perror( "getprotobyname" ); exit( 2 ); } if ( setsockopt( s, proto->p_proto, TCP_NODELAY, &one, sizeof( one )) != 0 ) { perror( "snet_setopt" ); exit( 2 ); } if ( verbose ) printf( "trying %s... ", inet_ntoa( sin->sin_addr )); if ( connect( s, (struct sockaddr *)sin, sizeof( struct sockaddr_in )) != 0 ) { if ( verbose ) printf( "failed: %s\n", strerror( errno )); fprintf( stderr, "connection to %s failed: %s\n", inet_ntoa( sin->sin_addr ), strerror( errno )); (void)close( s ); return( NULL ); } if ( verbose ) printf( "success!\n" ); if (( sn = snet_attach( s, 1024 * 1024 )) == NULL ) { perror( "snet_attach" ); exit( 2 ); } return( sn ); } SNET * connectsn( char *host, int port ) { int i; struct hostent *he; struct sockaddr_in sin; SNET *sn = NULL; memset( &sin, 0, sizeof( struct sockaddr_in )); sin.sin_family = AF_INET; sin.sin_port = port; #ifdef notdef /* * this code should be enabled only to deal with bugs in * the gethostbyname() routine */ if (( sin.sin_addr.s_addr = inet_addr( host )) != -1 ) { return( connectsn2( &sin )); } #endif // notdef if (( he = gethostbyname( host )) == NULL ) { fprintf( stderr, "%s: Unknown host\n", host ); return( NULL ); } for ( i = 0; he->h_addr_list[ i ] != NULL; i++ ) { memcpy( &sin.sin_addr.s_addr, he->h_addr_list[ i ], (unsigned int)he->h_length ); if (( sn = connectsn2( &sin )) != NULL ) { return( sn ); } } fprintf( stderr, "%s: connection failed\n", host ); return( NULL ); } int closesn( SNET *sn ) { char *line; struct timeval tv; /* Close network connection */ if ( snet_writef( sn, "QUIT\r\n" ) < 0 ) { fprintf( stderr, "QUIT failed: %s\n", strerror( errno )); exit( 2 ); } tv = timeout; if (( line = snet_getline_multi( sn, logger, &tv )) == NULL ) { fprintf( stderr, "close failed: %s\n", strerror( errno )); exit( 2 ); } if ( *line != '2' ) { perror( line ); return( -1 ); } if ( snet_close( sn ) != 0 ) { fprintf( stderr, "snet_close failed: %s\n", strerror( errno )); exit( 2 ); } return( 0 ); } char ** get_capabilities( SNET *sn ) { char *line; char temp[ MAXPATHLEN ]; char **capa = NULL; int i, ac; char **av; struct timeval tv; while( 1 ) { tv = timeout; if (( line = snet_getline( sn, &tv )) == NULL ) { fprintf( stderr, "connection failed\n" ); return( NULL ); } if ( *line != '2' ) { fprintf( stderr, "%s\n", line ); return( NULL ); } if ( verbose ) printf( "<<< %s\n", line ); strcpy( temp, line+4 ); if (( ac = argcargv( temp, &av )) != 0 ) { if ( strncasecmp( "CAPAbilities", av[0], MIN( 12, strlen( av[0] ))) == 0 ) { capa = malloc( sizeof(char *)*ac ); for ( i = 0; i+1 < ac; i++ ) { capa[i] = strdup( av[i+1] ); } capa[i] = NULL; } } switch( line[3] ) { case ' ': if( !capa ) { capa = malloc( sizeof( char * )); *capa = NULL; } return ( capa ); case '-': break; default: fprintf ( stderr, "%s\n", line ); return ( NULL ); } } } #ifdef HAVE_ZLIB int negotiate_compression( SNET *sn, char **capa ) { char *name = NULL; char *line; int type = 0; int level = 0; struct timeval tv; /* Place compression algorithms in descending order of desirability */ if ( zlib_level ) { /* walk through capabilities looking for "ZLIB" */ if ( check_capability( "ZLIB", capa ) == 1 ) { name = "ZLIB"; type = SNET_ZLIB; level = zlib_level; } if ( level == 0 ) { fprintf( stderr, "compression capability mismatch, " "compression disabled\n" ); return( 0 ); } } if ( verbose ) printf( ">>> COMP %s %d\n", name, level ); snet_writef( sn, "COMP %s %d\r\n", name, level ); tv = timeout; if (( line = snet_getline( sn, &tv )) == NULL ) { perror( "snet_getline" ); return( -1 ); } if( verbose ) printf( "<<< %s\n", line ); if ( *line != '3' ) { fprintf( stderr, "%s\n", line ); return( -1 ); } if ( snet_setcompression( sn, type, level ) < 0 ) { perror( "snet_setcompression" ); return( -1 ); } tv = timeout; if (( line = snet_getline( sn, &tv )) == NULL ) { perror( "snet_getline" ); return( -1 ); } if( verbose ) printf( "<<< %s\n", line ); if ( *line != '2' ) { fprintf( stderr, "%s\n", line ); return( -1 ); } return( 0 ); } int print_stats( SNET *sn ) { z_stream in_stream, out_stream; if ( snet_flags( sn ) & SNET_ZLIB ) { in_stream = snet_zistream( sn ); out_stream = snet_zostream( sn ); #define RATIO(a,b) (((double)(a))/((double)(b))) if ( verbose ) { printf( "zlib stats +++ In: %lu:%lu (%.3f:1) " "+++ Out: %lu:%lu (%.3f:1)\n", in_stream.total_out, in_stream.total_in, RATIO( in_stream.total_out, in_stream.total_in ), out_stream.total_in, out_stream.total_out, RATIO( out_stream.total_in, out_stream.total_out )); } else { syslog( LOG_INFO, "zlib stats +++ In: %lu:%lu (%.3f:1) " "+++ Out: %lu:%lu (%.3f:1)\n", in_stream.total_out, in_stream.total_in, RATIO( in_stream.total_out, in_stream.total_in ), out_stream.total_in, out_stream.total_out, RATIO( out_stream.total_in, out_stream.total_out )); } } return( 0 ); } #endif /* HAVE_ZLIB */ /* * check_capabilities: check to see if type is a listed capability * * return codes: * 0: type not in capability list * 1: type in capability list */ int check_capability( char *type, char **capa ) { char **p; /* walk through capabilities looking for "REPO" */ for ( p = capa; *p; p++ ) { if ( !strncasecmp( type, *p, MIN( 4, strlen( *p )))) { return( 1 ); } } return( 0 ); }