⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 connect.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 2 页
字号:
	for (i = conn_info->triedno + 1; i < conn_info->addrno; i++) {#ifdef CONFIG_IPV6		struct sockaddr_in6 addr = *((struct sockaddr_in6 *) &conn_info->addr[i]);#else		struct sockaddr_in addr = *((struct sockaddr_in *) &conn_info->addr[i]);#endif		int family;		int force_family = conn->uri->ip_family;#ifdef CONFIG_IPV6		family = addr.sin6_family;#else		family = addr.sin_family;#endif		conn_info->triedno++;		if (only_local) {			int local = 0;#ifdef CONFIG_IPV6			if (addr.sin6_family == AF_INET6)				local = check_if_local_address6((struct sockaddr_in6 *) &addr);			else#endif				local = check_if_local_address4((struct sockaddr_in *) &addr);			/* This forbids connections to anything but local, if option is set. */			if (!local) {				at_least_one_remote_ip = 1;				continue;			}		}#ifdef CONFIG_IPV6		if (family == AF_INET6 && (!get_opt_bool("connection.try_ipv6") || (force_family && force_family != 6))) {			silent_fail = 1;			continue;		} else#endif		if (family == AF_INET && (!get_opt_bool("connection.try_ipv4") || (force_family && force_family != 4))) {			silent_fail = 1;			continue;		}		silent_fail = 0;		sock = socket(family, SOCK_STREAM, IPPROTO_TCP);		if (sock == -1) {			if (errno && !saved_errno) saved_errno = errno;			continue;		}		if (set_nonblocking_fd(sock) < 0) {			if (errno && !saved_errno) saved_errno = errno;			close(sock);			continue;		}		conn_info->socket->fd = sock;#ifdef CONFIG_IPV6		addr.sin6_port = htons(conn_info->port);#else		addr.sin_port = htons(conn_info->port);#endif		/* We can set conn->protocol_family here even if the connection		 * will fail, as we will use it only when it will be successfully		 * established. At least I hope that noone else will want to do		 * something else ;-). --pasky */#ifdef CONFIG_IPV6		if (addr.sin6_family == AF_INET6) {			conn->protocol_family = 1;			if (connect(sock, (struct sockaddr *) &addr,					sizeof(struct sockaddr_in6)) == 0)				break;		} else#endif		{			conn->protocol_family = 0;			if (connect(sock, (struct sockaddr *) &addr,					sizeof(struct sockaddr_in)) == 0)				break; /* success */		}		if (errno == EALREADY#ifdef EWOULDBLOCK		    || errno == EWOULDBLOCK#endif		    || errno == EINPROGRESS) {			/* It will take some more time... */			set_handlers(sock, NULL, connected, dns_exception, conn);			set_connection_state(conn, S_CONN);			return;		}		if (errno && !saved_errno) saved_errno = errno;		close(sock);	}	if (i >= conn_info->addrno) {		/* Tried everything, but it didn't help :(. */		if (only_local && !saved_errno && at_least_one_remote_ip) {			/* Yes we might hit a local address and fail in the			 * process, but what matters is the last one because			 * we do not know the previous one's errno, and the			 * added complexity wouldn't really be worth it. */			abort_conn_with_state(conn, S_LOCAL_ONLY);			return;		}		/* We set new state only if we already tried something new. */		if (trno != conn_info->triedno && !silent_fail)			set_connection_state(conn, -errno);		else if (trno == -1 && silent_fail) 			/* All failed. */			set_connection_state(conn, S_NO_FORCED_DNS);		retry_connection(conn);		return;	}#ifdef CONFIG_SSL	/* Check if the connection should run over an encrypted link */	if (get_protocol_need_ssl(conn->uri->protocol)	    && ssl_connect(conn, conn_info->socket) < 0)		return;#endif	done_connection_info(conn);}static voidconnected(void *data){	struct connection *conn = (struct connection *) data;	struct conn_info *conn_info = conn->conn_info;	struct connection_socket *socket = conn_info->socket;	int err = 0;	int len = sizeof(err);	assertm(conn_info, "Lost conn_info!");	if_assert_failed return;	if (getsockopt(socket->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == 0) {		/* Why does EMX return so large values? */		if (err >= 10000) err -= 10000;	} else {		/* getsockopt() failed */		if (errno > 0)			err = errno;		else			err = -(S_STATE);	}	if (err > 0) {		set_connection_state(conn, -err);		/* There are maybe still some more candidates. */		close_socket(NULL, socket);		dns_found(conn, 0);		return;	}#ifdef CONFIG_SSL	/* Check if the connection should run over an encrypted link */	if (get_protocol_need_ssl(conn->uri->protocol)	    && ssl_connect(conn, socket) < 0)		return;#endif	done_connection_info(conn);}struct write_buffer {	/* A routine called when all the data is sent (therefore this is	 * _different_ from read_buffer.done !). */	void (*done)(struct connection *);	struct connection_socket *socket;	int len;	int pos;	unsigned char data[1]; /* must be at end of struct */};static voidwrite_select(struct connection *conn){	struct write_buffer *wb = conn->buffer;	int wr;	assertm(wb, "write socket has no buffer");	if_assert_failed {		abort_conn_with_state(conn, S_INTERNAL);		return;	}	/* We are making some progress, therefore reset the timeout; ie.  when	 * uploading large files the time needed for all the data to be sent	 * can easily exceed the timeout. We don't need to do this for	 * read_select() because it calls user handler every time new data is	 * acquired and the user handler does this. */	set_connection_timeout(conn);#if 0	printf("ws: %d\n",wb->len-wb->pos);	for (wr = wb->pos; wr < wb->len; wr++) printf("%c", wb->data[wr]);	printf("-\n");#endif#ifdef CONFIG_SSL	if (wb->socket->ssl) {		wr = ssl_write(conn, wb->socket, wb->data + wb->pos, wb->len - wb->pos);		if (wr <= 0) return;	} else#endif	{		assert(wb->len - wb->pos > 0);		wr = safe_write(wb->socket->fd, wb->data + wb->pos, wb->len - wb->pos);		if (wr <= 0) {			retry_conn_with_state(conn, wr ? -errno : S_CANT_WRITE);			return;		}	}	/*printf("wr: %d\n", wr);*/	wb->pos += wr;	if (wb->pos == wb->len) {		void (*f)(struct connection *) = wb->done;		conn->buffer = NULL;		clear_handlers(wb->socket->fd);		mem_free(wb);		f(conn);	}}voidwrite_to_socket(struct connection *conn, struct connection_socket *socket,		unsigned char *data, int len, void (*done)(struct connection *)){	struct write_buffer *wb;	debug_transfer_log(data, len);	assert(len > 0);	if_assert_failed return;	wb = mem_alloc(sizeof(*wb) + len);	if (!wb) {		abort_conn_with_state(conn, S_OUT_OF_MEM);		return;	}	wb->socket = socket;	wb->len = len;	wb->pos = 0;	wb->done = done;	memcpy(wb->data, data, len);	mem_free_set(&conn->buffer, wb);	set_handlers(socket->fd, NULL, (void *) write_select, (void *) exception, conn);}#define RD_ALLOC_GR (2<<11) /* 4096 */#define RD_MEM(rb) (sizeof(*(rb)) + 4 * RD_ALLOC_GR + RD_ALLOC_GR)#define RD_SIZE(rb, len) ((RD_MEM(rb) + (len)) & ~(RD_ALLOC_GR - 1))static voidread_select(struct connection *conn){	struct read_buffer *rb = conn->buffer;	int rd;	assertm(rb, "read socket has no buffer");	if_assert_failed {		abort_conn_with_state(conn, S_INTERNAL);		return;	}	/* XXX: Should we set_connection_timeout() as we do in write_select()?	 * --pasky */	clear_handlers(rb->socket->fd);	if (!rb->freespace) {		int size = RD_SIZE(rb, rb->len);		rb = mem_realloc(rb, size);		if (!rb) {			abort_conn_with_state(conn, S_OUT_OF_MEM);			return;		}		rb->freespace = size - sizeof(*rb) - rb->len;		assert(rb->freespace > 0);		conn->buffer = rb;	}#ifdef CONFIG_SSL	if (rb->socket->ssl) {		rd = ssl_read(conn, rb->socket, rb);		if (rd <= 0) return;	} else#endif	{		rd = safe_read(rb->socket->fd, rb->data + rb->len, rb->freespace);		if (rd <= 0) {			if (rb->close != READ_BUFFER_RETRY_ONCLOSE && !rd) {				rb->close = READ_BUFFER_END;				rb->done(conn, rb);				return;			}			retry_conn_with_state(conn, rd ? -errno : S_CANT_READ);			return;		}	}	debug_transfer_log(rb->data + rb->len, rd);	rb->len += rd;	rb->freespace -= rd;	assert(rb->freespace >= 0);	rb->done(conn, rb);}struct read_buffer *alloc_read_buffer(struct connection *conn){	struct read_buffer *rb;	rb = mem_calloc(1, RD_SIZE(rb, 0));	if (!rb) {		abort_conn_with_state(conn, S_OUT_OF_MEM);		return NULL;	}	rb->freespace = RD_SIZE(rb, 0) - sizeof(*rb);	return rb;}#undef RD_ALLOC_GR#undef RD_MEM#undef RD_SIZEvoidread_from_socket(struct connection *conn, struct connection_socket *socket,		 struct read_buffer *buffer,		 void (*done)(struct connection *, struct read_buffer *)){	buffer->done = done;	buffer->socket = socket;	if (conn->buffer && buffer != conn->buffer)		mem_free(conn->buffer);	conn->buffer = buffer;	set_handlers(socket->fd, (void *) read_select, NULL, (void *) exception, conn);}voidkill_buffer_data(struct read_buffer *rb, int n){	assertm(n >= 0 && n <= rb->len, "bad number of bytes: %d", n);	if_assert_failed { rb->len = 0;  return; }	if (!n) return; /* FIXME: We accept to kill 0 bytes... */	rb->len -= n;	memmove(rb->data, rb->data + n, rb->len);	rb->freespace += n;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -