apple / swift-nio

Event-driven network application framework for high performance protocol servers & clients, non-blocking.
https://swiftpackageindex.com/apple/swift-nio/documentation
Apache License 2.0
8k stars 652 forks source link

If a port is used, NIOHTTP1Server will not run. If it is stopped, it still will not run. #451

Closed azav closed 6 years ago

azav commented 6 years ago

Expected behavior

Find and echo the available port or return gracefully

Actual behavior

htdocs = /dev/null/ Fatal error: Error raised at top level: bind(descriptor:ptr:bytes:) failed: Address already in use (errno: 48) : file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.74.1/src/swift/stdlib/public/core/ErrorType.swift, line 187 Illegal instruction: 4

Steps to reproduce

  1. In the Terminal, connect to the proper directory and run as such: swift run NIOHTTP1Server localhost 9990
  2. Create another Terminal window and enter the same command. The error above is displayed.
  3. In the Terminal window where NIOHTTP1Server is running, press control Z to stop the server.
  4. Try to start it again without closing that Terminal window.
    It will not start and only returns the error listed above.
  5. Close the Terminal window that was used to run NIOHTTP1Server and run in another Terminal Window.
    It launches fine.
    Apparently when stopped via control z, the open port is not being closed.

If possible, minimal yet complete reproducer code (or URL to code)

SwiftNIO version/commit hash

78235f841c725a8879089bf7ab0f6f0cecff49d0

[the SwiftNIO tag/commit hash] HEAD 78235f841c725a8879089bf7ab0f6f0cecff49d0

Swift & OS version (output of swift --version && uname -a)

27-iMac:swift-nio Zav$ swift --version && uname -a Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2) Target: x86_64-apple-macosx10.9 Darwin 27-iMac.local 17.5.0 Darwin Kernel Version 17.5.0: Mon Mar 5 22:24:32 PST 2018; root:xnu-4570.51.1~1/RELEASE_X86_64 x86_64 27-iMac:swift-nio

Lukasa commented 6 years ago

This is behaving as expected. You raised two notes: binding to the same port, and ctrl-z. Let's address them in turn.

NIOHTTP1Server does not set SO_REUSEPORT. This means it is not possible to bind two processes to the same port. This is rather on purpose: as a simple example server, there is no point in having SO_REUSEPORT enabled, and it has subtle strange behaviours on some operating systems. This is why you get address in use from the second process: you can run multiple processes by using a separate port.

Secondly, ctrl-z. Ctrl-z sends the signal SIGSTP. The default behaviour of SIGSTP is not to cause a process to exit or relinquish its resources: instead it just pauses execution. NIOHTTP1Server does the exact same thing. As a result, it still holds its file descriptor and its bound port. That will prevent binding that port in another process, for the reasons mentioned above. And this is a good thing: if you ever restarted the paused process, and it had relinquished its port, it would be unable to get it back! That would be quite bad.