/**
 * Updates the horizon statistics in the statusbar.
 *
 * This is an event-driven callback called from the HSEP code
 * using the event listener framework. In addition to taking into account
 * the HSEP information, the number of established non-HSEP nodes and
 * their library size (if provided) are added to the values displayed.
 */
void
gnet_stats_gui_horizon_update(hsep_triple *table, guint32 triples)
{
	const guint32 hops = 4U;      /* must be <= HSEP_N_MAX */
	guint64 val;
	hsep_triple other;

	if (triples <= hops)     /* should not happen */
	    return;
	g_assert((gint32) triples > 0);

	guc_hsep_get_non_hsep_triple(&other);

	/*
	 * Update the 3 labels in the statusbar with the horizon values for a
	 * distance of 'hops' hops.
	 */

	val = table[hops][HSEP_IDX_NODES] + other[HSEP_IDX_NODES];
	gtk_label_printf(GTK_LABEL(
			gui_main_window_lookup("label_statusbar_horizon_node_count")),
		"%s %s", uint64_to_string(val), NG_("node", "nodes", val));

	val = table[hops][HSEP_IDX_FILES] + other[HSEP_IDX_FILES];
	gtk_label_printf(GTK_LABEL(
			gui_main_window_lookup("label_statusbar_horizon_file_count")),
		"%s %s", uint64_to_string(val), NG_("file", "files", val));

	val = table[hops][HSEP_IDX_KIB] + other[HSEP_IDX_KIB];
	gtk_label_printf(GTK_LABEL(
			gui_main_window_lookup("label_statusbar_horizon_kb_count")),
		"%s", short_kb_size(val, show_metric_units()));
}
Esempio n. 2
0
/**
 * Display the data gathered during the last time period.
 * Perhaps it would be better to have this done on a button click(?)
 */
static void
search_stats_gui_update_display(void)
{
    GtkWidget *clist_search_stats;
    GtkWidget *label_search_stats_count;

    clist_search_stats = gui_main_window_lookup("clist_search_stats");
    label_search_stats_count =
        gui_main_window_lookup("label_search_stats_count");

	stat_count = 0;
	gtk_clist_freeze(GTK_CLIST(clist_search_stats));

	gtk_clist_clear(GTK_CLIST(clist_search_stats));
	/* insert the hash table contents into the sorted clist */
	g_hash_table_foreach_remove(stat_hash, stats_hash_to_clist, NULL);
	gtk_clist_sort(GTK_CLIST(clist_search_stats));

	gtk_clist_thaw(GTK_CLIST(clist_search_stats));

	/* update the counter */
	gtk_label_printf(GTK_LABEL(label_search_stats_count),
		NG_("%u term counted", "%u terms counted", stat_count),
		stat_count);
}
Esempio n. 3
0
/**
 * Called from parse_dispatch_lines() on EOF.
 */
static void
ghc_host_eof(struct parse_context *ctx)
{
	char msg[256];

	if (GNET_PROPERTY(bootstrap_debug) > 2)
		g_debug("BOOT GHC all done (%u/%u lines processed)",
			ctx->processed, ctx->lines);

	/*
	 * Provide GUI feedback.
	 */

	str_bprintf(ARYLEN(msg),
		NG_("Got %d host from %s", "Got %d hosts from %s", ctx->processed),
		ctx->processed, http_async_url(ghc_ctx.ha));

	gcu_statusbar_message(msg);

	if (GNET_PROPERTY(bootstrap_debug))
		g_debug("BOOT GHC got %d host%s from %s",
			ctx->processed, plural(ctx->processed), http_async_url(ghc_ctx.ha));

	ghc_ctx.ha = NULL;
	ghc_connecting = FALSE;
}
Esempio n. 4
0
/**
 * Called from gwc_parse_dispatch_lines() on EOF.
 */
