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; }
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; }
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); }
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); }
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; }
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; }