示例#1
0
static WMA_STATUS jsr205_datagram_write(WMA_PROTOCOLS protocol, jint outPort, void* handle, char *toAddr,
    char* fromAddr, jint length, char* buf, jint *bytesWritten, jsr120_udp_emulator_context *context) {

    /** The maximum amount of data allowed within a network packet. */
    jint PACKET_MAX_SIZE = MAX_DATAGRAM_LENGTH - 10;  /* 3 shorts + 1 int */

    /** The socket descriptor that corresponds to the handle. */
    jint socket_fd;

    /** The total number of datagram packets to be sent. */
    jshort totalPackets;

    /** The pointer to buffer for all datagram data. */
    char *dgramBuffer = NULL;

    /** Number of bytes written for given packet. */
    int packetBytesWritten = 0;

    /** Return status. */
    WMA_STATUS status = WMA_NET_IOERROR;

    /** Status of low level operation. */
    int pcsl_status;

    /** The length of the IP address to be retrieved. */
    int plen = 0;

    /** The writing index into the datagram buffer. */
    jint index = 0;

    /*
     * The "to" and "from" addresses are not used in this implementation. In a
     * more sophisticated implementation that may involve more than one
     * recipient, the packets that get broadcast would need to be directed to
     * specific phones. The "to" address would then come into play and would
     * need to be for each specific phone in a phone list.
     */
    (void)toAddr;
    (void)fromAddr;

    /* Pick up the socket descriptor that corresponds to the handle. */
    socket_fd = wmaGetRawSocketFD(handle);

    switch (context->state) {
    case JSR120_UDP_EMULATOR_CONTEXT_STATE_INIT:
        /* First invocation. */
        *bytesWritten = 0;

        context->p = buf;

        context->remaining_length = length;

        /* Resolve host name as a first step. */
        pcsl_status = pcsl_network_gethostbyname_start(
            targetHost, context->ipAddr, sizeof(context->ipAddr), &plen,
            &context->pcsl_handle, &context->pcsl_context);
        switch (pcsl_status) {
        case PCSL_NET_SUCCESS:
            context->state = JSR120_UDP_EMULATOR_CONTEXT_STATE_GETHOSTBYNAME_DONE;
            status = WMA_NET_SUCCESS;
            break;
        case PCSL_NET_WOULDBLOCK:
            context->state = JSR120_UDP_EMULATOR_CONTEXT_STATE_GETHOSTBYNAME_INPROGRESS;
            /* temporarily create entry in emulator-managed sockets list */
            context->emulatorSocket =
                wmaCreateSocketHandle(protocol,
                                      (int)context->pcsl_handle);
            status = WMA_NET_WOULDBLOCK;
            break;
        case PCSL_NET_INTERRUPTED:
            status = WMA_NET_INTERRUPTED;
            break;
        default:
            status = WMA_NET_IOERROR;
        }
        break;

    case JSR120_UDP_EMULATOR_CONTEXT_STATE_GETHOSTBYNAME_INPROGRESS:
        /* Reinvocation after gethostbyname WOULDBLOCK. */
        pcsl_status = pcsl_network_gethostbyname_finish(
            context->ipAddr, sizeof(context->ipAddr), &plen,
            context->pcsl_handle, context->pcsl_context);

        if (pcsl_status != PCSL_NET_WOULDBLOCK)
            wmaDestroySocketHandle(context->emulatorSocket);

        switch (pcsl_status) {
        case PCSL_NET_SUCCESS:
            context->state = JSR120_UDP_EMULATOR_CONTEXT_STATE_GETHOSTBYNAME_DONE;
            status = WMA_NET_SUCCESS;
            break;
        case PCSL_NET_WOULDBLOCK:
            /* still cannot get host name. */
            status = WMA_NET_WOULDBLOCK;
            break;
        case PCSL_NET_INTERRUPTED:
            status = WMA_NET_INTERRUPTED;
            break;
        default:
            status = WMA_NET_IOERROR;
        }
        break;

    default:
        /* Continue with sendto operation. */
        status = WMA_NET_SUCCESS;
        break;
    }


    if (status == WMA_NET_SUCCESS) {
        /*
         * We must be in JSR120_UDP_EMULATOR_CONTEXT_STATE_SENDTO state if we
         * managed to get here. So start/continue sending data
         */

        /* Compute the total number of datagrams required to send the message. */
        totalPackets =
            (short)((length + PACKET_MAX_SIZE - 1) / PACKET_MAX_SIZE);
    
        dgramBuffer = context->buffer;

        if (context->state == JSR120_UDP_EMULATOR_CONTEXT_STATE_SENDTO_INPROGRESS) {
            /*
             * There were sendto operation resulted in WOULDBLOCK, need to finish it
             * Appropriate data is saved in context
             */
            pcsl_status = pcsl_datagram_write_finish(
                (void*)socket_fd, context->ipAddr, outPort,
                dgramBuffer, sizeof(dgramBuffer),
                &packetBytesWritten, &context->pcsl_context);

        } else {
            pcsl_status = PCSL_NET_SUCCESS;
        }

        /*
         * Perform next and possibly all the rest of writing operations
         *  till WOULDBLOCK or error is returned from network layer
         */
        while (pcsl_status == PCSL_NET_SUCCESS) {

            if (++context->packetNumber > totalPackets)
                break;

            if (context->state == JSR120_UDP_EMULATOR_CONTEXT_STATE_SENDTO_INPROGRESS ||
                context->state == JSR120_UDP_EMULATOR_CONTEXT_STATE_SENDTO_DONE ||
                context->state == JSR120_UDP_EMULATOR_CONTEXT_STATE_GETHOSTBYNAME_DONE) {
            
                *bytesWritten += packetBytesWritten;

                /* Move the pointer past the bytes just sent */
                context->p += context->count;
                context->remaining_length -= context->count;
            }

            /* Prepare next packet and start writing it */

            /** Reset the writing index into the datagram buffer. */
            index = 0;

            /* Initialize the datagram buffer. */
            memset(dgramBuffer, 0, MAX_DATAGRAM_LENGTH);

            /* Compute the number of bytes that can be stuffed into
             * this packet. 
             */
            context->count = context->remaining_length;
            if (context->count > PACKET_MAX_SIZE) {
                context->count = PACKET_MAX_SIZE;
            }

            /* Build the buffer to be written */
            wma_put_short(dgramBuffer, &index, context->packetNumber);
            wma_put_short(dgramBuffer, &index, totalPackets);
            /* Needed for: count < PACKET_MAX_SIZE */
            wma_put_short(dgramBuffer, &index, context->count);
            /* Total length of message. */
            wma_put_int(dgramBuffer, &index, context->remaining_length);
            /* Writes count bytes, starting at p. */
            wma_put_bytes(dgramBuffer, &index, context->p, context->count);

            pcsl_status = pcsl_datagram_write_start(
                (void*)socket_fd, context->ipAddr, outPort, dgramBuffer, MAX_DATAGRAM_LENGTH,
                &packetBytesWritten, &context->pcsl_context);

            context->state = pcsl_status != PCSL_NET_WOULDBLOCK ?
                JSR120_UDP_EMULATOR_CONTEXT_STATE_SENDTO_DONE :
                JSR120_UDP_EMULATOR_CONTEXT_STATE_SENDTO_INPROGRESS;
        }
        
        switch (pcsl_status) {
        case PCSL_NET_SUCCESS:
            /* We are done */
            status = WMA_NET_SUCCESS;
            break;
        case PCSL_NET_WOULDBLOCK:
            /* cannot send right now */
            status = WMA_NET_WOULDBLOCK;
            break;
        case PCSL_NET_INTERRUPTED:
            status = WMA_NET_INTERRUPTED;
            break;
        default:
            status = WMA_NET_IOERROR;
        }
    }

    return status;
}
示例#2
0
/**
 * Write an SMS datagram.
 */
