Once I call socket()
; bind()
(with a specific IP address, not INADDR_ANY
); listen()
, there seems to be no way of determining if the IP address is still a valid address of one of the system’s interfaces.
What I looked into using:
- Checking error with
getsockopt(SO_ERROR)
; - Using
epoll()
-ing on someEPOLLERR
,EPOLL{,RD}HUP
events; - Hoping that
accept()
would return an error if the IP address is deleted when process is blocked on this syscall;
Non of those above seem to detect the IP address vanishing and/or change of interface state at all.
- Calling
bind()
in some timer callback to periodically check if the IP address may be bound, but this requires another socket has to be created it is not feasible.
I did not test these:
Setting
SO_BINDTODEVICE
in the hope that this will change behavior of the facilities from the first triple in case interface goes down/IP address is removed.Calling some
ioctl()
likeSIOCSPGRP
orFIOASYNC
since they promise to signal process about asynchronous events that hopefully include disappearance of an IP address.Using
netlink
to get routing table events, but this is very Linux-specific.
I’m hopping for a more portable way.
What I needing is some event similar to RDMA_CM_EVENT_DEVICE_REMOVAL
, but with AF_INET
sockets that would notify me when there is no bound interface with that IP address. Even this may be impossible to fulfill, because even bind()
completes without error if the interface is down.
Advertisement
Answer
You do not need to close a socket when the link goes down with BSD sockets.
This other questions shows how to listen for network routing changes mentioned by Remy.
A simpler way may be to check if the IP is currently bound before using the socket. This is a way to verify that 127.0.0.1
is still valid:
% cat checksocket.c && cc -o checksocket checksocket.c ; ./checksocket #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <ifaddrs.h> #include <netdb.h> #include <net/if.h> int main (void) { struct ifaddrs *ifa, *i; char host[NI_MAXHOST]; int ret = getifaddrs(&ifa); if (ret) { perror("getifaddrs:"); exit(EXIT_FAILURE); } for (i = ifa; i != NULL; i = i->ifa_next) { ret = getnameinfo(i->ifa_addr, sizeof(*(i->ifa_addr)), host, sizeof(host), NULL, 0, NI_NUMERICHOST); char find[] = "127.0.0.1"; int len = strlen(host); if (!ret && len && !strncmp(host, find, len)) { printf("Still valid: %s %sn", i->ifa_name, ret ? "" : host); } } freeifaddrs(ifa); return 0; } Still valid: lo0 127.0.0.1