http://www.developer.com/ws/brew/article.php/3620351/New-Network-Interfaces-in-QUALCOMM-BREW.htm
QUALCOMM BREW has had support for TCP/IP sockets since its inception with the INetMgr and ISocket interfaces. Providing an asynchronous interface similar in use to the Berkeley Socket API, these interfaces (along with the IWeb interface for HTTP support) are the staple of networked applications on BREW handsets today. But, times are changing. With the release of BREW 3.1.3, QUALCOMM has introduced the ISockPort interface. With support for both IPv4 and IPv6, and an extensible mechanism for selecting both the protocol and the bearer network, the ISockPort interface is the one to use in future applications. In this article, I show how to use the ISockPort interface to create a simple TCP client application using ISockPort, and direct your attention to some of the new features of the ISockPort interface. Although INetMgr is a factory for ISocket interfaces, you create ISockPort instances directly from IShell like any other interface: This operation requires privilege, however. Be sure you have asserted network privileges in your Module Information File, or ISHELL_CreateInstance will return EPRIVLEVEL. Once the instance is created, you must connect it to the remote server. This involves specifying the address and making the connection; you may also want to select the network. Specifying the address is easy. Use the AEESockAddrStorage data structure: The first line indicates the protocol family you'd like to use; the other options include INET_AF_LOCAL for the local domain and INET_AF_INET6 for IPv6. A common mistake when using the network stack on any platform is to map addresses and other information to network byte order; I do this using the HTONS macro when setting the destination address port on the next line. Finally, I convert the address string "10.0.1.127" to the network address in network byte order by using the macro INET_PTON, which converts the address string for the indicated network and address. If you don't have the IP address of the server—the usual case, because it's best to keep host names, not IP addresses, as part of application configuration—simply use INETMGR_GetHostByName to obtain the IP address for a specific hostname. Another thing new to BREW 3.1.3 is the ability to pick the bearer network. Most of the time, you will want to let the handset pick the default bearer network (such as CDMA or UMTS). Occasionally, however, you might want to force the application to use a specific network (such as MediaFLO). To do this, invoke ISOCKPORT_SelectNetwork before connecting or binding the socket. For example, would select the WLAN network available to a WLAN-enabled handset for the specific socket. Finally, it's time to connect the socket. First, you open the socket: And then, you attempt to connect the socket. You must do this asynchronously in case the network stack is busy: This code: What if you want to listen on a socket instead of connect to a remote server? The flow is similar, but instead of invoking ISOCKPORT_Connect, first invoke ISOCKPORT_Bind to bind the socket to a destination address, and then invoke ISOCKPORT_Listen. These methods should be used asynchronously in the same manner as ISOCKPORT_Connect is. Also, be aware that many operators run networks using Network Address Translation, so there may be no way for nodes off the operator network to connect to your server. Consequently, a better strategy is to use SMS wakeup to instruct the handset to connect to a remote server. Reading and writing are essentially the same as using an ISocket instance: attempt to read or write, and if an error occurs, determine whether the error is an indication that the operation would block and a callback should be scheduled, or a bona fide error that needs to be handled. For example, to attempt writing: This code attempts to write the contents of pMe->abyWrite in chunks, handling the result values in one of four ways: Reading data is similar/ However, you likely have additional application-specific logic you need to put into place to determine when you've read enough data to process a message. Closing the socket is easy. Simply cancel any callbacks associated with the socket and release it, like this: You also could first invoke ISOCKPORT_Shutdown or ISOCKPORT_Close to shut a TCP connection gracefully. Using the new ISockPort interface is easy if you remember the following key points: Ray Rischpater is the chief architect at Rocket Mobile, Inc., specializing in the design and development of messaging and information access applications for today's wireless devices. Ray Rischpater is the author of several books on software development, including eBay Application Development and Software Development for the QUALCOMM BREW Platform, both available from Apress, and is an active amateur radio operator. Contact Ray at ^212ISockPort213^@lothlorien.com.
New Network Interfaces in QUALCOMM BREW
July 17, 2006
Creating an ISockPort Instance
result = ISHELL_CreateInstance( pMe->a.m_pIShell, AEECLSID_SOCKPORT,
(void **)&pMe->pISockPort );
Configuring & Opening an ISockPort Instance
#define SERVER_PORT 80
#define SERVER_ADDR "10.0.1.127"
pMe->sa.wFamily = AEE_AF_INET;
pMe->sa.inet.port = HTONS( SERVER_PORT );
INET_PTON( pMe->wFamily, SERVER_ADDR, &pMe->sa.inet.addr
);
Note: Like other network operations, INETMGR_GetHostByName is asynchronous. You must provide a callback that the system invokes with the result of your DNS query.
ISOCKPORT_SelectNetwork( pMe->pISockPort, AEE_NETWORK_WLAN )
pMe->wSockType = AEE_SOCKPORT_STREAM;
ISOCKPORT_OpenEx( pMe->pISockPort, pMe->sa.wFamily,
pMe-> pMe->wSockType, 0 );
static void TryConnect( CApp *pMe )
{
int result = ISOCKPORT_Connect( pMe->pISockPort, &pMe->sa );
switch( result )
{
case AEEPORT_WAIT:
ISOCKPORT_WritableEx( pMe->pISockPort, &pMe->cbWritable,
(PFNNOTIFY)TryConnect, pMe );
break;
case SUCCESS:
ISHELL_PostEvent( pMe->a.m_pIShell, pMe->a.clsID,
EVT_SOCKETCONNECT, 0, 0 );
break;
default:
ISHELL_PostEvent( pMe->a.m_pIShell, pMe->a.clsID,
EVT_SOCKETERROR,
ISOCKPORT_GetLastError(
pMe->pISockPort), 0 );
}
}
Reading & Writing via the ISockPort Instance
static void TryWrite( CApp *pMe )
{
int result = ISOCKPORT_Write( pMe->pISockPort,
pMe->abyWrite + pMe->wWritten,
pMe->wWrite - pMe->written );
switch( result )
{
case AEEPORT_WAIT:
ISOCKPORT_WritableEx( pMe->pISockPort, &pMe->cbWritable,
(PFNNOTIFY)TryWrite, pMe );
break;
case AEEPORT_ERROR:
ISHELL_PostEvent( pMe->a.m_pIShell, pMe->a.clsID,
EVT_SOCKETERROR,
ISOCKPORT_GetLastError( pMe->pISockPort), 0 );
break;
case AEEPORT_CLOSED:
ISHELL_PostEvent( pMe->a.m_pIShell, pMe->a.clsID,
EVT_SOCKETCLOSED, 0, 0 );
break;
default:
pMe->wWritten += result;
if (pMe->wWritten < pme->pMe->wWrite )
{
ISOCKPORT_WritableEx( pMe->pISockPort, &pMe->cbWritable,
(PFNNOTIFY)TryWrite, pMe );
}
else
{
pMe->wWritten = pMe->wWrite = 0;
}
}
}
Shutting Down the ISockPort Instance
CALLBACK_Cancel(pMe->cbWritable);
CALLBACK_Cancel(pMe->cbReadable);
if ( pMe->pISockPort )
{
ISOCKPORT_Release( pMe->pISockPort );
pMe->pISockPort = NULL;
}
Conclusion
Related Resource
About the Author