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

📄 cmppbuild.c

📁 Unix/Linux下的cmpp实现源程序
💻 C
字号:

/*******************************************************
    NAME:      cmppbuild.c
    PURPOSE:   China Mobile Peer to Peer Protocol 2.0
               Permanent connection implementation to
               submit data to Internet Short Message Gateway
               or deliver data from ISMG to upper layer.

               automatically building TCP connection implementation.

    VERSION:   0.0.1
    AUTHOR:    Ke Heng Zhong
    DATE:      2002/06/17 12:52
    MODIFIED:  2000/06/17 21:12
 ********************************************************/

#include "kevopsall.ext"
#include "cmpp.h"




int cmcon_get_unique_id()
{
    static int carcid = 0;
    if (++carcid == 0) ++carcid;
    return carcid;
}



int cmpp_build_conn (VTASK * entity, void * userInfo)
{
    CmppEntity         * cment = NULL;
    CmppCon            * cmcon = NULL;
    VTASK              * vtask = NULL;
    SPCMPP             * spc   = NULL;
    int                  addrlen;
    struct sockaddr_in   sock;
    int                  fd = -1;
    int                  connsucc = 0;

    /* current vtask is the entity */

#ifdef _DEBUG
info("cmpp_build_conn: building connection hook started.\n");
#endif

    if (!entity) return 0;
    cment = (CmppEntity *) entity->var;

    spc = (SPCMPP *)entity->cvopsState->ref;

#ifdef _DEBUG
info("cmpp_build_conn: non-block connect %s:%d\n", 
        cment->remote_host, cment->remote_port);
#endif

    fd = tcp_non_block_connect (cment->remote_host,
                        cment->remote_port, &connsucc);
    if (connsucc > 0) {
#ifdef _DEBUG
info("cmpp_build_conn: non-block connect returned connsucc:%d\n", connsucc);
#endif
        vtask = getFirstFreeConnection(entity);
        if (!vtask) {
            error("cmpp_build_conn: not enough virtual task.\n");
            close(fd);
            startTimer(entity, t_build, TBUILD);
            return 0;
        }

        cmcon = (CmppCon *) vtask->var;
        cmcon->fd = fd;

        addrlen = sizeof(sock);
        if (getpeername(fd, (struct sockaddr *)&sock, &addrlen) == 0) {
            cment->remote_ip   = sock.sin_addr;
            cmcon->remote_ip   = sock.sin_addr;
            cmcon->remote_port = sock.sin_port;
        } else {
            error("cmpp_build_conn: can't get peer address.\n");
            close(fd);
            cmcon->fd = -1;

            checkIdleConnection(vtask);
            startTimer(entity, t_build, TBUILD);
            return 0;
        }

        addrlen = sizeof(sock);
        if (getsockname(fd, (struct sockaddr *)&sock, &addrlen) == 0) {
            cmcon->local_ip = sock.sin_addr;
            cmcon->local_port = sock.sin_port;
        } else {
            cmcon->local_ip.s_addr = 0;
            cmcon->local_port = 0;
        }

        if (sk_num(cment->init_list) < cment->mt_num) {
            /* the connection is for CMPP MT connection */
            cmcon->is_mo = 0;
            cmcon->version = ((uint8)spc->mtmajorver << 4) & 0xF0;
            cmcon->version |= ((uint8)spc->mtminorver & 0x0F);
            /*cmcon->version = (((uint8)getConfInt ("General", "MTMajor_Version")) << 4) & 0xF0;;
            cmcon->version |= ((uint8)getConfInt("General","MTMinor_Version") & 0x0F);*/
        } else if (sk_num(cment->mo_list) < cment->mo_num) {
            /* the connection is for CMPP MO connection */
            cmcon->is_mo = 1;
            cmcon->version = ((uint8)spc->momajorver << 4) & 0xF0;;
            cmcon->version |= ((uint8)spc->mominorver & 0x0F);
            /*cmcon->version = (((uint8)getConfInt ("General", "MOMajor_Version")) << 4) & 0xF0;;
            cmcon->version |= ((uint8)getConfInt("General","MOMinor_Version") & 0x0F);*/
        } else {
            error("CMPP Connection number is exceeded. Now new built connection tearing down.\n");
            closesocket(fd);
            cmcon->fd = -1;
            vtask->state = cmpp_null;
            checkIdleConnection(vtask);
            return 0;
        }


        /* send CMPP connect PDU to ISMG */
        if (send_cmpp_connect (vtask) < 0) {
            error("cmpp_build_conn: TCP connection crashed while sending CMPP Connect.\n");
            vtask->state = cmpp_null;
            close(fd);   
            cmcon->fd = -1;
                         
            checkIdleConnection(vtask);
            startTimer(entity, t_build, TBUILD);
            return 0;
        }

        cmcon->devid = enterLongDevice(
                         entity->cvopsState,
                         vtask,
                         fd,
                         DF_READ,
                         cmpp_data_recv,
                         NULL,
                         "cmcon_init_recv");
        if (cmcon->devid == -1) {
            error("cmpp_build_conn: I/O device number exceeded.\n");
            close(fd);
            cmcon->fd = -1;

            checkIdleConnection(vtask);
            startTimer(entity, t_build, TBUILD);
            return 0;
        }

        cmcon->conid = cmcon_get_unique_id();
        vtask->state = cmpp_handshaking;

#ifdef _DEBUG
info("cmcon_build_conn: entity %s allocated conid %d.\n",
         entity->name, cmcon->conid);
#endif

tolog("CMPP SP TCP connect to %s:%d successfully from %s.\n",
      inet_ntoa(cmcon->remote_ip), cmcon->remote_port, vtask->name);

        return 0;
    }

    else { /* non-blocking connect operation unsuccessfully */

#ifdef _DEBUG
info("cmpp_build_conn: non-block connect not successfully, "
         "returned connsucc:%d\n", connsucc);
#endif

        if (fd != -1) {
#ifdef _DEBUG
info("cmpp_build_conn: non-block socket created, but connection coming later.\n");
#endif

            /* socket create successfully, but connection is ready later */
            vtask = getFirstFreeConnection(entity);
            if (!vtask) {
                error("cmpp_build_conn: not enough virtual task for non-blocking.\n");
                close(fd);
                startTimer(entity, t_build, TBUILD);
                return 0;
            }

            cmcon = (CmppCon *) vtask->var;
            cmcon->fd    = fd;
            cmcon->devid = enterLongDevice(
                             entity->cvopsState,
                             vtask,
                             fd,
                             DF_WRITE,
                             cmpp_conn_succ,
                             NULL,
                             "cmpp_non_blocking");
            if (cmcon->devid == -1) {
                error("cmpp_build_conn: I/O device number exceeded for non-blocking.\n");
                close(fd);
                cmcon->fd = -1;

                checkIdleConnection(vtask);
                startTimer(entity, t_build, TBUILD);
                return 0;
            }

#ifdef _DEBUG
info("cmpp_build_conn: one not-ready connection"
    " vtask %s for reserving.\n", vtask->name);
#endif
            return 0;

        } else { /* connect failed */
            error("cmpp_build_conn: non-block connect"
                  " failed completely, start t_build.\n");
            startTimer(entity, t_build, TBUILD);
        }
    }
    return 0;
}



