Messages in this thread | | | Date | Tue, 13 Oct 1998 18:25:02 +0200 | From | Andi Kleen <> | Subject | Re: Fw: sendpkt: Connection refused |
| |
On Tue, Oct 13, 1998 at 05:10:16PM +0200, Edgar Toernig wrote: > Andi Kleen wrote: > > > > mblack@csihq.com (Mike Black) writes: > > ... > > > >> Oct 10 06:27:18 defiant dhcpd: sendpkt: Connection refused > > > > > > > >Because Linux stupidly reports ICMP errors it receives for a given UDP > > > >port the next time you try to send on a socket bound to that port, > > > >even though the error has nothing to do with the packet you're trying > > > >to send. The error is essentially informational at this point - when > > > >send_packet gets it while transmitting a packet, it just retransmits > > > >the packet. Utterly bogus, but harmless to you. > > > > He should either fix his program to do correct error handling > > or set the SO_BSDCOMPAT option on the socket. > > How should the "correct error handling" look like? > > I got the same problem when building a daemon which talks to > a large number of clients. The problem: You don't know, whether > the error return of the send is for the current packet or for > one of the thousand packets before. If you try to resend the > current packet another icmp-error may have returned in the > meantime and you get just another -1.
One possibility is to check and clear the pending error first with getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, sizeof err); first. Also you get different error codes for local errors and errors generated by the network, e.g. ENETDOWN or EINVAL or EWOULDBLOCK is definitely a local error, EPROTO or EHOSTUNREACH a network error.
> > You may try to resend until you get a success but what, if the > error _is_ for the current packet and not for an earlier one? > > IMO, this interface is broken. I came to the solution, that > SO_BSDCOMPAT is the Right Thing and should be the default! > (I don't know, if this would break some 'standard'...) It breaks RFC1122. The main problem is that the BSD API has no way to deliver the complete error information, but that is not an excuse for hiding the error.
The vger kernel has a complete solution that will hopefully appear in the official 2.2 kernel. The user process can enable an per socket error queue that buffers incoming errors.
#include <linux/errqueue.h>
struct sock_extended_err { __u32 ee_errno; /* standard errno */ __u8 ee_origin; /* see below */ __u8 ee_type; /* ICMP type, code */ __u8 ee_code; __u8 ee_pad; __u32 ee_info; /* contains info like the path mtu */ __u32 ee_data; };
#define SO_EE_ORIGIN_NONE 0 #define SO_EE_ORIGIN_LOCAL 1 #define SO_EE_ORIGIN_ICMP 2 #define SO_EE_ORIGIN_ICMP6 3
#define SO_EE_OFFENDER(ee) ((struct sockaddr*)((ee)+1))
int on = 1; setsockopt(sk, SOL_IP, IP_RECVERR, &on, sizeof on);
err = sendmsg(sk, ..., 0); if (err < 0) { char buf[128]; struct sockaddr_in orig_dst; struct msghdr msgh = {0};
/* OK, process errors */ msgh.msg_control = buf; msgh.msg_controllen = sizeof buf; msgh.msg_name = (struct sockaddr *) &orig_dst; msgh.msg_namelen = sizeof orig_dst; for (;;) { struct cmsghdr *cmsg;
err = recvmsg(sk, &msgh, MSG_ERRQUEUE); if (err < 0) { if (errno == EAGAIN) break; else continue; } for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { struct sock_extended_err *err; err = CMSG_DATA(cmsg);
/* *err contains lots of information now */ switch (err->ee_origin) { case SO_EE_ORIGIN_LOCAL: /* local error */ case SO_EE_ORIGIN_ICMP: /* remote error */ } } } /* orig_dst contains the original destination of the packet that caused the error */ /* If an iov would have been initialised in msgh it would contain the data of the original packet as much as known */ } }
-Andi
}
> > Ciao, ET. > > > Don't try to handle something you don't know how to handle.
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |