/** * 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())); }
/** * 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); }
/** * 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; }
/** * 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; }
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); }
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); }
/** * 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)); }
/** * 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(); } }
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; }
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; }
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; } }
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; }
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; }