jdk/src/java.base/windows/native/libnet/SocketOutputStream.c
changeset 43202 29180c8db039
parent 41771 18c9669e76ca
equal deleted inserted replaced
43201:b4c682966e2a 43202:29180c8db039
    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     }