connect.cpp

来自「包含客户和服务器的升级程序,在linux下可以运行的.」· C++ 代码 · 共 613 行

CPP
613
字号
/* * Copyright (C) 2006, Binary Ma * Licence: GNU GPL 1991 - version 2 * Bug report: binary@eniak.org*/#include "connect.h"#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netdb.h>static const char* VERSION = "0.6.2";const int ONTIME                = 1;static const int BLOCKMODE      = MSG_DONTWAIT | MSG_NOSIGNAL;static const int NETBUF         = 4096;static const int INFOSIZE       = 256;static const int PROSIZE        = 32;static const char COMPART       = ':';static const char* VER          = "1.2";int select_io( int fd, int delay, bool is_in ){    if( fd < 0 )        return -__LINE__;        fd_set set;    FD_ZERO( &set );    FD_SET( fd, &set );    timeval timeout;    timeout.tv_sec = delay;    timeout.tv_usec = 0;    fd_set* read_p = &set;    fd_set* write_p = NULL;    if( !is_in )    {        read_p = NULL;        write_p = &set;    }    int retval = select( fd + 1, read_p, write_p, NULL, delay < 0 ? NULL : &timeout );    if( -1 == retval )        return -__LINE__;        if( 0 != retval )        retval = FD_ISSET( fd, &set );        return retval;}int select_i( int fd, int delay ){    return select_io( fd, delay, true );}int select_o( int fd, int delay ){    return select_io( fd, delay, false );}/*  verify whether the reveive version match with current version  and return the follow length of data indicate by protocol head */static long exthead( char* prohead ){    if( NULL == prohead )        return -__LINE__;    // protocol head format: "1.2:1024:"    char* point = strchr( prohead, COMPART );    if( NULL == point )        return -__LINE__;    // verify version    *point = 0;    if( 0 != strcmp( prohead, VER ) )        return -__LINE__;    prohead = point + 1;    point = strchr( prohead, COMPART );    if( NULL == point )        return -__LINE__;		// parse data length    *point = 0;    return atol( prohead );}static int char2bin( char* info, struct stat* st ){    if( NULL == info || NULL == st )        return -__LINE__;	    char* point = NULL;    int count = 0;    while( NULL != ( point = strchr( info, COMPART ) ) )    {        *point = 0;        switch( count++ )        {        case 0:            st->st_size = atoll( info );            break;        case 1:            st->st_mode = atoi( info );            break;        // reserve extend        default:            return 0;        }		        info = point + 1;    }    return 0;}tcpbase::tcpbase( int delay ): m_delay( delay ){    m_sock = -1;}tcpbase::tcpbase( int sock, int delay ): m_delay( delay ){    m_error = 0;    m_sock = dup( sock );    if( -1 == m_sock )        m_error = -__LINE__;}tcpbase::~tcpbase(){    close_sock();}long tcpbase::recv( void* buf, long size ){    if( 0 != m_error || NULL == buf )        return -__LINE__;    long retval = select_i( m_sock, m_delay );    if( retval != ONTIME )        return -__LINE__;    char prohead[PROSIZE];    bzero( prohead, sizeof( prohead ) );    long count      = 0;    long tmp        = sizeof( prohead ) - 1;    char* tmp_p     = prohead;        // first, receive protocol head.    // second, receive text.    for( int i = 0; i < 2; i++ )    {        if( 1 == i )        {            tmp = exthead( prohead );            if( tmp < 0 || tmp > size )                return -__LINE__;            tmp_p = (char*)buf;        }        count = 0;        while( count < tmp )        {            retval = select_i( m_sock, m_delay );            if( retval != ONTIME )                return -__LINE__;	            retval = ::recv( m_sock, tmp_p + count, tmp - count, BLOCKMODE );            if( -1 == retval )            {                if( EWOULDBLOCK == errno )                    continue;                else                    return -__LINE__;            }			            // indicate remote socket closed            if( 0 == retval )                return -__LINE__;                        count += retval;        }    }    return count;}long tcpbase::send( const void* buf, long len ){    if( 0 != m_error || NULL == buf )        return -__LINE__;    long retval = select_o( m_sock, m_delay );    if( retval != ONTIME )        return -__LINE__;        char prohead[PROSIZE];    bzero( prohead, sizeof( prohead ) );    snprintf( prohead, sizeof( prohead ), "%s%c%li%c", VER, COMPART, len, COMPART );    long count          = 0;    long tmp            = sizeof( prohead ) - 1;    const char* tmp_p   = prohead;    // first, send protocol head.    // second, send text.    for( int i = 0; i < 2; i++ )    {        if( 1 == i )        {            tmp = len;            tmp_p = (const char*)buf;        }        count = 0;        while( count < tmp )        {            retval = select_o( m_sock, m_delay );            if( retval != ONTIME )                return -__LINE__;                        retval = ::send( m_sock, tmp_p + count, tmp - count, BLOCKMODE );            if( -1 == retval )            {                if( EWOULDBLOCK == errno )                    continue;                else                    return -__LINE__;            }                        count += retval;        }    }        return count;}off_t tcpbase::recvfile( const char* file, bool brkmode ){    if( NULL == file )        return -__LINE__;        char info[INFOSIZE];    bzero( info, sizeof( info ) );    if( recv( info, sizeof( info ) - 1 ) < 0 )        return -__LINE__;    struct stat st;    if( 0 != char2bin( info, &st ) )        return -__LINE__;        umask( 0 );    int flag = O_RDWR | O_CREAT;    if( brkmode )    {        flag |= O_APPEND;    }    else    {        // will create new file        // dont need care file mode        if( 0 == access( file, F_OK ) )            remove( file );    }	    int	fd = open( file, flag, st.st_mode );    if( -1 == fd )        return -__LINE__;        long count = 0;    off_t retval = 0;    while( retval < st.st_size )    {        static char buf[NETBUF];        bzero( buf, sizeof( buf ) );        count = recv( buf, sizeof( buf ) );        if( count < 0 )        {            close( fd );            return -__LINE__;        }        if( count != write( fd, buf, count ) )        {            close( fd );            return -__LINE__;        }        retval += count;    }    close( fd );    return retval;}off_t tcpbase::sendfile( const char* file, off_t offset ){    if( NULL == file )        return -__LINE__;    int fd = open( file, O_RDONLY );    if( -1 == fd )        return -__LINE__;    struct stat st;    if( -1 == fstat( fd, &st ) )    {        close( fd );        return -__LINE__;    }    st.st_size -= offset;    if( st.st_size < 0 )    {        close( fd );        return -__LINE__;    }    if( -1 == lseek( fd, offset, SEEK_SET ) )    {        close( fd );        return -__LINE__;    }    char info[INFOSIZE];    bzero( info, sizeof( info ) );    long long tmp = st.st_size;    snprintf( info, sizeof( info ), "%lli%c%i%c", tmp, COMPART, st.st_mode, COMPART );    if( send( info, strlen( info ) ) < 0 )    {        close( fd );        return -__LINE__;    }    off_t retval = 0;    long count = 0;    while( retval < st.st_size )    {        static char buf[NETBUF];        bzero( buf, sizeof( buf ) );        count = read( fd, buf, sizeof( buf ) );        if( count <= 0 )        {            if( -1 == count )            {                close( fd );                return -__LINE__;            }            // indicate end of file            // but, impossible at here            if( 0 == count )                break;        }        if( send( buf, count ) < 0 )        {            close( fd );            return -__LINE__;        }        retval += count;    }	    close( fd );    return retval;}void tcpbase::close_sock(){    if( -1 != m_sock )    {        close( m_sock );        m_sock = -1;    }}int tcpbase::dup_sock(){    return dup( m_sock );}int tcpbase::error(){    return m_error;}/*// Obsolete function, see Listenstatic int Listen_Obsolete( int iPort, int iBackLog ){	int iSock = socket( AF_INET, SOCK_STREAM, 0 );	if( -1 == iSock )		return -__LINE__;	struct sockaddr_in stAddr;	memset( &stAddr, 0, sizeof( stAddr ) );	stAddr.sin_family = AF_INET;	stAddr.sin_port = htons( iPort );	stAddr.sin_addr.s_addr = htonl( INADDR_ANY );	const int iReuse = 1;	if( -1 == setsockopt( iSock, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof( iReuse ) ) )	{	    close( iSock );		return -__LINE__;	}	if( -1 == bind( iSock, (struct sockaddr*)&stAddr, sizeof( stAddr ) ) )	{	    close( iSock );		return -__LINE__;	}		if( -1 == listen( iSock, iBackLog ) )	{	    close( iSock );		return -__LINE__;	}	return iSock;}// Obsolete function, see Connectstatic int Connect_Obsolete( int iPort, const char* pcHost ){	if( NULL == pcHost )		return -__LINE__;	int iSock = socket( AF_INET, SOCK_STREAM, 0 );	if( -1 == iSock )		return -__LINE__;		struct sockaddr_in stAddr;	memset( &stAddr, 0, sizeof( stAddr ) );	stAddr.sin_family = AF_INET;	stAddr.sin_port = htons( iPort );		// The obsolete function is:	// stAddr.sin_addr.s_addr = inet_addr( pcHost );	if( inet_pton( AF_INET, pcHost, &stAddr.sin_addr ) <= 0 )	{	    close( iSock );		return -__LINE__;	}			if( -1 == connect( iSock, ( struct sockaddr* )( &stAddr ), ( socklen_t )( sizeof( stAddr ) ) ) )	{	    close( iSock );		return -__LINE__;	}		return iSock;}*/static int s_listen( const char* host, const char* port, int backlog ){    if( NULL == port )        return -__LINE__;        struct addrinfo* res = NULL;    struct addrinfo* res_head = NULL;    struct addrinfo hint;    bzero( &hint, sizeof( hint ) );    	hint.ai_flags = AI_PASSIVE;	hint.ai_family = AF_UNSPEC;	hint.ai_socktype = SOCK_STREAM;	if( 0 != getaddrinfo( host, port, &hint, &res ) )	    return -__LINE__;    int sock = -1;    const int reuse = 1;    for( res_head = res; NULL != res; res = res->ai_next )    {        sock = socket( res->ai_family, res->ai_socktype, res->ai_protocol );        if( -1 == sock )            continue;        setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof( reuse ) );        if( 0 == bind( sock, res->ai_addr, res->ai_addrlen ) )            break;                close( sock );    }    freeaddrinfo( res_head );	    // the final socket() or bind() error    if( NULL == res )        return -__LINE__;	    if( -1 == listen( sock, backlog ) )        return -__LINE__;	    return sock;}static int s_connect( const char* host, const char* port ){    if( NULL == port )        return -__LINE__;        struct addrinfo* res = NULL;    struct addrinfo* res_head = NULL;    struct addrinfo hint;    bzero( &hint, sizeof( hint ) );    hint.ai_family = AF_UNSPEC;    hint.ai_socktype = SOCK_STREAM;    if( 0 != getaddrinfo( host, port, &hint, &res ) )        return -__LINE__;    int sock = -1;    for( res_head = res; NULL != res; res = res->ai_next )    {        sock = socket( res->ai_family, res->ai_socktype, res->ai_protocol );        if( -1 == sock )            continue;        if( 0 == connect( sock, res->ai_addr, res->ai_addrlen ) )            break;        close( sock );    }    freeaddrinfo( res_head );    if( NULL == res )        return -__LINE__;    return sock;}tcpserver::tcpserver( const char* host, const char* port, int delay, int backlog ): tcpbase( delay ){    m_error = 0;    bzero( m_accept, sizeof( m_accept ) );    if( backlog < 0 )        backlog = 1024;    	    m_sock_listen = s_listen( host, port, backlog );    if( m_sock_listen < 0 )    {        m_error = m_sock_listen;        m_sock_listen = -1;    }}tcpserver::~tcpserver(){	close_sock();	close_listen();}int tcpserver::accept( int delay ){    struct sockaddr_in addr;    socklen_t len = sizeof( addr );    bzero( &addr, len );    if( ONTIME != select_i( m_sock_listen, delay ) )        return 1;	    // dont set m_error error, usually, the errno == EINTR    m_sock = ::accept( m_sock_listen, (struct sockaddr*)&addr, &len );    if( -1 == m_sock )        return -__LINE__;    bzero( m_accept, sizeof( m_accept ) );    inet_ntop( AF_INET, &addr.sin_addr, m_accept, sizeof( m_accept ) );    return 0;}const char* tcpserver::accept_addr(){    return m_accept;}void tcpserver::close_listen(){    if( -1 != m_sock_listen )    {        close( m_sock_listen );        m_sock_listen = -1;    }}tcpclient::tcpclient( const char* host, const char* port, int delay ): tcpbase( delay ){    m_error = 0;    m_sock = s_connect( host, port );    if( m_sock < 0 )    {        m_error = m_sock;        m_sock = -1;    }}tcpclient::~tcpclient(){    close_sock();}

⌨️ 快捷键说明

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