/*
 * @(#)SocketOutputStream.c	1.16 98/09/21
 *
 * Copyright 1997, 1998 by Sun Microsystems, Inc.,
 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
 * All rights reserved.
 * 
 * This software is the confidential and proprietary information
 * of Sun Microsystems, Inc. ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Sun.
 */

#include "jvm_utils.h"
#include "java_net_SocketOutputStream.h"

#define min(a, b)       ((a) < (b) ? (a) : (b))

/*
 * SocketOutputStream
 */

static jfieldID sos_fdID;

static jfieldID IO_fd_fdID;

/*
 * Class:     java_net_SocketOutputStream
 * Method:    init
 * Signature: ()V
 */
JNIEXPORT void JNICALL
Java_java_net_SocketOutputStream_init(JNIEnv *env, jclass cls) {

    sos_fdID = (*env)->GetFieldID(env, cls, "fd", "Ljava/io/FileDescriptor;");
    IO_fd_fdID = NET_GetFileDescriptorID(env);
}

/*
 * Class:     java_net_SocketOutputStream
 * Method:    socketWrite
 * Signature: ([BII)V
 */
JNIEXPORT void JNICALL
Java_java_net_SocketOutputStream_socketWrite(JNIEnv *env, jobject this, 
					     jbyteArray data,
					     jint off, jint len) {
    /*
     * We allocate a static buffer on the stack, copy successive
     * chunks of the buffer to be written into it, then write that. It
     * is believed that this is faster that doing a malloc and copy.  
     */
    char BUF[MAX_BUFFER_LEN];

    /* The fd field */
    jobject fdObj = (*env)->GetObjectField(env, this, sos_fdID);
    int fd;

    jint datalen;

    if (IS_NULL(fdObj)) {
	JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
	return;
    } else {
	fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
    }
    if (IS_NULL(data)) {
	JNU_ThrowNullPointerException(env, "data argument");
	return;
    }

    datalen = (*env)->GetArrayLength(env, data);

    if ((len < 0) || (off < 0) || (len + off > datalen)) {
        JNU_ThrowByName(env, "java/lang/ArrayIndexOutOfBoundsException", 0);
	return;
    }

    while(len > 0) {
	int loff = 0;
	int chunkLen = min(MAX_BUFFER_LEN, len);
	int llen = chunkLen;
	(*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)BUF);
      
	while(llen > 0) {
	    int n = JVM_Send(fd, BUF + loff, llen, 0);
	    if (n == JVM_IO_ERR) {
		JNU_ThrowByName(env, "java/io/IOException", strerror(errno));
		return;
	    }
	    if (n == JVM_IO_INTR) {
		JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
		return;
	    }
	    llen -= n;
	    loff += n;
	}
	len -= chunkLen;
	off += chunkLen;
    }
}




