📄 connect.c
字号:
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 + -