WMA_STATUS jsr120_sms_write(jchar msgType,
                               unsigned char address[],
                               unsigned char msgBuffer[],
                               jchar msgLen,
                               jchar sourcePort,
                               jchar destPort,
                               jint *bytesWritten,
                               void **pContext) {
  
    /* Contains context of current operation including
     * the buffer that will contain all data to be written. */
    jsr120_udp_emulator_context *context = NULL;

    /** The writing index. */
    jint index = 0;

    /** Return status */
    WMA_STATUS status = WMA_NET_SUCCESS;

    /** Internal sms phone number property. */
    const char *phNum = NULL;

    /** Physical port to be used to send SMS */
    jint sendPort = smsOutPortNumber; 

    /** Time related structs, variable */
    /* Need revisit: add time code to fetch time */
    jlong timestamp = 0;

    (void)sourcePort;

    if (*pContext == NULL) {
        /* Allocate and initialize datagram buffer */
        context = (jsr120_udp_emulator_context*)pcsl_mem_malloc(sizeof(*context));

        if (context == NULL) {
            return WMA_NET_IOERROR;
        }

        memset(context, 0, sizeof(*context));

        /* Get phone number */
        load_var_char_env_prop((char**)&phNum, "JSR_120_PHONE_NUMBER",
            "com.sun.midp.io.j2me.sms.PhoneNumber");

        if (phNum == NULL) {
            /* Free resources and quit */
            pcsl_mem_free(context);
            /* Cannot determine device's phone number. Fatal error. */
            return WMA_NET_IOERROR;
        }

        *pContext = context;

        /* Check if SMS is being sent to yourself */
        if (strcmp(phNum, (char *)address) == 0) {
            /*
             * Sending SMS to yourself, swicth port to the one you're 
             * listening on.
             */
            sendPort = smsInPortNumber;
        }

        /* Populate the datagram buffer */
        wma_put_int(context->buffer, &index, (int)msgType);
        wma_put_int(context->buffer, &index, (int)destPort);
        wma_put_long_long(context->buffer, &index, timestamp);
        wma_put_string(context->buffer, &index, (char *)address);
        wma_put_string(context->buffer, &index, (char *)phNum);
        wma_put_int(context->buffer, &index, (int)msgLen);
        if (msgLen > 0) {
            wma_put_bytes(context->buffer, &index, (char *)msgBuffer, msgLen);
        }

#if ENABLE_WMA_LOOPBACK
        {
            /*
             * This code is enabled mainly for unit tests
             * that want to test send/receive without the
             * network, i.e. message to be sent is put back
             * into the message pool and received by the sender.
             */
            SmsMessage *sms = (SmsMessage *)pcsl_mem_malloc(sizeof(SmsMessage));

            (void)bytesWritten;

            if (sms != NULL) {
                memset(sms, 0, sizeof(SmsMessage));

                sms->encodingType = msgType;
                sms->destPortNum = (unsigned short)destPort;
                sms->timeStamp = timestamp;
                sms->msgAddr = pcsl_mem_strdup((char *)phNum);
                sms->msgLen = msgLen;
                if (msgLen > 0) {
                    jint i;
                    char *msg = (char*)pcsl_mem_malloc(msgLen + 1);
                    for (i = 0; i < msgLen; i++) {
                        msg[i] = msgBuffer[i];
                    }
                    msg[i] = '\0';
                    sms->msgBuffer = msg;
                }
                /* add message to pool */
                jsr120_sms_pool_add_msg(sms);
                /* Notify all listeners of the new message. */
                jsr120_sms_message_arrival_notifier(sms);

                status = WMA_NET_SUCCESS;
            } else {
                status = WMA_NET_IOERROR;
            }

        }
#else
        {
            /** The status of networking operation. */
            int pcsl_status = PCSL_NET_SUCCESS;

            /** The length of the IP address to be retrieved. */
            int plen;

            pcsl_status = pcsl_network_gethostbyname_start(
                targetHost, context->ipAddr, sizeof(context->ipAddr), &plen,
                &context->pcsl_handle, &context->pcsl_context);

            switch (pcsl_status) {
            case PCSL_NET_SUCCESS:
                context->state = JSR120_UDP_EMULATOR_CONTEXT_STATE_GETHOSTBYNAME_DONE;
                status = WMA_NET_SUCCESS;
                break;
            case PCSL_NET_WOULDBLOCK:
                context->state = JSR120_UDP_EMULATOR_CONTEXT_STATE_GETHOSTBYNAME_INPROGRESS;
                /* temporarily create entry in emulator-managed sockets list */
                context->emulatorSocket =
                    wmaCreateSocketHandle(WMA_SMS_PROTOCOL,
                                          (int)context->pcsl_handle);
                status = WMA_NET_WOULDBLOCK;
                break;
            case PCSL_NET_INTERRUPTED:
                status = WMA_NET_INTERRUPTED;
                break;
            default:
                status = WMA_NET_IOERROR;
            }
        }
#endif
    }

#if ENABLE_WMA_LOOPBACK == 0
    {
        /** The status of networking operation. */
        int pcsl_status = PCSL_NET_SUCCESS;

        /** The length of the IP address to be retrieved. */
        int plen;

        if (status == WMA_NET_SUCCESS && *pContext != NULL) {
            /* handle reinvocation or continuation. RFC: is it needed for loopback mode?  */
            context = (jsr120_udp_emulator_context*)*pContext;

            switch (context->state) {
            case JSR120_UDP_EMULATOR_CONTEXT_STATE_INIT:
                /* Cannot have these states. */
                break;

            case JSR120_UDP_EMULATOR_CONTEXT_STATE_GETHOSTBYNAME_INPROGRESS:
                /* finish gethostbyname operation */

                pcsl_status = pcsl_network_gethostbyname_finish(
                    context->ipAddr, sizeof(context->ipAddr), &plen,
                    context->pcsl_handle, context->pcsl_context);

                if (pcsl_status != PCSL_NET_WOULDBLOCK)
                    wmaDestroySocketHandle(context->emulatorSocket);

                switch (pcsl_status) {
                case PCSL_NET_SUCCESS:
                    status = WMA_NET_SUCCESS;
                    break;
                case PCSL_NET_WOULDBLOCK:
                    /* still cannot get host name. */
                    status = WMA_NET_WOULDBLOCK;
                    break;
                case PCSL_NET_INTERRUPTED:
                    status = WMA_NET_INTERRUPTED;
                    break;
                default:
                    status = WMA_NET_IOERROR;
                }

                if (status != WMA_NET_SUCCESS)
                    break;
                /* Intentional fallthrough to continue with sendto. */
            case JSR120_UDP_EMULATOR_CONTEXT_STATE_GETHOSTBYNAME_DONE:
                context->state = JSR120_UDP_EMULATOR_CONTEXT_STATE_SENDTO_INPROGRESS;
                pcsl_status = pcsl_datagram_write_start(
                    (void*)wmaGetRawSocketFD(smsHandle), context->ipAddr, sendPort,
                    context->buffer, sizeof(context->buffer),
                    bytesWritten, &context->pcsl_context);

                switch (pcsl_status) {
                case PCSL_NET_SUCCESS:
                    /* finish */
                    status = WMA_NET_SUCCESS;
                    break;
                case PCSL_NET_WOULDBLOCK:
                    status = WMA_NET_WOULDBLOCK;
                    break;
                case PCSL_NET_INTERRUPTED:
                    status = WMA_NET_INTERRUPTED;
                    break;
                default:
                    status = WMA_NET_IOERROR;
                }
                break;

            case JSR120_UDP_EMULATOR_CONTEXT_STATE_SENDTO_INPROGRESS:
                pcsl_status = pcsl_datagram_write_finish(
                    (void*)wmaGetRawSocketFD(smsHandle), context->ipAddr, sendPort,
                    context->buffer, sizeof(context->buffer),
                    bytesWritten, &context->pcsl_context);

                switch (pcsl_status) {
                case PCSL_NET_SUCCESS:
                    /* finish */
                    status = WMA_NET_SUCCESS;
                    break;
                case PCSL_NET_WOULDBLOCK:
                    /* still cannot send */
                    status = WMA_NET_WOULDBLOCK;
                    break;
                case PCSL_NET_INTERRUPTED:
                    status = WMA_NET_INTERRUPTED;
                    break;
                default:
                    status = WMA_NET_IOERROR;
                }
                break;

            default:
                status = WMA_NET_IOERROR;
            }
        }
    }
#endif
    if (status != WMA_NET_WOULDBLOCK) {
        /* Message was sent, so free the buffer. */
        pcsl_mem_free(context);
        *pContext = NULL;
    }
    
    return status;
}
示例#3
0
/**
 * Sends a datagram.
 * <p>
 * Java declaration:
 * <pre>
 *     send0(II[BII)I
 * </pre>
 *
 * @param ipNumber raw IPv4 address of the remote host
 * @param port UDP port of the remote host
 * @param buf the data buffer to send
 * @param off the offset into the data buffer
 * @param len the length of the data in the buffer
 * @return number of bytes sent
 */
