@ -17,6 +17,7 @@ package caddy
import (
import (
"fmt"
"fmt"
"net"
"net"
"os"
"strconv"
"strconv"
"strings"
"strings"
"sync"
"sync"
@ -39,6 +40,10 @@ func Listen(network, addr string) (net.Listener, error) {
sharedLn , _ , err := listenerPool . LoadOrNew ( lnKey , func ( ) ( Destructor , error ) {
sharedLn , _ , err := listenerPool . LoadOrNew ( lnKey , func ( ) ( Destructor , error ) {
ln , err := net . Listen ( network , addr )
ln , err := net . Listen ( network , addr )
if err != nil {
if err != nil {
// https://github.com/caddyserver/caddy/pull/4534
if isUnixNetwork ( network ) && isListenBindAddressAlreadyInUseError ( err ) {
return nil , fmt . Errorf ( "%w: this can happen if Caddy was forcefully killed" , err )
}
return nil , err
return nil , err
}
}
return & sharedListener { Listener : ln , key : lnKey } , nil
return & sharedListener { Listener : ln , key : lnKey } , nil
@ -59,6 +64,10 @@ func ListenPacket(network, addr string) (net.PacketConn, error) {
sharedPc , _ , err := listenerPool . LoadOrNew ( lnKey , func ( ) ( Destructor , error ) {
sharedPc , _ , err := listenerPool . LoadOrNew ( lnKey , func ( ) ( Destructor , error ) {
pc , err := net . ListenPacket ( network , addr )
pc , err := net . ListenPacket ( network , addr )
if err != nil {
if err != nil {
// https://github.com/caddyserver/caddy/pull/4534
if isUnixNetwork ( network ) && isListenBindAddressAlreadyInUseError ( err ) {
return nil , fmt . Errorf ( "%w: this can happen if Caddy was forcefully killed" , err )
}
return nil , err
return nil , err
}
}
return & sharedPacketConn { PacketConn : pc , key : lnKey } , nil
return & sharedPacketConn { PacketConn : pc , key : lnKey } , nil
@ -322,6 +331,20 @@ func isUnixNetwork(netw string) bool {
return netw == "unix" || netw == "unixgram" || netw == "unixpacket"
return netw == "unix" || netw == "unixgram" || netw == "unixpacket"
}
}
func isListenBindAddressAlreadyInUseError ( err error ) bool {
switch networkOperationError := err . ( type ) {
case * net . OpError :
switch syscallError := networkOperationError . Err . ( type ) {
case * os . SyscallError :
if syscallError . Syscall == "bind" {
return true
}
}
}
return false
}
// ParseNetworkAddress parses addr into its individual
// ParseNetworkAddress parses addr into its individual
// components. The input string is expected to be of
// components. The input string is expected to be of
// the form "network/host:port-range" where any part is
// the form "network/host:port-range" where any part is