void cmpp_conn_succ (VTASK * vtask, int fd, unsigned event)
{
    VTASK             * entity = NULL;
    CmppCon           * cmcon = NULL;
    CmppEntity        * cment = NULL;
    SPCMPP            * spc = NULL;
    int                addrlen;
    struct sockaddr_in sock;
#ifdef UNIX
    int                sockerr, sockerrlen, retval;
#endif

    if (!vtask || fd == -1 || event != DF_WRITE)
        return;

#ifdef _DEBUG
info("cmpp_conn_succ: connect event started.\n");
#endif

   spc = (SPCMPP *)vtask->cvopsState->ref;

    cmcon = (CmppCon *)vtask->var;
    entity = (VTASK *) getEntity (vtask);
    cment = (CmppEntity *)entity->var;
    if (!cmcon || !cment) {
        error("cmpp_conn_succ: internal error.\n");
        vtask->state = cmpp_null;
        checkIdleConnection(vtask);

        startTimer(entity, t_build, TBUILD);
        return;
    }

    if (cmcon->fd != fd) {
        error("cmpp_conn_succ: non-blocking connection succ indication is invalid.\n");
        close(fd);

        vtask->state = cmpp_null;
        checkIdleConnection(vtask);

        if (cmcon->is_mo)
            sk_delete_ptr(cment->mo_list, vtask);
        else
            sk_delete_ptr(cment->init_list, vtask);

        startTimer(entity, t_build, TBUILD);

        return;
    }

#ifdef UNIX
        sockerrlen = sizeof(int);
        sockerr = 0;
        retval = getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sockerrlen);
        if (retval < 0 || sockerr != 0) {
            error("cmpp_conn_succ: %s.\n",
                    retval < 0 ? "getsockopt error":"non-blocking unsuccessfully!");
            removeDevice(vtask->cvopsState, cmcon->devid);
            cmcon->devid = -1;
            closesocket(cmcon->fd);
            cmcon->fd = INVALID_SOCKET;

            vtask->state = cmpp_null;
            checkIdleConnection(vtask);

            if (cmcon->is_mo)
                sk_delete_ptr(cment->mo_list, vtask);
            else
                sk_delete_ptr(cment->init_list, vtask);
            startTimer(entity, t_build, TBUILD);
            return;
        }
