static void Sockapp_Demo(CSocketApp *pme)
{
INetMgr *piNet;
ISocket *piSock;
INAddr nodeINAddr; // IP address in network byte order
//This is a sample function that tries to read from a socket:
xStatus(pme, 0, "Demo");
//Step 1: Create an instance of INetMgr
if (ISHELL_CreateInstance(pme->a.m_pIShell, AEECLSID_NET, (void**)(&piNet)) != SUCCESS)
{
xStatus(pme, 1, "INetMgr failed");
Sockapp_DemoCleanup(pme);
return; // failed
}
xStatus(pme, 1, "Got INetMgr");
//Set the member into our applet structure
pme->m_piNet = piNet;
INETMGR_SetLinger(pme->m_piNet, 0);
// Step 2: Open the socket. This shall be a TCP socket.
piSock = INETMGR_OpenSocket(piNet, AEE_SOCK_STREAM);
if (!piSock)
{
xStatus(pme, 2, "Socket failed");
Sockapp_DemoCleanup(pme);
return;
}
xStatus(pme, 2, "Got Socket");
//Set the member into our applet structure
pme->m_piSock = piSock;
//Step 3: Connect the Socket
xStatus(pme, 3, "Connecting...");
// Before we can pass on the address to connect the socket, we need to convert the
// address from a string to the INAddr format.
nodeINAddr = xConvertToINAddr(TIMESERVER_HOST);
// Connect the socket. Remember to convert the port number from Host to Network system
// format. This is done using HTONS.
ISOCKET_Connect(piSock, nodeINAddr, HTONS(TIMESERVER_PORT), Sockapp_ConnectCB, pme);
}
This is the function that reads from the socket. It will be called after a
successful connect, and after some data has been read it may schedule itself to
be called again.
It takes a 'void *' so it can be passed to the Readable() without a cast.
(Safer to cast a simple structure pointer than to cast a function pointer.)
PARAMETERS:
pme: Pointer to the AEEApplet structure.
ISocket *piSock = pme->m_piSock;
int rv; // Return value frm Read()
uint32 uTime; // Buffer to pass to socket-read function
char szBuf[50];
// Issue a read command on the socket. We know that the address that we have
// connected to returns an uint32 value. Hence, we cast that to char* and send
// it to the read function.
// Read() return values fall into four categories of interest:
//
// 1. AEE_NET_WOULDBLOCK: This means, data is not yet available on the socket.
// 2. AEE_NET_ERROR: An eror occurred
// 3. 0 (zero): No more data (the peer has closed the connection).
// 3. >0 : The actual data that was read
//
if (rv == AEE_NET_WOULDBLOCK)
{
// WOULDBLOCK => there is no more data available at the moment
//
// In this case, register a callback function using ISOCKET_Readable() and then
// return from this function. The callback will be called by the system at
// a later time. It is perfectly OK to give the current function itself
// as the callback. The callback can then proceed to call ISOCKET_Read()
// to obtain data (or perhaps an error, end of file, etc.).
xStatus(pme, 4, "Waiting...");
ISOCKET_Readable(piSock, Sockapp_ReadCB, (void*)pme);
return;
}
else if (rv == AEE_NET_ERROR)
{
// Connection hosed.
xStatus(pme, 4, "Read Error!");
}
else if (rv > 0) // data has been read
{
SPRINTF(szBuf, "Read: %d", rv);
xStatus(pme, 4, szBuf);
// The data has been read from the socket. So, convert the data from
// host network format to host format.
uTime = NTOHL(uTime) ;
// Display the data.
// This is the time elapsed in seconds since Jan 1 1900.
SPRINTF(szBuf, "Time = %lu", (long) uTime);
xStatus(pme, 5, szBuf);
// If we wanted to read more data, we could loop here or call Readable() here
// and return.
}
else // rv == 0
{
// This demo doesn't expect to see the end of the stream...
xStatus(pme, 4, "No Data!");
}
// Release interfaced used for network activity
Sockapp_DemoCleanup(pme);
}