jdk/src/java.base/windows/native/libnet/SocketOutputStream.c
author clanger
Thu, 27 Oct 2016 11:00:28 +0200
changeset 41771 18c9669e76ca
parent 25859 3317bb8137f4
child 43202 29180c8db039
permissions -rw-r--r--
8167481: cleanup of headers and includes for native libnet Reviewed-by: chegar
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
41771
18c9669e76ca 8167481: cleanup of headers and includes for native libnet
clanger
parents: 25859
diff changeset
     2
 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1247
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1247
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1247
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1247
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1247
diff changeset
    23
 * questions.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
41771
18c9669e76ca 8167481: cleanup of headers and includes for native libnet
clanger
parents: 25859
diff changeset
    25
#include <malloc.h>
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
41771
18c9669e76ca 8167481: cleanup of headers and includes for native libnet
clanger
parents: 25859
diff changeset
    27
#include "net_util.h"
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
#include "java_net_SocketOutputStream.h"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
/************************************************************************
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
 * SocketOutputStream
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
static jfieldID IO_fd_fdID;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
 * Class:     java_net_SocketOutputStream
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
 * Method:    init
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
 * Signature: ()V
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
JNIEXPORT void JNICALL
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
Java_java_net_SocketOutputStream_init(JNIEnv *env, jclass cls) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
    IO_fd_fdID = NET_GetFileDescriptorID(env);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 * Class:     java_net_SocketOutputStream
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 * Method:    socketWrite
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
 * Signature: (Ljava/io/FileDescriptor;[BII)V
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
JNIEXPORT void JNICALL
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
                                              jobject fdObj, jbyteArray data,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
                                              jint off, jint len) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
    char *bufP;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
    char BUF[MAX_BUFFER_LEN];
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
    int buflen;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
    int fd;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
    if (IS_NULL(fdObj)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
        return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
        fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
    if (IS_NULL(data)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
        JNU_ThrowNullPointerException(env, "data argument");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
        return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
     * Use stack allocate buffer if possible. For large sizes we allocate
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
     * an intermediate buffer from the heap (up to a maximum). If heap is
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
     * unavailable just use our stack buffer.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
    if (len <= MAX_BUFFER_LEN) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
        bufP = BUF;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
        buflen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
    } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
        buflen = min(MAX_HEAP_BUFFER_LEN, len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
        bufP = (char *)malloc((size_t)buflen);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
        if (bufP == NULL) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
            bufP = BUF;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
            buflen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
    while(len > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
        int loff = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
        int chunkLen = min(buflen, len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
        int llen = chunkLen;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
        int retry = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
        (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
        while(llen > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
            int n = send(fd, bufP + loff, llen, 0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
            if (n > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
                llen -= n;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
                loff += n;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
            /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
             * Due to a bug in Windows Sockets (observed on NT and Windows
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
             * 2000) it may be necessary to retry the send. The issue is that
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
             * on blocking sockets send/WSASend is supposed to block if there
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
             * is insufficient buffer space available. If there are a large
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
             * number of threads blocked on write due to congestion then it's
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
             * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
             * The workaround we use is to retry the send. If we have a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
             * large buffer to send (>2k) then we retry with a maximum of
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
             * 2k buffer. If we hit the issue with <=2k buffer then we backoff
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
             * for 1 second and retry again. We repeat this up to a reasonable
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
             * limit before bailing out and throwing an exception. In load
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
             * conditions we've observed that the send will succeed after 2-3
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
             * attempts but this depends on network buffers associated with
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
             * other sockets draining.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
            if (WSAGetLastError() == WSAENOBUFS) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
                if (llen > MAX_BUFFER_LEN) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
                    buflen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
                    chunkLen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
                    llen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
                    continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
                if (retry >= 30) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
                        "No buffer space available - exhausted attempts to queue buffer");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
                    if (bufP != BUF) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
                        free(bufP);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
                    return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
                Sleep(1000);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
                retry++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
            /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
             * Send failed - can be caused by close or write error.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
            if (WSAGetLastError() == WSAENOTSOCK) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
                NET_ThrowCurrent(env, "socket write error");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
            if (bufP != BUF) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
                free(bufP);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
        len -= chunkLen;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
        off += chunkLen;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
    if (bufP != BUF) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
        free(bufP);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
}