1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-27 09:42:57 +01:00

Set SO_REUSEADDR only non-Windows platforms (#3473)

* Fix: Per discussion in #2958, set `SO_REUSEADDR` only non-Windows platforms.

Add: Tests confirming that only a single webserver instance may
bind to a given address.

* Clean: Lint.

* Clean: another guess at making the formatter happy.

* Clean: More cargo fmt fun. (Running cargo fmt locally doesn't help.)

---------

Co-authored-by: Bryan A. Jones <bjones1@users.noreply.github.com>
Co-authored-by: Rob Ede <robjtede@icloud.com>
This commit is contained in:
Bryan A. Jones 2024-10-01 02:08:34 -05:00 committed by GitHub
parent d9d22825d4
commit 1c4e265a70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 29 additions and 7 deletions

View File

@ -3,6 +3,7 @@
## Unreleased ## Unreleased
- Minimum supported Rust version (MSRV) is now 1.75. - Minimum supported Rust version (MSRV) is now 1.75.
- On Windows platforms, produce an error when invoking `HttpServer::bind` on a socket that's already in use. See [issue 2958](https://github.com/actix/actix-web/issues/2958).
## 4.9.0 ## 4.9.0

View File

@ -1085,7 +1085,10 @@ fn create_tcp_listener(addr: net::SocketAddr, backlog: u32) -> io::Result<net::T
use socket2::{Domain, Protocol, Socket, Type}; use socket2::{Domain, Protocol, Socket, Type};
let domain = Domain::for_address(addr); let domain = Domain::for_address(addr);
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?; let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
#[cfg(not(windows))]
{
socket.set_reuse_address(true)?; socket.set_reuse_address(true)?;
}
socket.bind(&addr.into())?; socket.bind(&addr.into())?;
// clamp backlog to max u32 that fits in i32 range // clamp backlog to max u32 that fits in i32 range
let backlog = cmp::min(backlog, i32::MAX as u32) as i32; let backlog = cmp::min(backlog, i32::MAX as u32) as i32;

View File

@ -1,13 +1,10 @@
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
extern crate tls_openssl as openssl; extern crate tls_openssl as openssl;
#[cfg(any(unix, feature = "openssl"))] use std::{sync::mpsc, thread, time::Duration};
use {
actix_web::{web, App, HttpResponse, HttpServer}, use actix_web::{web, App, HttpResponse, HttpServer};
std::{sync::mpsc, thread, time::Duration},
};
#[cfg(unix)]
#[actix_rt::test] #[actix_rt::test]
async fn test_start() { async fn test_start() {
let addr = actix_test::unused_addr(); let addr = actix_test::unused_addr();
@ -53,6 +50,27 @@ async fn test_start() {
let response = client.get(host.clone()).send().await.unwrap(); let response = client.get(host.clone()).send().await.unwrap();
assert!(response.status().is_success()); assert!(response.status().is_success());
// Attempt to start a second server using the same address.
let result = HttpServer::new(|| {
App::new().service(
web::resource("/").route(web::to(|| async { HttpResponse::Ok().body("test") })),
)
})
.workers(1)
.backlog(1)
.max_connections(10)
.max_connection_rate(10)
.keep_alive(Duration::from_secs(10))
.client_request_timeout(Duration::from_secs(5))
.client_disconnect_timeout(Duration::ZERO)
.server_hostname("localhost")
.system_exit()
.disable_signals()
.bind(format!("{}", addr));
// This should fail: the address is in use.
assert!(result.is_err());
srv.stop(false).await; srv.stop(false).await;
} }