static void
gwc_host_eof(struct gwc_parse_context *ctx)
{
    const char *msg;

    if (GNET_PROPERTY(bootstrap_debug) > 2)
        g_message("GWC host all done (%d/%d lines processed)",
                  ctx->processed, ctx->lines);

    /*
     * Provide GUI feedback.
     */

    msg = str_smsg(
              NG_("Got %d host from %s", "Got %d hosts from %s", ctx->processed),
              ctx->processed, gwc_current_url);

    gcu_statusbar_message(msg);

    if (GNET_PROPERTY(bootstrap_debug))
        g_message("BOOT got %d host%s from GWC %s",
                  ctx->processed, plural(ctx->processed), gwc_current_url);

    /*
     * If we did not get enough addresses, try to feed the cache with ours.
     */

    if (ctx->processed < MIN_IP_LINES) {
        gwc_clear_current_url(FALSE);		/* Move to another cache */
    }

    gwc_get_running = FALSE;
}
Esempio n. 5
0
void
upgrade_weechat_end ()
{
    struct timeval tv_now;
    long time_diff;

    /* remove .upgrade files */
    util_exec_on_files (weechat_home,
                        0,
                        NULL,
                        &upgrade_weechat_remove_file_cb);

    /* display message for end of /upgrade with duration */
    gettimeofday (&tv_now, NULL);
    time_diff = util_timeval_diff (&weechat_current_start_timeval, &tv_now);
    gui_chat_printf (NULL,
                     /* TRANSLATORS: "%s" is translation of "second" or "seconds" */
                     _("Upgrade done (%.02f %s)"),
                     ((float)time_diff) / 1000,
                     NG_("second", "seconds", time_diff / 1000));

    /* upgrading ended */
    weechat_upgrading = 0;

    /* send signal for end of /upgrade */
    hook_signal_send ("upgrade_ended", WEECHAT_HOOK_SIGNAL_STRING, NULL);
}
Esempio n. 6
0
const char *
plugin_api_ngettext (const char *single, const char *plural, int count)
{
    /* make C compiler happy */
    (void) single;
    (void) count;

    return NG_(single, plural, count);
}
Esempio n. 7
0
/**
 * Display the data gathered during the last time period.
 * Perhaps it would be better to have this done on a button click(?)
 */
static void
search_stats_gui_update_display(void)
{
    gboolean sorting_disabled;
    tm_t start_time, end_time;
    time_delta_t elapsed;

    stat_count = 0;
    g_object_freeze_notify(G_OBJECT(treeview_search_stats));
    gtk_list_store_clear(store_search_stats);

    /*
     * Temporarily disable sorting while inserting the updated table.
     * Otherwise, CPU is overloaded with sorting every addition
     *  to the hash table.
     */
    sorting_disabled = FALSE;
    tm_now_exact(&start_time);
    if (store_search_stats->sort_column_id >= 0) {
        sorting_disabled = TRUE;
        search_stats_gui_sort_save();
    }
    /* insert the hash table contents into the sorted treeview */
    htable_foreach_remove(stat_hash, stats_hash_to_treeview, NULL);

    tm_now_exact(&end_time);
    elapsed = tm_elapsed_ms(&end_time, &start_time);

    /*
     * Re-enable sorting if previously disabled.
     * If too much time has elapsed, leave sorting disabled.
     */
    if (sorting_disabled && elapsed < 100) {
        search_stats_gui_sort_restore();
    } else if (!sorting_disabled && elapsed > 200) {
        /*
         * If sorting is disabled, and too much time is still elapsing,
         * then the search stats collection will need to be
         * discontinued
         */
        search_stats_gui_reset();
        search_stats_gui_disable();
        search_stats_gui_overload = TRUE;
    }

    if (search_stats_gui_overload) {
        /* update status bar message */
        gtk_label_set_text(GTK_LABEL(label_search_stats_count),
                           "Disabling Search Stats due to system load" );
    } else {
        /* update the status bar counter */
        gtk_label_printf(GTK_LABEL(label_search_stats_count),
                         NG_("%u term counted", "%u terms counted", stat_count),
                         stat_count);
    }
    g_object_thaw_notify(G_OBJECT(treeview_search_stats));
}
Esempio n. 8
0
/**
 * Called when a pong with an "IPP" extension was received.
 */
