Exemplo n.º 1
0
/*
 * Class:     sun_nio_ch_sctp_SctpNet
 * Method:    getPrimAddrOption0
 * Signature: (II)Ljava/net/SocketAddress;
 */
JNIEXPORT jobject JNICALL Java_sun_nio_ch_sctp_SctpNet_getPrimAddrOption0
  (JNIEnv *env, jclass klass, jint fd, jint assocId) {
    struct sctp_setprim prim;
    unsigned int prim_len = sizeof(prim);
    struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr;

    prim.ssp_assoc_id = assocId;

    if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.SctpNet.getPrimAddrOption0");
        return NULL;
    }

    return SockAddrToInetSocketAddress(env, sap);
}
void handlePeerAddrChange
  (JNIEnv* env, jobject resultContainerObj, struct sctp_paddr_change* spc) {
    int event = 0;
    jobject addressObj, resultObj;
    unsigned int state = spc->spc_state;

    switch (state) {
        case SCTP_ADDR_AVAILABLE :
            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_AVAILABLE;
            break;
        case SCTP_ADDR_UNREACHABLE :
            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_UNREACHABLE;
            break;
        case SCTP_ADDR_REMOVED :
            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_REMOVED;
            break;
        case SCTP_ADDR_ADDED :
            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_ADDED;
            break;
        case SCTP_ADDR_MADE_PRIM :
            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_MADE_PRIM;
#ifndef __solaris__  /* Solaris currently doesn't support SCTP_ADDR_CONFIRMED */
            break;
        case SCTP_ADDR_CONFIRMED :
            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_CONFIRMED;
#endif  /* __solaris__ */
    }

    addressObj = SockAddrToInetSocketAddress(env, (struct sockaddr*)&spc->spc_aaddr);

    /* create SctpPeerAddressChanged */
    resultObj = (*env)->NewObject(env, spc_class, spc_ctrID, spc->spc_assoc_id,
            addressObj, event);
    CHECK_NULL(resultObj);
    (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
    (*env)->SetIntField(env, resultContainerObj, src_typeID,
            sun_nio_ch_SctpResultContainer_PEER_ADDRESS_CHANGED);
}
void handleMessage
  (JNIEnv* env, jobject resultContainerObj, struct msghdr* msg,int read,
   jboolean isEOR, struct sockaddr* sap) {
    jobject isa, resultObj;
    struct controlData cdata[1];

    if (read == 0) {
        /* we reached EOF */
        read = -1;
    }

    isa = SockAddrToInetSocketAddress(env, sap);
    getControlData(msg, cdata);

    /* create SctpMessageInfoImpl */
    resultObj = (*env)->NewObject(env, smi_class, smi_ctrID, cdata->assocId,
                                  isa, read, cdata->streamNumber,
                                  isEOR ? JNI_TRUE : JNI_FALSE,
                                  cdata->unordered, cdata->ppid);
    CHECK_NULL(resultObj);
    (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
    (*env)->SetIntField(env, resultContainerObj, src_typeID,
                        sun_nio_ch_SctpResultContainer_MESSAGE);
}
// TODO: test: can create send failed without any data? if so need to
// update API so that buffer can be null if no data.
void handleSendFailed
  (JNIEnv* env, int fd, jobject resultContainerObj, struct sctp_send_failed *ssf,
   int read, jboolean isEOR, struct sockaddr* sap) {
    jobject bufferObj = NULL, resultObj, isaObj;
    char *addressP;
    struct sctp_sndrcvinfo *sri;
    int remaining, dataLength;

    /* the actual undelivered message data is directly after the ssf */
    int dataOffset = sizeof(struct sctp_send_failed);

    sri = (struct sctp_sndrcvinfo*) &ssf->ssf_info;

    /* the number of bytes remaining to be read in the sctp_send_failed notif*/
    remaining = ssf->ssf_length - read;

    /* the size of the actual undelivered message */
    dataLength = ssf->ssf_length - dataOffset;

    /* retrieved address from sockaddr */
    isaObj = SockAddrToInetSocketAddress(env, sap);

    /* data retrieved from sff_data */
    if (dataLength > 0) {
        struct iovec iov[1];
        struct msghdr msg[1];
        int rv, alreadyRead;
        char *dataP = (char*) ssf;
        dataP += dataOffset;

        if ((addressP = malloc(dataLength)) == NULL) {
            JNU_ThrowOutOfMemoryError(env, "handleSendFailed");
            return;
        }

        memset(msg, 0, sizeof (*msg));
        msg->msg_iov = iov;
        msg->msg_iovlen = 1;

        bufferObj = (*env)->NewDirectByteBuffer(env, addressP, dataLength);
        CHECK_NULL(bufferObj);

        alreadyRead = read - dataOffset;
        if (alreadyRead > 0) {
            memcpy(addressP, /*ssf->ssf_data*/ dataP, alreadyRead);
            iov->iov_base = addressP + alreadyRead;
            iov->iov_len = dataLength - alreadyRead;
        } else {
            iov->iov_base = addressP;
            iov->iov_len = dataLength;
        }

        if (remaining > 0) {
            if ((rv = recvmsg(fd, msg, 0)) < 0) {
                handleSocketError(env, errno);
                return;
            }

            if (rv != (dataLength - alreadyRead) || !(msg->msg_flags & MSG_EOR)) {
                //TODO: assert false: "should not reach here";
                return;
            }
            // TODO: Set and document (in API) buffers position.
        }
    }

    /* create SctpSendFailed */
    resultObj = (*env)->NewObject(env, ssf_class, ssf_ctrID, ssf->ssf_assoc_id,
            isaObj, bufferObj, ssf->ssf_error, sri->sinfo_stream);
    CHECK_NULL(resultObj);
    (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
    (*env)->SetIntField(env, resultContainerObj, src_typeID,
            sun_nio_ch_SctpResultContainer_SEND_FAILED);
}