jdk/src/java.base/windows/native/libnet/SocketOutputStream.c
author chegar
Sun, 17 Aug 2014 15:54:13 +0100
changeset 25859 3317bb8137f4
parent 5506 jdk/src/windows/native/java/net/SocketOutputStream.c@202f599c92aa
child 41771 18c9669e76ca
permissions -rw-r--r--
8054834: Modular Source Code Reviewed-by: alanb, chegar, ihse, mduigou Contributed-by: alan.bateman@oracle.com, alex.buckley@oracle.com, chris.hegarty@oracle.com, erik.joelsson@oracle.com, jonathan.gibbons@oracle.com, karen.kinnear@oracle.com, magnus.ihse.bursie@oracle.com, mandy.chung@oracle.com, mark.reinhold@oracle.com, paul.sandoz@oracle.com
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1247
diff changeset
     2
 * Copyright (c) 1997, 2008, 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
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
#include <windows.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
#include <winsock2.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
#include <ctype.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
#include <stdio.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
#include <stdlib.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
#include <malloc.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
#include <sys/types.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
#include "java_net_SocketOutputStream.h"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
#include "net_util.h"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
#include "jni_util.h"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
/************************************************************************
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
 * SocketOutputStream
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
static jfieldID IO_fd_fdID;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
 * Class:     java_net_SocketOutputStream
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
 * Method:    init
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 * Signature: ()V
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
JNIEXPORT void JNICALL
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
Java_java_net_SocketOutputStream_init(JNIEnv *env, jclass cls) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
    IO_fd_fdID = NET_GetFileDescriptorID(env);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
 * Class:     java_net_SocketOutputStream
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
 * Method:    socketWrite
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
 * Signature: (Ljava/io/FileDescriptor;[BII)V
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
JNIEXPORT void JNICALL
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
                                              jobject fdObj, jbyteArray data,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
                                              jint off, jint len) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    char *bufP;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
    char BUF[MAX_BUFFER_LEN];
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
    int buflen;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
    int fd;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
    if (IS_NULL(fdObj)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
        return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
    } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
        fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
    if (IS_NULL(data)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
        JNU_ThrowNullPointerException(env, "data argument");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
        return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
     * Use stack allocate buffer if possible. For large sizes we allocate
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
     * an intermediate buffer from the heap (up to a maximum). If heap is
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
     * unavailable just use our stack buffer.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
    if (len <= MAX_BUFFER_LEN) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
        bufP = BUF;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
        buflen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
    } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
        buflen = min(MAX_HEAP_BUFFER_LEN, len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
        bufP = (char *)malloc((size_t)buflen);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
        if (bufP == NULL) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
            bufP = BUF;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
            buflen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
    while(len > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
        int loff = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
        int chunkLen = min(buflen, len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
        int llen = chunkLen;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
        int retry = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
        (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
        while(llen > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
            int n = send(fd, bufP + loff, llen, 0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
            if (n > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
                llen -= n;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
                loff += n;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
            /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
             * Due to a bug in Windows Sockets (observed on NT and Windows
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
             * 2000) it may be necessary to retry the send. The issue is that
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
             * on blocking sockets send/WSASend is supposed to block if there
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
             * is insufficient buffer space available. If there are a large
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
             * number of threads blocked on write due to congestion then it's
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
             * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
             * The workaround we use is to retry the send. If we have a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
             * large buffer to send (>2k) then we retry with a maximum of
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
             * 2k buffer. If we hit the issue with <=2k buffer then we backoff
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
             * for 1 second and retry again. We repeat this up to a reasonable
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
             * limit before bailing out and throwing an exception. In load
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
             * conditions we've observed that the send will succeed after 2-3
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
             * attempts but this depends on network buffers associated with
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
             * other sockets draining.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
            if (WSAGetLastError() == WSAENOBUFS) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
                if (llen > MAX_BUFFER_LEN) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
                    buflen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
                    chunkLen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
                    llen = MAX_BUFFER_LEN;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
                    continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
                if (retry >= 30) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
                        "No buffer space available - exhausted attempts to queue buffer");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
                    if (bufP != BUF) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
                        free(bufP);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
                    return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
                Sleep(1000);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
                retry++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
            /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
             * Send failed - can be caused by close or write error.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
            if (WSAGetLastError() == WSAENOTSOCK) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
                NET_ThrowCurrent(env, "socket write error");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
            if (bufP != BUF) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
                free(bufP);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
        len -= chunkLen;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
        off += chunkLen;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
    if (bufP != BUF) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
        free(bufP);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
}