1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
--- net.cc.orig Thu Mar 21 03:49:18 1996
+++ net.cc Sun Dec 3 19:04:01 2006
@@ -163,46 +163,49 @@
{
int cc = ::send(fd, (char*)buf, len, 0);
if (cc < 0) {
- switch (errno) {
+ /*
+ * Due to a bug in kern/uipc_socket.c, on several
+ * systems, datagram sockets incorrectly persist
+ * in an error state on receipt of any ICMP
+ * error. This causes unicast connection
+ * rendezvous problems, and worse, multicast
+ * transmission problems because several systems
+ * incorrectly send port unreachables for
+ * multicast destinations. Our work around
+ * is to call getsockopt(..., SO_ERROR, ...)
+ * which resets so->so_error.
+ *
+ * This bug originated at CSRG in Berkeley
+ * and was present in the BSD Reno networking
+ * code release. It has since been fixed
+ * in OSF-3.x. It is know to remain
+ * in 4.4BSD and AIX-4.1.3.
+ *
+ * A fix is to change the following lines from
+ * kern/uipc_socket.c:
+ *
+ * if (so_serror)
+ * snderr(so->so_error);
+ *
+ * to:
+ *
+ * if (so->so_error) {
+ * error = so->so_error;
+ * so->so_error = 0;
+ * splx(s);
+ * goto release;
+ * }
+ *
+ */
+ int err, savederrno;
+ socklen_t errlen = sizeof(err);
+
+ savederrno = errno;
+ getsockopt(fd, SOL_SOCKET, SO_ERROR, &err,
+ &errlen);
+ switch (savederrno) {
case ECONNREFUSED:
/* no one listening at some site - ignore */
-#if defined(__osf__) || defined(_AIX)
- /*
- * Due to a bug in kern/uipc_socket.c, on several
- * systems, datagram sockets incorrectly persist
- * in an error state on receipt of an ICMP
- * port-unreachable. This causes unicast connection
- * rendezvous problems, and worse, multicast
- * transmission problems because several systems
- * incorrectly send port unreachables for
- * multicast destinations. Our work around
- * is to simply close and reopen the socket
- * (by calling reset() below).
- *
- * This bug originated at CSRG in Berkeley
- * and was present in the BSD Reno networking
- * code release. It has since been fixed
- * in 4.4BSD and OSF-3.x. It is know to remain
- * in AIX-4.1.3.
- *
- * A fix is to change the following lines from
- * kern/uipc_socket.c:
- *
- * if (so_serror)
- * snderr(so->so_error);
- *
- * to:
- *
- * if (so->so_error) {
- * error = so->so_error;
- * so->so_error = 0;
- * splx(s);
- * goto release;
- * }
- *
- */
- reset();
-#endif
break;
case ENETUNREACH:
@@ -217,7 +220,7 @@
* icmp unreachable, so we should be able to
* send now.
*/
- (void)::send(ssock_, (char*)buf, len, 0);
+ (void)::send(fd, (char*)buf, len, 0);
break;
default:
@@ -264,12 +267,15 @@
}
int cc = ::sendmsg(ssock_, (msghdr*)&mh, 0);
if (cc < 0) {
- switch (errno) {
+ int err, savederrno;
+ socklen_t errlen = sizeof(err);
+
+ savederrno = errno;
+ getsockopt(ssock_, SOL_SOCKET, SO_ERROR, &err,
+ &errlen);
+ switch (savederrno) {
case ECONNREFUSED:
/* no one listening at some site - ignore */
-#if defined(__osf__) || defined(_AIX)
- reset();
-#endif
break;
case ENETUNREACH:
@@ -297,7 +303,7 @@
int Network::dorecv(u_char* buf, int len, u_int32_t& from, int fd)
{
sockaddr_in sfrom;
- int fromlen = sizeof(sfrom);
+ socklen_t fromlen = sizeof(sfrom);
int cc = ::recvfrom(fd, (char*)buf, len, 0,
(sockaddr*)&sfrom, &fromlen);
if (cc < 0) {
|