#endif

    removeDevice(vtask->cvopsState, cmcon->devid);
    cmcon->devid = -1;

    addrlen = sizeof(sock);
    if (getpeername(fd, (struct sockaddr *)&sock, &addrlen) == 0) {
        cment->remote_ip   = sock.sin_addr;
        cmcon->remote_ip   = sock.sin_addr;
        cmcon->remote_port = sock.sin_port;
    } else {
        error("cmpp_conn_succ: can't get peer address.\n");
        close(cmcon->fd);
        cmcon->fd = -1;

        vtask->state = cmpp_null;
        checkIdleConnection(vtask);

        if (cmcon->is_mo)
            sk_delete_ptr(cment->mo_list, vtask);
        else
            sk_delete_ptr(cment->init_list, vtask);
        startTimer(entity, t_build, TBUILD);
        return;
    }

    addrlen = sizeof(sock);
    if (getsockname(fd, (struct sockaddr *)&sock, &addrlen) == 0) {
        cmcon->local_ip = sock.sin_addr;
        cmcon->local_port = sock.sin_port;
    } else {
        cmcon->local_ip.s_addr = 0;
        cmcon->local_port = 0;
    }

    if (sk_num(cment->init_list) < cment->mt_num) {
        /* the connection is for CMPP MT connection */
        cmcon->is_mo = 0;
        cmcon->version = ((uint8)spc->mtmajorver << 4) & 0xF0;
        cmcon->version |= ((uint8)spc->mtminorver & 0x0F);
        /*cmcon->version = (((uint8)getConfInt ("General", "MTMajor_Version")) << 4) & 0xF0;;
        cmcon->version |= ((uint8)getConfInt("General","MTMinor_Version") & 0x0F);*/
    } else if (sk_num(cment->mo_list) < cment->mo_num) {
        /* the connection is for CMPP MO connection */
        cmcon->is_mo = 1;
        cmcon->version = ((uint8)spc->momajorver << 4) & 0xF0;;
        cmcon->version |= ((uint8)spc->mominorver & 0x0F);
        /*cmcon->version = (((uint8)getConfInt ("General", "MOMajor_Version")) << 4) & 0xF0;;
        cmcon->version |= ((uint8)getConfInt("General","MOMinor_Version") & 0x0F);*/
    } else {
        error("CMPP Connection number is exceeded. Now new built connection tearing down.\n");
        closesocket(fd);
        cmcon->fd = -1;
        vtask->state = cmpp_null;
        checkIdleConnection(vtask);
        return;
    }



    /* send CMPP connect PDU to ISMG */
    if (send_cmpp_connect (vtask) < 0) {
        error("cmpp_build_conn: TCP connection crashed while sending CMPP Connect.\n");
        vtask->state = cmpp_null;
        close(fd);
        cmcon->fd = -1;

        checkIdleConnection(vtask);
        startTimer(entity, t_build, TBUILD);
        return;
    }

    cmcon->devid = enterLongDevice(
                     vtask->cvopsState,
                     vtask,
                     fd,
                     DF_READ,
                     cmpp_data_recv,
                     NULL,
                     "cmcon_init_recv");
    if (cmcon->devid == -1) {
        error("cmpp_conn_succ: I/O device number exceeded.\n");
        close(fd);
        cmcon->fd = -1;

        vtask->state = cmpp_null;
        checkIdleConnection(vtask);
 
        if (cmcon->is_mo)
            sk_delete_ptr(cment->mo_list, vtask);
        else
            sk_delete_ptr(cment->init_list, vtask);
        startTimer(entity, t_build, TBUILD);

        return;
    }

    cmcon->conid = cmcon_get_unique_id();

#ifdef _DEBUG
info("cmpp_conn_succ: alloc connection id:%d.\n", cmcon->conid);
#endif

    vtask->state = cmpp_handshaking;

tolog("CMPP SP TCP connect to %s:%d successfully from %s.\n",
      inet_ntoa(cmcon->remote_ip), cmcon->remote_port, vtask->name);

    checkIdleConnection(vtask);
    return;
}



⌨️ 快捷键说明

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