diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 663ba69..cfb2c04 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -2,6 +2,7 @@
 set(HEADER_FILES
 		include/chiaki/session.h
 		include/chiaki/common.h
+		include/chiaki/sock.h
 		include/chiaki/thread.h
 		include/chiaki/base64.h
 		include/chiaki/http.h
@@ -37,6 +38,7 @@ set(HEADER_FILES
 
 set(SOURCE_FILES
 		src/common.c
+		src/sock.c
 		src/session.c
 		src/thread.c
 		src/base64.c
diff --git a/lib/include/chiaki/common.h b/lib/include/chiaki/common.h
index f0cd66d..c521ecf 100644
--- a/lib/include/chiaki/common.h
+++ b/lib/include/chiaki/common.h
@@ -18,27 +18,14 @@
 #ifndef CHIAKI_COMMON_H
 #define CHIAKI_COMMON_H
 
-#include <stdbool.h>
 #ifdef _WIN32
-#define chiaki_socket_t SOCKET
-#define CHIAKI_SOCKET_IS_INVALID(s) ((s) == INVALID_SOCKET)
-#define CHIAKI_INVALID_SOCKET INVALID_SOCKET
-#define CHIAKI_SOCKET_CLOSE(s) closesocket(s)
-#define CHIAKI_SOCKET_ERROR_FMT "%d"
-#define CHIAKI_SOCKET_ERROR_VALUE (WSAGetLastError())
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
 #endif
-#else
-#include <unistd.h>
-#define chiaki_socket_t int
-#define CHIAKI_SOCKET_IS_INVALID(s) ((s) < 0)
-#define CHIAKI_INVALID_SOCKET (-1)
-#define CHIAKI_SOCKET_CLOSE(s) close(s)
-#define CHIAKI_SOCKET_ERROR_FMT "%s"
-#define CHIAKI_SOCKET_ERROR_VALUE (strerror(errno))
 #endif
 
+#include <stddef.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -56,6 +43,9 @@ typedef enum
 	CHIAKI_ERR_MEMORY,
 	CHIAKI_ERR_OVERFLOW,
 	CHIAKI_ERR_NETWORK,
+	CHIAKI_ERR_CONNECTION_REFUSED,
+	CHIAKI_ERR_HOST_DOWN,
+	CHIAKI_ERR_HOST_UNREACH,
 	CHIAKI_ERR_DISCONNECTED,
 	CHIAKI_ERR_INVALID_DATA,
 	CHIAKI_ERR_BUF_TOO_SMALL,
diff --git a/lib/include/chiaki/sock.h b/lib/include/chiaki/sock.h
new file mode 100644
index 0000000..c675b8c
--- /dev/null
+++ b/lib/include/chiaki/sock.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of Chiaki.
+ *
+ * Chiaki is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chiaki is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chiaki.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHIAKI_SOCK_H
+#define CHIAKI_SOCK_H
+
+#include "common.h"
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+typedef SOCKET chiaki_socket_t;
+#define CHIAKI_SOCKET_IS_INVALID(s) ((s) == INVALID_SOCKET)
+#define CHIAKI_INVALID_SOCKET INVALID_SOCKET
+#define CHIAKI_SOCKET_CLOSE(s) closesocket(s)
+#define CHIAKI_SOCKET_ERROR_FMT "%d"
+#define CHIAKI_SOCKET_ERROR_VALUE (WSAGetLastError())
+#define CHIAKI_SOCKET_EINPROGRESS (WSAGetLastError() == WSAEWOULDBLOCK)
+#else
+#include <unistd.h>
+#include <errno.h>
+typedef int chiaki_socket_t;
+#define CHIAKI_SOCKET_IS_INVALID(s) ((s) < 0)
+#define CHIAKI_INVALID_SOCKET (-1)
+#define CHIAKI_SOCKET_CLOSE(s) close(s)
+#define CHIAKI_SOCKET_ERROR_FMT "%s"
+#define CHIAKI_SOCKET_ERROR_VALUE (strerror(errno))
+#define CHIAKI_SOCKET_EINPROGRESS (errno == EINPROGRESS)
+#endif
+
+CHIAKI_EXPORT ChiakiErrorCode chiaki_socket_set_nonblock(chiaki_socket_t sock, bool nonblock);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //CHIAKI_SOCK_H
diff --git a/lib/include/chiaki/stoppipe.h b/lib/include/chiaki/stoppipe.h
index b5d93b3..229995e 100644
--- a/lib/include/chiaki/stoppipe.h
+++ b/lib/include/chiaki/stoppipe.h
@@ -18,10 +18,11 @@
 #ifndef CHIAKI_STOPPIPE_H
 #define CHIAKI_STOPPIPE_H
 
-#include "common.h"
+#include "sock.h"
 
 #include <stdint.h>
 #include <stddef.h>
+#include <stdbool.h>
 
 #ifdef _WIN32
 #include <winsock2.h>
@@ -40,11 +41,17 @@ typedef struct chiaki_stop_pipe_t
 #endif
 } ChiakiStopPipe;
 
+struct sockaddr;
+
 CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_init(ChiakiStopPipe *stop_pipe);
 CHIAKI_EXPORT void chiaki_stop_pipe_fini(ChiakiStopPipe *stop_pipe);
 CHIAKI_EXPORT void chiaki_stop_pipe_stop(ChiakiStopPipe *stop_pipe);
-CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_select_single(ChiakiStopPipe *stop_pipe, chiaki_socket_t fd, uint64_t timeout_ms);
-static inline ChiakiErrorCode chiaki_stop_pipe_sleep(ChiakiStopPipe *stop_pipe, uint64_t timeout_ms) { return chiaki_stop_pipe_select_single(stop_pipe, CHIAKI_INVALID_SOCKET, timeout_ms); }
+CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_select_single(ChiakiStopPipe *stop_pipe, chiaki_socket_t fd, bool write, uint64_t timeout_ms);
+/**
+ * Like connect(), but can be canceled by the stop pipe. Only makes sense with a non-blocking socket.
+ */
+CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_connect(ChiakiStopPipe *stop_pipe, chiaki_socket_t fd, struct sockaddr *addr, size_t addrlen);
+static inline ChiakiErrorCode chiaki_stop_pipe_sleep(ChiakiStopPipe *stop_pipe, uint64_t timeout_ms) { return chiaki_stop_pipe_select_single(stop_pipe, CHIAKI_INVALID_SOCKET, false, timeout_ms); }
 CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_reset(ChiakiStopPipe *stop_pipe);
 
 #ifdef __cplusplus
diff --git a/lib/include/chiaki/takion.h b/lib/include/chiaki/takion.h
index 1b29bda..b242769 100644
--- a/lib/include/chiaki/takion.h
+++ b/lib/include/chiaki/takion.h
@@ -213,7 +213,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send(ChiakiTakion *takion, uint8_t *
 /**
  * Thread-safe while Takion is running.
  *
- * @param optional pointer to write the sequence number of the sent package to
+ * @param optional pointer to write the sequence number of the sent packet to
  */
 CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_message_data(ChiakiTakion *takion, uint8_t chunk_flags, uint16_t channel, uint8_t *buf, size_t buf_size, ChiakiSeqNum32 *seq_num);
 
diff --git a/lib/src/common.c b/lib/src/common.c
index 5808039..824ed13 100644
--- a/lib/src/common.c
+++ b/lib/src/common.c
@@ -43,6 +43,12 @@ CHIAKI_EXPORT const char *chiaki_error_string(ChiakiErrorCode code)
 			return "Memory error";
 		case CHIAKI_ERR_NETWORK:
 			return "Network error";
+		case CHIAKI_ERR_CONNECTION_REFUSED:
+			return "Connection Refused";
+		case CHIAKI_ERR_HOST_DOWN:
+			return "Host is down";
+		case CHIAKI_ERR_HOST_UNREACH:
+			return "No route to host";
 		case CHIAKI_ERR_DISCONNECTED:
 			return "Disconnected";
 		case CHIAKI_ERR_INVALID_DATA:
diff --git a/lib/src/ctrl.c b/lib/src/ctrl.c
index f1fdece..9c3fae7 100644
--- a/lib/src/ctrl.c
+++ b/lib/src/ctrl.c
@@ -151,18 +151,19 @@ static void *ctrl_thread_func(void *user)
 {
 	ChiakiCtrl *ctrl = user;
 
-	ChiakiErrorCode err = ctrl_connect(ctrl);
+	ChiakiErrorCode err = chiaki_mutex_lock(&ctrl->notif_mutex);
+	assert(err == CHIAKI_ERR_SUCCESS);
+
+	err = ctrl_connect(ctrl);
 	if(err != CHIAKI_ERR_SUCCESS)
 	{
 		ctrl_failed(ctrl, CHIAKI_QUIT_REASON_CTRL_CONNECT_FAILED);
+		chiaki_mutex_unlock(&ctrl->notif_mutex);
 		return NULL;
 	}
 
 	CHIAKI_LOGI(ctrl->session->log, "Ctrl connected");
 
-	err = chiaki_mutex_lock(&ctrl->notif_mutex);
-	assert(err == CHIAKI_ERR_SUCCESS);
-
 	while(true)
 	{
 		bool overflow = false;
@@ -197,7 +198,7 @@ static void *ctrl_thread_func(void *user)
 		}
 
 		chiaki_mutex_unlock(&ctrl->notif_mutex);
-		err = chiaki_stop_pipe_select_single(&ctrl->notif_pipe, ctrl->sock, UINT64_MAX);
+		err = chiaki_stop_pipe_select_single(&ctrl->notif_pipe, ctrl->sock, false, UINT64_MAX);
 		chiaki_mutex_lock(&ctrl->notif_mutex);
 		if(err == CHIAKI_ERR_CANCELED)
 		{
@@ -511,29 +512,38 @@ static ChiakiErrorCode ctrl_connect(ChiakiCtrl *ctrl)
 		return CHIAKI_ERR_NETWORK;
 	}
 
-	int r = connect(sock, sa, addr->ai_addrlen);
+	ChiakiErrorCode err = chiaki_socket_set_nonblock(sock, true);
+	if(err != CHIAKI_ERR_SUCCESS)
+		CHIAKI_LOGE(session->log, "Failed to set ctrl socket to non-blocking: %s", chiaki_error_string(err));
+
+
+	chiaki_mutex_unlock(&ctrl->notif_mutex);
+	err = chiaki_stop_pipe_connect(&ctrl->notif_pipe, sock, sa, addr->ai_addrlen);
+	chiaki_mutex_lock(&ctrl->notif_mutex);
 	free(sa);
-	if(r < 0)
+	if(err != CHIAKI_ERR_SUCCESS)
 	{
-#ifdef _WIN32
-		int errsv = WSAGetLastError();
-		CHIAKI_LOGE(session->log, "Ctrl connect failed: %d", errsv);
-		ChiakiQuitReason quit_reason = errsv == WSAECONNREFUSED ? CHIAKI_QUIT_REASON_CTRL_CONNECTION_REFUSED : CHIAKI_QUIT_REASON_CTRL_UNKNOWN;
-#else
-		int errsv = errno;
-		CHIAKI_LOGE(session->log, "Ctrl connect failed: %s", strerror(errsv));
-		ChiakiQuitReason quit_reason = errsv == ECONNREFUSED ? CHIAKI_QUIT_REASON_CTRL_CONNECTION_REFUSED : CHIAKI_QUIT_REASON_CTRL_UNKNOWN;
-#endif
-		ctrl_failed(ctrl, quit_reason);
-		CHIAKI_SOCKET_CLOSE(sock);
-		return CHIAKI_ERR_NETWORK;
+		if(err == CHIAKI_ERR_CANCELED)
+		{
+			if(ctrl->should_stop)
+				CHIAKI_LOGI(session->log, "Ctrl requested to stop while connecting");
+			else
+				CHIAKI_LOGE(session->log, "Ctrl notif pipe signaled without should_stop during connect");
+			CHIAKI_SOCKET_CLOSE(sock);
+		}
+		else
+		{
+			CHIAKI_LOGE(session->log, "Ctrl connect failed: %s", chiaki_error_string(err));
+			ChiakiQuitReason quit_reason = err == CHIAKI_ERR_CONNECTION_REFUSED ? CHIAKI_QUIT_REASON_CTRL_CONNECTION_REFUSED : CHIAKI_QUIT_REASON_CTRL_UNKNOWN;
+			ctrl_failed(ctrl, quit_reason);
+		}
+		goto error;
 	}
 
-	CHIAKI_LOGI(session->log, "Connected to %s:%d", session->connect_info.hostname, SESSION_CTRL_PORT);
-
+	CHIAKI_LOGI(session->log, "Ctrl connected to %s:%d", session->connect_info.hostname, SESSION_CTRL_PORT);
 
 	uint8_t auth_enc[CHIAKI_RPCRYPT_KEY_SIZE];
-	ChiakiErrorCode err = chiaki_rpcrypt_encrypt(&session->rpcrypt, ctrl->crypt_counter_local++, (const uint8_t *)session->connect_info.regist_key, auth_enc, CHIAKI_RPCRYPT_KEY_SIZE);
+	err = chiaki_rpcrypt_encrypt(&session->rpcrypt, ctrl->crypt_counter_local++, (const uint8_t *)session->connect_info.regist_key, auth_enc, CHIAKI_RPCRYPT_KEY_SIZE);
 	if(err != CHIAKI_ERR_SUCCESS)
 		goto error;
 	char auth_b64[CHIAKI_RPCRYPT_KEY_SIZE*2];
diff --git a/lib/src/discovery.c b/lib/src/discovery.c
index 6ab20c1..e2d5205 100644
--- a/lib/src/discovery.c
+++ b/lib/src/discovery.c
@@ -245,7 +245,7 @@ static void *discovery_thread_func(void *user)
 
 	while(1)
 	{
-		ChiakiErrorCode err = chiaki_stop_pipe_select_single(&thread->stop_pipe, discovery->socket, UINT64_MAX);
+		ChiakiErrorCode err = chiaki_stop_pipe_select_single(&thread->stop_pipe, discovery->socket, false, UINT64_MAX);
 		if(err == CHIAKI_ERR_CANCELED)
 			break;
 		if(err != CHIAKI_ERR_SUCCESS)
diff --git a/lib/src/http.c b/lib/src/http.c
index 7e9d000..50c86fe 100644
--- a/lib/src/http.c
+++ b/lib/src/http.c
@@ -157,7 +157,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_recv_http_header(int sock, char *buf, size_
 	{
 		if(stop_pipe)
 		{
-			ChiakiErrorCode err = chiaki_stop_pipe_select_single(stop_pipe, sock, timeout_ms);
+			ChiakiErrorCode err = chiaki_stop_pipe_select_single(stop_pipe, sock, false, timeout_ms);
 			if(err != CHIAKI_ERR_SUCCESS)
 				return err;
 		}
diff --git a/lib/src/regist.c b/lib/src/regist.c
index 16a4f62..947b713 100644
--- a/lib/src/regist.c
+++ b/lib/src/regist.c
@@ -349,7 +349,7 @@ static ChiakiErrorCode regist_search(ChiakiRegist *regist, struct addrinfo *addr
 		if(now_ms > timeout_abs_ms)
 			err = CHIAKI_ERR_TIMEOUT;
 		else
-			err = chiaki_stop_pipe_select_single(&regist->stop_pipe, sock, timeout_abs_ms - now_ms);
+			err = chiaki_stop_pipe_select_single(&regist->stop_pipe, sock, false, timeout_abs_ms - now_ms);
 		if(err != CHIAKI_ERR_SUCCESS)
 		{
 			if(err == CHIAKI_ERR_TIMEOUT)
@@ -551,7 +551,7 @@ static ChiakiErrorCode regist_recv_response(ChiakiRegist *regist, ChiakiRegister
 
 	while(buf_filled_size < content_size + header_size)
 	{
-		err = chiaki_stop_pipe_select_single(&regist->stop_pipe, sock, REGIST_REPONSE_TIMEOUT_MS);
+		err = chiaki_stop_pipe_select_single(&regist->stop_pipe, sock, false, REGIST_REPONSE_TIMEOUT_MS);
 		if(err != CHIAKI_ERR_SUCCESS)
 		{
 			if(err == CHIAKI_ERR_TIMEOUT)
diff --git a/lib/src/session.c b/lib/src/session.c
index d37bae0..db86c70 100644
--- a/lib/src/session.c
+++ b/lib/src/session.c
@@ -628,29 +628,36 @@ static bool session_thread_request_session(ChiakiSession *session, ChiakiRpVersi
 			free(sa);
 			continue;
 		}
-		r = connect(session_sock, sa, ai->ai_addrlen);
-		if(r < 0)
+
+		ChiakiErrorCode err = chiaki_socket_set_nonblock(session_sock, true);
+		if(err != CHIAKI_ERR_SUCCESS)
+			CHIAKI_LOGE(session->log, "Failed to set session socket to non-blocking: %s", chiaki_error_string(err));
+
+		chiaki_mutex_unlock(&session->state_mutex);
+		err = chiaki_stop_pipe_connect(&session->stop_pipe, session_sock, sa, ai->ai_addrlen);
+		chiaki_mutex_lock(&session->state_mutex);
+		if(err == CHIAKI_ERR_CANCELED)
 		{
-#ifdef _WIN32
-			int err = WSAGetLastError();
-			CHIAKI_LOGE(session->log, "Session request connect failed: %u", err);
-			if(err == WSAECONNREFUSED)
+			CHIAKI_LOGI(session->log, "Session stopped while connecting for session request");
+			session->quit_reason = CHIAKI_QUIT_REASON_STOPPED;
+			CHIAKI_SOCKET_CLOSE(session_sock);
+			session_sock = -1;
+			free(sa);
+			break;
+		}
+		else if(err != CHIAKI_ERR_SUCCESS)
+		{
+			CHIAKI_LOGE(session->log, "Session request connect failed: %s", chiaki_error_string(err));
+			if(err == CHIAKI_ERR_CONNECTION_REFUSED)
 				session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_CONNECTION_REFUSED;
 			else
 				session->quit_reason = CHIAKI_QUIT_REASON_NONE;
-#else
-			int errsv = errno;
-			CHIAKI_LOGE(session->log, "Session request connect failed: %s", strerror(errsv));
-			if(errsv == ECONNREFUSED)
-				session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_CONNECTION_REFUSED;
-			else
-				session->quit_reason = CHIAKI_QUIT_REASON_NONE;
-#endif
 			CHIAKI_SOCKET_CLOSE(session_sock);
 			session_sock = -1;
 			free(sa);
 			continue;
 		}
+
 		free(sa);
 
 		session->connect_info.host_addrinfo_selected = ai;
diff --git a/lib/src/sock.c b/lib/src/sock.c
new file mode 100644
index 0000000..f8d224e
--- /dev/null
+++ b/lib/src/sock.c
@@ -0,0 +1,36 @@
+/*
+ * This file is part of Chiaki.
+ *
+ * Chiaki is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chiaki is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chiaki.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <chiaki/sock.h>
+#include <fcntl.h>
+
+CHIAKI_EXPORT ChiakiErrorCode chiaki_socket_set_nonblock(chiaki_socket_t sock, bool nonblock)
+{
+#ifdef _WIN32
+	u_long nbio = nonblock ? 1 : 0;
+	if(ioctlsocket(sock, FIONBIO, &nbio) != NO_ERROR)
+		return CHIAKI_ERR_UNKNOWN;
+#else
+	int flags = fcntl(sock, F_GETFL, 0);
+	if(flags == -1)
+		return CHIAKI_ERR_UNKNOWN;
+	flags = nonblock ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK);
+	if(fcntl(sock, F_SETFL, flags) == -1)
+		return CHIAKI_ERR_UNKNOWN;
+#endif
+	return CHIAKI_ERR_SUCCESS;
+}
\ No newline at end of file
diff --git a/lib/src/stoppipe.c b/lib/src/stoppipe.c
index 0180751..cb90309 100644
--- a/lib/src/stoppipe.c
+++ b/lib/src/stoppipe.c
@@ -16,11 +16,12 @@
  */
 
 #include <chiaki/stoppipe.h>
+#include <chiaki/sock.h>
 
 #include <fcntl.h>
 
 #ifdef _WIN32
-#include <winsock2.h>
+#include <ws2tcpip.h>
 #else
 #include <unistd.h>
 #include <sys/socket.h>
@@ -69,7 +70,7 @@ CHIAKI_EXPORT void chiaki_stop_pipe_stop(ChiakiStopPipe *stop_pipe)
 #endif
 }
 
-CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_select_single(ChiakiStopPipe *stop_pipe, chiaki_socket_t fd, uint64_t timeout_ms)
+CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_select_single(ChiakiStopPipe *stop_pipe, chiaki_socket_t fd, bool write, uint64_t timeout_ms)
 {
 #ifdef _WIN32
 	WSAEVENT events[2];
@@ -82,7 +83,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_select_single(ChiakiStopPipe *sto
 		events[1] = WSACreateEvent();
 		if(events[1] == WSA_INVALID_EVENT)
 			return CHIAKI_ERR_UNKNOWN;
-		WSAEventSelect(fd, events[1], FD_READ);
+		WSAEventSelect(fd, events[1], write ? FD_WRITE : FD_READ);
 	}
 
 	DWORD r = WSAWaitForMultipleEvents(events_count, events, FALSE, timeout_ms == UINT64_MAX ? WSA_INFINITE : (DWORD)timeout_ms, FALSE);
@@ -102,14 +103,17 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_select_single(ChiakiStopPipe *sto
 			return CHIAKI_ERR_UNKNOWN;
 	}
 #else
-	fd_set fds;
-	FD_ZERO(&fds);
-	FD_SET(stop_pipe->fds[0], &fds);
+	fd_set rfds;
+	FD_ZERO(&rfds);
+	FD_SET(stop_pipe->fds[0], &rfds);
+
+	fd_set wfds;
+	FD_ZERO(&wfds);
 
 	int nfds = stop_pipe->fds[0];
-	if(fd >= 0)
+	if(!CHIAKI_SOCKET_IS_INVALID(fd))
 	{
-		FD_SET(fd, &fds);
+		FD_SET(fd, write ? &wfds : &rfds);
 		if(fd > nfds)
 			nfds = fd;
 	}
@@ -124,20 +128,96 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_select_single(ChiakiStopPipe *sto
 		timeout = &timeout_s;
 	}
 
-	int r = select(nfds, &fds, NULL, NULL, timeout);
+	int r = select(nfds, &rfds, write ? &wfds : NULL, NULL, timeout);
 	if(r < 0)
 		return CHIAKI_ERR_UNKNOWN;
 
-	if(FD_ISSET(stop_pipe->fds[0], &fds))
+	if(FD_ISSET(stop_pipe->fds[0], &rfds))
 		return CHIAKI_ERR_CANCELED;
 
-	if(fd >= 0 && FD_ISSET(fd, &fds))
+	if(!CHIAKI_SOCKET_IS_INVALID(fd) && FD_ISSET(fd, write ? &wfds : &rfds))
 		return CHIAKI_ERR_SUCCESS;
 
 	return CHIAKI_ERR_TIMEOUT;
 #endif
 }
 
+CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_connect(ChiakiStopPipe *stop_pipe, chiaki_socket_t fd, struct sockaddr *addr, size_t addrlen)
+{
+	int r = connect(fd, addr, (socklen_t)addrlen);
+	if(r >= 0)
+		return CHIAKI_ERR_SUCCESS;
+
+	if(CHIAKI_SOCKET_EINPROGRESS)
+	{
+		ChiakiErrorCode err = chiaki_stop_pipe_select_single(stop_pipe, fd, true, UINT64_MAX);
+		if(err != CHIAKI_ERR_SUCCESS)
+			return err;
+	}
+	else
+	{
+#ifdef _WIN32
+		int err = WSAGetLastError();
+		if(err == WSAECONNREFUSED)
+			return CHIAKI_ERR_CONNECTION_REFUSED;
+		else
+			return CHIAKI_ERR_NETWORK;
+#else
+		if(errno == ECONNREFUSED)
+			return CHIAKI_ERR_CONNECTION_REFUSED;
+		else
+			return CHIAKI_ERR_NETWORK;
+#endif
+	}
+
+	struct sockaddr peer;
+	socklen_t peerlen = sizeof(peer);
+	if(getpeername(fd, &peer, &peerlen) == 0)
+		return CHIAKI_ERR_SUCCESS;
+
+	if(errno != ENOTCONN)
+		return CHIAKI_ERR_UNKNOWN;
+
+#ifdef _WIN32
+	DWORD sockerr;
+#else
+	int sockerr;
+#endif
+	socklen_t sockerr_sz = sizeof(sockerr);
+	if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sockerr_sz) < 0)
+		return CHIAKI_ERR_UNKNOWN;
+
+#ifdef _WIN32
+	switch(sockerr)
+	{
+		case WSAETIMEDOUT:
+			return CHIAKI_ERR_TIMEOUT;
+		case WSAECONNREFUSED:
+			return CHIAKI_ERR_CONNECTION_REFUSED;
+		case WSAEHOSTDOWN:
+			return CHIAKI_ERR_HOST_DOWN;
+		case WSAEHOSTUNREACH:
+			return CHIAKI_ERR_HOST_UNREACH;
+		default:
+			return CHIAKI_ERR_UNKNOWN;
+	}
+#else
+	switch(sockerr)
+	{
+		case ETIMEDOUT:
+			return CHIAKI_ERR_TIMEOUT;
+		case ECONNREFUSED:
+			return CHIAKI_ERR_CONNECTION_REFUSED;
+		case EHOSTDOWN:
+			return CHIAKI_ERR_HOST_DOWN;
+		case EHOSTUNREACH:
+			return CHIAKI_ERR_HOST_UNREACH;
+		default:
+			return CHIAKI_ERR_UNKNOWN;
+	}
+#endif
+}
+
 CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_reset(ChiakiStopPipe *stop_pipe)
 {
 #ifdef _WIN32
diff --git a/lib/src/takion.c b/lib/src/takion.c
index bdba21a..e992cc7 100644
--- a/lib/src/takion.c
+++ b/lib/src/takion.c
@@ -757,7 +757,7 @@ beach:
 
 static ChiakiErrorCode takion_recv(ChiakiTakion *takion, uint8_t *buf, size_t *buf_size, uint64_t timeout_ms)
 {
-	ChiakiErrorCode err = chiaki_stop_pipe_select_single(&takion->stop_pipe, takion->sock, timeout_ms);
+	ChiakiErrorCode err = chiaki_stop_pipe_select_single(&takion->stop_pipe, takion->sock, false, timeout_ms);
 	if(err == CHIAKI_ERR_TIMEOUT || err == CHIAKI_ERR_CANCELED)
 		return err;
 	if(err != CHIAKI_ERR_SUCCESS)
diff --git a/lib/src/utils.h b/lib/src/utils.h
index a88208f..0bd86a7 100644
--- a/lib/src/utils.h
+++ b/lib/src/utils.h
@@ -18,7 +18,7 @@
 #ifndef CHIAKI_UTILS_H
 #define CHIAKI_UTILS_H
 
-#include <chiaki/common.h>
+#include <chiaki/sock.h>
 #include <chiaki/log.h>
 #ifdef _WIN32
 #include <ws2tcpip.h>