Exemple #1
0
void
xfer_network_send_file_fork (struct t_xfer *xfer)
{
    pid_t pid;
    int rc;

    if (!xfer_network_create_pipe (xfer))
        return;

    xfer->file = open (xfer->local_filename, O_RDONLY | O_NONBLOCK, 0644);

    switch (pid = fork ())
    {
    case -1:  /* fork failed */
        dogechat_printf (NULL,
                         _("%s%s: unable to fork"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME);
        xfer_close (xfer, XFER_STATUS_FAILED);
        xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);
        return;
    case 0:  /* child process */
        rc = setuid (getuid ());
        (void) rc;
        close (xfer->child_read);
        switch (xfer->protocol)
        {
        case XFER_NO_PROTOCOL:
            _exit (EXIT_SUCCESS);
            break;
        case XFER_PROTOCOL_DCC:
            xfer_dcc_send_file_child (xfer);
            break;
        case XFER_NUM_PROTOCOLS:
            break;
        }
        _exit (EXIT_SUCCESS);
    }

    dogechat_printf (NULL,
                     _("%s: sending file to %s (%s, %s.%s), "
                       "name: %s (local filename: %s), %llu bytes (protocol: %s)"),
                     XFER_PLUGIN_NAME,
                     xfer->remote_nick,
                     xfer->remote_address_str,
                     xfer->plugin_name,
                     xfer->plugin_id,
                     xfer->filename,
                     xfer->local_filename,
                     xfer->size,
                     xfer_protocol_string[xfer->protocol]);

    /* parent process */
    xfer->child_pid = pid;
    close (xfer->child_write);
    xfer->child_write = -1;
    xfer->hook_fd = dogechat_hook_fd (xfer->child_read,
                                      1, 0, 0,
                                      &xfer_network_child_read_cb,
                                      xfer);
}
Exemple #2
0
void
xfer_network_recv_file_fork (struct t_xfer *xfer)
{
    pid_t pid;
    int rc;

    if (!xfer_network_create_pipe (xfer))
        return;

    if (xfer->start_resume > 0)
        xfer->file = open (xfer->local_filename,
                           O_APPEND | O_WRONLY | O_NONBLOCK);
    else
        xfer->file = open (xfer->local_filename,
                           O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
                           0644);

    switch (pid = fork ())
    {
    case -1:  /* fork failed */
        dogechat_printf (NULL,
                         _("%s%s: unable to fork"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME);
        xfer_close (xfer, XFER_STATUS_FAILED);
        xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);
        return;
    case 0:  /* child process */
        rc = setuid (getuid ());
        (void) rc;
        close (xfer->child_read);
        switch (xfer->protocol)
        {
        case XFER_NO_PROTOCOL:
            _exit (EXIT_SUCCESS);
            break;
        case XFER_PROTOCOL_DCC:
            xfer_dcc_recv_file_child (xfer);
            break;
        case XFER_NUM_PROTOCOLS:
            break;
        }
        _exit (EXIT_SUCCESS);
    }

    /* parent process */
    xfer->child_pid = pid;
    close (xfer->child_write);
    xfer->child_write = -1;
    xfer->hook_fd = dogechat_hook_fd (xfer->child_read,
                                      1, 0, 0,
                                      &xfer_network_child_read_cb,
                                      xfer);
}
Exemple #3
0
int
relay_server_create_socket (struct t_relay_server *server)
{
    int domain, set, max_clients, addr_size;
    struct sockaddr_in server_addr;
    struct sockaddr_in6 server_addr6;
    const char *bind_address;
    void *ptr_addr;

    bind_address = dogechat_config_string (relay_config_network_bind_address);

    if (server->ipv6)
    {
        domain = AF_INET6;
        memset (&server_addr6, 0, sizeof (struct sockaddr_in6));
        server_addr6.sin6_family = domain;
        server_addr6.sin6_port = htons (server->port);
        server_addr6.sin6_addr = in6addr_any;
        if (bind_address && bind_address[0])
        {
            if (!inet_pton (domain, bind_address, &server_addr6.sin6_addr))
            {
                dogechat_printf (NULL,
                                /* TRANSLATORS: second "%s" is "IPv4" or "IPv6" */
                                _("%s%s: invalid bind address \"%s\" for %s"),
                                dogechat_prefix ("error"), RELAY_PLUGIN_NAME,
                                bind_address, "IPv6");
                return 0;
            }
        }
        ptr_addr = &server_addr6;
        addr_size = sizeof (struct sockaddr_in6);
    }
    else
    {
        domain = AF_INET;
        memset (&server_addr, 0, sizeof (struct sockaddr_in));
        server_addr.sin_family = domain;
        server_addr.sin_port = htons (server->port);
        server_addr.sin_addr.s_addr = INADDR_ANY;
        if (bind_address && bind_address[0])
        {
            if (!inet_pton (domain, bind_address, &server_addr.sin_addr))
            {
                dogechat_printf (NULL,
                                /* TRANSLATORS: second "%s" is "IPv4" or "IPv6" */
                                _("%s%s: invalid bind address \"%s\" for %s"),
                                dogechat_prefix ("error"), RELAY_PLUGIN_NAME,
                                bind_address, "IPv4");
                return 0;
            }
        }
        ptr_addr = &server_addr;
        addr_size = sizeof (struct sockaddr_in);
    }

    /* create socket */
    server->sock = socket (domain, SOCK_STREAM, 0);
    if (server->sock < 0)
    {
        dogechat_printf (NULL,
                        _("%s%s: cannot create socket: error %d %s"),
                        dogechat_prefix ("error"), RELAY_PLUGIN_NAME,
                        errno, strerror (errno));
        if (errno == EAFNOSUPPORT)
        {
            dogechat_printf (NULL,
                            _("%s%s: try /set relay.network.ipv6 off"),
                            dogechat_prefix ("error"), RELAY_PLUGIN_NAME);
        }
        return 0;
    }

#ifdef IPV6_V6ONLY
    /* set option IPV6_V6ONLY to 0 or 1 */
    if (server->ipv6)
    {
        set = (server->ipv4) ? 0 : 1;
        if (setsockopt (server->sock, IPPROTO_IPV6, IPV6_V6ONLY,
                        (void *) &set, sizeof (set)) < 0)
        {
            dogechat_printf (NULL,
                            _("%s%s: cannot set socket option \"%s\" "
                              "to %d: error %d %s"),
                            dogechat_prefix ("error"), RELAY_PLUGIN_NAME,
                            "IPV6_V6ONLY", set, errno, strerror (errno));
            close (server->sock);
            server->sock = -1;
            return 0;
        }
    }
#endif /* IPV6_V6ONLY */

    /* set option SO_REUSEADDR to 1 */
    set = 1;
    if (setsockopt (server->sock, SOL_SOCKET, SO_REUSEADDR,
                    (void *) &set, sizeof (set)) < 0)
    {
        dogechat_printf (NULL,
                        _("%s%s: cannot set socket option \"%s\" to %d: "
                          "error %d %s"),
                        dogechat_prefix ("error"), RELAY_PLUGIN_NAME,
                        "SO_REUSEADDR", set, errno, strerror (errno));
        close (server->sock);
        server->sock = -1;
        return 0;
    }

    /* set option SO_KEEPALIVE to 1 */
    set = 1;
    if (setsockopt (server->sock, SOL_SOCKET, SO_KEEPALIVE,
                    (void *) &set, sizeof (set)) < 0)
    {
        dogechat_printf (NULL,
                        _("%s%s: cannot set socket option \"%s\" to %d: "
                          "error %d %s"),
                        dogechat_prefix ("error"), RELAY_PLUGIN_NAME,
                        "SO_KEEPALIVE", set, errno, strerror (errno));
        close (server->sock);
        server->sock = -1;
        return 0;
    }

    /* bind */
    if (bind (server->sock, (struct sockaddr *)ptr_addr, addr_size) < 0)
    {
        dogechat_printf (NULL,
                        _("%s%s: cannot \"bind\" on port %d (%s): error %d %s"),
                        dogechat_prefix ("error"), RELAY_PLUGIN_NAME,
                        server->port, server->protocol_string,
                        errno, strerror (errno));
        close (server->sock);
        server->sock = -1;
        return 0;
    }

    max_clients = dogechat_config_integer (relay_config_network_max_clients);

    if (listen (server->sock, max_clients) != 0)
    {
        dogechat_printf (NULL,
                        _("%s%s: cannot \"listen\" on port %d (%s): error %d %s"),
                        dogechat_prefix ("error"), RELAY_PLUGIN_NAME,
                        server->port, server->protocol_string,
                        errno, strerror (errno));
        close (server->sock);
        server->sock = -1;
        return 0;
    }

    dogechat_printf (NULL,
                    _("%s: listening on port %d (relay: %s, %s, max %d clients)"),
                    RELAY_PLUGIN_NAME,
                    server->port,
                    server->protocol_string,
                    ((server->ipv4 && server->ipv6) ? "IPv4+6" : ((server->ipv6) ? "IPv6" : "IPv4")),
                    max_clients);

    server->hook_fd = dogechat_hook_fd (server->sock,
                                       1, 0, 0,
                                       &relay_server_sock_cb,
                                       server);

    server->start_time = time (NULL);

    return 1;
}
Exemple #4
0
int
fifo_read (void *data, int fd)
{
    static char buffer[4096 + 2];
    char *buf2, *pos, *ptr_buf, *next_ptr_buf;
    int num_read;

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

    num_read = read (fifo_fd, buffer, sizeof (buffer) - 2);
    if (num_read > 0)
    {
        buffer[num_read] = '\0';

        buf2 = NULL;
        ptr_buf = buffer;
        if (fifo_unterminated)
        {
            buf2 = malloc (strlen (fifo_unterminated) +
                           strlen (buffer) + 1);
            if (buf2)
            {
                strcpy (buf2, fifo_unterminated);
                strcat (buf2, buffer);
            }
            ptr_buf = buf2;
            free (fifo_unterminated);
            fifo_unterminated = NULL;
        }

        while (ptr_buf && ptr_buf[0])
        {
            next_ptr_buf = NULL;
            pos = strstr (ptr_buf, "\r\n");
            if (pos)
            {
                pos[0] = '\0';
                next_ptr_buf = pos + 2;
            }
            else
            {
                pos = strstr (ptr_buf, "\n");
                if (pos)
                {
                    pos[0] = '\0';
                    next_ptr_buf = pos + 1;
                }
                else
                {
                    fifo_unterminated = strdup (ptr_buf);
                    ptr_buf = NULL;
                    next_ptr_buf = NULL;
                }
            }

            if (ptr_buf)
                fifo_exec (ptr_buf);

            ptr_buf = next_ptr_buf;
        }

        if (buf2)
            free (buf2);
    }
    else
    {
        if (num_read < 0)
        {
#ifdef __CYGWIN__
            if ((errno == EAGAIN) || (errno == ECOMM))
#else
            if (errno == EAGAIN)
#endif /* __CYGWIN__ */
                return DOGECHAT_RC_OK;

            dogechat_printf (NULL,
                            _("%s%s: error reading pipe (%d %s), closing it"),
                            dogechat_prefix ("error"), FIFO_PLUGIN_NAME,
                            errno, strerror (errno));
            fifo_remove ();
        }
        else
        {
            dogechat_unhook (fifo_fd_hook);
            fifo_fd_hook = NULL;
            close (fifo_fd);
            fifo_fd = open (fifo_filename, O_RDONLY | O_NONBLOCK);
            if (fifo_fd < 0)
            {
                dogechat_printf (NULL,
                                _("%s%s: error opening file, closing it"),
                                dogechat_prefix ("error"), FIFO_PLUGIN_NAME);
                fifo_remove ();
            }
            else
                fifo_fd_hook = dogechat_hook_fd (fifo_fd, 1, 0, 0,
                                                &fifo_read, NULL);
        }
    }

    return DOGECHAT_RC_OK;
}
Exemple #5
0
void
fifo_create ()
{
    int filename_length;
    const char *fifo_option, *dogechat_home;

    fifo_option = dogechat_config_get_plugin ("fifo");
    if (!fifo_option)
    {
        dogechat_config_set_plugin ("fifo", "on");
        fifo_option = dogechat_config_get_plugin ("fifo");
    }

    dogechat_home = dogechat_info_get ("dogechat_dir", "");

    if (fifo_option && dogechat_home)
    {
        fifo_remove_old_pipes ();

        if (dogechat_strcasecmp (fifo_option, "on") == 0)
        {
            /*
             * build FIFO filename:
             *   "<dogechat_home>/dogechat_fifo_" + process PID
             */
            if (!fifo_filename)
            {
                filename_length = strlen (dogechat_home) + 64;
                fifo_filename = malloc (filename_length);
                snprintf (fifo_filename, filename_length,
                          "%s/%s%d",
                          dogechat_home, FIFO_FILENAME_PREFIX, (int) getpid());
            }

            fifo_fd = -1;

            /* create FIFO pipe, writable for user only */
            if (mkfifo (fifo_filename, 0600) == 0)
            {
                /* open FIFO pipe in read-only, non-blocking mode */
                if ((fifo_fd = open (fifo_filename,
                                     O_RDONLY | O_NONBLOCK)) != -1)
                {
                    if ((dogechat_fifo_plugin->debug >= 1) || !fifo_quiet)
                    {
                        dogechat_printf (NULL,
                                        _("%s: pipe opened (file: %s)"),
                                        FIFO_PLUGIN_NAME,
                                        fifo_filename);
                    }
                    fifo_fd_hook = dogechat_hook_fd (fifo_fd, 1, 0, 0,
                                                    &fifo_read, NULL);
                }
                else
                    dogechat_printf (NULL,
                                    _("%s%s: unable to open pipe (%s) for "
                                      "reading"),
                                    dogechat_prefix ("error"), FIFO_PLUGIN_NAME,
                                    fifo_filename);
            }
            else
            {
                dogechat_printf (NULL,
                                _("%s%s: unable to create pipe for remote "
                                  "control (%s): error %d %s"),
                                dogechat_prefix ("error"), FIFO_PLUGIN_NAME,
                                fifo_filename, errno, strerror (errno));
            }
        }
    }
}
Exemple #6
0
int
xfer_network_connect (struct t_xfer *xfer)
{
    int flags;

    if (xfer->type == XFER_TYPE_CHAT_SEND)
        xfer->status = XFER_STATUS_WAITING;
    else
        xfer->status = XFER_STATUS_CONNECTING;

    if (XFER_IS_SEND(xfer->type))
    {
        /* create socket */
        if (xfer->sock < 0)
        {
            xfer->sock = socket (xfer->local_address->sa_family, SOCK_STREAM,
                                 0);
            if (xfer->sock < 0)
                return 0;
        }

        /* listen to socket */
        flags = fcntl (xfer->sock, F_GETFL);
        if (flags == -1)
            flags = 0;
        if (fcntl (xfer->sock, F_SETFL, flags | O_NONBLOCK) == -1)
            return 0;
        if (listen (xfer->sock, 1) == -1)
            return 0;
        if (fcntl (xfer->sock, F_SETFL, flags) == -1)
            return 0;

        xfer->hook_fd = dogechat_hook_fd (xfer->sock,
                                          1, 0, 0,
                                          &xfer_network_fd_cb,
                                          xfer);

        /* add timeout */
        if (dogechat_config_integer (xfer_config_network_timeout) > 0)
        {
            xfer->hook_timer = dogechat_hook_timer (dogechat_config_integer (xfer_config_network_timeout) * 1000,
                                                    0, 1,
                                                    &xfer_network_timer_cb,
                                                    xfer);
        }
    }

    /* for chat receiving, connect to listening host */
    if (xfer->type == XFER_TYPE_CHAT_RECV)
    {
        xfer->hook_connect = dogechat_hook_connect (xfer->proxy,
                             xfer->remote_address_str,
                             xfer->port, 1, 0, NULL, NULL,
                             0, "NONE", NULL,
                             &xfer_network_connect_chat_recv_cb,
                             xfer);
    }

    /* for file receiving, connection is made in child process (blocking) */

    return 1;
}
Exemple #7
0
int
xfer_network_connect_chat_recv_cb (void *data, int status, int gnutls_rc,
                                   int sock, const char *error,
                                   const char *ip_address)
{
    struct t_xfer *xfer;
    int flags;

    /* make C compiler happy */
    (void) gnutls_rc;
    (void) ip_address;

    xfer = (struct t_xfer*)data;

    dogechat_unhook (xfer->hook_connect);
    xfer->hook_connect = NULL;

    /* connection OK? */
    if (status == DOGECHAT_HOOK_CONNECT_OK)
    {
        xfer->sock = sock;

        flags = fcntl (xfer->sock, F_GETFL);
        if (flags == -1)
            flags = 0;
        if (fcntl (xfer->sock, F_SETFL, flags | O_NONBLOCK) == -1)
        {
            dogechat_printf (NULL,
                             _("%s%s: unable to set option \"nonblock\" "
                               "for socket: error %d %s"),
                             dogechat_prefix ("error"), XFER_PLUGIN_NAME,
                             errno, strerror (errno));
            close (xfer->sock);
            xfer->sock = -1;
            xfer_close (xfer, XFER_STATUS_FAILED);
            xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);
            return DOGECHAT_RC_OK;
        }

        xfer->hook_fd = dogechat_hook_fd (xfer->sock,
                                          1, 0, 0,
                                          &xfer_chat_recv_cb,
                                          xfer);

        xfer_chat_open_buffer (xfer);
        xfer->status = XFER_STATUS_ACTIVE;
        xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);

        return DOGECHAT_RC_OK;
    }

    /* connection error */
    switch (status)
    {
    case DOGECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND:
        dogechat_printf (NULL,
                         (xfer->proxy && xfer->proxy[0]) ?
                         _("%s%s: proxy address \"%s\" not found") :
                         _("%s%s: address \"%s\" not found"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME,
                         xfer->remote_address_str);
        break;
    case DOGECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND:
        dogechat_printf (NULL,
                         (xfer->proxy && xfer->proxy[0]) ?
                         _("%s%s: proxy IP address not found") :
                         _("%s%s: IP address not found"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME);
        break;
    case DOGECHAT_HOOK_CONNECT_CONNECTION_REFUSED:
        dogechat_printf (NULL,
                         (xfer->proxy && xfer->proxy[0]) ?
                         _("%s%s: proxy connection refused") :
                         _("%s%s: connection refused"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME);
        break;
    case DOGECHAT_HOOK_CONNECT_PROXY_ERROR:
        dogechat_printf (NULL,
                         _("%s%s: proxy fails to establish connection to "
                           "server (check username/password if used and if "
                           "server address/port is allowed by proxy)"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME);
        break;
    case DOGECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR:
        dogechat_printf (NULL,
                         _("%s%s: unable to set local hostname/IP"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME);
        break;
    case DOGECHAT_HOOK_CONNECT_MEMORY_ERROR:
        dogechat_printf (NULL,
                         _("%s%s: not enough memory"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME);
        break;
    case DOGECHAT_HOOK_CONNECT_TIMEOUT:
        dogechat_printf (NULL,
                         _("%s%s: timeout"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME);
        break;
    case DOGECHAT_HOOK_CONNECT_SOCKET_ERROR:
        dogechat_printf (NULL,
                         _("%s%s: unable to create socket"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME);
        break;
    default:
        dogechat_printf (NULL,
                         _("%s%s: unable to connect: unexpected error (%d)"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME,
                         status);
        break;
    }
    if (error && error[0])
    {
        dogechat_printf (NULL,
                         _("%s%s: error: %s"),
                         dogechat_prefix ("error"), XFER_PLUGIN_NAME, error);
    }

    xfer_close (xfer, XFER_STATUS_FAILED);
    xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);

    return DOGECHAT_RC_OK;
}
Exemple #8
0
int
xfer_network_fd_cb (void *arg_xfer, int fd)
{
    struct t_xfer *xfer;
    int sock, flags, error;
    struct sockaddr_storage addr;
    socklen_t length;
    char str_address[NI_MAXHOST];

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

    length = sizeof (addr);
    memset (&addr, 0, length);
    xfer = (struct t_xfer *)arg_xfer;

    if (xfer->status == XFER_STATUS_CONNECTING)
    {
        if (xfer->type == XFER_TYPE_FILE_SEND)
        {
            xfer->last_activity = time (NULL);
            sock = accept (xfer->sock,
                           (struct sockaddr *) &addr, &length);
            error = errno;
            dogechat_unhook (xfer->hook_fd);
            xfer->hook_fd = NULL;
            close (xfer->sock);
            xfer->sock = -1;
            if (sock < 0)
            {
                dogechat_printf (NULL,
                                 _("%s%s: unable to create socket for sending "
                                   "file: error %d %s"),
                                 dogechat_prefix ("error"), XFER_PLUGIN_NAME,
                                 error, strerror (error));
                xfer_close (xfer, XFER_STATUS_FAILED);
                xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);
                return DOGECHAT_RC_OK;
            }
            xfer->sock = sock;
            flags = fcntl (xfer->sock, F_GETFL);
            if (flags == -1)
                flags = 0;
            if (fcntl (xfer->sock, F_SETFL, flags | O_NONBLOCK) == -1)
            {
                dogechat_printf (NULL,
                                 _("%s%s: unable to set option \"nonblock\" "
                                   "for socket: error %d %s"),
                                 dogechat_prefix ("error"), XFER_PLUGIN_NAME,
                                 errno, strerror (errno));
                xfer_close (xfer, XFER_STATUS_FAILED);
                xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);
                return DOGECHAT_RC_OK;
            }
            error = getnameinfo ((struct sockaddr *)&addr, length, str_address,
                                 sizeof (str_address), NULL, 0, NI_NUMERICHOST);
            if (error != 0)
            {
                snprintf (str_address, sizeof (str_address),
                          "error: %s", gai_strerror (error));
            }
            xfer_set_remote_address (xfer, (struct sockaddr *)&addr, length,
                                     str_address);
            xfer->status = XFER_STATUS_ACTIVE;
            xfer->start_transfer = time (NULL);
            xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);
            xfer_network_send_file_fork (xfer);
        }
    }

    if (xfer->status == XFER_STATUS_WAITING)
    {
        if (xfer->type == XFER_TYPE_CHAT_SEND)
        {
            length = sizeof (addr);
            sock = accept (xfer->sock, (struct sockaddr *) &addr, &length);
            error = errno;
            dogechat_unhook (xfer->hook_fd);
            xfer->hook_fd = NULL;
            close (xfer->sock);
            xfer->sock = -1;
            if (sock < 0)
            {
                dogechat_printf (NULL,
                                 _("%s%s: unable to create socket for sending "
                                   "file: error %d %s"),
                                 dogechat_prefix ("error"), XFER_PLUGIN_NAME,
                                 error, strerror (error));
                xfer_close (xfer, XFER_STATUS_FAILED);
                xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);
                return DOGECHAT_RC_OK;
            }
            xfer->sock = sock;
            flags = fcntl (xfer->sock, F_GETFL);
            if (flags == -1)
                flags = 0;
            if (fcntl (xfer->sock, F_SETFL, flags | O_NONBLOCK) == -1)
            {
                dogechat_printf (NULL,
                                 _("%s%s: unable to set option \"nonblock\" "
                                   "for socket: error %d %s"),
                                 dogechat_prefix ("error"), XFER_PLUGIN_NAME,
                                 errno, strerror (errno));
                xfer_close (xfer, XFER_STATUS_FAILED);
                xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);
                return DOGECHAT_RC_OK;
            }
            error = getnameinfo ((struct sockaddr *)&addr, length, str_address,
                                 sizeof (str_address), NULL, 0, NI_NUMERICHOST);
            if (error != 0)
            {
                snprintf (str_address, sizeof (str_address),
                          "error: %s", gai_strerror (error));
            }
            xfer_set_remote_address (xfer, (struct sockaddr *)&addr, length,
                                     str_address);
            xfer->status = XFER_STATUS_ACTIVE;
            xfer_buffer_refresh (DOGECHAT_HOTLIST_MESSAGE);
            xfer->hook_fd = dogechat_hook_fd (xfer->sock,
                                              1, 0, 0,
                                              &xfer_chat_recv_cb,
                                              xfer);
            xfer_chat_open_buffer (xfer);
        }
    }

    return DOGECHAT_RC_OK;
}