Ejemplo n.º 1
0
int nntp_threaded_connect(Folder * folder, const char * server, int port)
{
	struct connect_param param;
	struct connect_result result;
	chashdatum key;
	chashdatum value;
	newsnntp * nntp, * oldnntp;
	
	oldnntp = get_nntp(folder);

	nntp = newsnntp_new(0, NULL);
	
	if (oldnntp) {
		debug_print("deleting old nntp %p\n", oldnntp);
		delete_nntp(folder, oldnntp);
	}
	
	key.data = &folder;
	key.len = sizeof(folder);
	value.data = nntp;
	value.len = 0;
	chash_set(session_hash, &key, &value, NULL);
	
	param.nntp = nntp;
	param.server = server;
	param.port = port;
	
	refresh_resolvers();
	threaded_run(folder, &param, &result, connect_run);
	
	debug_print("connect ok %i with nntp %p\n", result.error, nntp);
	
	return result.error;
}
Ejemplo n.º 2
0
static gint sock_connect_by_hostname(gint sock, const gchar *hostname,
				     gushort port)
{
	struct hostent *hp;
	struct sockaddr_in ad;

	memset(&ad, 0, sizeof(ad));
	ad.sin_family = AF_INET;
	ad.sin_port = htons(port);

	refresh_resolvers();

	if (!my_inet_aton(hostname, &ad.sin_addr)) {
		if ((hp = my_gethostbyname(hostname)) == NULL) {
			g_printerr("%s: unknown host.\n", hostname);
			errno = 0;
			return -1;
		}

		if (hp->h_length != 4 && hp->h_length != 8) {
			g_printerr("illegal address length received for host %s\n", hostname);
			errno = 0;
			return -1;
		}

		memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
	}

	return sock_connect_with_timeout(sock, (struct sockaddr *)&ad,
					 sizeof(ad), io_timeout);
}
Ejemplo n.º 3
0
static SockLookupData *sock_get_address_info_async(const gchar *hostname,
						   gushort port,
						   SockAddrFunc func,
						   gpointer data)
{
	SockLookupData *lookup_data = NULL;
	
	refresh_resolvers();

        lookup_data = g_new0(SockLookupData, 1);
        lookup_data->hostname = g_strdup(hostname);
        lookup_data->func = func;
        lookup_data->data = data;
        lookup_data->port = port;
        lookup_data->child_pid = (pid_t)(-1);
        lookup_data->pipe_fds[0] = -1;
        lookup_data->pipe_fds[1] = -1;

	if (pipe(lookup_data->pipe_fds) < 0) {
		perror("pipe");
		func(NULL, data);
                g_free (lookup_data->hostname);
                g_free (lookup_data);
		return NULL;
	}

#ifndef G_OS_WIN32
	if ((lookup_data->child_pid = fork()) < 0) {
		perror("fork");
		func(NULL, data);
                g_free (lookup_data->hostname);
                g_free (lookup_data);
		return NULL;
	}

	if (lookup_data->child_pid == 0) {
                /* Child process. */
                address_info_async_child (lookup_data);
                g_assert_not_reached ();
	}
        /* Parent process. */
        close(lookup_data->pipe_fds[1]);
        lookup_data->pipe_fds[1] = -1;
#endif  /*!G_OS_WIN32 */
        
#ifndef G_OS_WIN32
        lookup_data->channel = g_io_channel_unix_new(lookup_data->pipe_fds[0]);
#else
        lookup_data->channel = g_io_channel_win32_new_fd(lookup_data->pipe_fds[0]);
#endif
        lookup_data->io_tag = g_io_add_watch(lookup_data->channel, G_IO_IN,
                                             sock_get_address_info_async_cb,
                                             lookup_data);
#ifdef G_OS_WIN32
	lookup_data->child_pid = _beginthread(
		address_info_async_child, 0, lookup_data);
#endif

	return lookup_data;
}
Ejemplo n.º 4
0
int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
{
	struct connect_param param;
	struct connect_result result;
	chashdatum key;
	chashdatum value;
	newsnntp * nntp, * oldnntp;
	gboolean accept_if_valid = FALSE;

	oldnntp = get_nntp(folder);

	nntp = newsnntp_new(0, NULL);

	if (oldnntp) {
		debug_print("deleting old nntp %p\n", oldnntp);
		delete_nntp(folder, oldnntp);
	}

	key.data = &folder;
	key.len = sizeof(folder);
	value.data = nntp;
	value.len = 0;
	chash_set(session_hash, &key, &value, NULL);

	param.nntp = nntp;
	param.server = server;
	param.port = port;
	param.account = folder->account;

	if (folder->account)
		accept_if_valid = folder->account->ssl_certs_auto_accept;

	refresh_resolvers();
	threaded_run(folder, &param, &result, connect_ssl_run);

	if (result.error == NEWSNNTP_NO_ERROR && !etpan_skip_ssl_cert_check) {
		if (etpan_certificate_check(nntp->nntp_stream, server, port,
					    accept_if_valid) != TRUE)
			return -1;
	}
	debug_print("connect %d with nntp %p\n", result.error, nntp);
	
	return result.error;
}
Ejemplo n.º 5
0
int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
{
	struct connect_param param;
	struct connect_result result;
	chashdatum key;
	chashdatum value;
	newsnntp * nntp, * oldnntp;
	unsigned char *certificate = NULL;
	int cert_len;
	
	oldnntp = get_nntp(folder);

	nntp = newsnntp_new(0, NULL);
	
	if (oldnntp) {
		debug_print("deleting old nntp %p\n", oldnntp);
		delete_nntp(folder, oldnntp);
	}

	key.data = &folder;
	key.len = sizeof(folder);
	value.data = nntp;
	value.len = 0;
	chash_set(session_hash, &key, &value, NULL);
	
	param.nntp = nntp;
	param.server = server;
	param.port = port;
	param.account = folder->account;

	refresh_resolvers();
	threaded_run(folder, &param, &result, connect_ssl_run);

	if (result.error == NEWSNNTP_NO_ERROR && !etpan_skip_ssl_cert_check) {
		cert_len = (int)mailstream_ssl_get_certificate(nntp->nntp_stream, &certificate);
		if (etpan_certificate_check(certificate, cert_len, &param) < 0)
			return -1;
		if (certificate) 
			free(certificate); 
	}
	debug_print("connect %d with nntp %p\n", result.error, nntp);
	
	return result.error;
}
Ejemplo n.º 6
0
/* Due to the fact that socket under Windows are not represented by
   standard file descriptors, we sometimes need to check whether a
   given file descriptor is actually a socket.  This is done by
   testing for an error.  Returns true under W32 if FD is a socket. */
