RIM 950/957 devices communicate with each other using Mobitex network. Each device is assigned a unique number call MAN ( Mobitech Access Number ) as identified number. And the data units that they exchange are call MPAK ( Mobitech packet ).
In order to enable a custom host and Rim devices communicate with each other, an IAS server is introduced. IAS server acts as a gateway between the custom host and the Mobitex network. The custom host is assigned a unique MAN number, too ( and it becomes a big Rim device, with powerful compilers, tools, and a big vivid monitor [perhaps it is better on to mention this monitor in my case. It is a Linux box, and I rarely need to use this monitor or the keyboard] ). To the Rim devices, this custom host is just another Rim device. In their point of view, they communicate this host exactly as with other Rim devices. Custom communicates with IAS thru tcp protocol. There is at least another option for custom host to communicate with Mobitech network, that is X.25, but it is beyond of the scope of this note.
You also need to register all your Rim 950/957 MAN numbers to be in the same group ( CUG ) with the number assigned to the custom host. This will enable your MPAKs of the devices to be able to be forwarded to the custom host, and vice versa.
Because the data unit that Rim devices use is MPAK, these MPAK are tunnelled under tcp: each MPAK is encapsuled with a four-byte header. This header contains the 2-byte length of the MPAK. This protocol is called MDOT ( MPAK Datagram over TCPIP ). Then, the main work the custom host must do, in order to exchange MPAKs with other Rim devices, are:
1. The structure of the MDOT header
This structure has four bytes: one byte for version ( cureently 2 ), one byte for flags ( that must be zero for now ),
anf the rest is a short int for the length of the MPAK that followed. This 2-byte length is in
network-byte-order.The following is defined in my header file.
typedef struct tagIASHeader { unsigned char version; unsigned char flags; // must be zero unsigned short length; } IASHeader;
The following code is part of the receive module.
// read the IAS header IASHeader iasheader; unsigned char *p; if ( ProcessTcpReceive( isocket, ( unsigned char*) &iasheader, sizeof(iasheader) ) == -1 ) continue; if( iasheader.version != IAS_VERSION || iasheader.flags != 0 ) { // Out-of-boundary error may happen ProcessErrorOrOutOfSync(); continue; } unsigned int mpaklength = ntohs( iasheader.length ); sprintf( message, "InIASLayerProc receives header with mpak length of %d", mpaklength ); writelog_iniaslayer( message );ProcessTcpReceive is an encapsulation of recv with some processing codes for NONBLOCK I/O, and to detect if the connection is still good.
2. Building a reliable protocol layer over MPAK
I have no way to be sure that MPAKs will reach their destination sucessfully, and if they reach in
the order they are sent. Therefore I build another protocol layer over MPAK.
What I built can be temporaroly called "reliable connectionless session" in the meaning that each sending session needs
to be acknowledged. Also, if a session is so big that it must be laid over many mpaks, then these mpaks
will be numberred, and the receivingend must check the order or lost of mpaks. In cast of losing mpak,
the receicing end must send a request to the sender to resend.
This is a little similar to "reliable UDP"; why don't I build a connection-oriented protocol ? The reasons are I have not enough time ( and talent ) to do so, also there are some rumor that there will be a tcpip stack for RIM, and this specific protocol seems serving the current requirements of my application rather good.
To do this, my protocol divides the MPAK data part into two parts : Datagram header and Subdata. The Datagram header is to help controlling the reliable feature, and the Subdata is for the data of my application.
typedef struct tagDatagramHeader { unsigned short int sessionnumber; unsigned short int datagramnumber; unsigned short int datagramtotal; unsigned short int length; unsigned char protocol; } DatagramHeader;
The common format for my MDOT is as follows:
[Start of MDOT] [MDOT Header] unsigned char version; unsigned char flags; unsigned short length; [Start of MPAK] [Start of MPAK Header] See Radio Guide. [End of MPAK Header] [Start of MPAK Data] [Start of Datagram Header] unsigned short int sessionnumber; unsigned short int datagramnumber; unsigned short int datagramtotal; unsigned short int length; unsigned char protocol; [End of Datagram Header] [Subdata] My protocol-specific header ( if available) and real data here. [End of MPAK Data] [End of MPAK] [End of MDOT]We can see that with the Datagram Header inserted into the MPAK data, I loose at least 9 bytes for the DatagramHeader. To be able to make the data smaller, I use the porting version of zlib to compress that MPAK data. The compression library is really a good thing to do. After adding the compression layer, the above structure becomes:
[Start of MDOT] [MDOT Header] unsigned char version; unsigned char flags; unsigned short length; [Start of MPAK] [Start of MPAK Header] See Radio Guide. [End of MPAK Header] [Start of MPAK Data] unsigned short decompression_length; unsigned char compression_data[]; [End of MPAK Data] [End of MPAK] [End of MDOT]My custom host 's application uses pthread to deal with this multiple layers:
More information on pthread propgramming
3. Keep your custom host connect with IAS server up
One of the guides that IAS Description and
Programming Guide states is to try to reconnect after a disconnect. The reason is
to be able to receive MPAKs from Rim devices send to the server.
Tcpip 's recv is a good way to detect if the connection is closed. If recv returns 0, it means the other end has been closed. If the socket on which recv is wating for is on NON-BLOCK mode, then if recv returns -1 and variable errno is not EWOULDBLOCK, then it indicates there is an error. To detect these cases, custom host put the socket in non-blocking mode, then poll for data every M miliseconds.
Also tcpip 's send can be used to detect also. If you call a send when the connection is closed, send will return -1 with errno having signal error EINTR. This is a PIPE BROKEN error. This means that if your application does not catch this signal, it will be core-dumped.
4. Prepare to process error MPAKs
If some MPAK can not reach the RIM devices for some reason, it will be sent back to your custom host
with the status 's traffic bits set to error. For receiving MPAKs, these bits are bit 5 to 7 of the status byte.
Only 000xxxxx and 001xxxxx of these three bits are acceptable as no error generated. All other values mean error.
The most common error I met is 011xxxxx. It means No Transfer : the packet could not be delivered
to the destination device.
The custom host can not just simply resend the error MPAKs, because it may be the case that the device has been turned off or it may be because of the problem from Cingular towers. If you keep resending, the IAS server will keep sending back to the custom host. The custom host needs to implement some mechanic to solve this problem. For example, an error counter that reaches its maximum number will signal the application to stop resending and set a flag indicating that the corresponding device is out-of-service at this time. Any MPAK from the out-of-service device will signal the custom host to put this device back to normal state.
5. My server configuration
- P3-800 Mhz, 256 Mb RAM
- Adaptec 29160 with a 20Gb UltraWide SCSII drive
- Linux Redhat 7.1
- gcc 3.0: Its configure parameter is
Reading specs from /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.0/specs
Configured with: ../gcc-3.0/configure --enable-threads=posix
Thread model: posix
gcc version 3.0
- Interbase 6.0
- Apache server with PHP 4.0
I use the gcc 3.00 in order to be able to use STL lirbary. With all the lists, vectors of datagrams and mpaks ... it would take me a lot of time if I didn't use STL. I am very happy that I have spent time on STL, then I gain a lot of time later.