KNIEXPORT KNI_RETURNTYPE_INT
Java_com_sun_midp_io_j2me_datagram_Protocol_send0(void) {
    int ipAddress;
    int port;
    int offset;
    int length;
    int bytesSent = 0;
    void *socketHandle;
    MidpReentryData* info;
    unsigned char ipBytes[MAX_ADDR_LENGTH];

    KNI_StartHandles(2);

    KNI_DeclareHandle(bufferObject);
    KNI_DeclareHandle(thisObject);
    KNI_GetThisPointer(thisObject);

    ipAddress = (int)KNI_GetParameterAsInt(1);
    port      = (int)KNI_GetParameterAsInt(2);
    KNI_GetParameterAsObject(3, bufferObject);
    offset    = (int)KNI_GetParameterAsInt(4);
    length    = (int)KNI_GetParameterAsInt(5);

    socketHandle =
        (void *)getMidpDatagramProtocolPtr(thisObject)->nativeHandle;

    REPORT_INFO5(LC_PROTOCOL,
        "datagram::send0 off=%d len=%d port=%d ip=0x%x handle=0x%x",
        offset, length, port, ipAddress, (int)socketHandle);

    /* Convert ipAddress(integer) to ipBytes */
    memcpy(ipBytes, &ipAddress, sizeof(ipBytes));

    info = (MidpReentryData*)SNI_GetReentryData(NULL);

    if (socketHandle != INVALID_HANDLE) {
        int status;
        void *context;

        if (info == NULL) {
            /* initial invocation */
            INC_NETWORK_INDICATOR;
            SNI_BEGIN_RAW_POINTERS;
            status = pcsl_datagram_write_start(
                socketHandle, ipBytes, port,
                (char*)&(JavaByteArray(bufferObject)[offset]),
                length, &bytesSent, &context);
            SNI_END_RAW_POINTERS;
        } else {
            /* reinvocation */
            if ((void *)info->descriptor != socketHandle) {
                REPORT_CRIT2(LC_PROTOCOL,
                    "datagram::send0 handle mismatch 0x%x != 0x%x\n",
                        socketHandle, info->descriptor);
            }
	    context = info->pResult;
            SNI_BEGIN_RAW_POINTERS;
	    status = pcsl_datagram_write_finish(
                socketHandle, ipBytes, port,
                (char*)&(JavaByteArray(bufferObject)[offset]),
                length, &bytesSent, context);
            SNI_END_RAW_POINTERS;
        }

        if (status == PCSL_NET_SUCCESS) {
            DEC_NETWORK_INDICATOR;
        } else if (status == PCSL_NET_WOULDBLOCK) {
            midp_thread_wait(NETWORK_WRITE_SIGNAL, (int)socketHandle, context);
        } else if (status == PCSL_NET_INTERRUPTED) {
            KNI_ThrowNew(midpInterruptedIOException, NULL);
            DEC_NETWORK_INDICATOR;
        } else {
            /* status == PCSL_NET_IOERROR */
            midp_snprintf(gKNIBuffer, KNI_BUFFER_SIZE,
                "error code %d", pcsl_network_error(socketHandle));
            KNI_ThrowNew(midpIOException, gKNIBuffer);
            DEC_NETWORK_INDICATOR;
        }

    } else {
        if (info == NULL) {
            /* initial invocation */
            KNI_ThrowNew(midpIOException, "socket closed");
        } else {
            /* reinvocation */
            KNI_ThrowNew(midpInterruptedIOException, NULL);
            DEC_NETWORK_INDICATOR;
        }
    }

    KNI_EndHandles();
    KNI_ReturnInt((jint)bytesSent);
}