static int fd_is_w32_socket(gint fd)
{
#ifdef G_OS_WIN32
        gint optval;
        gint retval = sizeof(optval);
        
        return !getsockopt(fd, SOL_SOCKET, SO_TYPE, (char*)&optval, &retval);
#else
        return 0;
#endif 
}

gint fd_connect_inet(gushort port)
{
	gint sock;
	struct sockaddr_in addr;

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (!SOCKET_IS_VALID(sock)) {
#ifdef G_OS_WIN32
		debug_print("fd_connect_inet(): socket() failed: %d\n",
			  WSAGetLastError());
#else
		perror("fd_connect_inet(): socket");
#endif
		return -1;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		fd_close(sock);
		return -1;
	}

	return sock;
}
gint fd_open_inet(gushort port)
{
	gint sock;
	struct sockaddr_in addr;
	gint val;

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (!SOCKET_IS_VALID(sock)) {
#ifdef G_OS_WIN32
		g_warning("fd_open_inet(): socket() failed: %d\n",
			  WSAGetLastError());
#else
		perror("fd_open_inet(): socket");
#endif
		return -1;
	}

	val = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val,
		       sizeof(val)) < 0) {
		perror("setsockopt");
		fd_close(sock);
		return -1;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		perror("bind");
		fd_close(sock);
		return -1;
	}

	if (listen(sock, 1) < 0) {
		perror("listen");
		fd_close(sock);
		return -1;
	}

	return sock;
}

gint fd_connect_unix(const gchar *path)
{
#ifdef G_OS_UNIX
	gint sock;
	struct sockaddr_un addr;

	sock = socket(PF_UNIX, SOCK_STREAM, 0);
	if (sock < 0) {
		perror("sock_connect_unix(): socket");
		return -1;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);

	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		close(sock);
		return -1;
	}

	return sock;
#else
	return -1;
#endif
}

gint fd_open_unix(const gchar *path)
{
#ifdef G_OS_UNIX
	gint sock;
	struct sockaddr_un addr;

	sock = socket(PF_UNIX, SOCK_STREAM, 0);

	if (sock < 0) {
		perror("sock_open_unix(): socket");
		return -1;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);

	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		gchar *buf = g_strdup_printf("can't bind to %s", path);
		perror(buf);
		g_free(buf);
		close(sock);
		return -1;
	}

	if (listen(sock, 1) < 0) {
		gchar *buf = g_strdup_printf("can't listen on %s", path);
		perror(buf);
		g_free(buf);
		close(sock);
		return -1;		
	}

	return sock;
#else
	return -1;
#endif
}

