int xfer_network_connect (struct t_xfer *xfer) { if (xfer->type == XFER_TYPE_CHAT_SEND) xfer->status = XFER_STATUS_WAITING; else xfer->status = XFER_STATUS_CONNECTING; if (xfer->sock < 0) { xfer->sock = socket (AF_INET, SOCK_STREAM, 0); if (xfer->sock < 0) return 0; } if (XFER_IS_SEND(xfer->type)) { /* listen to socket */ if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) return 0; if (listen (xfer->sock, 1) == -1) return 0; if (fcntl (xfer->sock, F_SETFL, 0) == -1) return 0; xfer->hook_fd = weechat_hook_fd (xfer->sock, 1, 0, 0, &xfer_network_fd_cb, xfer); /* add timeout */ if (weechat_config_integer (xfer_config_network_timeout) > 0) { xfer->hook_timer = weechat_hook_timer (weechat_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) { if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) return 0; weechat_network_connect_to (xfer->proxy, xfer->sock, xfer->address, xfer->port); xfer->hook_fd = weechat_hook_fd (xfer->sock, 1, 0, 0, &xfer_chat_recv_cb, xfer); } /* for file receiving, connection is made in child process (blocking) */ return 1; }
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 */ weechat_printf (NULL, _("%s%s: unable to fork (%s)"), weechat_prefix ("error"), XFER_PLUGIN_NAME, strerror (errno)); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_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 = weechat_hook_fd (xfer->child_read, 1, 0, 0, &xfer_network_child_read_cb, xfer, NULL); }
void xfer_network_send_file_fork (struct t_xfer *xfer) { pid_t pid; if (!xfer_network_create_pipe (xfer)) return; xfer->file = open (xfer->local_filename, O_RDONLY | O_NONBLOCK, 0644); switch (pid = fork ()) { /* fork failed */ case -1: weechat_printf (NULL, _("%s%s: unable to fork"), weechat_prefix ("error"), XFER_PLUGIN_NAME); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return; /* child process */ case 0: setuid (getuid ()); 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); } /* parent process */ xfer->child_pid = pid; close (xfer->child_write); xfer->child_write = -1; xfer->hook_fd = weechat_hook_fd (xfer->child_read, 1, 0, 0, &xfer_network_child_read_cb, xfer); }
static gint _wec_try_connect(gconstpointer user_data, gpointer data, gint remaining_calls) { gint error = 0; if ( eventc_light_connection_is_connected(_wec_context.client, &error) ) return WEECHAT_RC_OK; if ( _wec_context.connect_hook != NULL ) return WEECHAT_RC_ERROR; if ( eventc_light_connection_connect(_wec_context.client) < 0 ) { _wec_context.connect_hook = weechat_hook_timer(GPOINTER_TO_UINT(user_data) * 1000, 60, 1, _wec_try_connect, GUINT_TO_POINTER(GPOINTER_TO_UINT(user_data) * 2), NULL); return WEECHAT_RC_ERROR; } _wec_context.connect_hook = NULL; _wec_context.fd = eventc_light_connection_get_socket(_wec_context.client); _wec_context.fd_hook = weechat_hook_fd(_wec_context.fd, 1, 0, 0, _wec_fd_callback, NULL, NULL); return WEECHAT_RC_OK; }
int irc_upgrade_read_cb (void *data, struct t_upgrade_file *upgrade_file, int object_id, struct t_infolist *infolist) { int flags, sock, size, i, index, nicks_count, num_items; long number; time_t join_time; char *buf, option_name[64], **nicks, *nick_join, *pos, *error; char **items; const char *buffer_name, *str, *nick; struct t_irc_nick *ptr_nick; struct t_irc_redirect *ptr_redirect; struct t_irc_notify *ptr_notify; struct t_gui_buffer *ptr_buffer; /* make C compiler happy */ (void) data; (void) upgrade_file; weechat_infolist_reset_item_cursor (infolist); while (weechat_infolist_next (infolist)) { switch (object_id) { case IRC_UPGRADE_TYPE_SERVER: irc_upgrade_current_server = irc_server_search (weechat_infolist_string (infolist, "name")); if (irc_upgrade_current_server) { irc_upgrade_current_server->temp_server = weechat_infolist_integer (infolist, "temp_server"); irc_upgrade_current_server->buffer = NULL; buffer_name = weechat_infolist_string (infolist, "buffer_name"); if (buffer_name && buffer_name[0]) { ptr_buffer = weechat_buffer_search (IRC_PLUGIN_NAME, buffer_name); if (ptr_buffer) irc_upgrade_current_server->buffer = ptr_buffer; } irc_upgrade_current_server->index_current_address = weechat_infolist_integer (infolist, "index_current_address"); str = weechat_infolist_string (infolist, "current_address"); if (str) { irc_upgrade_current_server->current_address = strdup (str); irc_upgrade_current_server->current_port = weechat_infolist_integer (infolist, "current_port"); } else { if (irc_upgrade_current_server->index_current_address < irc_upgrade_current_server->addresses_count) { irc_upgrade_current_server->current_address = strdup (irc_upgrade_current_server->addresses_array[irc_upgrade_current_server->index_current_address]); irc_upgrade_current_server->current_port = irc_upgrade_current_server->ports_array[irc_upgrade_current_server->index_current_address]; } } str = weechat_infolist_string (infolist, "current_ip"); if (str) irc_upgrade_current_server->current_ip = strdup (str); sock = weechat_infolist_integer (infolist, "sock"); if (sock >= 0) { irc_upgrade_current_server->sock = sock; irc_upgrade_current_server->hook_fd = weechat_hook_fd (irc_upgrade_current_server->sock, 1, 0, 0, &irc_server_recv_cb, irc_upgrade_current_server); } irc_upgrade_current_server->is_connected = weechat_infolist_integer (infolist, "is_connected"); irc_upgrade_current_server->ssl_connected = weechat_infolist_integer (infolist, "ssl_connected"); irc_upgrade_current_server->disconnected = weechat_infolist_integer (infolist, "disconnected"); str = weechat_infolist_string (infolist, "unterminated_message"); if (str) irc_upgrade_current_server->unterminated_message = strdup (str); str = weechat_infolist_string (infolist, "nick"); if (str) irc_server_set_nick (irc_upgrade_current_server, str); str = weechat_infolist_string (infolist, "nick_modes"); if (str) irc_upgrade_current_server->nick_modes = strdup (str); str = weechat_infolist_string (infolist, "isupport"); if (str) irc_upgrade_current_server->isupport = strdup (str); /* * "prefix" is not any more in this infolist (since * WeeChat 0.3.4), but we read it to keep compatibility * with old WeeChat versions, on /upgrade) */ str = weechat_infolist_string (infolist, "prefix"); if (str) irc_server_set_prefix_modes_chars (irc_upgrade_current_server, str); /* "prefix_modes" is new in WeeChat 0.3.4 */ str = weechat_infolist_string (infolist, "prefix_modes"); if (str) { if (irc_upgrade_current_server->prefix_modes) free (irc_upgrade_current_server->prefix_modes); irc_upgrade_current_server->prefix_modes = strdup (str); } /* "prefix_chars" is new in WeeChat 0.3.4 */ str = weechat_infolist_string (infolist, "prefix_chars"); if (str) { if (irc_upgrade_current_server->prefix_chars) free (irc_upgrade_current_server->prefix_chars); irc_upgrade_current_server->prefix_chars = strdup (str); } irc_upgrade_current_server->nick_max_length = weechat_infolist_integer (infolist, "nick_max_length"); irc_upgrade_current_server->casemapping = weechat_infolist_integer (infolist, "casemapping"); str = weechat_infolist_string (infolist, "chantypes"); if (str) irc_upgrade_current_server->chantypes = strdup (str); str = weechat_infolist_string (infolist, "chanmodes"); if (str) irc_upgrade_current_server->chanmodes = strdup (str); else { str = irc_server_get_isupport_value (irc_upgrade_current_server, "CHANMODES"); if (str) irc_upgrade_current_server->chanmodes = strdup (str); } /* "monitor" is new in WeeChat 0.4.3 */ if (weechat_infolist_search_var (infolist, "monitor")) { irc_upgrade_current_server->monitor = weechat_infolist_integer (infolist, "monitor"); } else { /* WeeChat <= 0.4.2 */ str = irc_server_get_isupport_value (irc_upgrade_current_server, "MONITOR"); if (str) { error = NULL; number = strtol (str, &error, 10); if (error && !error[0]) irc_upgrade_current_server->monitor = (int)number; } } irc_upgrade_current_server->reconnect_delay = weechat_infolist_integer (infolist, "reconnect_delay"); irc_upgrade_current_server->reconnect_start = weechat_infolist_time (infolist, "reconnect_start"); irc_upgrade_current_server->command_time = weechat_infolist_time (infolist, "command_time"); irc_upgrade_current_server->reconnect_join = weechat_infolist_integer (infolist, "reconnect_join"); irc_upgrade_current_server->disable_autojoin = weechat_infolist_integer (infolist, "disable_autojoin"); irc_upgrade_current_server->is_away = weechat_infolist_integer (infolist, "is_away"); str = weechat_infolist_string (infolist, "away_message"); if (str) irc_upgrade_current_server->away_message = strdup (str); irc_upgrade_current_server->away_time = weechat_infolist_time (infolist, "away_time"); irc_upgrade_current_server->lag = weechat_infolist_integer (infolist, "lag"); buf = weechat_infolist_buffer (infolist, "lag_check_time", &size); if (buf) memcpy (&(irc_upgrade_current_server->lag_check_time), buf, size); irc_upgrade_current_server->lag_next_check = weechat_infolist_time (infolist, "lag_next_check"); irc_upgrade_current_server->lag_last_refresh = weechat_infolist_time (infolist, "lag_last_refresh"); irc_upgrade_current_server->last_user_message = weechat_infolist_time (infolist, "last_user_message"); irc_upgrade_current_server->last_away_check = weechat_infolist_time (infolist, "last_away_check"); irc_upgrade_current_server->last_data_purge = weechat_infolist_time (infolist, "last_data_purge"); } break; case IRC_UPGRADE_TYPE_CHANNEL: if (irc_upgrade_current_server) { irc_upgrade_current_channel = irc_channel_new (irc_upgrade_current_server, weechat_infolist_integer (infolist, "type"), weechat_infolist_string (infolist, "name"), 0, 0); if (irc_upgrade_current_channel) { str = weechat_infolist_string (infolist, "topic"); if (str) irc_channel_set_topic (irc_upgrade_current_channel, str); str = weechat_infolist_string (infolist, "modes"); if (str) irc_upgrade_current_channel->modes = strdup (str); irc_upgrade_current_channel->limit = weechat_infolist_integer (infolist, "limit"); str = weechat_infolist_string (infolist, "key"); if (str) irc_upgrade_current_channel->key = strdup (str); str = weechat_infolist_string (infolist, "join_msg_received"); if (str) { items = weechat_string_split (str, ",", 0, 0, &num_items); if (items) { for (i = 0; i < num_items; i++) { weechat_hashtable_set (irc_upgrade_current_channel->join_msg_received, items[i], "1"); } weechat_string_free_split (items); } } irc_upgrade_current_channel->checking_away = weechat_infolist_integer (infolist, "checking_away"); str = weechat_infolist_string (infolist, "away_message"); if (str) irc_upgrade_current_channel->away_message = strdup (str); irc_upgrade_current_channel->has_quit_server = weechat_infolist_integer (infolist, "has_quit_server"); irc_upgrade_current_channel->cycle = weechat_infolist_integer (infolist, "cycle"); irc_upgrade_current_channel->part = weechat_infolist_integer (infolist, "part"); irc_upgrade_current_channel->nick_completion_reset = weechat_infolist_integer (infolist, "nick_completion_reset"); for (i = 0; i < 2; i++) { index = 0; while (1) { snprintf (option_name, sizeof (option_name), "nick_speaking%d_%05d", i, index); nick = weechat_infolist_string (infolist, option_name); if (!nick) break; irc_channel_nick_speaking_add (irc_upgrade_current_channel, nick, i); index++; } } index = 0; while (1) { snprintf (option_name, sizeof (option_name), "nick_speaking_time_nick_%05d", index); nick = weechat_infolist_string (infolist, option_name); if (!nick) break; snprintf (option_name, sizeof (option_name), "nick_speaking_time_time_%05d", index); irc_channel_nick_speaking_time_add (irc_upgrade_current_server, irc_upgrade_current_channel, nick, weechat_infolist_time (infolist, option_name)); index++; } str = weechat_infolist_string (infolist, "join_smart_filtered"); if (str) { nicks = weechat_string_split (str, ",", 0, 0, &nicks_count); if (nicks) { for (i = 0; i < nicks_count; i++) { pos = strchr (nicks[i], ':'); if (pos) { nick_join = weechat_strndup (nicks[i], pos - nicks[i]); if (nick_join) { error = NULL; number = strtol (pos + 1, &error, 10); if (error && !error[0]) { join_time = (time_t)number; irc_channel_join_smart_filtered_add (irc_upgrade_current_channel, nick_join, join_time); } free (nick_join); } } } weechat_string_free_split (nicks); } } } } break; case IRC_UPGRADE_TYPE_NICK: if (irc_upgrade_current_server && irc_upgrade_current_channel) { ptr_nick = irc_nick_new (irc_upgrade_current_server, irc_upgrade_current_channel, weechat_infolist_string (infolist, "name"), weechat_infolist_string (infolist, "host"), weechat_infolist_string (infolist, "prefixes"), weechat_infolist_integer (infolist, "away")); if (ptr_nick) { /* * "flags" is not any more in this infolist (since * WeeChat 0.3.4), but we read it to keep compatibility * with old WeeChat versions, on /upgrade) * We try to restore prefixes with old flags, but * this is approximation, it's not sure we will * restore good prefixes here (a /names on channel * will fix problem if prefixes are wrong). * Flags were defined in irc-nick.h: * #define IRC_NICK_CHANOWNER 1 * #define IRC_NICK_CHANADMIN 2 * #define IRC_NICK_CHANADMIN2 4 * #define IRC_NICK_OP 8 * #define IRC_NICK_HALFOP 16 * #define IRC_NICK_VOICE 32 * #define IRC_NICK_AWAY 64 * #define IRC_NICK_CHANUSER 128 */ flags = weechat_infolist_integer (infolist, "flags"); if (flags > 0) { /* channel owner */ if (flags & 1) { irc_nick_set_mode (irc_upgrade_current_server, irc_upgrade_current_channel, ptr_nick, 1, 'q'); } /* channel admin */ if ((flags & 2) || (flags & 4)) { irc_nick_set_mode (irc_upgrade_current_server, irc_upgrade_current_channel, ptr_nick, 1, 'a'); } /* op */ if (flags & 8) { irc_nick_set_mode (irc_upgrade_current_server, irc_upgrade_current_channel, ptr_nick, 1, 'o'); } /* half-op */ if (flags & 16) { irc_nick_set_mode (irc_upgrade_current_server, irc_upgrade_current_channel, ptr_nick, 1, 'h'); } /* voice */ if (flags & 32) { irc_nick_set_mode (irc_upgrade_current_server, irc_upgrade_current_channel, ptr_nick, 1, 'v'); } /* away */ if (flags & 64) { irc_nick_set_away (irc_upgrade_current_server, irc_upgrade_current_channel, ptr_nick, 1); } /* channel user */ if (flags & 128) { irc_nick_set_mode (irc_upgrade_current_server, irc_upgrade_current_channel, ptr_nick, 1, 'u'); } } } } break; case IRC_UPGRADE_TYPE_REDIRECT: if (irc_upgrade_current_server) { ptr_redirect = irc_redirect_new_with_commands ( irc_upgrade_current_server, weechat_infolist_string (infolist, "pattern"), weechat_infolist_string (infolist, "signal"), weechat_infolist_integer (infolist, "count"), weechat_infolist_string (infolist, "string"), weechat_infolist_integer (infolist, "timeout"), weechat_infolist_string (infolist, "cmd_start"), weechat_infolist_string (infolist, "cmd_stop"), weechat_infolist_string (infolist, "cmd_extra"), weechat_infolist_string (infolist, "cmd_filter")); if (ptr_redirect) { ptr_redirect->current_count = weechat_infolist_integer (infolist, "current_count"); str = weechat_infolist_string (infolist, "command"); if (str) ptr_redirect->command = strdup (str); ptr_redirect->assigned_to_command = weechat_infolist_integer (infolist, "assigned_to_command"); ptr_redirect->start_time = weechat_infolist_time (infolist, "start_time"); ptr_redirect->cmd_start_received = weechat_infolist_integer (infolist, "cmd_start_received"); ptr_redirect->cmd_stop_received = weechat_infolist_integer (infolist, "cmd_stop_received"); str = weechat_infolist_string (infolist, "output"); if (str) ptr_redirect->output = strdup (str); ptr_redirect->output_size = weechat_infolist_integer (infolist, "output_size"); } } break; case IRC_UPGRADE_TYPE_REDIRECT_PATTERN: irc_redirect_pattern_new ( weechat_infolist_string (infolist, "name"), weechat_infolist_integer (infolist, "temp_pattern"), weechat_infolist_integer (infolist, "timeout"), weechat_infolist_string (infolist, "cmd_start"), weechat_infolist_string (infolist, "cmd_stop"), weechat_infolist_string (infolist, "cmd_extra")); break; case IRC_UPGRADE_TYPE_NOTIFY: if (irc_upgrade_current_server) { ptr_notify = irc_notify_search (irc_upgrade_current_server, weechat_infolist_string (infolist, "nick")); if (ptr_notify) { ptr_notify->is_on_server = weechat_infolist_integer (infolist, "is_on_server"); str = weechat_infolist_string (infolist, "away_message"); if (str) ptr_notify->away_message = strdup (str); } } break; case IRC_UPGRADE_TYPE_RAW_MESSAGE: irc_raw_message_add_to_list (weechat_infolist_time (infolist, "date"), weechat_infolist_string (infolist, "prefix"), weechat_infolist_string (infolist, "message")); break; } } return WEECHAT_RC_OK; }
int xfer_network_fd_cb (void *arg_xfer, int fd) { struct t_xfer *xfer; int sock; struct sockaddr_in addr; socklen_t length; /* make C compiler happy */ (void) fd; xfer = (struct t_xfer *)arg_xfer; if (xfer->status == XFER_STATUS_CONNECTING) { if (xfer->type == XFER_TYPE_FILE_SEND) { xfer->last_activity = time (NULL); length = sizeof (addr); sock = accept (xfer->sock, (struct sockaddr *) &addr, &length); weechat_unhook (xfer->hook_fd); xfer->hook_fd = NULL; close (xfer->sock); xfer->sock = -1; if (sock < 0) { weechat_printf (NULL, _("%s%s: unable to create socket for sending " "file"), weechat_prefix ("error"), XFER_PLUGIN_NAME); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_RC_OK; } xfer->sock = sock; if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) { weechat_printf (NULL, _("%s%s: unable to set option \"nonblock\" " "for socket"), weechat_prefix ("error"), XFER_PLUGIN_NAME); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_RC_OK; } xfer->address = ntohl (addr.sin_addr.s_addr); xfer->status = XFER_STATUS_ACTIVE; xfer->start_transfer = time (NULL); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); xfer_network_send_file_fork (xfer); } /* if (xfer->type == XFER_TYPE_FILE_RECV) { if (xfer->child_read != -1) irc_dcc_file_child_read (dcc); } */ } if (xfer->status == XFER_STATUS_WAITING) { if (xfer->type == XFER_TYPE_CHAT_SEND) { length = sizeof (addr); sock = accept (xfer->sock, (struct sockaddr *) &addr, &length); weechat_unhook (xfer->hook_fd); xfer->hook_fd = NULL; close (xfer->sock); xfer->sock = -1; if (sock < 0) { weechat_printf (NULL, _("%s%s: unable to create socket for sending " "file"), weechat_prefix ("error"), XFER_PLUGIN_NAME); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_RC_OK; } xfer->sock = sock; if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) { weechat_printf (NULL, _("%s%s: unable to set option \"nonblock\" " "for socket"), weechat_prefix ("error"), XFER_PLUGIN_NAME); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_RC_OK; } xfer->address = ntohl (addr.sin_addr.s_addr); xfer->status = XFER_STATUS_ACTIVE; xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); xfer->hook_fd = weechat_hook_fd (xfer->sock, 1, 0, 0, &xfer_chat_recv_cb, xfer); xfer_chat_open_buffer (xfer); } } /* if (xfer->status == XFER_STATUS_ACTIVE) { if (XFER_IS_CHAT(dcc->type)) { irc_dcc_chat_recv (dcc); } else irc_dcc_file_child_read (dcc); } */ return WEECHAT_RC_OK; }
struct t_relay_client * relay_client_new (int sock, const char *address, struct t_relay_server *server) { struct t_relay_client *new_client; new_client = malloc (sizeof (*new_client)); if (new_client) { new_client->id = (relay_clients) ? relay_clients->id + 1 : 1; new_client->sock = sock; new_client->address = strdup ((address) ? address : "?"); new_client->status = RELAY_STATUS_CONNECTED; new_client->protocol = server->protocol; new_client->protocol_args = (server->protocol_args) ? strdup (server->protocol_args) : NULL; new_client->listen_start_time = server->start_time; new_client->start_time = time (NULL); new_client->end_time = 0; new_client->hook_fd = NULL; new_client->last_activity = new_client->start_time; new_client->bytes_recv = 0; new_client->bytes_sent = 0; new_client->protocol_data = NULL; switch (new_client->protocol) { case RELAY_PROTOCOL_WEECHAT: relay_weechat_alloc (new_client); break; case RELAY_PROTOCOL_IRC: relay_irc_alloc (new_client); break; case RELAY_NUM_PROTOCOLS: break; } new_client->prev_client = NULL; new_client->next_client = relay_clients; if (relay_clients) relay_clients->prev_client = new_client; else last_relay_client = new_client; relay_clients = new_client; weechat_printf (NULL, _("%s: new client from %s%s%s on port %d (id: %d, relaying: %s%s%s)"), RELAY_PLUGIN_NAME, RELAY_COLOR_CHAT_HOST, new_client->address, RELAY_COLOR_CHAT, server->port, new_client->id, relay_protocol_string[new_client->protocol], (new_client->protocol_args) ? "." : "", (new_client->protocol_args) ? new_client->protocol_args : ""); new_client->hook_fd = weechat_hook_fd (new_client->sock, 1, 0, 0, &relay_client_recv_cb, new_client); relay_client_count++; if (!relay_buffer && weechat_config_boolean (relay_config_look_auto_open_buffer)) { relay_buffer_open (); } relay_buffer_refresh (WEECHAT_HOTLIST_PRIVATE); } else { weechat_printf (NULL, _("%s%s: not enough memory for new client"), weechat_prefix ("error"), RELAY_PLUGIN_NAME); } return new_client; }
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 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 = weechat_hook_fd (xfer->sock, 1, 0, 0, &xfer_network_fd_cb, xfer, NULL); /* add timeout */ if (weechat_config_integer (xfer_config_network_timeout) > 0) { xfer->hook_timer = weechat_hook_timer (weechat_config_integer (xfer_config_network_timeout) * 1000, 0, 1, &xfer_network_timer_cb, xfer, NULL); } } /* for chat receiving, connect to listening host */ if (xfer->type == XFER_TYPE_CHAT_RECV) { xfer->hook_connect = weechat_hook_connect (xfer->proxy, xfer->remote_address_str, xfer->port, 1, 0, NULL, NULL, 0, "NONE", NULL, &xfer_network_connect_chat_recv_cb, xfer, NULL); } /* for file receiving, connection is made in child process (blocking) */ return 1; }
int xfer_network_connect_chat_recv_cb (const void *pointer, 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) data; (void) gnutls_rc; (void) ip_address; xfer = (struct t_xfer*)pointer; weechat_unhook (xfer->hook_connect); xfer->hook_connect = NULL; /* connection OK? */ if (status == WEECHAT_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) { weechat_printf (NULL, _("%s%s: unable to set option \"nonblock\" " "for socket: error %d %s"), weechat_prefix ("error"), XFER_PLUGIN_NAME, errno, strerror (errno)); close (xfer->sock); xfer->sock = -1; xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_RC_OK; } xfer->hook_fd = weechat_hook_fd (xfer->sock, 1, 0, 0, &xfer_chat_recv_cb, xfer, NULL); xfer_chat_open_buffer (xfer); xfer->status = XFER_STATUS_ACTIVE; xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_RC_OK; } /* connection error */ switch (status) { case WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND: weechat_printf (NULL, (xfer->proxy && xfer->proxy[0]) ? _("%s%s: proxy address \"%s\" not found") : _("%s%s: address \"%s\" not found"), weechat_prefix ("error"), XFER_PLUGIN_NAME, xfer->remote_address_str); break; case WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND: weechat_printf (NULL, (xfer->proxy && xfer->proxy[0]) ? _("%s%s: proxy IP address not found") : _("%s%s: IP address not found"), weechat_prefix ("error"), XFER_PLUGIN_NAME); break; case WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED: weechat_printf (NULL, (xfer->proxy && xfer->proxy[0]) ? _("%s%s: proxy connection refused") : _("%s%s: connection refused"), weechat_prefix ("error"), XFER_PLUGIN_NAME); break; case WEECHAT_HOOK_CONNECT_PROXY_ERROR: weechat_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)"), weechat_prefix ("error"), XFER_PLUGIN_NAME); break; case WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR: weechat_printf (NULL, _("%s%s: unable to set local hostname/IP"), weechat_prefix ("error"), XFER_PLUGIN_NAME); break; case WEECHAT_HOOK_CONNECT_MEMORY_ERROR: weechat_printf (NULL, _("%s%s: not enough memory (%s)"), weechat_prefix ("error"), XFER_PLUGIN_NAME, (error) ? error : "-"); break; case WEECHAT_HOOK_CONNECT_TIMEOUT: weechat_printf (NULL, _("%s%s: timeout"), weechat_prefix ("error"), XFER_PLUGIN_NAME); break; case WEECHAT_HOOK_CONNECT_SOCKET_ERROR: weechat_printf (NULL, _("%s%s: unable to create socket"), weechat_prefix ("error"), XFER_PLUGIN_NAME); break; default: weechat_printf (NULL, _("%s%s: unable to connect: unexpected error (%d)"), weechat_prefix ("error"), XFER_PLUGIN_NAME, status); break; } if (error && error[0]) { weechat_printf (NULL, _("%s%s: error: %s"), weechat_prefix ("error"), XFER_PLUGIN_NAME, error); } xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_RC_OK; }
int xfer_network_fd_cb (const void *pointer, void *data, 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) data; (void) fd; length = sizeof (addr); memset (&addr, 0, length); xfer = (struct t_xfer *)pointer; 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; weechat_unhook (xfer->hook_fd); xfer->hook_fd = NULL; close (xfer->sock); xfer->sock = -1; if (sock < 0) { weechat_printf (NULL, _("%s%s: unable to create socket for sending " "file: error %d %s"), weechat_prefix ("error"), XFER_PLUGIN_NAME, error, strerror (error)); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_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) { weechat_printf (NULL, _("%s%s: unable to set option \"nonblock\" " "for socket: error %d %s"), weechat_prefix ("error"), XFER_PLUGIN_NAME, errno, strerror (errno)); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_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 (WEECHAT_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; weechat_unhook (xfer->hook_fd); xfer->hook_fd = NULL; close (xfer->sock); xfer->sock = -1; if (sock < 0) { weechat_printf (NULL, _("%s%s: unable to create socket for sending " "file: error %d %s"), weechat_prefix ("error"), XFER_PLUGIN_NAME, error, strerror (error)); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_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) { weechat_printf (NULL, _("%s%s: unable to set option \"nonblock\" " "for socket: error %d %s"), weechat_prefix ("error"), XFER_PLUGIN_NAME, errno, strerror (errno)); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); return WEECHAT_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 (WEECHAT_HOTLIST_MESSAGE); xfer->hook_fd = weechat_hook_fd (xfer->sock, 1, 0, 0, &xfer_chat_recv_cb, xfer, NULL); xfer_chat_open_buffer (xfer); } } return WEECHAT_RC_OK; }
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 */ weechat_printf (NULL, _("%s%s: unable to fork (%s)"), weechat_prefix ("error"), XFER_PLUGIN_NAME, strerror (errno)); xfer_close (xfer, XFER_STATUS_FAILED); xfer_buffer_refresh (WEECHAT_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); } weechat_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 = weechat_hook_fd (xfer->child_read, 1, 0, 0, &xfer_network_child_read_cb, xfer, NULL); }
int relay_server_create_socket (struct t_relay_server *server) { int set, max_clients; struct sockaddr_in server_addr; server->sock = socket (AF_INET, SOCK_STREAM, 0); if (server->sock < 0) { weechat_printf (NULL, _("%s%s: cannot create socket"), weechat_prefix ("error"), RELAY_PLUGIN_NAME); return 0; } set = 1; if (setsockopt (server->sock, SOL_SOCKET, SO_REUSEADDR, (void *) &set, sizeof (set)) < 0) { weechat_printf (NULL, _("%s%s: cannot set socket option " "\"SO_REUSEADDR\""), weechat_prefix ("error"), RELAY_PLUGIN_NAME); close (server->sock); server->sock = -1; return 0; } set = 1; if (setsockopt (server->sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &set, sizeof (set)) < 0) { weechat_printf (NULL, _("%s%s: cannot set socket option " "\"SO_KEEPALIVE\""), weechat_prefix ("error"), RELAY_PLUGIN_NAME); close (server->sock); server->sock = -1; return 0; } memset(&server_addr, 0, sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; if (weechat_config_string (relay_config_network_bind_address) && weechat_config_string (relay_config_network_bind_address)[0]) { server_addr.sin_addr.s_addr = inet_addr (weechat_config_string (relay_config_network_bind_address)); } else { server_addr.sin_addr.s_addr = INADDR_ANY; } server_addr.sin_port = htons (server->port); if (bind (server->sock, (struct sockaddr *) &server_addr, sizeof (server_addr)) < 0) { weechat_printf (NULL, _("%s%s: error with \"bind\" on port %d (%s%s%s)"), weechat_prefix ("error"), RELAY_PLUGIN_NAME, server->port, relay_protocol_string[server->protocol], (server->protocol_args) ? "." : "", (server->protocol_args) ? server->protocol_args : ""); close (server->sock); server->sock = -1; return 0; } max_clients = weechat_config_integer (relay_config_network_max_clients); listen (server->sock, max_clients); weechat_printf (NULL, _("%s: listening on port %d (relay: %s%s%s, max %d clients)"), RELAY_PLUGIN_NAME, server->port, relay_protocol_string[server->protocol], (server->protocol_args) ? "." : "", (server->protocol_args) ? server->protocol_args : "", max_clients); server->hook_fd = weechat_hook_fd (server->sock, 1, 0, 0, &relay_server_sock_cb, server); server->start_time = time (NULL); return 1; }
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 = 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 { 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); } /* 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; } #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) { 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) { 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; } max_clients = weechat_config_integer (relay_config_network_max_clients); if (listen (server->sock, max_clients) != 0) { 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; } weechat_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 = weechat_hook_fd (server->sock, 1, 0, 0, &relay_server_sock_cb, server); server->start_time = time (NULL); return 1; }