void
uhc_ipp_extract(gnutella_node_t *n, const char *payload, int paylen,
	enum net_type type)
{
	int i, cnt;
	int len = NET_TYPE_IPV6 == type ? 18 : 6;
	const void *p;

	g_assert(0 == paylen % len);

	cnt = paylen / len;

	if (GNET_PROPERTY(bootstrap_debug))
		g_debug("extracting %d host%s in UDP IPP pong #%s from %s",
			cnt, plural(cnt),
			guid_hex_str(gnutella_header_get_muid(&n->header)), node_addr(n));

	for (i = 0, p = payload; i < cnt; i++, p = const_ptr_add_offset(p, len)) {
		host_addr_t ha;
		uint16 port;

		host_ip_port_peek(p, type, &ha, &port);
		hcache_add_caught(HOST_ULTRA, ha, port, "UDP-HC");

		if (GNET_PROPERTY(bootstrap_debug) > 2)
			g_debug("BOOT collected %s from UDP IPP pong from %s",
				host_addr_port_to_string(ha, port), node_addr(n));
	}

	if (!uhc_connecting)
		return;

	/*
	 * Check whether this was a reply from our request.
	 *
	 * The reply could come well after we decided it timed out and picked
	 * another UDP host cache, which ended-up replying, so we must really
	 * check whether we're still in a probing cycle.
	 */

	if (!guid_eq(&uhc_ctx.muid, gnutella_header_get_muid(&n->header)))
		return;

	if (GNET_PROPERTY(bootstrap_debug)) {
		g_debug("BOOT UDP cache \"%s\" replied: got %d host%s from %s",
			uhc_ctx.host, cnt, plural(cnt), node_addr(n));
	}

	/*
	 * Terminate the probing cycle if we got hosts.
	 */