gint fd_accept(gint sock)
{
	struct sockaddr_in caddr;
	guint caddr_len;

	caddr_len = sizeof(caddr);
	return accept(sock, (struct sockaddr *)&caddr, &caddr_len);
}


static gint set_nonblocking_mode(gint fd, gboolean nonblock)
{
#ifdef G_OS_UNIX
	gint flags;

	flags = fcntl(fd, F_GETFL, 0);
	if (flags < 0) {
		perror("fcntl");
		return -1;
	}

	if (nonblock)
		flags |= O_NONBLOCK;
	else
		flags &= ~O_NONBLOCK;

	return fcntl(fd, F_SETFL, flags);
#else
	return -1;
#endif
}

gint sock_set_nonblocking_mode(SockInfo *sock, gboolean nonblock)
{
	cm_return_val_if_fail(sock != NULL, -1);

	return set_nonblocking_mode(sock->sock, nonblock);
}

static gboolean is_nonblocking_mode(gint fd)
{
#ifdef G_OS_UNIX
	gint flags;

	flags = fcntl(fd, F_GETFL, 0);
	if (flags < 0) {
		perror("fcntl");
		return FALSE;
	}

	return ((flags & O_NONBLOCK) != 0);
#else
	return FALSE;
#endif
}

gboolean sock_is_nonblocking_mode(SockInfo *sock)
{
	cm_return_val_if_fail(sock != NULL, FALSE);

	return is_nonblocking_mode(sock->sock);
}


#ifdef USE_GNUTLS
static gboolean ssl_sock_prepare(GSource *source, gint *timeout)
{
	*timeout = 1;
	return FALSE;
}

static gboolean ssl_sock_check(GSource *source)
{
	SockInfo *sock = ((SockSource *)source)->sock;
	struct timeval timeout = {0, 0};
	fd_set fds;
	GIOCondition condition = 0;
        
	if (!sock || !sock->sock)
		return FALSE;

	condition = sock->condition;

	if ((condition & G_IO_IN) == G_IO_IN &&
	    gnutls_record_check_pending(sock->ssl) != 0)
		return TRUE;

	FD_ZERO(&fds);
	FD_SET(sock->sock, &fds);

	select(sock->sock + 1,
	       (condition & G_IO_IN)  ? &fds : NULL,
	       (condition & G_IO_OUT) ? &fds : NULL,
	       NULL, &timeout);

	return FD_ISSET(sock->sock, &fds) != 0;
}

static gboolean ssl_sock_dispatch(GSource *source, GSourceFunc callback,
			      gpointer user_data)
{
	SockInfo *sock = ((SockSource *)source)->sock;

	if (!sock || !sock->callback || !sock->data)
		return FALSE;

	return sock->callback(sock, sock->condition, sock->data);
}
#endif

static gboolean sock_watch_cb(GIOChannel *source, GIOCondition condition,
			      gpointer data)
{
	SockInfo *sock = (SockInfo *)data;

	if ((condition & sock->condition) == 0)
		return TRUE;

	return sock->callback(sock, sock->condition, sock->data);
}

guint sock_add_watch(SockInfo *sock, GIOCondition condition, SockFunc func,
		     gpointer data)
{
	if (!sock)
		return FALSE;

	sock->callback = func;
	sock->condition = condition;
	sock->data = data;

#ifdef USE_GNUTLS
	if (sock->ssl)
	{
		GSource *source = g_source_new(&ssl_watch_funcs,
					       sizeof(SockSource));
		((SockSource *) source)->sock = sock;
		g_source_set_priority(source, G_PRIORITY_DEFAULT);
		g_source_set_can_recurse(source, FALSE);
		sock->g_source = g_source_attach(source, NULL);
		g_source_unref (source); /* Refcount back down to 1 */
		return sock->g_source;
	}
#endif

	return g_io_add_watch(sock->sock_ch, condition, sock_watch_cb, sock);
}

static gint fd_check_io(gint fd, GIOCondition cond)
{
	struct timeval timeout;
	fd_set fds;

	if (is_nonblocking_mode(fd))
		return 0;

	timeout.tv_sec  = io_timeout;
	timeout.tv_usec = 0;

	FD_ZERO(&fds);
	FD_SET(fd, &fds);

	if (cond == G_IO_IN) {
		select(fd + 1, &fds, NULL, NULL,
		       io_timeout > 0 ? &timeout : NULL);
	} else {
		select(fd + 1, NULL, &fds, NULL,
		       io_timeout > 0 ? &timeout : NULL);
	}

	if (FD_ISSET(fd, &fds)) {
		return 0;
	} else {
		g_warning("Socket IO timeout\n");
		log_error(LOG_PROTOCOL, _("Socket IO timeout.\n"));
		return -1;
	}
}

