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

📄 connect.c

📁 ELinks is an advanced and well-established feature-rich text mode web (HTTP/FTP/..) browser. ELinks
💻 C
字号:
/* connect.c * (c) 2002 Mikulas Patocka * This file is a part of the Links program, released under GPL. */#include "links.h"/*#define LOG_TRANSFER	"/tmp/log"*//* prototypes */void ssl_want_read(struct connection *);void write_select(struct connection *);void read_select(struct connection *);#ifdef LOG_TRANSFERstatic void log_data(unsigned char *data, int len){	static int hlaseno = 0;	int fd;	if (!hlaseno) {		printf("\n\e[1mWARNING -- LOGGING NETWORK TRANSFERS !!!\e[0m%c\n", 7);		fflush(stdout);		sleep(1);		hlaseno = 1;	}	if ((fd = open(LOG_TRANSFER, O_WRONLY | O_APPEND | O_CREAT, 0600)) != -1) {		set_bin(fd);		write(fd, data, len);		close(fd);	}}#else#define log_data(x, y)#endifvoid exception(struct connection *c){	setcstate(c, S_EXCEPT);	retry_connection(c);}void close_socket(int *s){	if (*s == -1) return;	close(*s);	set_handlers(*s, NULL, NULL, NULL, NULL);	*s = -1;}void connected(struct connection *);struct conn_info {	void (*func)(struct connection *);	struct sockaddr_in sa;	ip__address addr;	int port;	int *sock;	int real_port;	int socks_byte_count;	unsigned char socks_reply[8];};void dns_found(struct connection *, int);void handle_socks(struct connection *);void handle_socks_reply(struct connection *);void make_connection(struct connection *c, int port, int *sock, void (*func)(struct connection *)){	int real_port = -1;	int as;	unsigned char *host;	struct conn_info *b;	if (*c->socks_proxy) {		unsigned char *p = strchr(c->socks_proxy, '@');		if (p) p++;		else p = c->socks_proxy;		host = stracpy(p);		real_port = port;		port = 1080;		if ((p = strchr(host, ':'))) {			*p++ = 0;			if (!*p) goto badu;			port = strtoul(p, (char **)(void *)&p, 10);			if (*p) {				badu:				mem_free(host);				setcstate(c, S_BAD_URL);				abort_connection(c);				return;			}		}	} else if (!(host = get_host_name(c->url))) {		setcstate(c, S_INTERNAL);		abort_connection(c);		return;	}	if (c->newconn)		internal("already making a connection");	b = mem_alloc(sizeof(struct conn_info));	b->func = func;	b->sock = sock;	b->port = port;	b->real_port = real_port;	b->socks_byte_count = 0;	c->newconn = b;	log_data("\nCONNECTION: ", 13);	log_data(host, strlen(host));	log_data("\n", 1);	if (c->no_cache >= NC_RELOAD) as = find_host_no_cache(host, &b->addr, &c->dnsquery, (void(*)(void *, int))dns_found, c);	else as = find_host(host, &b->addr, &c->dnsquery, (void(*)(void *, int))dns_found, c);	mem_free(host);	if (as) setcstate(c, S_DNS);}int get_pasv_socket(struct connection *c, int cc, int *sock, unsigned char *port){	int s;	struct sockaddr_in sa;	struct sockaddr_in sb;	socklen_t len = sizeof(sa);	memset(&sa, 0, sizeof sa);	memset(&sb, 0, sizeof sb);	if (getsockname(cc, (struct sockaddr *)(void *)&sa, &len)) {		e:		setcstate(c, -errno);		retry_connection(c);		return -1;	}	if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) goto e;	*sock = s;	fcntl(s, F_SETFL, O_NONBLOCK);	memcpy(&sb, &sa, sizeof(struct sockaddr_in));	sb.sin_port = 0;	if (bind(s, (struct sockaddr *)(void *)&sb, sizeof sb)) goto e;	len = sizeof(sa);	if (getsockname(s, (struct sockaddr *)(void *)&sa, &len)) goto e;	if (listen(s, 1)) goto e;	memcpy(port, &sa.sin_addr.s_addr, 4);	memcpy(port + 4, &sa.sin_port, 2);	return 0;}#ifdef HAVE_SSLvoid ssl_want_read(struct connection *c){	struct conn_info *b = c->newconn;	set_timeout(c);	if (c->no_tsl) c->ssl->options |= SSL_OP_NO_TLSv1;	switch (SSL_get_error(c->ssl, SSL_connect(c->ssl))) {		case SSL_ERROR_NONE:			c->newconn = NULL;			b->func(c);			mem_free(b);			break;		case SSL_ERROR_WANT_READ:			set_handlers(*b->sock, (void(*)(void *))ssl_want_read, NULL, (void(*)(void *))exception, c);			break;		case SSL_ERROR_WANT_WRITE:			set_handlers(*b->sock, NULL, (void(*)(void *))ssl_want_read, (void(*)(void *))exception, c);			break;		default:			c->no_tsl++;			setcstate(c, S_SSL_ERROR);			retry_connection(c);			break;	}}#endifvoid handle_socks(struct connection *c){	struct conn_info *b = c->newconn;	unsigned char *command = init_str();	int len = 0;	unsigned char *host;	int wr;	setcstate(c, S_SOCKS_NEG);	set_timeout(c);	add_bytes_to_str(&command, &len, "\004\001", 2);	add_chr_to_str(&command, &len, b->real_port >> 8);	add_chr_to_str(&command, &len, b->real_port);	add_bytes_to_str(&command, &len, "\000\000\000\001", 4);	if (strchr(c->socks_proxy, '@'))		add_bytes_to_str(&command, &len, c->socks_proxy, strcspn(c->socks_proxy, "@"));	add_chr_to_str(&command, &len, 0);	if (!(host = get_host_name(c->url))) {		mem_free(command);		setcstate(c, S_INTERNAL);		abort_connection(c);		return;	}	add_to_str(&command, &len, host);	add_chr_to_str(&command, &len, 0);	mem_free(host);	wr = write(*b->sock, command + b->socks_byte_count, len - b->socks_byte_count);	mem_free(command);	if (wr <= 0) {		setcstate(c, wr ? -errno : S_CANT_WRITE);		retry_connection(c);		return;	}	b->socks_byte_count += wr;	if (b->socks_byte_count < len) {		set_handlers(*b->sock, NULL, (void(*)(void *))handle_socks, (void(*)(void *))exception, c);		return;	} else {		b->socks_byte_count = 0;		set_handlers(*b->sock, (void(*)(void *))handle_socks_reply, NULL, (void(*)(void *))exception, c);		return;	}}void handle_socks_reply(struct connection *c){	struct conn_info *b = c->newconn;	int rd;	set_timeout(c);	rd = read(*b->sock, b->socks_reply + b->socks_byte_count, sizeof b->socks_reply - b->socks_byte_count);	if (rd <= 0) {		setcstate(c, rd ? -errno : S_CANT_READ);		retry_connection(c);		return;	}	b->socks_byte_count += rd;	if (b->socks_byte_count < (int)sizeof b->socks_reply) return;	/* debug("%x %x %x %x %x %x %x %x", b->socks_reply[0], b->socks_reply[1], b->socks_reply[2], b->socks_reply[3], b->socks_reply[4], b->socks_reply[5], b->socks_reply[6], b->socks_reply[7]); */	if (b->socks_reply[0]) {		setcstate(c, S_BAD_SOCKS_VERSION);		abort_connection(c);		return;	}	switch (b->socks_reply[1]) {		case 91:			setcstate(c, S_SOCKS_REJECTED);			retry_connection(c);			return;		case 92:			setcstate(c, S_SOCKS_NO_IDENTD);			abort_connection(c);			return;		case 93:			setcstate(c, S_SOCKS_BAD_USERID);			abort_connection(c);			return;		default:			setcstate(c, S_SOCKS_UNKNOWN_ERROR);			retry_connection(c);			return;		case 90:			break;	}	b->real_port = -1;	connected(c);}void dns_found(struct connection *c, int state){	int s;	struct conn_info *b = c->newconn;	if (state) {		setcstate(c, S_NO_DNS);		abort_connection(c);		return;	}	if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {		setcstate(c, -errno);		retry_connection(c);		return;	}	*b->sock = s;	fcntl(s, F_SETFL, O_NONBLOCK);	memset(&b->sa, 0, sizeof(struct sockaddr_in));	b->sa.sin_family = AF_INET;	b->sa.sin_addr.s_addr = b->addr;	b->sa.sin_port = htons(b->port);	if (connect(s, (struct sockaddr *)(void *)&b->sa, sizeof b->sa)) {		if (errno != EALREADY && errno != EINPROGRESS) {			setcstate(c, -errno);			retry_connection(c);			return;		}		set_handlers(s, NULL, (void(*)(void *))connected, (void(*)(void *))exception, c);		setcstate(c, S_CONN);	} else {		connected(c);	}}void connected(struct connection *c){	struct conn_info *b = c->newconn;	int err = 0;	socklen_t len = sizeof(int);	if (getsockopt(*b->sock, SOL_SOCKET, SO_ERROR, (void *)&err, &len))		if (!(err = errno)) {			err = -(S_STATE);			goto bla;		}	if (err >= 10000) err -= 10000;	/* Why does EMX return so large values? */	if (err > 0) {		bla:		setcstate(c, -err);		retry_connection(c);		return;	}	set_timeout(c);	if (b->real_port != -1) {		handle_socks(c);		return;	}#ifdef HAVE_SSL	if (c->ssl) {		c->ssl = getSSL();		SSL_set_fd(c->ssl, *b->sock);		if (c->no_tsl) c->ssl->options |= SSL_OP_NO_TLSv1;		switch (SSL_get_error(c->ssl, SSL_connect(c->ssl))) {			case SSL_ERROR_WANT_READ:				setcstate(c, S_SSL_NEG);				set_handlers(*b->sock, (void(*)(void *))ssl_want_read, NULL, (void(*)(void *))exception, c);				return;			case SSL_ERROR_WANT_WRITE:				setcstate(c, S_SSL_NEG);				set_handlers(*b->sock, NULL, (void(*)(void *))ssl_want_read, (void(*)(void *))exception, c);				return;			case SSL_ERROR_NONE:				break;			default:				c->no_tsl++;				setcstate(c, S_SSL_ERROR);				retry_connection(c);				return;		}	}#endif	c->newconn = NULL;	b->func(c);	mem_free(b);}struct write_buffer {	int sock;	int len;	int pos;	void (*done)(struct connection *);	unsigned char data[1];};void write_select(struct connection *c){	struct write_buffer *wb;	int wr;	if (!(wb = c->buffer)) {		internal("write socket has no buffer");		setcstate(c, S_INTERNAL);		abort_connection(c);		return;	}	set_timeout(c);	/*printf("ws: %d\n",wb->len-wb->pos);	for (wr = wb->pos; wr < wb->len; wr++) printf("%c", wb->data[wr]);	printf("-\n");*/#ifdef HAVE_SSL	if(c->ssl) {		if ((wr = SSL_write(c->ssl, wb->data + wb->pos, wb->len - wb->pos)) <= 0) {			int err;			if ((err = SSL_get_error(c->ssl, wr)) != SSL_ERROR_WANT_WRITE) {				setcstate(c, wr ? (err == SSL_ERROR_SYSCALL ? -errno : S_SSL_ERROR) : S_CANT_WRITE);				if (!wr || err == SSL_ERROR_SYSCALL) retry_connection(c);				else abort_connection(c);				return;			}			else return;		}	} else#endif		if ((wr = write(wb->sock, wb->data + wb->pos, wb->len - wb->pos)) <= 0) {			setcstate(c, wr ? -errno : S_CANT_WRITE);			retry_connection(c);			return;		}	/*printf("wr: %d\n", wr);*/	if ((wb->pos += wr) == wb->len) {		void (*f)(struct connection *) = wb->done;		c->buffer = NULL;		set_handlers(wb->sock, NULL, NULL, NULL, NULL);		mem_free(wb);		f(c);	}}void write_to_socket(struct connection *c, int s, unsigned char *data, int len, void (*write_func)(struct connection *)){	struct write_buffer *wb;	log_data(data, len);	if ((unsigned)len > MAXINT - sizeof(struct write_buffer)) overalloc();	wb = mem_alloc(sizeof(struct write_buffer) + len);	wb->sock = s;	wb->len = len;	wb->pos = 0;	wb->done = write_func;	memcpy(wb->data, data, len);	if (c->buffer) mem_free(c->buffer);	c->buffer = wb;	set_handlers(s, NULL, (void (*)(void*))write_select, (void (*)(void*))exception, c);  /* code review */}#define READ_SIZE	64240void read_select(struct connection *c){	struct read_buffer *rb;	int rd;	if (!(rb = c->buffer)) {		internal("read socket has no buffer");		setcstate(c, S_INTERNAL);		abort_connection(c);		return;	}	set_handlers(rb->sock, NULL, NULL, NULL, NULL);	if ((unsigned)rb->len > MAXINT - sizeof(struct read_buffer) - READ_SIZE) overalloc();	rb = mem_realloc(rb, sizeof(struct read_buffer) + rb->len + READ_SIZE);	c->buffer = rb;#ifdef HAVE_SSL	if(c->ssl) {		if ((rd = SSL_read(c->ssl, rb->data + rb->len, READ_SIZE)) <= 0) {			int err;			if ((err = SSL_get_error(c->ssl, rd)) == SSL_ERROR_WANT_READ) {				read_from_socket(c, rb->sock, rb, rb->done);				return;			}			if (rb->close && !rd) {				rb->close = 2;				rb->done(c, rb);				return;			}			setcstate(c, rd ? (err == SSL_ERROR_SYSCALL ? -errno : S_SSL_ERROR) : S_CANT_READ);			/*mem_free(rb);*/			if (!rd || err == SSL_ERROR_SYSCALL) retry_connection(c);			else abort_connection(c);			return;		}	} else#endif		if ((rd = read(rb->sock, rb->data + rb->len, READ_SIZE)) <= 0) {			if (rb->close && !rd) {				rb->close = 2;				rb->done(c, rb);				return;			}			if (!rd) {/* Many servers supporting compression have a bug   --- they send the size of uncompressed data.   Turn off compression support once before the final retry.*/				unsigned char *prot, *h;				int is_restartable;				c->tries++;				is_restartable = is_connection_restartable(c) && c->tries < 10;				c->tries--;				if (!is_restartable && (prot = get_protocol_name(c->url))) {					if (!strcasecmp(prot, "http")) {						if ((h = get_host_name(c->url))) {							add_blacklist_entry(h, BL_NO_COMPRESSION);							mem_free(h);						}					}					mem_free(prot);				}			}			setcstate(c, rd ? -errno : S_CANT_READ);			/*mem_free(rb);*/			retry_connection(c);			return;		}	log_data(rb->data + rb->len, rd);	rb->len += rd;	rb->done(c, rb);}struct read_buffer *alloc_read_buffer(struct connection *c){	struct read_buffer *rb;	rb = mem_alloc(sizeof(struct read_buffer) + READ_SIZE);	memset(rb, 0, sizeof(struct read_buffer));	return rb;}void read_from_socket(struct connection *c, int s, struct read_buffer *buf, void (*read_func)(struct connection *, struct read_buffer *)){	buf->done = read_func;	buf->sock = s;	if (c->buffer && buf != c->buffer) mem_free(c->buffer);	c->buffer = buf;	set_handlers(s, (void (*)(void*))read_select, NULL, (void (*)(void*))exception, c); /* code review */}void kill_buffer_data(struct read_buffer *rb, int n){	if (n > rb->len || n < 0) {		internal("called kill_buffer_data with bad value");		rb->len = 0;		return;	}	memmove(rb->data, rb->data + n, rb->len - n);	rb->len -= n;}

⌨️ 快捷键说明

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