The Wireless Application Protocol (WAP) is described as "the de-facto world standard for the presentation and delivery of wireless information and telephony services on mobile phones and other wireless terminals."  The standard encompasses transport and delivery protocols as well as content technology. Series 60 has a WAP stack implementation and provides developers with the APIs required to use it. These APIs are the main focus of this section, after a brief introduction to the WAP architecture.
The hierarchy of the stack can be seen in Figure 10-2. Note that the bearer layer is not specified as part of the WAP standard ”the existence of suitable bearer, such as GSM, SMS, or GPRS, and appropriate APIs are assumed.
WDP is an unreliable transport protocol, analogous to UDP, which is essentially responsible for moving data between the sender and receiver and back again. As the base of the WAP stack it provides an interface to the different bearers . The WTLS protocol provides a mechanism for secure connections that is based on the industry-standard Transport Secure Layer (TSL). It can perform encryption of data, has methods for authentication, and ensures privacy of data. The WSP layer of the stack is concerned with the delivery of data and offers both a connected and connectionless service. If a connected service is requested , the WTP layer manages the transaction by demanding an acknowledgement of the receipt of data and resending any packets that are not acknowledged . The top layer of the WAP stack, WAE, defines the development environment for applications and specifies the mark-up and scripting languages and the telephony interface.
WAP supports two modes of transaction between client and server: client pull and server push . In a client pull transaction, a client sends a request for data to a server, and the server then responds. In a server push transaction, data is sent from server to client without having been requested by the client.
WAP was supported in early releases of Series 60, but Series 60 2.x introduces a new API and, unfortunately , provides no backward compatibility. The new API supports the multihoming framework discussed in the previous chapter.
In Series 60 1.x, a WAP stack API allows the client access to the WSP, WTP and WDP layers , providing a means of performing connected and connectionless transactions. A Client/Server architecture is used, with the WAP server (this is not the remote server that provides WAP content) managing client access to WAP services. The client can access the WAP server through the RWapServ class. A session with this server must be opened ( RWapServ::Connect() ) before any of the other protocol session is opened ”this is analogous to opening a session with RSocketServ in sockets programming.
The various layers of the WAP stack were outlined earlier in this chapter. In Series 60 there are classes to represent each layer, and, as many of the functions that must be available at each layer are the same, they are all derived from the base class, RWAPConn . An Open () function is defined in RWAPConn that takes the parameters necessary to open a WAP protocol session; these include a reference to the WAP server, the address of the remote host, port numbers , bearer and whether the connection should be secure. This Open() function can be described as fully specified, meaning that the address for each end of the connection is defined. Methods to cancel pending operations and close the session are, of course, provided, as well as functions to retrieve the remote address, port and the like. If a secure connection was requested, the WTLS layer is created, and the function Wtls() will return a handle to this layer.
It is usual, when sending WAP content, to do so using the upper levels of the protocol stack, creating a WSP session to ensure a reliable transport. However, it is also possible to use the WDP protocol to send WAP datagrams ”you would use the RWDPConn class for this. This class implements the base class, fully specified, Open() function, but also defines an Open() method that just takes a reference to the Symbian OS WAP server and local port number as parameters. When sending data there are two options: the fully specified version of Open() can be used in conjunction with Send() , or SendTo() , which requires a destination address to be passed through, and can be used with the overloaded Open() implementation. SendTo() allows data to be sent to multiple destinations, whereas with Send() you are restricted to the one address.
The asynchronous Recv() function also takes a remote address as a parameter, meaning that, as long as the fully specified Open() was not used, datagrams can be received from multiple destinations, too.
Since the most common way to perform WAP transactions is to create a WSP session, the related APIs will be examined in more detail and supported with example code. The idea of connected and connectionless sessions is common in communications programming, and WSP sessions can be of either variety. Connected sessions are appropriate if a reliable medium for request and response is required; connectionless can be used if a conversational protocol is not needed. Both session types support the push model of delivery as well as the usual pull mode.
The class designed to create a connected WSP session is RWSPCOConn . To use the class, you must first create a session with the WAP server. As it is used only for connected sessions, RWSPCOConn defines just the fully specified version of the Open() function.
[View full width]User::LeaveIfError(iWapServ->Connect()); User::LeaveIfError(iWspConn->Open(*iWapServ, remoteHost, remotePort, iLocalPort, iBearer, EFalse));
The local port number can be left as zero to indicate that the device should allocate a suitable port ( GetLocalPort() can be used later to retrieve the port number). Suitable bearers are defined by the enumeration TBearer and include EIP (Internet Protocol) and ESMS (8-bit SMS). As secure connections are not supported, the aSecureConn parameter should be set to EFalse .
To start an open WSP session, you use the Connect() method. Session headers are sent to the remote server, and, optionally , information about the size of buffers and data packets is communicated through the codec, CCapCodec . You can set the desired client parameters ”for example, SDU size (set by default to 1400) ”using the functions on CCapCodec , and the WAP server will also set server parameters, which you can retrieve.
iCapCodec = CCapCodec::NewL(); iCapCodec->SetClientSDUSize(KClientSDUSize); User::LeaveIfError(iWSPConn->Connect(clientHeaders, iCapCodec));
Besides the systemwide error codes that can be returned, WAP- specific errors are defined by RWSPCOConn::TReturnCodes and RWapConn::TReturnCodes .
CreateTransaction() , as the name suggests, is used to kick-off the data exchange process. TMethod describes the type of transaction ”examples include EGet , Etrace , and EPost . Other parameters to be passed are the URI of the destination, the body and WAP headers. You must also create an RWSPCOTrans object and pass a reference to it as a parameter. On return of the function, you can use this object to manage the transaction. For example, you could call GetState() to determine what stage the transaction is at.
[View full width]iWSPTransaction = new (ELeave) RWSPCOTrans(); User::LeaveIfError(iWSPConn->CreateTransaction(RWapConn::EGet, uri, headers, body, *iWSPTransaction));
During one transaction, a number of different events can occur at both session level and transaction level. You can monitor the events by use of the GetEvent() function, which has a synchronous and asynchronous implementation ”as usual, the asynchronous version is preferred. The types of event are described by the enumeration TEventType and include notification of exceptions and disconnection. If data is associated with the event, then you can retrieve it by calling GetSessionData() with the appropriate TSessionDataType parameter. Note that if the buffer you pass in is too small, EMoreData will be returned.
To retrieve the data from the transaction, once it has completed, you need to call the Getdata() function of the RWSPCOTrans object, passing in a buffer for the data and specifying the data type as RWSSPCOTrans::EResultBody . As with GetSessionData() , EMoreData will be returned if the buffer is too small.
TInt error = iWSPTransaction->GetData(iData, RWSPCOTrans::EResultBody);
When all transactions are complete, the WTP session should be disconnected and the WAP server session closed.
If you require a connectionless WSP session, RWSPCLConn should be used. The session is created in much the same way as for a connected session, the difference being the availability of both fully specified and not fully specified Open() functions. The connectionless session does not afford the same degree of transaction management as the connected session, relying on just an ID for control ”this means that you do not need to create a transaction object.
To retrieve content, the method you select depends upon whether a push or pull model is being used. For the pull method, you call UnitInvoke() to initiate the transaction. Note that the parameters for this function are the same as those in the CreateTransaction() function used for connected sessions, except that an ID is passed in place of the transaction object. You do not need to set the ID yourself; an ID will be allocated, and on return of the function the aID parameter will have been updated. To retrieve the response from this initial request, you call UnitWaitResult() (available as either a synchronous or an asynchronous implementation). If the ID returned matches that from the UnitInvoke() function, then you can be sure it is a response to your request. The body and WAP headers are returned.
If the data is to be pushed to the client, then UnitWaitPush() can be called to wait for the incoming message ”synchronous and asynchronous versions are available. On return, the body and headers can be retrieved.
The WAP stack API that was described for Series 60 1.x has been withdrawn in Series 60 2.x and replaced with a WAP messaging API. The differentiation between a fully specified connection and one that does not define a specific endpoint for all transactions leads to the definition of four interfaces ( ECom plug-in interface).
The classes CWAPBoundDatagramService and CWAPFullySpecDatagramService offer functionality akin to that of the RWDPConn class that was previously supported. One major difference is that, in 2.x, the client can specify which network interface should be used for the connection, employing the multihoming framework. The difference between CWAPBoundDatagramService and CWAPFullySpecDatagramService is that the latter should be used if you want to restrict all transactions to a specific remote host.
If you are not just concerned with one specific remote host, CWAPBoundDatagramService can be used to send and receive datagrams ”instantiation of an object is through the NewL() function. To connect to the WAP server, you obviously use a version of the Connect() function. There are two implementations , one that takes the IP address of the network interface to be used, and another that does not ”you need to decide whether or not you wish to use the default interface. The other parameters you need to pass through relate to the bearer you want to use (you can choose TBearer::EAll for listening and then define a particular bearer when you send data) and the local port number to listen on (a value of leaves the selection to the system).
When you want to send data, you will need to use the SendTo() function and nominate the recipient ”the format of the address of the remote host will depend upon the bearer that you are using. You will need to select a bearer type for the transaction ”this is necessary even if you specified a particular bearer during connection, but will be ignored unless you specified the bearer value EAll initially. The remote port number needs to be set and the data to be sent passed through in an 8-bit descriptor. The SendTo() function is synchronous and returns KErrNone if successful.
The asynchronous AwaitRecvDataSize() should be called when you want to listen for a datagram, as this will allow you to retrieve the size of the data. When you have done this, you can then call RecvFrom() with a buffer of the appropriate size to get hold of the data. Note that you can set a timeout value using the aTimeout parameter ”it is probably a good idea to do so, but as you have been notified that there is data waiting for you (through AwaitRcvData() ), it should be OK to set an infinite timeout using aTimeout = 0 .
There is no specific Disconnect() function; destruction of the object closes the connection, but you should always make sure you have canceled any outstanding asynchronous listening functions using CancelRecv() .
If you want to exchange datagrams with a particular remote host, CWAPFullySpecDatagramService can be used. Use of this class is very similar to that of CWAPBoundDatagramService that has just been described, but its connection function is fully specified. As both endpoints have been nominated, there is a Send() function with just one parameter, the descriptor to be sent, instead of SendTo() . Similarly this class has a Recv() function rather than a RecvFrom() , because you have already set up the remote address.
The CWAPBoundCLPushService class can be used to listen for push messages from any sender. Again, the class is used in much the same way as the datagram classes, but because it operates above the WDP layer, there is the option of creating a secure connection. This is simply achieved by setting the Boolean parameter, aSecure . Once you have made a connection to the WAP stack, you can listen for messages by calling the asynchronous AwaitPush() method, passing through buffers for the headers and body. If the buffers you have allocated will not hold all of the data received, then the iStatus returned will be RWAPConn::EMoreData . If this is the case, you will need to reissue the AwaitPush() request to retrieve the remaining data. Note that once the complete message has been received, you can create a CPushMessage object using the headers and body.
CWAPFullySpecCLPushService , as you would expect, is the fully specified version of CWAPBoundCLPushService , to be used for listening to push messages from a single remote host.