	if (cnt > 0) {
		char msg[256];

		cq_cancel(&uhc_ctx.timeout_ev);
		uhc_connecting = FALSE;

		str_bprintf(msg, sizeof(msg),
			NG_("Got %d host from UDP host cache %s",
				"Got %d hosts from UDP host cache %s",
				cnt),
			cnt, uhc_ctx.host);

		gcu_statusbar_message(msg);
	} else {
		uhc_try_next();
	}
}
Esempio n. 9
0
int
relay_signal_upgrade_cb (const void *pointer, void *data,
                         const char *signal, const char *type_data,
                         void *signal_data)
{
    struct t_relay_server *ptr_server;
    struct t_relay_client *ptr_client;
    int quit, ssl_disconnected;

    /* make C compiler happy */
    (void) pointer;
    (void) data;
    (void) signal;
    (void) type_data;
    (void) signal_data;

    relay_signal_upgrade_received = 1;

    /* close socket for relay servers */
    for (ptr_server = relay_servers; ptr_server;
         ptr_server = ptr_server->next_server)
    {
        relay_server_close_socket (ptr_server);
    }

    quit = (signal_data && (strcmp (signal_data, "quit") == 0));
    ssl_disconnected = 0;

    for (ptr_client = relay_clients; ptr_client;
         ptr_client = ptr_client->next_client)
    {
        /*
         * FIXME: it's not possible to upgrade with SSL clients connected (GnuTLS
         * lib can't reload data after upgrade), so we close connection for
         * all SSL clients currently connected
         */
        if ((ptr_client->sock >= 0) && (ptr_client->ssl || quit))
        {
            if (!quit)
            {
                ssl_disconnected++;
                weechat_printf (NULL,
                                _("%s%s: disconnecting from client %s%s%s because "
                                  "upgrade can't work for clients connected via SSL"),
                                weechat_prefix ("error"),
                                RELAY_PLUGIN_NAME,
                                RELAY_COLOR_CHAT_CLIENT,
                                ptr_client->desc,
                                RELAY_COLOR_CHAT);
            }
            relay_client_set_status (ptr_client, RELAY_STATUS_DISCONNECTED);
        }
    }
    if (ssl_disconnected > 0)
    {
        weechat_printf (NULL,
                        /* TRANSLATORS: "%s" after "%d" is "client" or "clients" */
                        _("%s%s: disconnected from %d %s (SSL connection "
                          "not supported with upgrade)"),
                        weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                        ssl_disconnected,
                        NG_("client", "clients", ssl_disconnected));
    }

    return WEECHAT_RC_OK;
}
Esempio n. 10
0
int
irc_signal_upgrade_cb (void *data, const char *signal, const char *type_data,
                       void *signal_data)
{
    struct t_irc_server *ptr_server;
    int quit, ssl_disconnected;

    /* make C compiler happy */
    (void) data;
    (void) signal;
    (void) type_data;

    irc_signal_upgrade_received = 1;

    quit = (signal_data && (strcmp (signal_data, "quit") == 0));
    ssl_disconnected = 0;

    for (ptr_server = irc_servers; ptr_server;
         ptr_server = ptr_server->next_server)
    {
        /*
         * FIXME: it's not possible to upgrade with SSL servers connected
         * (GnuTLS library can't reload data after upgrade), so we close
         * connection for all SSL servers currently connected
         */
        if (ptr_server->is_connected && (ptr_server->ssl_connected || quit))
        {
            if (!quit)
            {
                ssl_disconnected++;
                dogechat_printf (
                    ptr_server->buffer,
                    _("%s%s: disconnecting from server because upgrade can't "
                      "work for servers connected via SSL"),
                    dogechat_prefix ("error"), IRC_PLUGIN_NAME);
            }
            irc_server_disconnect (ptr_server, 0, 0);
            /*
             * schedule reconnection: DogeChat will reconnect to this server
             * after restart
             */
            ptr_server->index_current_address = 0;
            ptr_server->reconnect_delay = IRC_SERVER_OPTION_INTEGER(ptr_server, IRC_SERVER_OPTION_AUTORECONNECT_DELAY);
            ptr_server->reconnect_start = time (NULL) - ptr_server->reconnect_delay - 1;
        }
    }
    if (ssl_disconnected > 0)
    {
        dogechat_printf (
            NULL,
            /* TRANSLATORS: "%s" after "%d" is "server" or "servers" */
            _("%s%s: disconnected from %d %s (SSL connection not supported "
              "with upgrade)"),
            dogechat_prefix ("error"),
            IRC_PLUGIN_NAME,
            ssl_disconnected,
            NG_("server", "servers", ssl_disconnected));
    }

    return DOGECHAT_RC_OK;
}
Esempio n. 11
0
void
irc_ctcp_display_reply_from_nick (struct t_irc_server *server,
                                  const char *command, const char *nick,
                                  char *arguments)
{
    char *pos_end, *pos_space, *pos_args, *pos_usec;
    struct timeval tv;
    long sec1, usec1, sec2, usec2, difftime;

    while (arguments && arguments[0])
    {
        pos_end = strchr (arguments + 1, '\01');
        if (pos_end)
            pos_end[0] = '\0';

        pos_space = strchr (arguments + 1, ' ');
        if (pos_space)
        {
            pos_space[0] = '\0';
            pos_args = pos_space + 1;
            while (pos_args[0] == ' ')
            {
                pos_args++;
            }
            if (strcmp (arguments + 1, "PING") == 0)
            {
                pos_usec = strchr (pos_args, ' ');
                if (pos_usec)
                {
                    pos_usec[0] = '\0';

                    gettimeofday (&tv, NULL);
                    sec1 = atol (pos_args);
                    usec1 = atol (pos_usec + 1);
                    sec2 = tv.tv_sec;
                    usec2 = tv.tv_usec;

                    difftime = ((sec2 * 1000000) + usec2) -
                        ((sec1 * 1000000) + usec1);
                    weechat_printf_tags (irc_msgbuffer_get_target_buffer (server,
                                                                          nick,
                                                                          NULL,
                                                                          "ctcp",
                                                                          NULL),
                                         irc_protocol_tags (command,
                                                            "irc_ctcp",
                                                            NULL),
                                         _("%sCTCP reply from %s%s%s: %s%s%s "
                                           "%ld.%ld %s"),
                                         weechat_prefix ("network"),
                                         IRC_COLOR_CHAT_NICK,
                                         nick,
                                         IRC_COLOR_RESET,
                                         IRC_COLOR_CHAT_CHANNEL,
                                         arguments + 1,
                                         IRC_COLOR_RESET,
                                         difftime / 1000000,
                                         (difftime % 1000000) / 1000,
                                         (NG_("second", "seconds",
                                              (difftime / 1000000))));

                    pos_usec[0] = ' ';
                }
            }
            else
            {
                weechat_printf_tags (irc_msgbuffer_get_target_buffer (server,
                                                                      nick,
                                                                      NULL,
                                                                      "ctcp",
                                                                      NULL),
                                     irc_protocol_tags (command,
                                                        "irc_ctcp",
                                                        NULL),
                                     _("%sCTCP reply from %s%s%s: %s%s%s%s%s"),
                                     weechat_prefix ("network"),
                                     IRC_COLOR_CHAT_NICK,
                                     nick,
                                     IRC_COLOR_RESET,
                                     IRC_COLOR_CHAT_CHANNEL,
                                     arguments + 1,
                                     IRC_COLOR_RESET,
                                     " ",
                                     pos_args);
            }
            pos_space[0] = ' ';
        }
        else
        {
            weechat_printf_tags (irc_msgbuffer_get_target_buffer (server, nick,
                                                                  NULL, "ctcp",
                                                                  NULL),
                                 irc_protocol_tags (command, NULL, NULL),
                                 _("%sCTCP reply from %s%s%s: %s%s%s%s%s"),
                                 weechat_prefix ("network"),
                                 IRC_COLOR_CHAT_NICK,
                                 nick,
                                 IRC_COLOR_RESET,
                                 IRC_COLOR_CHAT_CHANNEL,
                                 arguments + 1,
                                 "",
                                 "",
                                 "");
        }

        if (pos_end)
            pos_end[0] = '\01';

        arguments = (pos_end) ? pos_end + 1 : NULL;
    }
}
Esempio n. 12
0
int
relay_server_create_socket (struct t_relay_server *server)
{
    int domain, set, max_clients, addr_size, rc;
    struct sockaddr_in server_addr;
    struct sockaddr_in6 server_addr6;
    struct sockaddr_un server_addr_unix;
    const char *bind_address;
    void *ptr_addr;

    bind_address = weechat_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))
            {
                weechat_printf (NULL,
                                /* TRANSLATORS: second "%s" is "IPv4" or "IPv6" */
                                _("%s%s: invalid bind address \"%s\" for %s"),
                                weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                                bind_address, "IPv6");
                return 0;
            }
        }
        ptr_addr = &server_addr6;
        addr_size = sizeof (struct sockaddr_in6);
    }
    else if (server->ipv4)
    {
        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))
            {
                weechat_printf (NULL,
                                /* TRANSLATORS: second "%s" is "IPv4" or "IPv6" */
                                _("%s%s: invalid bind address \"%s\" for %s"),
                                weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                                bind_address, "IPv4");
                return 0;
            }
        }
        ptr_addr = &server_addr;
        addr_size = sizeof (struct sockaddr_in);
    }
    else
    {
        domain = AF_UNIX;
        memset (&server_addr_unix, 0, sizeof (struct sockaddr_un));
        server_addr_unix.sun_family = domain;
        strncpy (server_addr_unix.sun_path, server->path,
                 sizeof (server_addr_unix.sun_path));
        ptr_addr = &server_addr_unix;
        addr_size = sizeof (struct sockaddr_un);
        if (!relay_config_check_path_length (server->path))
        {
            weechat_printf (NULL,
                            _("%s%s: socket path \"%s\" is invalid"),
                            weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                            server->path);
            return 0;
        }
        rc = relay_config_check_path_available (server->path);
        switch (rc)
        {
            case -1:
                weechat_printf (NULL,
                                _("%s%s: socket path \"%s\" already exists "
                                  "and is not a socket"),
                                weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                                server->path);
                break;
            case -2:
                weechat_printf (NULL,
                                _("%s%s: socket path \"%s\" is invalid"),
                                weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                                server->path);
        }
        if (rc < 0)
            return 0;
        /* just in case a socket already exists */
        unlink (server->path);
    }


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

