summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h11
-rw-r--r--source3/lib/util_sock.c224
-rw-r--r--source3/libads/krb5_setpw.c31
-rw-r--r--source3/libsmb/cliconnect.c23
-rw-r--r--source3/modules/vfs_smb_traffic_analyzer.c5
-rw-r--r--source3/rpc_client/cli_pipe.c5
6 files changed, 215 insertions, 84 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index dc636115141..957302c378f 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1457,9 +1457,14 @@ int open_socket_in(int type,
int dlevel,
const struct sockaddr_storage *psock,
bool rebind);
-int open_socket_out(const struct sockaddr_storage *pss,
- uint16_t port,
- int timeout);
+NTSTATUS open_socket_out(const struct sockaddr_storage *pss, uint16_t port,
+ int timeout, int *pfd);
+struct async_req *open_socket_out_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ const struct sockaddr_storage *pss,
+ uint16_t port,
+ int timeout);
+NTSTATUS open_socket_out_recv(struct async_req *req, int *pfd);
bool open_any_socket_out(struct sockaddr_storage *addrs, int num_addrs,
int timeout, int *fd_index, int *fd);
int open_udp_socket(const char *host, int port);
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
index a8c3b3031d7..3356318c88a 100644
--- a/source3/lib/util_sock.c
+++ b/source3/lib/util_sock.c
@@ -948,96 +948,208 @@ int open_socket_in(int type,
return( res );
}
+struct open_socket_out_state {
+ int fd;
+ struct event_context *ev;
+ struct sockaddr_storage ss;
+ socklen_t salen;
+ uint16_t port;
+ int wait_nsec;
+};
+
+static void open_socket_out_connected(struct async_req *subreq);
+
+static int open_socket_out_state_destructor(struct open_socket_out_state *s)
+{
+ if (s->fd != -1) {
+ close(s->fd);
+ }
+ return 0;
+}
+
/****************************************************************************
Create an outgoing socket. timeout is in milliseconds.
**************************************************************************/
-int open_socket_out(const struct sockaddr_storage *pss, uint16_t port,
- int timeout)
+struct async_req *open_socket_out_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ const struct sockaddr_storage *pss,
+ uint16_t port,
+ int timeout)
{
char addr[INET6_ADDRSTRLEN];
- struct sockaddr_storage sock_out = *pss;
- int res,ret;
- int connect_loop = 10;
- int increment = 10;
+ struct async_req *result, *subreq;
+ struct open_socket_out_state *state;
+ NTSTATUS status;
- /* create a socket to write to */
- res = socket(pss->ss_family, SOCK_STREAM, 0);
- if (res == -1) {
- DEBUG(0,("socket error (%s)\n", strerror(errno)));
- return -1;
+ result = async_req_new(mem_ctx);
+ if (result == NULL) {
+ return NULL;
+ }
+ state = talloc(result, struct open_socket_out_state);
+ if (state == NULL) {
+ goto fail;
+ }
+ result->private_data = state;
+
+ state->ev = ev;
+ state->ss = *pss;
+ state->port = port;
+ state->wait_nsec = 10000;
+ state->salen = -1;
+
+ state->fd = socket(state->ss.ss_family, SOCK_STREAM, 0);
+ if (state->fd == -1) {
+ status = map_nt_error_from_unix(errno);
+ goto post_status;
+ }
+ talloc_set_destructor(state, open_socket_out_state_destructor);
+
+ if (!async_req_set_timeout(result, ev, timeval_set(0, timeout*1000))) {
+ goto fail;
}
#if defined(HAVE_IPV6)
if (pss->ss_family == AF_INET6) {
- struct sockaddr_in6 *psa6 = (struct sockaddr_in6 *)&sock_out;
+ struct sockaddr_in6 *psa6;
+ psa6 = (struct sockaddr_in6 *)&state->ss;
psa6->sin6_port = htons(port);
- if (psa6->sin6_scope_id == 0 &&
- IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) {
- setup_linklocal_scope_id((struct sockaddr *)&sock_out);
+ if (psa6->sin6_scope_id == 0
+ && IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) {
+ setup_linklocal_scope_id(
+ (struct sockaddr *)&(state->ss));
}
+ state->salen = sizeof(struct sockaddr_in6);
}
#endif
if (pss->ss_family == AF_INET) {
- struct sockaddr_in *psa = (struct sockaddr_in *)&sock_out;
+ struct sockaddr_in *psa;
+ psa = (struct sockaddr_in *)&state->ss;
psa->sin_port = htons(port);
+ state->salen = sizeof(struct sockaddr_in);
}
- /* set it non-blocking */
- set_blocking(res,false);
+ print_sockaddr(addr, sizeof(addr), &state->ss);
+ DEBUG(3,("Connecting to %s at port %u\n", addr, (unsigned int)port));
- print_sockaddr(addr, sizeof(addr), &sock_out);
- DEBUG(3,("Connecting to %s at port %u\n",
- addr,
- (unsigned int)port));
+ subreq = async_connect_send(state, state->ev, state->fd,
+ (struct sockaddr *)&state->ss,
+ state->salen);
+ if ((subreq == NULL)
+ || !async_req_set_timeout(subreq, state->ev,
+ timeval_set(0, state->wait_nsec))) {
+ status = NT_STATUS_NO_MEMORY;
+ goto post_status;
+ }
+ subreq->async.fn = open_socket_out_connected;
+ subreq->async.priv = result;
+ return result;
- /* and connect it to the destination */
- connect_again:
+ post_status:
+ if (!async_post_status(result, ev, status)) {
+ goto fail;
+ }
+ return result;
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
- ret = sys_connect(res, (struct sockaddr *)&sock_out);
+static void open_socket_out_connected(struct async_req *subreq)
+{
+ struct async_req *req = talloc_get_type_abort(
+ subreq->async.priv, struct async_req);
+ struct open_socket_out_state *state = talloc_get_type_abort(
+ req->private_data, struct open_socket_out_state);
+ NTSTATUS status;
+ int sys_errno;
- /* Some systems return EAGAIN when they mean EINPROGRESS */
- if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
- errno == EAGAIN) && (connect_loop < timeout) ) {
- smb_msleep(connect_loop);
- timeout -= connect_loop;
- connect_loop += increment;
- if (increment < 250) {
- /* After 8 rounds we end up at a max of 255 msec */
- increment *= 1.5;
- }
- goto connect_again;
+ status = async_connect_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_IS_OK(status)) {
+ async_req_done(req);
+ return;
}
- if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
- errno == EAGAIN)) {
- DEBUG(1,("timeout connecting to %s:%u\n",
- addr,
- (unsigned int)port));
- close(res);
- return -1;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)
+ || (sys_errno == EINPROGRESS)
+ || (sys_errno == EALREADY)
+ || (sys_errno == EAGAIN)) {
+
+ /*
+ * retry
+ */
+
+ if (state->wait_nsec < 250000) {
+ state->wait_nsec *= 1.5;
+ }
+
+ subreq = async_connect_send(state, state->ev, state->fd,
+ (struct sockaddr *)&state->ss,
+ state->salen);
+ if (async_req_nomem(subreq, req)) {
+ return;
+ }
+ if (!async_req_set_timeout(subreq, state->ev,
+ timeval_set(0, state->wait_nsec))) {
+ async_req_error(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ subreq->async.fn = open_socket_out_connected;
+ subreq->async.priv = req;
+ return;
}
#ifdef EISCONN
- if (ret < 0 && errno == EISCONN) {
- errno = 0;
- ret = 0;
+ if (sys_errno == EISCONN) {
+ async_req_done(req);
+ return;
}
#endif
- if (ret < 0) {
- DEBUG(2,("error connecting to %s:%d (%s)\n",
- addr,
- (unsigned int)port,
- strerror(errno)));
- close(res);
- return -1;
+ /* real error */
+ async_req_error(req, map_nt_error_from_unix(sys_errno));
+}
+
+NTSTATUS open_socket_out_recv(struct async_req *req, int *pfd)
+{
+ struct open_socket_out_state *state = talloc_get_type_abort(
+ req->private_data, struct open_socket_out_state);
+ NTSTATUS status;
+
+ if (async_req_is_error(req, &status)) {
+ return status;
}
+ *pfd = state->fd;
+ state->fd = -1;
+ return NT_STATUS_OK;
+}
- /* set it blocking again */
- set_blocking(res,true);
+NTSTATUS open_socket_out(const struct sockaddr_storage *pss, uint16_t port,
+ int timeout, int *pfd)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct async_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- return res;
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = open_socket_out_send(frame, ev, pss, port, timeout);
+ if (req == NULL) {
+ goto fail;
+ }
+ while (req->state < ASYNC_REQ_DONE) {
+ event_loop_once(ev);
+ }
+
+ status = open_socket_out_recv(req, pfd);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
}
/*******************************************************************
diff --git a/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c
index e164a55b389..7cdfbc58a4a 100644
--- a/source3/libads/krb5_setpw.c
+++ b/source3/libads/krb5_setpw.c
@@ -425,21 +425,28 @@ static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,
if (!use_tcp) {
sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT);
-
+ if (sock == -1) {
+ int rc = errno;
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("failed to open kpasswd socket to %s "
+ "(%s)\n", kdc_host, strerror(errno)));
+ return ADS_ERROR_SYSTEM(rc);
+ }
} else {
-
- sock = open_socket_out(&addr, DEFAULT_KPASSWD_PORT,
- LONG_CONNECT_TIMEOUT);
+ NTSTATUS status;
+ status = open_socket_out(&addr, DEFAULT_KPASSWD_PORT,
+ LONG_CONNECT_TIMEOUT, &sock);
+ if (!NT_STATUS_IS_OK(status)) {
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("failed to open kpasswd socket to %s "
+ "(%s)\n", kdc_host,
+ nt_errstr(status)));
+ return ADS_ERROR_NT(status);
+ }
}
- if (sock == -1) {
- int rc = errno;
- SAFE_FREE(ap_req.data);
- krb5_auth_con_free(context, auth_context);
- DEBUG(1,("failed to open kpasswd socket to %s (%s)\n",
- kdc_host, strerror(errno)));
- return ADS_ERROR_SYSTEM(rc);
- }
addr_len = sizeof(remote_addr);
if (getpeername(sock, (struct sockaddr *)&remote_addr, &addr_len) != 0) {
close(sock);
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 44899e3b1a3..1b03459658d 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -1494,15 +1494,17 @@ bool cli_session_request(struct cli_state *cli,
*/
uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
struct in_addr dest_ip;
+ NTSTATUS status;
/* SESSION RETARGET */
putip((char *)&dest_ip,cli->inbuf+4);
in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
- cli->fd = open_socket_out(&cli->dest_ss, port,
- LONG_CONNECT_TIMEOUT);
- if (cli->fd == -1)
+ status = open_socket_out(&cli->dest_ss, port,
+ LONG_CONNECT_TIMEOUT, &cli->fd);
+ if (!NT_STATUS_IS_OK(status)) {
return False;
+ }
DEBUG(3,("Retargeted\n"));
@@ -1587,12 +1589,17 @@ NTSTATUS cli_connect(struct cli_state *cli,
} else {
/* try 445 first, then 139 */
uint16_t port = cli->port?cli->port:445;
- cli->fd = open_socket_out(&cli->dest_ss, port,
- cli->timeout);
- if (cli->fd == -1 && cli->port == 0) {
+ NTSTATUS status;
+
+ cli->fd = -1;
+
+ status = open_socket_out(&cli->dest_ss, port,
+ cli->timeout, &cli->fd);
+ if (!NT_STATUS_IS_OK(status) && cli->port == 0) {
port = 139;
- cli->fd = open_socket_out(&cli->dest_ss,
- port, cli->timeout);
+ status = open_socket_out(
+ &cli->dest_ss, port, cli->timeout,
+ &cli->fd);
}
if (cli->fd != -1) {
cli->port = port;
diff --git a/source3/modules/vfs_smb_traffic_analyzer.c b/source3/modules/vfs_smb_traffic_analyzer.c
index fe292e5ce8f..3ac5a4971b7 100644
--- a/source3/modules/vfs_smb_traffic_analyzer.c
+++ b/source3/modules/vfs_smb_traffic_analyzer.c
@@ -78,6 +78,7 @@ static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle,
for (res = ailist; res; res = res->ai_next) {
struct sockaddr_storage ss;
+ NTSTATUS status;
if (!res->ai_addr || res->ai_addrlen == 0) {
continue;
@@ -86,8 +87,8 @@ static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle,
ZERO_STRUCT(ss);
memcpy(&ss, res->ai_addr, res->ai_addrlen);
- sockfd = open_socket_out(&ss, port, 10000);
- if (sockfd != -1) {
+ status = open_socket_out(&ss, port, 10000, &sockfd);
+ if (NT_STATUS_IS_OK(status)) {
break;
}
}
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 45eab503fe7..3fd31e28676 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -2618,9 +2618,8 @@ static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
goto fail;
}
- result->trans.sock.fd = open_socket_out(&addr, port, 60);
- if (result->trans.sock.fd == -1) {
- status = map_nt_error_from_unix(errno);
+ status = open_socket_out(&addr, port, 60, &result->trans.sock.fd);
+ if (!NT_STATUS_IS_OK(status)) {
goto fail;
}