90 int chunkLen = min(buflen, len); |
90 int chunkLen = min(buflen, len); |
91 int llen = chunkLen; |
91 int llen = chunkLen; |
92 int retry = 0; |
92 int retry = 0; |
93 |
93 |
94 (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP); |
94 (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP); |
95 |
95 if ((*env)->ExceptionCheck(env)) { |
96 while(llen > 0) { |
96 break; |
97 int n = send(fd, bufP + loff, llen, 0); |
97 } else { |
98 if (n > 0) { |
98 while(llen > 0) { |
99 llen -= n; |
99 int n = send(fd, bufP + loff, llen, 0); |
100 loff += n; |
100 if (n > 0) { |
101 continue; |
101 llen -= n; |
102 } |
102 loff += n; |
103 |
|
104 /* |
|
105 * Due to a bug in Windows Sockets (observed on NT and Windows |
|
106 * 2000) it may be necessary to retry the send. The issue is that |
|
107 * on blocking sockets send/WSASend is supposed to block if there |
|
108 * is insufficient buffer space available. If there are a large |
|
109 * number of threads blocked on write due to congestion then it's |
|
110 * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS. |
|
111 * The workaround we use is to retry the send. If we have a |
|
112 * large buffer to send (>2k) then we retry with a maximum of |
|
113 * 2k buffer. If we hit the issue with <=2k buffer then we backoff |
|
114 * for 1 second and retry again. We repeat this up to a reasonable |
|
115 * limit before bailing out and throwing an exception. In load |
|
116 * conditions we've observed that the send will succeed after 2-3 |
|
117 * attempts but this depends on network buffers associated with |
|
118 * other sockets draining. |
|
119 */ |
|
120 if (WSAGetLastError() == WSAENOBUFS) { |
|
121 if (llen > MAX_BUFFER_LEN) { |
|
122 buflen = MAX_BUFFER_LEN; |
|
123 chunkLen = MAX_BUFFER_LEN; |
|
124 llen = MAX_BUFFER_LEN; |
|
125 continue; |
103 continue; |
126 } |
104 } |
127 if (retry >= 30) { |
105 |
128 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", |
106 /* |
129 "No buffer space available - exhausted attempts to queue buffer"); |
107 * Due to a bug in Windows Sockets (observed on NT and Windows |
130 if (bufP != BUF) { |
108 * 2000) it may be necessary to retry the send. The issue is that |
131 free(bufP); |
109 * on blocking sockets send/WSASend is supposed to block if there |
|
110 * is insufficient buffer space available. If there are a large |
|
111 * number of threads blocked on write due to congestion then it's |
|
112 * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS. |
|
113 * The workaround we use is to retry the send. If we have a |
|
114 * large buffer to send (>2k) then we retry with a maximum of |
|
115 * 2k buffer. If we hit the issue with <=2k buffer then we backoff |
|
116 * for 1 second and retry again. We repeat this up to a reasonable |
|
117 * limit before bailing out and throwing an exception. In load |
|
118 * conditions we've observed that the send will succeed after 2-3 |
|
119 * attempts but this depends on network buffers associated with |
|
120 * other sockets draining. |
|
121 */ |
|
122 if (WSAGetLastError() == WSAENOBUFS) { |
|
123 if (llen > MAX_BUFFER_LEN) { |
|
124 buflen = MAX_BUFFER_LEN; |
|
125 chunkLen = MAX_BUFFER_LEN; |
|
126 llen = MAX_BUFFER_LEN; |
|
127 continue; |
132 } |
128 } |
133 return; |
129 if (retry >= 30) { |
|
130 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", |
|
131 "No buffer space available - exhausted attempts to queue buffer"); |
|
132 if (bufP != BUF) { |
|
133 free(bufP); |
|
134 } |
|
135 return; |
|
136 } |
|
137 Sleep(1000); |
|
138 retry++; |
|
139 continue; |
134 } |
140 } |
135 Sleep(1000); |
141 |
136 retry++; |
142 /* |
137 continue; |
143 * Send failed - can be caused by close or write error. |
|
144 */ |
|
145 if (WSAGetLastError() == WSAENOTSOCK) { |
|
146 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); |
|
147 } else { |
|
148 NET_ThrowCurrent(env, "socket write error"); |
|
149 } |
|
150 if (bufP != BUF) { |
|
151 free(bufP); |
|
152 } |
|
153 return; |
138 } |
154 } |
139 |
155 len -= chunkLen; |
140 /* |
156 off += chunkLen; |
141 * Send failed - can be caused by close or write error. |
|
142 */ |
|
143 if (WSAGetLastError() == WSAENOTSOCK) { |
|
144 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); |
|
145 } else { |
|
146 NET_ThrowCurrent(env, "socket write error"); |
|
147 } |
|
148 if (bufP != BUF) { |
|
149 free(bufP); |
|
150 } |
|
151 return; |
|
152 } |
157 } |
153 len -= chunkLen; |
|
154 off += chunkLen; |
|
155 } |
158 } |
156 |
159 |
157 if (bufP != BUF) { |
160 if (bufP != BUF) { |
158 free(bufP); |
161 free(bufP); |
159 } |
162 } |