#if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
    /* 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)
        {
            weechat_printf (NULL,
                            _("%s%s: cannot set socket option \"%s\" "
                              "to %d: error %d %s"),
                            weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                            "IPV6_V6ONLY", set, errno, strerror (errno));
            close (server->sock);
            server->sock = -1;
            return 0;
        }
    }
#endif

    /* set option SO_REUSEADDR to 1 */
    set = 1;
    if (setsockopt (server->sock, SOL_SOCKET, SO_REUSEADDR,
                    (void *) &set, sizeof (set)) < 0)
    {
        weechat_printf (NULL,
                        _("%s%s: cannot set socket option \"%s\" to %d: "
                          "error %d %s"),
                        weechat_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)
    {
        weechat_printf (NULL,
                        _("%s%s: cannot set socket option \"%s\" to %d: "
                          "error %d %s"),
                        weechat_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)
    {
        if (server->unix_socket)
        {
            weechat_printf (NULL,
                            _("%s%s: cannot \"bind\" on path %s (%s): "
                              "error %d %s"),
                            weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                            server->path, server->protocol_string,
                            errno, strerror (errno));
        }
        else
        {
            weechat_printf (NULL,
                            _("%s%s: cannot \"bind\" on port %d (%s): "
                              "error %d %s"),
                            weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                            server->port, server->protocol_string,
                            errno, strerror (errno));
        }
        close (server->sock);
        server->sock = -1;
        return 0;
    }

    /* change permissions: only the owner can use the unix socket */
    if (server->unix_socket)
        chmod (server->path, 0700);

#ifdef SOMAXCONN
    if (listen (server->sock, SOMAXCONN) != 0)
#else
    if (listen (server->sock, 1) != 0)
#endif
    {
        if (server->unix_socket)
        {
            weechat_printf (NULL,
                            _("%s%s: cannot \"listen\" on path %s (%s): "
                              "error %d %s"),
                            weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                            server->path, server->protocol_string,
                            errno, strerror (errno));
        }
        else
        {
            weechat_printf (NULL,
                            _("%s%s: cannot \"listen\" on port %d (%s): "
                              "error %d %s"),
                            weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                            server->port, server->protocol_string,
                            errno, strerror (errno));
        }
        close (server->sock);
        server->sock = -1;
        return 0;
    }

    max_clients = weechat_config_integer (relay_config_network_max_clients);
    if (max_clients > 0)
    {
        if (server->unix_socket)
        {
            weechat_printf (
                NULL,
                NG_("%s: listening on path %s (relay: %s, %s, max %d client)",
                    "%s: listening on path %s (relay: %s, %s, max %d clients)",
                    max_clients),
                RELAY_PLUGIN_NAME,
                server->path,
                server->protocol_string,
                ((server->ipv4 && server->ipv6) ? "IPv4+6" : ((server->ipv6) ? "IPv6" : ((server->ipv4) ? "IPv4" : "UNIX"))),
                max_clients);
        }
        else
        {
            weechat_printf (
                NULL,
                NG_("%s: listening on port %d (relay: %s, %s, max %d client)",
                    "%s: listening on port %d (relay: %s, %s, max %d clients)",
                    max_clients),
                RELAY_PLUGIN_NAME,
                server->port,
                server->protocol_string,
                ((server->ipv4 && server->ipv6) ? "IPv4+6" : ((server->ipv6) ? "IPv6" : ((server->ipv4) ? "IPv4" : "UNIX"))),
                max_clients);
        }
    }
    else
    {
        if (server->unix_socket)
        {
            weechat_printf (
                NULL,
                _("%s: listening on path %s (relay: %s, %s)"),
                RELAY_PLUGIN_NAME,
                server->path,
                server->protocol_string,
                ((server->ipv4 && server->ipv6) ? "IPv4+6" : ((server->ipv6) ? "IPv6" : ((server->ipv4) ? "IPv4" : "UNIX"))));
        }
        else
        {
            weechat_printf (
                NULL,
                _("%s: listening on port %d (relay: %s, %s)"),
                RELAY_PLUGIN_NAME,
                server->port,
                server->protocol_string,
                ((server->ipv4 && server->ipv6) ? "IPv4+6" : ((server->ipv6) ? "IPv6" : ((server->ipv4) ? "IPv4" : "UNIX"))));
        }
    }
    server->hook_fd = weechat_hook_fd (server->sock,
                                       1, 0, 0,
                                       &relay_server_sock_cb,
                                       server, NULL);

    server->start_time = time (NULL);

    return 1;
}
Esempio n. 13
0
int
relay_server_sock_cb (const void *pointer, void *data, int fd)
{
    struct t_relay_server *server;
    struct sockaddr_in client_addr;
    struct sockaddr_in6 client_addr6;
    struct sockaddr_un client_addr_unix;

    socklen_t client_addr_size;
    void *ptr_addr;
    int client_fd, flags, set, max_clients, num_clients_on_port;
    char ipv4_address[INET_ADDRSTRLEN + 1], ipv6_address[INET6_ADDRSTRLEN + 1];
    char unix_address[sizeof (client_addr_unix.sun_path)];
    char *ptr_ip_address, *relay_password, *relay_totp_secret;

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

    client_fd = -1;
    relay_password = NULL;
    relay_totp_secret = NULL;

    server = (struct t_relay_server *)pointer;

    if (server->ipv6)
    {
        ptr_addr = &client_addr6;
        client_addr_size = sizeof (struct sockaddr_in6);
    }
    else if (server->ipv4)
    {
        ptr_addr = &client_addr;
        client_addr_size = sizeof (struct sockaddr_in);
    }
    else
    {
        ptr_addr = &client_addr_unix;
        client_addr_size = sizeof (struct sockaddr_un);
    }

    memset (ptr_addr, 0, client_addr_size);

    client_fd = accept (server->sock, (struct sockaddr *)ptr_addr,
                        &client_addr_size);
    if (client_fd < 0)
    {
        if (server->unix_socket)
        {
            weechat_printf (NULL,
                            _("%s%s: cannot accept client on path %s (%s): "
                              "error %d %s"),
                            weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                            server->path, server->protocol_string,
                            errno, strerror (errno));
        }
        else
        {
            weechat_printf (NULL,
                            _("%s%s: cannot accept client on port %d (%s): "
                              "error %d %s"),
                            weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                            server->port, server->protocol_string,
                            errno, strerror (errno));
        }
        goto error;
    }

    /* check if relay password is empty and if it is not allowed */
    relay_password = weechat_string_eval_expression (
        weechat_config_string (relay_config_network_password),
        NULL, NULL, NULL);
    if (!weechat_config_boolean (relay_config_network_allow_empty_password)
        && (!relay_password || !relay_password[0]))
    {
        weechat_printf (NULL,
                        _("%s%s: cannot accept client because relay password "
                          "is empty, and option "
                          "relay.network.allow_empty_password is off"),
                        weechat_prefix ("error"), RELAY_PLUGIN_NAME);
        goto error;
    }

    if (server->protocol == RELAY_PROTOCOL_WEECHAT)
    {
        /*
         * TOTP can be enabled only as second factor, in addition to the
         * password (only for weechat protocol)
         */
        relay_totp_secret = weechat_string_eval_expression (
            weechat_config_string (relay_config_network_totp_secret),
            NULL, NULL, NULL);
        if ((!relay_password || !relay_password[0])
            && relay_totp_secret && relay_totp_secret[0])
        {
            weechat_printf (NULL,
                            _("%s%s: Time-based One-Time Password (TOTP) "
                              "can be enabled only as second factor, if the "
                              "password is not empty"),
                            weechat_prefix ("error"), RELAY_PLUGIN_NAME);
            goto error;
        }
        if (!relay_config_check_network_totp_secret (
                NULL, NULL, NULL,
                weechat_config_string (relay_config_network_totp_secret)))
        {
            goto error;
        }
    }

    /* check if we have reached the max number of clients on this port */
    max_clients = weechat_config_integer (relay_config_network_max_clients);
    if (max_clients > 0)
    {
        num_clients_on_port = relay_client_count_active_by_port (server->port);
        if (num_clients_on_port >= max_clients)
        {
            weechat_printf (
                NULL,
                NG_("%s%s: client not allowed (max %d client is "
                    "allowed at same time)",
                    "%s%s: client not allowed (max %d clients are "
                    "allowed at same time)",
                    max_clients),
                weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                max_clients);
            goto error;
        }
    }

    /* get the IP address */
    ptr_ip_address = NULL;
    if (server->ipv6)
    {
        if (inet_ntop (AF_INET6,
                       &(client_addr6.sin6_addr),
                       ipv6_address,
                       INET6_ADDRSTRLEN))
        {
            ptr_ip_address = ipv6_address;

            if (strncmp (ptr_ip_address, "::ffff:", 7) == 0)
            {
                /* actually an IPv4-mapped IPv6 address, so skip "::ffff:" */
                ptr_ip_address += 7;
            }
        }
    }
    else if (server->ipv4)
    {
        if (inet_ntop (AF_INET,
                       &(client_addr.sin_addr),
                       ipv4_address,
                       INET_ADDRSTRLEN))
        {
            ptr_ip_address = ipv4_address;
        }
    }
    else
    {
        strncpy (unix_address, client_addr_unix.sun_path,
                 sizeof (unix_address));
        ptr_ip_address = unix_address;
    }

    /* check if IP is allowed, if not, just close socket */
    if (relay_config_regex_allowed_ips
        && (regexec (relay_config_regex_allowed_ips, ptr_ip_address, 0, NULL, 0) != 0))
    {
        if (weechat_relay_plugin->debug >= 1)
        {
            weechat_printf (NULL,
                            _("%s%s: IP address \"%s\" not allowed for relay"),
                            weechat_prefix ("error"),
                            RELAY_PLUGIN_NAME,
                            ptr_ip_address);
        }
        goto error;
    }

    /* set non-blocking mode for socket */
    flags = fcntl (client_fd, F_GETFL);
    if (flags == -1)
        flags = 0;
    fcntl (client_fd, F_SETFL, flags | O_NONBLOCK);

    /* set socket option SO_REUSEADDR */
    set = 1;
    if (setsockopt (client_fd, SOL_SOCKET, SO_REUSEADDR,
                    (void *) &set, sizeof (set)) < 0)
    {
        weechat_printf (NULL,
                        _("%s%s: cannot set socket option \"%s\" to %d: "
                          "error %d %s"),
                        weechat_prefix ("error"), RELAY_PLUGIN_NAME,
                        "SO_REUSEADDR", set, errno, strerror (errno));
        goto error;
    }

    /* add the client */
    relay_client_new (client_fd, ptr_ip_address, server);

    goto end;

error:
    if (client_fd >= 0)
        close (client_fd);

end:
    if (relay_password)
        free (relay_password);
    if (relay_totp_secret)
        free (relay_totp_secret);

    return WEECHAT_RC_OK;
}