Пример #1
0
int
network_connect_child_timer_cb (void *arg_hook_connect, int remaining_calls)
{
    struct t_hook *hook_connect;

    /* make C compiler happy */
    (void) remaining_calls;

    hook_connect = (struct t_hook *)arg_hook_connect;

    HOOK_CONNECT(hook_connect, hook_child_timer) = NULL;

    (void) (HOOK_CONNECT(hook_connect, callback))
        (hook_connect->callback_data,
         WEECHAT_HOOK_CONNECT_TIMEOUT,
         0, NULL, NULL);
    unhook (hook_connect);

    return WEECHAT_RC_OK;
}
int pa__init (pa_module *m)
{
  struct userdata *u;

  u = pa_xnew (struct userdata, 1);
  u->c = m->core;
  u->m = m;


  /* connect hooks */
  u->sink_input_new_cb = HOOK_CONNECT(m, PA_CORE_HOOK_SINK_INPUT_NEW, PA_HOOK_EARLY, sink_input_new_callback, u);
  u->sink_input_fixate_cb = HOOK_CONNECT(m, PA_CORE_HOOK_SINK_INPUT_FIXATE, PA_HOOK_EARLY, sink_input_fixate_callback, u);
  u->sink_input_put_cb = HOOK_CONNECT(m, PA_CORE_HOOK_SINK_INPUT_PUT, PA_HOOK_EARLY, sink_input_put_callback, u);
  u->sink_input_state_changed_cb = HOOK_CONNECT(m, PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED, PA_HOOK_EARLY, 
    sink_input_state_changed_callback, u);
  u->sink_input_unlink_cb = HOOK_CONNECT(m, PA_CORE_HOOK_SINK_INPUT_UNLINK, PA_HOOK_EARLY,
    sink_input_unlink_callback, u);
 u->sink_input_unlink_post_cb = HOOK_CONNECT(m, PA_CORE_HOOK_SINK_INPUT_UNLINK, PA_HOOK_EARLY, 
    sink_input_unlink_post_callback, u);



  
  pa_log_info ("pa_core(%p) : pa_module(%p)\n", u->c, u->m);

  
  
  return 0;
}
Пример #3
0
int
network_connect_gnutls_handshake_timer_cb (void *arg_hook_connect,
                                           int remaining_calls)
{
    struct t_hook *hook_connect;

    /* make C compiler happy */
    (void) remaining_calls;

    hook_connect = (struct t_hook *)arg_hook_connect;

    HOOK_CONNECT(hook_connect, handshake_hook_timer) = NULL;

    (void) (HOOK_CONNECT(hook_connect, callback))
            (hook_connect->callback_data,
             WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
             GNUTLS_E_EXPIRED,
             gnutls_strerror (GNUTLS_E_EXPIRED),
             HOOK_CONNECT(hook_connect, handshake_ip_address));
    unhook (hook_connect);

    return WEECHAT_RC_OK;
}
Пример #4
0
void
network_connect_child (struct t_hook *hook_connect)
{
    struct t_proxy *ptr_proxy;
    struct addrinfo hints, *res, *res_local, *ptr_res;
    char status_str[2], *ptr_address, *status_with_string;
    char ipv4_address[INET_ADDRSTRLEN + 1], ipv6_address[INET6_ADDRSTRLEN + 1];
    char status_without_string[1 + 5 + 1];
    const char *error;
    int rc, length, num_written;

    res = NULL;
    res_local = NULL;

    status_str[1] = '\0';

    ptr_address = NULL;

    ptr_proxy = NULL;
    if (HOOK_CONNECT(hook_connect, proxy)
        && HOOK_CONNECT(hook_connect, proxy)[0])
    {
        ptr_proxy = proxy_search (HOOK_CONNECT(hook_connect, proxy));
        if (!ptr_proxy)
        {
            /* proxy not found */
            snprintf (status_without_string, sizeof (status_without_string),
                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_PROXY_ERROR);
            num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                 status_without_string, strlen (status_without_string));
            (void) num_written;
            return;
        }
    }

    if (ptr_proxy)
    {
        /* get info about peer */
        memset (&hints, 0, sizeof (hints));
        hints.ai_family = (CONFIG_BOOLEAN(ptr_proxy->options[PROXY_OPTION_IPV6])) ?
            AF_INET6 : AF_INET;
        hints.ai_socktype = SOCK_STREAM;
        rc = getaddrinfo (CONFIG_STRING(ptr_proxy->options[PROXY_OPTION_ADDRESS]), NULL, &hints, &res);
        if (rc != 0)
        {
            /* address not found */
            status_with_string = NULL;
            error = gai_strerror (rc);
            if (error)
            {
                length = 1 + 5 + strlen (error) + 1;
                status_with_string = malloc (length);
                if (status_with_string)
                {
                    snprintf (status_with_string, length, "%c%05d%s",
                              '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND,
                              (int)strlen (error), error);
                }
            }
            if (status_with_string)
            {
                num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                     status_with_string, strlen (status_with_string));
            }
            else
            {
                snprintf (status_without_string, sizeof (status_without_string),
                          "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
                num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                     status_without_string, strlen (status_without_string));
            }
            if (status_with_string)
                free (status_with_string);
            (void) num_written;
            return;
        }
        if (!res)
        {
            /* adddress not found */
            snprintf (status_without_string, sizeof (status_without_string),
                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
            num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                 status_without_string, strlen (status_without_string));
            (void) num_written;
            return;
        }
        if ((CONFIG_BOOLEAN(ptr_proxy->options[PROXY_OPTION_IPV6]) && (res->ai_family != AF_INET6))
            || ((!CONFIG_BOOLEAN(ptr_proxy->options[PROXY_OPTION_IPV6]) && (res->ai_family != AF_INET))))
        {
            /* IP address not found */
            snprintf (status_without_string, sizeof (status_without_string),
                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND);
            num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                 status_without_string, strlen (status_without_string));
            (void) num_written;
            freeaddrinfo (res);
            return;
        }

        if (CONFIG_BOOLEAN(ptr_proxy->options[PROXY_OPTION_IPV6]))
            ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port = htons (CONFIG_INTEGER(ptr_proxy->options[PROXY_OPTION_PORT]));
        else
            ((struct sockaddr_in *)(res->ai_addr))->sin_port = htons (CONFIG_INTEGER(ptr_proxy->options[PROXY_OPTION_PORT]));

        /* connect to peer */
        if (!network_connect (HOOK_CONNECT(hook_connect, sock),
                              res->ai_addr, res->ai_addrlen))
        {
            /* connection refused */
            snprintf (status_without_string, sizeof (status_without_string),
                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED);
            num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                 status_without_string, strlen (status_without_string));
            (void) num_written;
            freeaddrinfo (res);
            return;
        }

        if (!network_pass_proxy (HOOK_CONNECT(hook_connect, proxy),
                                 HOOK_CONNECT(hook_connect, sock),
                                 HOOK_CONNECT(hook_connect, address),
                                 HOOK_CONNECT(hook_connect, port)))
        {
            /* proxy fails to connect to peer */
            snprintf (status_without_string, sizeof (status_without_string),
                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_PROXY_ERROR);
            num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                 status_without_string, strlen (status_without_string));
            (void) num_written;
            freeaddrinfo (res);
            return;
        }

        status_str[0] = '0' + WEECHAT_HOOK_CONNECT_OK;
    }
    else
    {
        /* set local hostname/IP if asked by user */
        if (HOOK_CONNECT(hook_connect, local_hostname)
            && HOOK_CONNECT(hook_connect, local_hostname[0]))
        {
            memset (&hints, 0, sizeof(hints));
            hints.ai_family = (HOOK_CONNECT(hook_connect, ipv6)) ? AF_INET6 : AF_INET;
            hints.ai_socktype = SOCK_STREAM;
            rc = getaddrinfo (HOOK_CONNECT(hook_connect, local_hostname),
                              NULL, &hints, &res_local);
            if (rc != 0)
            {
                /* fails to set local hostname/IP */
                status_with_string = NULL;
                error = gai_strerror (rc);
                if (error)
                {
                    length = 1 + 5 + strlen (error) + 1;
                    status_with_string = malloc (length);
                    if (status_with_string)
                    {
                        snprintf (status_with_string, length, "%c%05d%s",
                                  '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR,
                                  (int)strlen (error), error);
                    }
                }
                if (status_with_string)
                {
                    num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                         status_with_string, strlen (status_with_string));
                }
                else
                {
                    snprintf (status_without_string, sizeof (status_without_string),
                              "%c00000", '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR);
                    num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                         status_without_string, strlen (status_without_string));
                }
                if (status_with_string)
                    free (status_with_string);
                (void) num_written;
                if (res_local)
                    freeaddrinfo (res_local);
                return;
            }
            else if (!res_local
                     || (HOOK_CONNECT(hook_connect, ipv6)
                         && (res_local->ai_family != AF_INET6))
                     || ((!HOOK_CONNECT(hook_connect, ipv6)
                          && (res_local->ai_family != AF_INET))))
            {
                /* fails to set local hostname/IP */
                snprintf (status_without_string, sizeof (status_without_string),
                          "%c00000", '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR);
                num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                     status_without_string, strlen (status_without_string));
                (void) num_written;
                if (res_local)
                    freeaddrinfo (res_local);
                return;
            }
            if (bind (HOOK_CONNECT(hook_connect, sock),
                      res_local->ai_addr, res_local->ai_addrlen) < 0)
            {
                /* fails to set local hostname/IP */
                snprintf (status_without_string, sizeof (status_without_string),
                          "%c00000", '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR);
                num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                     status_without_string, strlen (status_without_string));
                (void) num_written;
                if (res_local)
                    freeaddrinfo (res_local);
                return;
            }
        }

        /* get info about peer */
        memset (&hints, 0, sizeof(hints));
        hints.ai_family = (HOOK_CONNECT(hook_connect, ipv6)) ? AF_INET6 : AF_INET;
        hints.ai_socktype = SOCK_STREAM;
        rc = getaddrinfo (HOOK_CONNECT(hook_connect, address),
                          NULL, &hints, &res);
        if (rc != 0)
        {
            status_with_string = NULL;
            error = gai_strerror (rc);
            if (error)
            {
                length = 1 + 5 + strlen (error) + 1;
                status_with_string = malloc (length);
                if (status_with_string)
                {
                    snprintf (status_with_string, length, "%c%05d%s",
                              '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND,
                              (int)strlen (error), error);
                }
            }
            if (status_with_string)
            {
                num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                     status_with_string, strlen (status_with_string));
            }
            else
            {
                snprintf (status_without_string, sizeof (status_without_string),
                          "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
                num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                     status_without_string, strlen (status_without_string));
            }
            if (status_with_string)
                free (status_with_string);
            (void) num_written;
            if (res)
                freeaddrinfo (res);
            if (res_local)
                freeaddrinfo (res_local);
            return;
        }
        else if (!res)
        {
            /* address not found */
            snprintf (status_without_string, sizeof (status_without_string),
                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
            num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                 status_without_string, strlen (status_without_string));
            (void) num_written;
            if (res)
                freeaddrinfo (res);
            if (res_local)
                freeaddrinfo (res_local);
            return;
        }

        status_str[0] = '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND;

        /* try all IP addresses found, stop when connection is ok */
        for (ptr_res = res; ptr_res; ptr_res = ptr_res->ai_next)
        {
            /* skip IP address if it's not good family */
            if ((HOOK_CONNECT(hook_connect, ipv6) && (ptr_res->ai_family != AF_INET6))
                || ((!HOOK_CONNECT(hook_connect, ipv6) && (ptr_res->ai_family != AF_INET))))
                continue;

            /* connect to peer */
            if (HOOK_CONNECT(hook_connect, ipv6))
                ((struct sockaddr_in6 *)(ptr_res->ai_addr))->sin6_port =
                    htons (HOOK_CONNECT(hook_connect, port));
            else
                ((struct sockaddr_in *)(ptr_res->ai_addr))->sin_port =
                    htons (HOOK_CONNECT(hook_connect, port));

            if (network_connect (HOOK_CONNECT(hook_connect, sock),
                                 ptr_res->ai_addr, ptr_res->ai_addrlen))
            {
                status_str[0] = '0' + WEECHAT_HOOK_CONNECT_OK;
                if (HOOK_CONNECT(hook_connect, ipv6))
                {
                    if (inet_ntop (AF_INET6,
                                   &((struct sockaddr_in6 *)(ptr_res->ai_addr))->sin6_addr,
                                   ipv6_address,
                                   INET6_ADDRSTRLEN))
                    {
                        ptr_address = ipv6_address;
                    }
                }
                else
                {
                    if (inet_ntop (AF_INET,
                                   &((struct sockaddr_in *)(ptr_res->ai_addr))->sin_addr,
                                   ipv4_address,
                                   INET_ADDRSTRLEN))
                    {
                        ptr_address = ipv4_address;
                    }
                }
                break;
            }
            else
                status_str[0] = '0' + WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED;
        }
    }

    if (status_str[0] == '0' + WEECHAT_HOOK_CONNECT_OK)
    {
        status_with_string = NULL;
        if (ptr_address)
        {
            length = strlen (status_str) + 5 + strlen (ptr_address) + 1;
            status_with_string = malloc (length);
            if (status_with_string)
            {
                snprintf (status_with_string, length, "%s%05d%s",
                          status_str, (int)strlen (ptr_address), ptr_address);
            }
        }

        if (status_with_string)
        {
            num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                 status_with_string, strlen (status_with_string));
            (void) num_written;
            free (status_with_string);
        }
        else
        {
            snprintf (status_without_string, sizeof (status_without_string),
                      "%s00000", status_str);
            num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                 status_without_string, strlen (status_without_string));
            (void) num_written;
        }
    }
    else
    {
        snprintf (status_without_string, sizeof (status_without_string),
                  "%s00000", status_str);
        num_written = write (HOOK_CONNECT(hook_connect, child_write),
                             status_without_string, strlen (status_without_string));
        (void) num_written;
    }

    if (res)
        freeaddrinfo (res);
    if (res_local)
        freeaddrinfo (res_local);
}
Пример #5
0
void
network_connect_with_fork (struct t_hook *hook_connect)
{
    int child_pipe[2];
#ifdef HAVE_GNUTLS
    int rc;
    const char *pos_error;
#endif
    pid_t pid;

#ifdef HAVE_GNUTLS
    /* initialize GnuTLS if SSL asked */
    if (HOOK_CONNECT(hook_connect, gnutls_sess))
    {
        if (gnutls_init (HOOK_CONNECT(hook_connect, gnutls_sess), GNUTLS_CLIENT) != GNUTLS_E_SUCCESS)
        {
            (void) (HOOK_CONNECT(hook_connect, callback))
                (hook_connect->callback_data,
                 WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR,
                 0, NULL, NULL);
            unhook (hook_connect);
            return;
        }
        rc = gnutls_priority_set_direct (*HOOK_CONNECT(hook_connect, gnutls_sess),
                                         HOOK_CONNECT(hook_connect, gnutls_priorities),
                                         &pos_error);
        if (rc != GNUTLS_E_SUCCESS)
        {
            (void) (HOOK_CONNECT(hook_connect, callback))
                (hook_connect->callback_data,
                 WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR,
                 0, _("invalid priorities"), NULL);
            unhook (hook_connect);
            return;
        }
        gnutls_credentials_set (*HOOK_CONNECT(hook_connect, gnutls_sess),
                                GNUTLS_CRD_CERTIFICATE,
                                gnutls_xcred);
        gnutls_transport_set_ptr (*HOOK_CONNECT(hook_connect, gnutls_sess),
                                  (gnutls_transport_ptr) ((unsigned long) HOOK_CONNECT(hook_connect, sock)));
    }
#endif

    /* create pipe for child process */
    if (pipe (child_pipe) < 0)
    {
        (void) (HOOK_CONNECT(hook_connect, callback))
            (hook_connect->callback_data,
             WEECHAT_HOOK_CONNECT_MEMORY_ERROR,
             0, NULL, NULL);
        unhook (hook_connect);
        return;
    }
    HOOK_CONNECT(hook_connect, child_read) = child_pipe[0];
    HOOK_CONNECT(hook_connect, child_write) = child_pipe[1];

    switch (pid = fork ())
    {
        /* fork failed */
        case -1:
            (void) (HOOK_CONNECT(hook_connect, callback))
                (hook_connect->callback_data,
                 WEECHAT_HOOK_CONNECT_MEMORY_ERROR,
                 0, NULL, NULL);
            unhook (hook_connect);
            return;
        /* child process */
        case 0:
            setuid (getuid ());
            close (HOOK_CONNECT(hook_connect, child_read));
            network_connect_child (hook_connect);
            _exit (EXIT_SUCCESS);
    }
    /* parent process */
    HOOK_CONNECT(hook_connect, child_pid) = pid;
    close (HOOK_CONNECT(hook_connect, child_write));
    HOOK_CONNECT(hook_connect, child_write) = -1;
    HOOK_CONNECT(hook_connect, hook_child_timer) = hook_timer (hook_connect->plugin,
                                                               CONFIG_INTEGER(config_network_connection_timeout) * 1000,
                                                               0, 1,
                                                               &network_connect_child_timer_cb,
                                                               hook_connect);
    HOOK_CONNECT(hook_connect, hook_fd) = hook_fd (hook_connect->plugin,
                                                   HOOK_CONNECT(hook_connect, child_read),
                                                   1, 0, 0,
                                                   &network_connect_child_read_cb,
                                                   hook_connect);
}
Пример #6
0
int
network_connect_child_read_cb (void *arg_hook_connect, int fd)
{
    struct t_hook *hook_connect;
    char buffer[1], buf_size[6], *cb_error, *cb_ip_address, *error;
    int num_read;
    long size_msg;
#ifdef HAVE_GNUTLS
    int rc, direction;
#endif

    /* make C compiler happy */
    (void) fd;

    hook_connect = (struct t_hook *)arg_hook_connect;

    cb_error = NULL;
    cb_ip_address = NULL;

    num_read = read (HOOK_CONNECT(hook_connect, child_read),
                     buffer, sizeof (buffer));
    if (num_read > 0)
    {
        if (buffer[0] - '0' == WEECHAT_HOOK_CONNECT_OK)
        {
            /* connection ok, read IP address */
            buf_size[5] = '\0';
            num_read = read (HOOK_CONNECT(hook_connect, child_read),
                             buf_size, 5);
            if (num_read == 5)
            {
                error = NULL;
                size_msg = strtol (buf_size, &error, 10);
                if (error && !error[0] && (size_msg > 0))
                {
                    cb_ip_address = malloc (size_msg + 1);
                    if (cb_ip_address)
                    {
                        num_read = read (HOOK_CONNECT(hook_connect, child_read),
                                         cb_ip_address, size_msg);
                        if (num_read == size_msg)
                            cb_ip_address[size_msg] = '\0';
                        else
                        {
                            free (cb_ip_address);
                            cb_ip_address = NULL;
                        }
                    }
                }
            }
#ifdef HAVE_GNUTLS
            if (HOOK_CONNECT(hook_connect, gnutls_sess))
            {
                /*
                 * the socket needs to be non-blocking since the call to
                 * gnutls_handshake can block
                 */
                HOOK_CONNECT(hook_connect, handshake_fd_flags) =
                    fcntl (HOOK_CONNECT(hook_connect, sock), F_GETFL);
                if (HOOK_CONNECT(hook_connect, handshake_fd_flags) == -1)
                    HOOK_CONNECT(hook_connect, handshake_fd_flags) = 0;
                fcntl (HOOK_CONNECT(hook_connect, sock), F_SETFL,
                       HOOK_CONNECT(hook_connect, handshake_fd_flags) | O_NONBLOCK);
                gnutls_transport_set_ptr (*HOOK_CONNECT(hook_connect, gnutls_sess),
                                          (gnutls_transport_ptr) ((ptrdiff_t) HOOK_CONNECT(hook_connect, sock)));
                if (HOOK_CONNECT(hook_connect, gnutls_dhkey_size) > 0)
                {
                    gnutls_dh_set_prime_bits (*HOOK_CONNECT(hook_connect, gnutls_sess),
                                              (unsigned int) HOOK_CONNECT(hook_connect, gnutls_dhkey_size));
                }
                rc = gnutls_handshake (*HOOK_CONNECT(hook_connect, gnutls_sess));
                if ((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED))
                {
                    /*
                     * gnutls was unable to proceed with the handshake without
                     * blocking: non fatal error, we just have to wait for an
                     * event about handshake
                     */
                    unhook (HOOK_CONNECT(hook_connect, hook_fd));
                    HOOK_CONNECT(hook_connect, hook_fd) = NULL;
                    direction = gnutls_record_get_direction (*HOOK_CONNECT(hook_connect, gnutls_sess));
                    HOOK_CONNECT(hook_connect, handshake_ip_address) = cb_ip_address;
                    HOOK_CONNECT(hook_connect, handshake_hook_fd) =
                        hook_fd (hook_connect->plugin,
                                 HOOK_CONNECT(hook_connect, sock),
                                 (!direction ? 1 : 0), (direction  ? 1 : 0), 0,
                                 &network_connect_gnutls_handshake_fd_cb,
                                 hook_connect);
                    HOOK_CONNECT(hook_connect, handshake_hook_timer) =
                        hook_timer (hook_connect->plugin,
                                    CONFIG_INTEGER(config_network_gnutls_handshake_timeout) * 1000,
                                    0, 1,
                                    &network_connect_gnutls_handshake_timer_cb,
                                    hook_connect);
                    return WEECHAT_RC_OK;
                }
                else if (rc != GNUTLS_E_SUCCESS)
                {
                    (void) (HOOK_CONNECT(hook_connect, callback))
                        (hook_connect->callback_data,
                         WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
                         rc,
                         gnutls_strerror (rc),
                         cb_ip_address);
                    unhook (hook_connect);
                    if (cb_ip_address)
                        free (cb_ip_address);
                    return WEECHAT_RC_OK;
                }
                fcntl (HOOK_CONNECT(hook_connect, sock), F_SETFL,
                       HOOK_CONNECT(hook_connect, handshake_fd_flags));
#if LIBGNUTLS_VERSION_NUMBER < 0x02090a
                /*
                 * gnutls only has the gnutls_certificate_set_verify_function()
                 * function since version 2.9.10. We need to call our verify
                 * function manually after the handshake for old gnutls versions
                 */
                if (hook_connect_gnutls_verify_certificates (*HOOK_CONNECT(hook_connect, gnutls_sess)) != 0)
                {
                    (void) (HOOK_CONNECT(hook_connect, callback))
                        (hook_connect->callback_data,
                         WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
                         rc,
                         "Error in the certificate.",
                         cb_ip_address);
                    unhook (hook_connect);
                    if (cb_ip_address)
                        free (cb_ip_address);
                    return WEECHAT_RC_OK;
                }
#endif
            }
#endif
        }
        else
        {
            /* connection error, read error */
            buf_size[5] = '\0';
            num_read = read (HOOK_CONNECT(hook_connect, child_read),
                             buf_size, 5);
            if (num_read == 5)
            {
                error = NULL;
                size_msg = strtol (buf_size, &error, 10);
                if (error && !error[0] && (size_msg > 0))
                {
                    cb_error = malloc (size_msg + 1);
                    if (cb_error)
                    {
                        num_read = read (HOOK_CONNECT(hook_connect, child_read),
                                         cb_error, size_msg);
                        if (num_read == size_msg)
                            cb_error[size_msg] = '\0';
                        else
                        {
                            free (cb_error);
                            cb_error = NULL;
                        }
                    }
                }
            }
        }
        (void) (HOOK_CONNECT(hook_connect, callback))
            (hook_connect->callback_data, buffer[0] - '0', 0,
             cb_error, cb_ip_address);
        unhook (hook_connect);
    }

    if (cb_error)
        free (cb_error);
    if (cb_ip_address)
        free (cb_ip_address);

    return WEECHAT_RC_OK;
}
Пример #7
0
int
network_connect_gnutls_handshake_fd_cb (void *arg_hook_connect, int fd)
{
    struct t_hook *hook_connect;
    int rc, direction, flags;

    /* make C compiler happy */
    (void) fd;

    hook_connect = (struct t_hook *)arg_hook_connect;

    rc = gnutls_handshake (*HOOK_CONNECT(hook_connect, gnutls_sess));

    if ((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED))
    {
        direction = gnutls_record_get_direction (*HOOK_CONNECT(hook_connect, gnutls_sess));
        flags = HOOK_FD(HOOK_CONNECT(hook_connect, handshake_hook_fd), flags);
        if ((((flags & HOOK_FD_FLAG_READ) == HOOK_FD_FLAG_READ)
             && (direction != 0))
            || (((flags & HOOK_FD_FLAG_WRITE) == HOOK_FD_FLAG_WRITE)
                && (direction != 1)))
        {
            HOOK_FD(HOOK_CONNECT(hook_connect, handshake_hook_fd), flags) =
                (direction) ? HOOK_FD_FLAG_WRITE: HOOK_FD_FLAG_READ;
        }
    }
    else if (rc != GNUTLS_E_SUCCESS)
    {
        (void) (HOOK_CONNECT(hook_connect, callback))
            (hook_connect->callback_data,
             WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
             rc,
             gnutls_strerror (rc),
             HOOK_CONNECT(hook_connect, handshake_ip_address));
        unhook (hook_connect);
    }
    else
    {
        fcntl (HOOK_CONNECT(hook_connect, sock), F_SETFL,
               HOOK_CONNECT(hook_connect, handshake_fd_flags));
#if LIBGNUTLS_VERSION_NUMBER < 0x02090a
        /*
         * gnutls only has the gnutls_certificate_set_verify_function()
         * function since version 2.9.10. We need to call our verify
         * function manually after the handshake for old gnutls versions
         */
        if (hook_connect_gnutls_verify_certificates (*HOOK_CONNECT(hook_connect, gnutls_sess)) != 0)
        {
            (void) (HOOK_CONNECT(hook_connect, callback))
                (hook_connect->callback_data,
                 WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
                 rc,
                 "Error in the certificate.",
                 HOOK_CONNECT(hook_connect, handshake_ip_address));
            unhook (hook_connect);
            return WEECHAT_RC_OK;
        }
#endif
        unhook (HOOK_CONNECT(hook_connect, handshake_hook_fd));
        (void) (HOOK_CONNECT(hook_connect, callback))
                (hook_connect->callback_data, WEECHAT_HOOK_CONNECT_OK, 0, NULL,
                 HOOK_CONNECT(hook_connect, handshake_ip_address));
        unhook (hook_connect);
    }

    return WEECHAT_RC_OK;
}