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; }
/** * 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; }
/** * 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); }