Logo Search packages:      
Sourcecode: jabberd14 version File versions  Download package

static void* _mio_connect ( void *  arg  )  [static]

helper-thread for mio_connect() to connect to a host

Parameters:
arg connect_data for the connection

Definition at line 593 of file mio.cc.

References _mio_connect_helper(), _mio_link(), mio_connect_st::cb, mio_st::cb, mio_connect_st::cb_arg, mio_st::cb_arg, mio_st::connect_errmsg, mio_connect_st::connected, mio_st::fd, greymatter__, mio_connect_st::ip, mio_main_st::k, make_addr(), mio_st::mh, mio_connect_st::mh, mio_handlers_free(), mio_karma2(), mio_set_handlers(), mio_st::p, mio_st::peer_ip, mio_st::peer_port, pmalloco(), pool_free(), mio_connect_st::port, pstrdup(), mio_st::state, mio_st::type, xhash_new(), xhash_put(), xmlnode_get_data(), xmlnode_get_list_item(), xmlnode_get_tags(), mio_main_st::zzz, and mio_main_st::zzz_active.

Referenced by mio_connect().

                                     {
    connect_data  cd = (connect_data)arg;
#ifdef WITH_IPV6
    struct sockaddr_in6 sa;
    struct in6_addr     *saddr;
#else
    struct sockaddr_in  sa;
    struct in_addr*     saddr;
#endif
    int                 flag = 1,
                  flags;
    mio                 newm;
    pool          p;
    sigset_t            set;
    static xht          namespaces = NULL;

    if (namespaces == NULL) {
      namespaces = xhash_new(3);
      xhash_put(namespaces, "", const_cast<char*>(NS_JABBERD_CONFIGFILE));
    }

    /* _mio_connect_timeout() is sending SIGUSR2 to signal a connect timeout */
    sigemptyset(&set);
    sigaddset(&set, SIGUSR2);
    pth_sigmask(SIG_BLOCK, &set, NULL);

    bzero((void*)&sa, sizeof(sa));

    /* create the new mio object, can't call mio_new.. don't want it in select yet */
    p           = pool_new();
    newm         = static_cast<mio>(pmalloco(p, sizeof(_mio)));
    newm->p      = p;
    newm->type   = type_NORMAL;
    newm->state  = state_ACTIVE;
    newm->peer_ip= pstrdup(p,cd->ip);
    newm->peer_port = cd->port;
    newm->cb     = cd->cb;
    newm->cb_arg = cd->cb_arg;
    mio_set_handlers(newm, cd->mh);

    /* create a socket to connect with */
#ifdef WITH_IPV6
    newm->fd = socket(PF_INET6, SOCK_STREAM,0);
#else
    newm->fd = socket(PF_INET, SOCK_STREAM,0);
#endif

    /* set socket options */
    if (newm->fd < 0 || setsockopt(newm->fd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0) {
      /* get the error message */
      newm->connect_errmsg = strerror(errno);
      
        if (cd->cb != NULL)
            (*cd->cb)(newm, MIO_CLOSED, cd->cb_arg, NULL, NULL, 0);
        cd->connected = -1;

        mio_handlers_free(newm->mh);
        if (newm->fd > 0)
            close(newm->fd);
        pool_free(p);
        return NULL;
    }

    /* optionally bind to a local address */
    pool temp_pool = pool_new();
    if (xmlnode_get_data(xmlnode_get_list_item(xmlnode_get_tags(greymatter__, "io/bind", namespaces, temp_pool), 0)) != NULL) {
#ifdef WITH_IPV6
      struct sockaddr_in6 sa;
      char *addr_str = xmlnode_get_data(xmlnode_get_list_item(xmlnode_get_tags(greymatter__, "io/bind", namespaces, temp_pool), 0));
      char temp_addr[INET6_ADDRSTRLEN];
      struct in_addr tmp;

      if (inet_pton(AF_INET, addr_str, &tmp)) {
          strcpy(temp_addr, "::ffff:");
          strcat(temp_addr, addr_str);
          addr_str = temp_addr;
      }

      sa.sin6_family = AF_INET6;
      sa.sin6_port = 0;
      sa.sin6_flowinfo = 0;

      inet_pton(AF_INET6, addr_str, &sa.sin6_addr);
#else
        struct sockaddr_in sa;
        sa.sin_family = AF_INET;
        sa.sin_port   = 0;
        inet_aton(xmlnode_get_data(xmlnode_get_list_item(xmlnode_get_tags(greymatter__, "io/bind", namespaces, temp_pool), 0)), &sa.sin_addr);
#endif
        bind(newm->fd, (struct sockaddr*)&sa, sizeof(sa));
    }
    pool_free(temp_pool);
    temp_pool = NULL;

    /* parse the IP to connect to */
#ifdef WITH_IPV6
    saddr = make_addr_ipv6(cd->ip);
#else
    saddr = make_addr(cd->ip);
#endif
    if (saddr == NULL) {
      newm->connect_errmsg = "Could not resolve hostname or parse IP address";
        if (cd->cb != NULL)
            (*cd->cb)(newm, MIO_CLOSED, cd->cb_arg, NULL, NULL, 0);
        cd->connected = -1;

        mio_handlers_free(newm->mh);
        if (newm->fd > 0)
            close(newm->fd);
        pool_free(p);
        return NULL;
    }

#ifdef WITH_IPV6
    sa.sin6_family = AF_INET6;
    sa.sin6_port = htons(cd->port);
    sa.sin6_addr = *saddr;
#else
    sa.sin_family = AF_INET;
    sa.sin_port = htons(cd->port);
    sa.sin_addr.s_addr = saddr->s_addr;
#endif

    log_debug2(ZONE, LOGT_IO, "calling the connect handler for mio object %X", newm);
    if (_mio_connect_helper(newm, (struct sockaddr*)&sa, sizeof sa) < 0) {
      /* get the error message */
      newm->connect_errmsg = strerror(errno);

        if (cd->cb != NULL)
            (*cd->cb)(newm, MIO_CLOSED, cd->cb_arg, NULL, NULL, 0);
        cd->connected = -1;

        if (newm->fd > 0)
            close(newm->fd);
        mio_handlers_free(newm->mh);
        pool_free(p);
        return NULL;
    }

    newm->connect_errmsg = "";

    /* set the socket to non-blocking */
    flags =  fcntl(newm->fd, F_GETFL, 0);
    flags |= O_NONBLOCK;
    fcntl(newm->fd, F_SETFL, flags);

    /* XXX pthreads race condition.. cd->connected may be checked in the timeout, and cd freed before these calls */

    /* set the default karma values */
    mio_karma2(newm, mio__data->k);
    
    /* add to the select loop */
    _mio_link(newm);
    cd->connected = 1; 

    /* notify the select loop */
    if (mio__data != NULL) {
      /* we don't have to send multiple signals */
      if (mio__data->zzz_active <= 0) {
          mio__data->zzz_active++;
          pth_write(mio__data->zzz[1]," ",1);
      }
    }

    /* notify the client that the socket is born */
    if (newm->cb != NULL)
        (*newm->cb)(newm, MIO_NEW, newm->cb_arg, NULL, NULL, 0);

    return NULL;
}


Generated by  Doxygen 1.6.0   Back to index