mirror of
https://github.com/actix/actix-web.git
synced 2024-11-22 09:31:10 +00: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:
parent
d9d22825d4
commit
1c4e265a70
3 changed files with 29 additions and 7 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue