⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socket.c

📁 站点映像程序
💻 C
字号:
/*    socket handling routines   Copyright (C) 1998, Joe Orton <joe@orton.demon.co.uk>, except where   otherwise indicated.                                                                        This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.     This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.     You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   $Id: socket.c,v 1.12.2.6 1999/08/19 10:26:07 joe Exp $*/#include <config.h>#include <sys/types.h>#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#include <sys/socket.h>#include <sys/stat.h>#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <errno.h>#ifdef HAVE_LX22_SENDFILE#include <linux/unistd.h>/* We have sendfile()... the macro does not produce a prototype * though, so we prototype it too.  */_syscall4(int, sendfile, int, out_fd, int, in_fd, off_t *, offset,	  size_t, count);int sendfile(int out_fd, int in_fd, off_t *offset, size_t count);#endif /* HAVE_LX22_SENDFILE */#include <fcntl.h>#include <stdio.h>#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_STRINGS_H#include <strings.h>#endif #ifdef HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#ifdef HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#include "socket.h"#include "common.h"#include "frontend.h"/* sock_read is read() with a timeout of SOCKET_TIMEOUT. */int sock_read( const int sock, void *buffer, const size_t count ) {    int ret;    ret = sock_block( sock, SOCKET_TIMEOUT );    if( ret > 0 ) /* Got data */	ret = read( sock, buffer, count );    return ret;}/* sock_recv is recv() with a timeout of SOCKET_TIMEOUT */int sock_recv( const int sock, void *buffer, const size_t count,	       const unsigned int flags ) {    int ret;    ret = sock_block( sock, SOCKET_TIMEOUT );    if( ret > 0 ) /* Got data */	ret = recv( sock, buffer, count, flags );    return ret;}/* Blocks waiting for input on the given socket for the given time. */int sock_block( const int sock, const int timeout ) {    static struct timeval tv;    static fd_set fds;    /* Init the fd set */    FD_ZERO( &fds );    FD_SET( sock, &fds );    /* Set the timeout */    tv.tv_sec = timeout;    tv.tv_usec = 0;    return select( sock+1, &fds, NULL, NULL, &tv );}/* Send the given line down the socket with CRLF appended.  * Returns 0 on success or -1 on failure. */int send_line( const int sock, const char *line ) {    char *buffer;    int ret;    buffer = malloc( strlen(line) + 3 );    strcpy( buffer, line );    /* Add \r\n on the end - Unix servers will ignore the \r,      * Windows ones require \r\n */    strcat( buffer, "\r\n" );    ret = send_string( sock, buffer );    free( buffer );    return ret;}/* Send a block of data down the given fd. * Returns 0 on success or -1 on failure */int send_data( const int fd, const char *data, const size_t length ) {    size_t sent, wrote;    const char *pnt;    sent = 0;    pnt = data;    while( sent < length ) {	wrote = write( fd, pnt, length-sent );	if( wrote < 0 ) {	    perror( "write" );	    return -1;	}	sent += wrote;    }    return 0;}/* Sends the given string down the given socket. * Returns 0 on success or -1 on failure. */int send_string( const int sock, const char *data ) {    return send_data( sock, data, strlen( data ) );}/* This is from from Eric Raymond's fetchmail (SockRead() in socket.c) * since I wouldn't have a clue how to do it properly. * This function is Copyright (C) Eric Raymond. * *  Actually, it's now been slightly modified to return -2 *  if we don't find a newline within len. This is necessary  *  for reading HTTP header lines, which have no maximum length. */int read_line( const int sock, char *buffer, int len) {    char *newline, *bp = buffer;    int n;        if (--len < 1)	return(-1);    do {	/*	 * The reason for these gymnastics is that we want two things:	 * (1) to read \n-terminated lines,	 * (2) to return the true length of data read, even if the	 *     data coming in has embedded NULS.	 */	if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0) {	    DEBUG( DEBUG_SOCKET, "recv: %d - error: %s\n", n, 		   strerror(errno) );	    return(-1);	}	if ((newline = memchr(bp, '\n', n)) != NULL)	    n = newline - bp + 1;	if ((n = sock_read(sock, bp, n)) == -1) {	    DEBUG( DEBUG_SOCKET, "read error: %s\n", strerror(errno) );	    return(-1);	}	bp += n;	len -= n;	if( len == 0 ) return -2;    } while (!newline && len);    *bp = '\0';    return bp - buffer;}/* Reads readlen bytes from srcfd and writes to destfd. * (Not all in one go, obviously). * If readlen == -1, then it reads from srcfd until EOF. * Returns number of bytes written to destfd, or -1 on error. * Calls fe_transfer_progress( a, b ) during transfers, where *  a = bytes transferred so far, and b = readlen */size_t transfer( const int srcfd, const int destfd, const size_t readlen ) {    char buffer[BUFSIZ], *pnt;    int rdlen, wrlen, len2;    size_t curlen; /* total bytes yet to read from srcfd */    size_t sumwrlen; /* total bytes written to destfd */    if( readlen == -1 ) {	curlen = BUFSIZ; /* so the buffer size test works */    } else {#ifdef HAVE_LX22_SENDFILE	/* We can only use sendfile if we know how much we're sending.	 * Eyeballing kernel source shows offset can be NULL. */	DEBUG( DEBUG_SOCKET, "Using Linux 2.2 sendfile...\n" );	wrlen = sendfile( destfd, srcfd, NULL, readlen );	/* I think that sendfile only works on some filesystems...	 * on others it will give -EINVAL */	if( wrlen >= 0 || errno != EINVAL ) {	    return wrlen;	}	DEBUG( DEBUG_SOCKET, "sendfile failed... falling back.\n" );#endif /* HAVE_LX22_SENDFILE */	curlen = readlen; /* everything to do */    }    sumwrlen = 0; /* nowt done yet */    while( curlen > 0 ) {	/* Get a chunk... if the number of bytes that are left to read	 * is less than the buffer size, only read that many bytes. */	rdlen = sock_read( srcfd, buffer, 			   (readlen==-1)?BUFSIZ:(min( BUFSIZ, curlen )) );	fe_transfer_progress( sumwrlen, readlen );	if( rdlen < 0 ) { 	    perror("read");	    return -1;	} else if( rdlen == 0 ) { 	    /* End of file... get out of here */	    break;	}	if( readlen != -1 )	    curlen -= rdlen;	/* Otherwise, we have bytes!  Write them to destfd... might	 * only manage to write a few of them at a time, so we have	 * to deal with that too. */	/* Replace this with a call to send_data? */	pnt = buffer;	len2 = rdlen;	while( len2 > 0 ) {	    wrlen = write( destfd, pnt, len2 );	    if( wrlen < 0 ) { 		perror( "write" );		return -1;	    }	    len2 -= wrlen;	    pnt += wrlen;	    sumwrlen += wrlen;	}    }    return sumwrlen;}/* Reads buflen bytes into buffer until it's full. * Returns 0 on success, -1 on error */int read_data( const int sock, char *buffer, int buflen ) {    char *pnt; /* current position within buffer */    int len;    pnt = buffer;    while( buflen > 0 ) {	len = sock_read( sock, pnt, buflen );	if( len < 0 ) return len;	buflen -= len;	pnt += len;    }    return 0;}/* Dump the given filename down the given socket. * Returns non-zero value if successful */int send_file_binary( const int sock, const char *filename ) {    int fd, wrote;    struct stat fs;#if defined (__EMX__) || defined(__CYGWIN__)    if( (fd = open( filename, O_RDONLY | O_BINARY )) < 0 ) {#else    if( (fd = open( filename, O_RDONLY )) < 0 ) {#endif     	perror( "open" ); 	return -1;    }    if( fstat( fd, &fs ) < 0 ) {	perror( "fstat" );	close( fd );	return -2;    }    /* What's the Right Thing to do? Choices:     *  a) Let transfer send everything from fd until EOF     *    + If the EOF pos changes, we'll know and can signal an error     *    - Unsafe - the transfer might not end if someone does      *        yes > file     *  b) Tell transfer to send only the number of bytes from the stat()     *    + Safe - the transfer WILL end.     *    - If the EOF pos changes, we'll have a partial (corrupt) file.     * I'm not sure. I think (a) gets my vote but it doesn't allow     * nice transfer progress bars in the FE under the current API     * so we go with (b).     */    wrote = transfer( fd, sock, fs.st_size );    close( fd ); /* any point in checking that one? */    /* Return whether we transferred the correct number of bytes */    return (wrote == fs.st_size );}/* Dump the given filename down the given socket, in ASCII translation * mode. Returns non-zero value if successful. */int send_file_ascii( const int sock, const char *filename ) {    int ret;    char buffer[BUFSIZ], *pnt;    FILE *f;        f = fopen( filename, "r" );    if( f == NULL ) {	perror( "fopen" ); 	return -1;    }    /* Init to success */    ret = 1;    while(1) {	if( fgets( buffer, BUFSIZ - 1, f ) == NULL ) {	    if( ferror( f ) ) {		ret = 0;		break;	    }	    /* Finished upload */	    ret = 1;	    break;	}	/* To send in ASCII mode, we need to send CRLF as the EOL.	 * We might or might not already have CRLF-delimited lines.	 * So we mess about a bit to ensure that we do.	 */	pnt = strchr( buffer, '\r' );	if( pnt == NULL ) {	    /* We need to add the CR in */	    pnt = strchr( buffer, '\n' );	    if( pnt == NULL ) {		/* No CRLF found at all */		pnt = strchr( buffer, '\0' );		if( pnt == NULL ) /* crud in buffer */		    pnt = buffer;	    }	    /* Now, pnt points to the first character after the 	     * end of the line, i.e., where we want to put the CR.	     */	    *pnt++ = '\r';	    /* And lob in an LF afterwards */	    *pnt-- = '\n';	}	/* At this point, pnt points to the CR.	 * We send everything between pnt and the beginning of the buffer,	 * +2 for the CRLF	 */	if( send_data( sock, buffer, (pnt - buffer) +2 ) != 0 ) {	    ret = 0;	    break;	}    }    fclose( f ); /* any point in checking that one? */    /* Return true */    return ret;}/* Dump from given socket into given file. Reads only filesize bytes, * or until EOF if filesize == -1. * Returns number of bytes written on success, or -1 on error */int recv_file( const int sock, const char *filename, const size_t filesize ) {    int fd;    size_t wrote;#if defined (__EMX__) || defined(__CYGWIN__)    /* We have to set O_BINARY, thus need open(). Otherwise it should be       equivalent to creat(). */    if( (fd = open( filename, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0644 )) < 0 ) {	perror( "open" );	return -1;    }#else    if( (fd = creat( filename, 0644 )) < 0 ) {	perror( "creat" );	return -1;    }#endif    wrote = transfer( sock, fd, filesize );    if( close( fd ) == -1 ) {	/* Close failed - file was not written correctly */	return -1;    }    if( filesize == -1 ) {	return wrote;    } else {	return (wrote==filesize);    }}/* Do a name lookup on given hostname, writes the address into * given address buffer. Return -1 on failure. */int host_lookup( const char *hostname, struct in_addr *addr ) {    struct hostent *hp;    unsigned long laddr;        DEBUG( DEBUG_SOCKET, "host_lookup: trying inet_addr\n" );    laddr = (unsigned long)inet_addr(hostname);    if ((int)laddr == -1) {	/* inet_addr failed. */	DEBUG( DEBUG_SOCKET, "trying gethostbyname\n" );	hp = gethostbyname(hostname);	if( hp == NULL ) {	    DEBUG( DEBUG_SOCKET, "gethostbyname failed\n" );	    return -1;	}	DEBUG( DEBUG_SOCKET, "gethostbyname worked.\n" );	memcpy( addr, hp->h_addr, hp->h_length );    } else {	DEBUG( DEBUG_SOCKET, "inet_addr succeeded\n" );	addr->s_addr = laddr;    }    return 0;}/* Opens a socket to the given port at the given address. * Returns -1 on failure, or the socket on success.  * portnum must be in HOST byte order */int socket_connect( const struct in_addr addr, const int portnum ) {    struct sockaddr_in sa;    int sock;    /* Look up the host name */    /* Create the socket */    if( ( sock = socket(AF_INET, SOCK_STREAM, 0) ) < 0)	return -1;    /* Connect the socket */    sa.sin_family = AF_INET;    sa.sin_port = htons(portnum); /* host -> net byte orders */    sa.sin_addr = addr;    if( connect(sock, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0 )	return -1;    /* Success - return the socket */    return sock;}/* Closes given socket */void socket_close( const int sock ) {    close( sock );}/* Returns HOST byte order port of given name */int get_tcp_port( const char *name ) {    struct servent *ent;    ent = getservbyname( name, "tcp" );    if( ent == NULL ) {	return 0;    } else {	return ntohs( ent->s_port );    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -