diff options
author | Timo Sirainen <cras@irssi.org> | 2002-05-19 14:43:16 +0000 |
---|---|---|
committer | cras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564> | 2002-05-19 14:43:16 +0000 |
commit | 6f7485b8fa6888d137243742cb31fa0848abe3ba (patch) | |
tree | fc8ad5d0a1df7d353ed70507a0cdced76696f84e /src/core | |
parent | 7437bbea5fa8025374b4b127d4a6e4e67d75ab94 (diff) | |
download | irssi-6f7485b8fa6888d137243742cb31fa0848abe3ba.zip |
net_connect*() contains now error parameter, so it can be used to properly
check the errno if connect() fails.
Added support for connecting to named UNIX sockets. Some cleanups with
session handling / server connecting as well.
git-svn-id: http://svn.irssi.org/repos/irssi/trunk@2819 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/chat-commands.c | 5 | ||||
-rw-r--r-- | src/core/chatnets.c | 3 | ||||
-rw-r--r-- | src/core/net-nonblock.c | 5 | ||||
-rw-r--r-- | src/core/network.c | 56 | ||||
-rw-r--r-- | src/core/network.h | 6 | ||||
-rw-r--r-- | src/core/server-connect-rec.h | 4 | ||||
-rw-r--r-- | src/core/servers.c | 152 | ||||
-rw-r--r-- | src/core/session.c | 5 |
8 files changed, 163 insertions, 73 deletions
diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c index 838db914..debe6655 100644 --- a/src/core/chat-commands.c +++ b/src/core/chat-commands.c @@ -69,7 +69,7 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr, g_hash_table_lookup(optlist, proto->chatnet); conn = server_create_conn(proto != NULL ? proto->id : -1, addr, atoi(portstr), chatnet, password, nick); - if (proto == NULL) + if (proto == NULL) proto = chat_protocol_find_id(conn->chat_type); if (proto->not_initialized) { @@ -80,6 +80,9 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr, return NULL; } + if (strchr(addr, '/') != NULL) + conn->unix_socket = TRUE; + if (g_hash_table_lookup(optlist, "6") != NULL) conn->family = AF_INET6; else if (g_hash_table_lookup(optlist, "4") != NULL) diff --git a/src/core/chatnets.c b/src/core/chatnets.c index 502d11d7..f7b0ec62 100644 --- a/src/core/chatnets.c +++ b/src/core/chatnets.c @@ -118,8 +118,7 @@ static void sig_connected(SERVER_REC *server) g_return_if_fail(IS_SERVER(server)); - if (server->connrec->chatnet == NULL || - server->session_reconnect) + if (server->connrec->chatnet == NULL || server->session_reconnect) return; rec = chatnet_find(server->connrec->chatnet); diff --git a/src/core/net-nonblock.c b/src/core/net-nonblock.c index 7392f429..cf0b9596 100644 --- a/src/core/net-nonblock.c +++ b/src/core/net-nonblock.c @@ -186,7 +186,8 @@ static void simple_readpipe(SIMPLE_THREAD_REC *rec, GIOChannel *pipe) { RESOLVED_IP_REC iprec; GIOChannel *handle; - IPADDR *ip; + IPADDR *ip; + int error; g_return_if_fail(rec != NULL); @@ -202,7 +203,7 @@ static void simple_readpipe(SIMPLE_THREAD_REC *rec, GIOChannel *pipe) ip = iprec.ip4.family != 0 ? &iprec.ip4 : &iprec.ip6; handle = iprec.error == -1 ? NULL : - net_connect_ip(ip, rec->port, rec->my_ip); + net_connect_ip(ip, rec->port, rec->my_ip, &error); g_free_not_null(rec->my_ip); diff --git a/src/core/network.c b/src/core/network.c index e53b0189..5b4fa1ed 100644 --- a/src/core/network.c +++ b/src/core/network.c @@ -21,6 +21,8 @@ #include "module.h" #include "network.h" +#include <sys/un.h> + #ifndef INADDR_NONE # define INADDR_NONE INADDR_BROADCAST #endif @@ -133,7 +135,7 @@ int sin_get_port(union sockaddr_union *so) } /* Connect to socket */ -GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) +GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip, int *error) { IPADDR ip4, ip6, *ip; int family; @@ -141,8 +143,11 @@ GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) g_return_val_if_fail(addr != NULL, NULL); family = my_ip == NULL ? 0 : my_ip->family; - if (net_gethostbyname(addr, &ip4, &ip6) == -1) + if (net_gethostbyname(addr, &ip4, &ip6) == -1) { + if (error != NULL) + *error = errno; return NULL; + } if (my_ip == NULL) { /* prefer IPv4 addresses */ @@ -165,11 +170,11 @@ GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) } } - return net_connect_ip(ip, port, my_ip); + return net_connect_ip(ip, port, my_ip, error); } /* Connect to socket with ip address */ -GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) +GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip, int *error) { union sockaddr_union so; int handle, ret, opt = 1; @@ -184,8 +189,11 @@ GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) so.sin.sin_family = ip->family; handle = socket(ip->family, SOCK_STREAM, 0); - if (handle == -1) + if (handle == -1) { + if (error != NULL) + *error = errno; return NULL; + } /* set socket options */ #ifndef WIN32 @@ -217,6 +225,44 @@ GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) #endif { + if (error != NULL) + *error = errno; + close(handle); + return NULL; + } + + return g_io_channel_new(handle); +} + +/* Connect to named UNIX socket */ +GIOChannel *net_connect_unix(const char *path, int *error) +{ + struct sockaddr_un sa; + int handle, ret; + + /* create the socket */ + handle = socket(PF_UNIX, SOCK_STREAM, 0); + if (handle == -1) { + if (error != NULL) + *error = errno; + return NULL; + } + + /* set socket options */ +#ifndef WIN32 + fcntl(handle, F_SETFL, O_NONBLOCK); +#endif + + /* connect */ + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, path, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path)-1] = '\0'; + + ret = connect(handle, (struct sockaddr *) &sa, sizeof(sa)); + if (ret < 0 && errno != EINPROGRESS) { + if (error != NULL) + *error = errno; close(handle); return NULL; } diff --git a/src/core/network.h b/src/core/network.h index 4c25740f..c65c23ca 100644 --- a/src/core/network.h +++ b/src/core/network.h @@ -43,9 +43,11 @@ struct _IPADDR { int net_ip_compare(IPADDR *ip1, IPADDR *ip2); /* Connect to socket */ -GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip); +GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip, int *error); /* Connect to socket with ip address */ -GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip); +GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip, int *error); +/* Connect to named UNIX socket */ +GIOChannel *net_connect_unix(const char *path, int *error); /* Disconnect socket */ void net_disconnect(GIOChannel *handle); /* Try to let the other side close the connection, if it still isn't diff --git a/src/core/server-connect-rec.h b/src/core/server-connect-rec.h index a59880e4..cc5afa57 100644 --- a/src/core/server-connect-rec.h +++ b/src/core/server-connect-rec.h @@ -23,8 +23,12 @@ char *nick; char *username; char *realname; +GIOChannel *connect_handle; /* connect using this handle */ + /* when reconnecting, the old server status */ unsigned int reconnection:1; /* we're trying to reconnect */ unsigned int no_autojoin_channels:1; /* don't autojoin any channels */ +unsigned int unix_socket:1; /* Connect using named unix socket */ +unsigned int session_reconnect:1; /* Connected to this server with /UPGRADE */ char *channels; char *away_reason; diff --git a/src/core/servers.c b/src/core/servers.c index 1e5c0b84..e16d323c 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -161,16 +161,47 @@ static void server_connect_callback_init(SERVER_REC *server, GIOChannel *handle) server_connect_finished(server); } +static void server_real_connect(SERVER_REC *server, IPADDR *ip, + const char *unix_socket) +{ + GIOChannel *handle; + IPADDR *own_ip; + int port, error; + + g_return_if_fail(ip != NULL || unix_socket != NULL); + + signal_emit("server connecting", 2, server, ip); + + if (ip != NULL) { + own_ip = ip == NULL ? NULL : + (IPADDR_IS_V6(ip) ? server->connrec->own_ip6 : + server->connrec->own_ip4); + port = server->connrec->proxy != NULL ? + server->connrec->proxy_port : server->connrec->port; + handle = net_connect_ip(ip, port, own_ip, &error); + } else { + handle = net_connect_unix(unix_socket, &error); + } + + if (handle == NULL) { + /* failed */ + server->connection_lost = TRUE; + server_connect_failed(server, g_strerror(error)); + } else { + server->handle = net_sendbuffer_create(handle, 0); + server->connect_tag = + g_input_add(handle, G_INPUT_WRITE | G_INPUT_READ, + (GInputFunction) + server_connect_callback_init, + server); + } +} + static void server_connect_callback_readpipe(SERVER_REC *server) { - SERVER_CONNECT_REC *conn; RESOLVED_IP_REC iprec; - GIOChannel *handle; - IPADDR *ip, *own_ip; + IPADDR *ip; const char *errormsg; - int port; - - g_return_if_fail(IS_SERVER(server)); g_source_remove(server->connect_tag); server->connect_tag = -1; @@ -204,33 +235,18 @@ static void server_connect_callback_readpipe(SERVER_REC *server) &iprec.ip6 : &iprec.ip4; } - conn = server->connrec; - port = conn->proxy != NULL ? conn->proxy_port : conn->port; - own_ip = ip == NULL ? NULL : - (IPADDR_IS_V6(ip) ? conn->own_ip6 : conn->own_ip4); - - handle = NULL; if (ip != NULL) { - signal_emit("server connecting", 2, server, ip); - if (server->handle == NULL) - handle = net_connect_ip(ip, port, own_ip); - else - handle = net_sendbuffer_handle(server->handle); - } - - if (handle == NULL) { - /* failed */ - if (ip == NULL && (iprec.error == 0 || - net_hosterror_notfound(iprec.error))) { - /* IP wasn't found for the host, don't try to reconnect - back to this server */ + /* host lookup ok */ + server_real_connect(server, ip, NULL); + errormsg = NULL; + } else { + if (iprec.error == 0 || net_hosterror_notfound(iprec.error)) { + /* IP wasn't found for the host, don't try to + reconnect back to this server */ server->dns_error = TRUE; } - if (ip != NULL) { - /* connect() failed */ - errormsg = g_strerror(errno); - } else if (iprec.error == 0) { + if (iprec.error == 0) { /* forced IPv4 or IPv6 address but it wasn't found */ errormsg = server->connrec->family == AF_INET ? "IPv4 address not found for host" : @@ -240,18 +256,12 @@ static void server_connect_callback_readpipe(SERVER_REC *server) errormsg = iprec.errorstr != NULL ? iprec.errorstr : "Host lookup failed"; } + server->connection_lost = TRUE; server_connect_failed(server, errormsg); - g_free_not_null(iprec.errorstr); - return; } - if (server->handle == NULL) - server->handle = net_sendbuffer_create(handle, 0); - server->connect_tag = - g_input_add(handle, G_INPUT_WRITE | G_INPUT_READ, - (GInputFunction) server_connect_callback_init, - server); + g_free(iprec.errorstr); } /* initializes server record but doesn't start connecting */ @@ -282,6 +292,7 @@ void server_connect_init(SERVER_REC *server) } server->tag = server_create_tag(server->connrec); + server->connect_tag = -1; } /* starts connecting to server */ @@ -291,34 +302,56 @@ int server_start_connect(SERVER_REC *server) int fd[2]; g_return_val_if_fail(server != NULL, FALSE); - if (server->connrec->port <= 0) return FALSE; + if (!server->connrec->unix_socket && server->connrec->port <= 0) + return FALSE; server_connect_init(server); + server->rawlog = rawlog_create(); - if (pipe(fd) != 0) { - g_warning("server_connect(): pipe() failed."); - g_free(server->tag); - g_free(server->nick); - return FALSE; + if (server->connrec->session_reconnect) { + /* /UPGRADE connection - the session_connect is meant + for us only once, move it into server->session_connect */ + server->connrec->session_reconnect = FALSE; + server->session_reconnect = TRUE; } - server->connect_pipe[0] = g_io_channel_unix_new(fd[0]); - server->connect_pipe[1] = g_io_channel_unix_new(fd[1]); - - connect_address = server->connrec->proxy != NULL ? - server->connrec->proxy : server->connrec->address; - server->connect_pid = - net_gethostbyname_nonblock(connect_address, - server->connect_pipe[1]); - server->connect_tag = - g_input_add(server->connect_pipe[0], G_INPUT_READ, - (GInputFunction) server_connect_callback_readpipe, - server); - server->rawlog = rawlog_create(); + if (server->connrec->connect_handle != NULL) { + /* already connected */ + GIOChannel *handle = server->connrec->connect_handle; + + server->connrec->connect_handle = NULL; + server->handle = net_sendbuffer_create(handle, 0); + server_connect_finished(server); + } else if (server->connrec->unix_socket) { + /* connect with unix socket */ + server_real_connect(server, NULL, server->connrec->address); + } else { + /* resolve host name */ + if (pipe(fd) != 0) { + g_warning("server_connect(): pipe() failed."); + g_free(server->tag); + g_free(server->nick); + return FALSE; + } + + server->connect_pipe[0] = g_io_channel_unix_new(fd[0]); + server->connect_pipe[1] = g_io_channel_unix_new(fd[1]); + + connect_address = server->connrec->proxy != NULL ? + server->connrec->proxy : server->connrec->address; + server->connect_pid = + net_gethostbyname_nonblock(connect_address, + server->connect_pipe[1]); + server->connect_tag = + g_input_add(server->connect_pipe[0], G_INPUT_READ, + (GInputFunction) + server_connect_callback_readpipe, + server); - lookup_servers = g_slist_append(lookup_servers, server); + lookup_servers = g_slist_append(lookup_servers, server); - signal_emit("server looking", 1, server); + signal_emit("server looking", 1, server); + } return TRUE; } @@ -486,6 +519,9 @@ void server_connect_unref(SERVER_CONNECT_REC *conn) CHAT_PROTOCOL(conn)->destroy_server_connect(conn); + if (conn->connect_handle != NULL) + net_disconnect(conn->connect_handle); + g_free_not_null(conn->proxy); g_free_not_null(conn->proxy_string); g_free_not_null(conn->proxy_string_after); diff --git a/src/core/session.c b/src/core/session.c index 4e7a832c..94bedfb6 100644 --- a/src/core/session.c +++ b/src/core/session.c @@ -276,11 +276,10 @@ static void session_restore_server(CONFIG_NODE *node) chatnet, password, nick); if (conn != NULL) { conn->reconnection = TRUE; + conn->connect_handle = g_io_channel_unix_new(handle); + conn->session_reconnect = TRUE; server = proto->server_connect(conn); - server->handle = net_sendbuffer_create(g_io_channel_unix_new(handle), 0); - server->session_reconnect = TRUE; - signal_emit("session restore server", 2, server, node); } } |