/* Connect to server, call func when finished */ int net_connect_nonblock(const char *server, int port, const IPADDR *my_ip, NET_CALLBACK func, void *data) { SIMPLE_THREAD_REC *rec; int fd[2]; g_return_val_if_fail(server != NULL, FALSE); g_return_val_if_fail(func != NULL, FALSE); if (pipe(fd) != 0) { g_warning("net_connect_nonblock(): pipe() failed."); return FALSE; } rec = g_new0(SIMPLE_THREAD_REC, 1); rec->port = port; if (my_ip != NULL) { rec->my_ip = g_malloc(sizeof(IPADDR)); memcpy(rec->my_ip, my_ip, sizeof(IPADDR)); } rec->func = func; rec->data = data; rec->pipes[0] = g_io_channel_new(fd[0]); rec->pipes[1] = g_io_channel_new(fd[1]); /* start nonblocking host name lookup */ net_gethostbyname_nonblock(server, rec->pipes[1], 0); rec->tag = g_input_add(rec->pipes[0], G_INPUT_READ, (GInputFunction) simple_readpipe, rec); return TRUE; }
/* starts connecting to server */ int server_start_connect(SERVER_REC *server) { const char *connect_address; int fd[2]; g_return_val_if_fail(server != NULL, FALSE); if (!server->connrec->unix_socket && server->connrec->port <= 0) return FALSE; 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_new(fd[0]); server->connect_pipe[1] = g_io_channel_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], settings_get_bool("resolve_reverse_lookup")); 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); signal_emit("server looking", 1, server); } return TRUE; }
/* Connect to named UNIX socket */ GIOChannel *net_connect_unix(const char *path) { struct sockaddr_un sa; int handle, ret; /* create the socket */ handle = socket(PF_UNIX, SOCK_STREAM, 0); if (handle == -1) 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) { int old_errno = errno; close(handle); errno = old_errno; return NULL; } return g_io_channel_new(handle); }
/* Connect to socket with ip address */ GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) { union sockaddr_union so; int handle, ret, opt = 1; if (my_ip != NULL && ip->family != my_ip->family) { g_warning("net_connect_ip(): ip->family != my_ip->family"); my_ip = NULL; } /* create the socket */ memset(&so, 0, sizeof(so)); so.sin.sin_family = ip->family; handle = socket(ip->family, SOCK_STREAM, 0); if (handle == -1) return NULL; /* set socket options */ #ifndef WIN32 fcntl(handle, F_SETFL, O_NONBLOCK); #endif setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)); setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt)); /* set our own address */ if (my_ip != NULL) { sin_set_ip(&so, my_ip); if (bind(handle, &so.sa, SIZEOF_SOCKADDR(so)) == -1) { /* failed, set it back to INADDR_ANY */ sin_set_ip(&so, NULL); bind(handle, &so.sa, SIZEOF_SOCKADDR(so)); } } /* connect */ sin_set_ip(&so, ip); sin_set_port(&so, port); ret = connect(handle, &so.sa, SIZEOF_SOCKADDR(so)); #ifndef WIN32 if (ret < 0 && errno != EINPROGRESS) #else if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) #endif { int old_errno = errno; close(handle); errno = old_errno; return NULL; } return g_io_channel_new(handle); }
/* Listen for connections on a socket. if `my_ip' is NULL, listen in any address. */ GIOChannel *net_listen(IPADDR *my_ip, int *port) { union sockaddr_union so; int ret, handle, opt = 1; socklen_t len; g_return_val_if_fail(port != NULL, NULL); memset(&so, 0, sizeof(so)); sin_set_port(&so, *port); sin_set_ip(&so, my_ip); /* create the socket */ handle = socket(so.sin.sin_family, SOCK_STREAM, 0); #ifdef HAVE_IPV6 if (handle == -1 && (errno == EINVAL || errno == EAFNOSUPPORT)) { /* IPv6 is not supported by OS */ so.sin.sin_family = AF_INET; so.sin.sin_addr.s_addr = INADDR_ANY; handle = socket(AF_INET, SOCK_STREAM, 0); } #endif if (handle == -1) return NULL; /* set socket options */ #ifndef WIN32 fcntl(handle, F_SETFL, O_NONBLOCK); #endif setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)); setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt)); /* specify the address/port we want to listen in */ ret = bind(handle, &so.sa, SIZEOF_SOCKADDR(so)); if (ret >= 0) { /* get the actual port we started listen */ len = SIZEOF_SOCKADDR(so); ret = getsockname(handle, &so.sa, &len); if (ret >= 0) { *port = sin_get_port(&so); /* start listening */ if (listen(handle, 1) >= 0) return g_io_channel_new(handle); } } /* error */ close(handle); return NULL; }
/* Accept a connection on a socket */ GIOChannel *net_accept(GIOChannel *handle, IPADDR *addr, int *port) { union sockaddr_union so; int ret; socklen_t addrlen; g_return_val_if_fail(handle != NULL, NULL); addrlen = sizeof(so); ret = accept(g_io_channel_unix_get_fd(handle), &so.sa, &addrlen); if (ret < 0) return NULL; if (addr != NULL) sin_get_ip(&so, addr); if (port != NULL) *port = sin_get_port(&so); #ifndef WIN32 fcntl(ret, F_SETFL, O_NONBLOCK); #endif return g_io_channel_new(ret); }
static void session_restore_server(CONFIG_NODE *node) { CHAT_PROTOCOL_REC *proto; SERVER_CONNECT_REC *conn; SERVER_REC *server; const char *chat_type, *address, *chatnet, *password, *nick; int port, handle; chat_type = config_node_get_str(node, "chat_type", NULL); address = config_node_get_str(node, "address", NULL); port = config_node_get_int(node, "port", 0); chatnet = config_node_get_str(node, "chatnet", NULL); password = config_node_get_str(node, "password", NULL); nick = config_node_get_str(node, "nick", NULL); handle = config_node_get_int(node, "handle", -1); if (chat_type == NULL || address == NULL || nick == NULL || handle < 0) return; proto = chat_protocol_find(chat_type); if (proto == NULL || proto->not_initialized) { if (handle < 0) close(handle); return; } conn = server_create_conn(proto->id, address, port, chatnet, password, nick); if (conn != NULL) { conn->reconnection = TRUE; conn->connect_handle = g_io_channel_new(handle); server = proto->server_init_connect(conn); server->version = g_strdup(config_node_get_str(node, "version", NULL)); server->session_reconnect = TRUE; signal_emit("session restore server", 2, server, node); proto->server_connect(server); } }