summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Schleifer <js@heap.zone>2019-09-08 01:28:50 +0200
committerJonathan Schleifer <js@heap.zone>2019-09-08 01:28:50 +0200
commit85479694c83b47bde31f935e4683e25485ad176a (patch)
treec9a86a3217248b51930b34ddde394604c8cf9445
parent0bb50108cd4b5c446f5a0a8962f5baefdcfdd594 (diff)
Fix async connect with epoll
-rw-r--r--src/OFEpollKernelEventObserver.m12
-rw-r--r--src/OFRunLoop.m25
2 files changed, 31 insertions, 6 deletions
diff --git a/src/OFEpollKernelEventObserver.m b/src/OFEpollKernelEventObserver.m
index 4028ad0a..8a440472 100644
--- a/src/OFEpollKernelEventObserver.m
+++ b/src/OFEpollKernelEventObserver.m
@@ -130,9 +130,15 @@ static const of_map_table_functions_t mapFunctions = { NULL };
if (events == 0) {
if (epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, NULL) == -1)
- @throw [OFObserveFailedException
- exceptionWithObserver: self
- errNo: errno];
+ /*
+ * When an async connect fails, it seems the socket is
+ * automatically removed from epoll, meaning ENOENT is
+ * returned when we try to remove it after it failed.
+ */
+ if (errno != ENOENT)
+ @throw [OFObserveFailedException
+ exceptionWithObserver: self
+ errNo: errno];
[_FDToEvents removeObjectForKey: (void *)((intptr_t)fd + 1)];
} else {
diff --git a/src/OFRunLoop.m b/src/OFRunLoop.m
index 15095fc8..4f4ddb3c 100644
--- a/src/OFRunLoop.m
+++ b/src/OFRunLoop.m
@@ -704,9 +704,28 @@ static OFRunLoop *mainRunLoop = nil;
errNo: errNo];
if ([_delegate respondsToSelector:
- @selector(of_socketDidConnect:exception:)])
- [_delegate of_socketDidConnect: object
- exception: exception];
+ @selector(of_socketDidConnect:exception:)]) {
+ /*
+ * Make sure we only call the delegate once we removed the
+ * socket from the kernel event observer. This is necessary as
+ * otherwise we could try to connect to the next address and it
+ * would not be re-registered with the kernel event observer,
+ * which is necessary for some kernel event observers (e.g.
+ * epoll) even if the fd of the new socket is the same.
+ */
+ OFRunLoop *runLoop = [OFRunLoop currentRunLoop];
+ OFTimer *timer = [OFTimer
+ timerWithTimeInterval: 0
+ target: _delegate
+ selector: @selector(of_socketDidConnect:
+ exception:)
+ object: object
+ object: exception
+ repeats: false];
+
+ [runLoop addTimer: timer
+ forMode: runLoop.currentMode];
+ }
return false;
}