#ifdef G_OS_UNIX
static sigjmp_buf jmpenv;

static void timeout_handler(gint sig)
{
	siglongjmp(jmpenv, 1);
}
#endif /*G_OS_UNIX*/

static gint sock_connect_with_timeout(gint sock,
				      const struct sockaddr *serv_addr,
				      gint addrlen,
				      guint timeout_secs)
{
	gint ret;
#ifdef G_OS_UNIX
	void (*prev_handler)(gint);
	
	alarm(0);
	prev_handler = signal(SIGALRM, timeout_handler);
	if (sigsetjmp(jmpenv, 1)) {
		alarm(0);
		signal(SIGALRM, prev_handler);
		errno = ETIMEDOUT;
		log_error(LOG_PROTOCOL, _("Connection timed out.\n"));
		return -1;
	}
	alarm(timeout_secs);
#endif

	ret = connect(sock, serv_addr, addrlen);

#ifdef G_OS_UNIX
	alarm(0);
	signal(SIGALRM, prev_handler);
#endif

	return ret;
}

struct hostent *my_gethostbyname(const gchar *hostname)
{
	struct hostent *hp;
#ifdef G_OS_UNIX
	void (*prev_handler)(gint);
	
	alarm(0);
	prev_handler = signal(SIGALRM, timeout_handler);
	if (sigsetjmp(jmpenv, 1)) {
		alarm(0);
		signal(SIGALRM, prev_handler);
		g_printerr("%s: host lookup timed out.\n", hostname);
		log_error(LOG_PROTOCOL, _("%s: host lookup timed out.\n"), hostname);
		errno = 0;
		return NULL;
	}
	alarm(io_timeout);
#endif

	if ((hp = gethostbyname(hostname)) == NULL) {
#ifdef G_OS_UNIX
		alarm(0);
		signal(SIGALRM, prev_handler);
#endif
		g_printerr("%s: unknown host.\n", hostname);
		log_error(LOG_PROTOCOL, _("%s: unknown host.\n"), hostname);
		errno = 0;
		return NULL;
	}

#ifdef G_OS_UNIX
	alarm(0);
	signal(SIGALRM, prev_handler);
#endif

	return hp;
}

#ifndef INET6
static gint my_inet_aton(const gchar *hostname, struct in_addr *inp)
{
#if HAVE_INET_ATON
	return inet_aton(hostname, inp);
#else
#if HAVE_INET_ADDR
	guint32 inaddr;

	inaddr = inet_addr(hostname);
	if (inaddr != -1) {
		memcpy(inp, &inaddr, sizeof(inaddr));
		return 1;
	} else
		return 0;
#else
	return 0;
#endif
#endif /* HAVE_INET_ATON */
}

static gint sock_connect_by_hostname(gint sock, const gchar *hostname,
				     gushort port)
{
	struct hostent *hp;
	struct sockaddr_in ad;

	memset(&ad, 0, sizeof(ad));
	ad.sin_family = AF_INET;
	ad.sin_port = htons(port);

	refresh_resolvers();

	if (!my_inet_aton(hostname, &ad.sin_addr)) {
		if ((hp = my_gethostbyname(hostname)) == NULL) {
			g_printerr("%s: unknown host.\n", hostname);
			errno = 0;
			return -1;
		}

		if (hp->h_length != 4 && hp->h_length != 8) {
			g_printerr("illegal address length received for host %s\n", hostname);
			errno = 0;
			return -1;
		}

		memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
	}

	return sock_connect_with_timeout(sock, (struct sockaddr *)&ad,
					 sizeof(ad), io_timeout);
}

#else /* INET6 */
static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort	port)
{
	gint sock = -1, gai_error;
	struct addrinfo hints, *res, *ai;
	gchar port_str[6];

	refresh_resolvers();

	memset(&hints, 0, sizeof(hints));
	/* hints.ai_flags = AI_CANONNAME; */
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	/* convert port from integer to string. */
	g_snprintf(port_str, sizeof(port_str), "%d", port);

	if ((gai_error = getaddrinfo(hostname, port_str, &hints, &res)) != 0) {
		g_printerr("getaddrinfo for %s:%s failed: %s\n",
			hostname, port_str, gai_strerror(gai_error));
		return -1;
	}

	for (ai = res; ai != NULL; ai = ai->ai_next) {
		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (sock < 0)
			continue;

		if (sock_connect_with_timeout
			(sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0)
			break;

		close(sock);
	}

	if (res != NULL)
		freeaddrinfo(res);

	if (ai == NULL)
		return -1;

	return sock;
}