summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2002-05-19 14:43:16 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2002-05-19 14:43:16 +0000
commit6f7485b8fa6888d137243742cb31fa0848abe3ba (patch)
treefc8ad5d0a1df7d353ed70507a0cdced76696f84e /src/core
parent7437bbea5fa8025374b4b127d4a6e4e67d75ab94 (diff)
downloadirssi-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.c5
-rw-r--r--src/core/chatnets.c3
-rw-r--r--src/core/net-nonblock.c5
-rw-r--r--src/core/network.c56
-rw-r--r--src/core/network.h6
-rw-r--r--src/core/server-connect-rec.h4
-rw-r--r--src/core/servers.c152
-rw-r--r--src/core/session.c5
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);
}
}