Forums | developer.brewmp.com Forums | developer.brewmp.com

Developer

Forums

Forums:

I am trying to connect to a specific server to send and receive HTTP packets.  I am trying the following steps but I get an error -1 from the ISockPort_Connect() function.  The callback is triggered very quickly and I continue to get the error -1.  Any suggestions.

1. Create Instance

2. Open Socket

3. Connect

 

bool OpenTCPSock()
{
    DBGPRINTF("OpenTCPSock Called");               //****************************

    // Variables
    AEESockAddrStorage sockAddr;
    sockAddr.wFamily = AEE_AF_INET; 
    sockAddr.inet.port = HTONS(80); 
    sockAddr.inet.addr = AEE_INADDR_ANY;
    int nErr;



    // Create the Instance and Open the socket
    if(!up->pSockPort) {
       DBGPRINTF("ISHELL_CreateInstance");
       if(IShell_CreateInstance(up->piShell, AEECLSID_SockPort, (void**)&up->pSockPort) != SUCCESS)
          return FALSE;

       DBGPRINTF("ISockPort_OpenEX");
       nErr = ISockPort_OpenEx(up->pSockPort, sockAddr.wFamily, AEE_SOCKPORT_STREAM, AEE_IPPROTO_TCP);
       if(nErr != SUCCESS)
          return FALSE;
    }




    // Bind the socket
    DBGPRINTF("ISockPort_Bind");
    nErr = ISockPort_Bind(up->pSockPort, &sockAddr);
    if (SUCCESS == nErr)
    {
       DBGPRINTF("*******Socket BIND Success");
       getmyip();
       TurnOnConnect();
       return TRUE;
    }
    if (SUCCESS != nErr)
    {
       DBGPRINTF("*******Socket BIND Waiting : %d", nErr);
       ISockPort_WriteableEx(up->pSockPort, &up->readCB, OpenTCPSock, up);
       return FALSE;
    }

    return FALSE;

void TurnOnConnect()
{
    DBGPRINTF("TurnOnConnect");

    // variables
    INAddr     addr;
    char       addr_str[16] = "74.125.45.106";
    int        nErr;

    INET_ATON(addr_str, &addr);
    DBGPRINTF("IP Address : %s", addr_str);

    // connect
    DBGPRINTF("ISockPort_Connect");
    nErr = ISockPort_Connect(up->pSockPort, &addr);

    if (AEE_SUCCESS == nErr) 
    {
        DBGPRINTF("*************Connect Success");
        return;
    }
    if (IPORT_WAIT == nErr) 
    {
        DBGPRINTF("*************Connect Waiting");
        ISockPort_WriteableEx(up->pSockPort, &up->readCB, TurnOnConnect, up);
        return;
    }
    if (AEE_NET_WOULDBLOCK == nErr) 
    {
        DBGPRINTF("*************Would Block");
        ISockPort_WriteableEx(up->pSockPort, &up->readCB, TurnOnConnect, up);
        return;
    }
    DBGPRINTF("************Some Other Connect Error : %d", nErr);
    ISockPort_WriteableEx(up->pSockPort, &up->readCB, TurnOnConnect, up);

    return;

there is a bit of problem in your code.
1. for TCP client, you do not need to Bind the Socket.
2. i see that in the call to ISockPort_Connect(), PORT number is not specified in addr.
 
here is a sample code snipet:-
/*definations INAddr     addr;
 INPort     port;
 ISockPort    *pSockPort;
 AEESockAddrStorage   sockAddr;
 AEECallback    connectCB;
*/
boolean httpConnect(mySock *pMe)
{
  int       nErr;

//setting IP & Port  
  pMe->sockAddr.inet.addr = ConvertToINAddr(IP);
  pMe->sockAddr.inet.port = HTONS(80);//Port 80 for HTTP Services
  pMe->sockAddr.inet.wFamily = AEE_AF_INET;
  if(ISHELL_CreateInstance(pMe->m_pIShell, AEECLSID_SOCKPORT, (void**)&pMe->pSockPort) != SUCCESS)
              return FALSE;
  nErr = ISockPort_OpenEx(pMe->pSockPort, AEE_AF_INET, AEE_SOCKPORT_STREAM, AEE_IPPROTO_TCP);
    if(nErr != SUCCESS)
      return FALSE;
   connectNotify(pMe);
}
 
 
void connectNotify(mySock *pMe)
{
  int errCode;
  errCode = ISockPort_Connect(pMe->pSockPort, (void*)&pMe->sockAddr);
   switch (errCode)
  {
  case AEE_NET_WOULDBLOCK:
        DBGPRINTF("WAIT...");
        CALLBACK_Init(&pMe->connectCB, connectNotify, pMe);
        ISOCKPORT_Writeable(pMe->pSockPort, &pMe->connectCB);
        break;
  case AEE_NET_SUCCESS:
        DBGPRINTF("Connect completed successfully and the socket is prepared for reading or writing.");
        // Now u may read/write 
         break;
 //check for other errors here like AEE_NET_EBADF, AEE_NET_ECONNREFUSED, AEE_NET_ETIMEDOUT, etc..
}
 
INAddr ConvertToINAddr(const char *psz)
{
   INAddr ul = 0;
   int nByte = 0;
   char c;
   if(!psz)
      return 0;
   while (ISDIGIT(*psz)) {
      int n = 0;
      while ( ISDIGIT(c=*psz)) {
         n = n*10 + (c - '0');
         ++psz;
      }
      ((char*)&ul)[nByte++] = n;
       if (nByte == 4 || *psz != '.')
         break;
       ++psz;
   }   if (nByte < 4 || ISALNUM(*psz))
      ul = 0xFFFFFFFF;    // Invalid address
   return ul;
}

there is a bit of problem in your code.
1. for TCP client, you do not need to Bind the Socket.
2. i see that in the call to ISockPort_Connect(), PORT number is not specified in addr.
 
here is a sample code snipet:-
/*definations INAddr     addr;
 INPort     port;
 ISockPort    *pSockPort;
 AEESockAddrStorage   sockAddr;
 AEECallback    connectCB;
*/
boolean httpConnect(mySock *pMe)
{
  int       nErr;

//setting IP & Port  
  pMe->sockAddr.inet.addr = ConvertToINAddr(IP);
  pMe->sockAddr.inet.port = HTONS(80);//Port 80 for HTTP Services
  pMe->sockAddr.inet.wFamily = AEE_AF_INET;
  if(ISHELL_CreateInstance(pMe->m_pIShell, AEECLSID_SOCKPORT, (void**)&pMe->pSockPort) != SUCCESS)
              return FALSE;
  nErr = ISockPort_OpenEx(pMe->pSockPort, AEE_AF_INET, AEE_SOCKPORT_STREAM, AEE_IPPROTO_TCP);
    if(nErr != SUCCESS)
      return FALSE;
   connectNotify(pMe);
}
 
 
void connectNotify(mySock *pMe)
{
  int errCode;
  errCode = ISockPort_Connect(pMe->pSockPort, (void*)&pMe->sockAddr);
   switch (errCode)
  {
  case AEE_NET_WOULDBLOCK:
        DBGPRINTF("WAIT...");
        CALLBACK_Init(&pMe->connectCB, connectNotify, pMe);
        ISOCKPORT_Writeable(pMe->pSockPort, &pMe->connectCB);
        break;
  case AEE_NET_SUCCESS:
        DBGPRINTF("Connect completed successfully and the socket is prepared for reading or writing.");
        // Now u may read/write 
         break;
 //check for other errors here like AEE_NET_EBADF, AEE_NET_ECONNREFUSED, AEE_NET_ETIMEDOUT, etc..
}
 
INAddr ConvertToINAddr(const char *psz)
{
   INAddr ul = 0;
   int nByte = 0;
   char c;
   if(!psz)
      return 0;
   while (ISDIGIT(*psz)) {
      int n = 0;
      while ( ISDIGIT(c=*psz)) {
         n = n*10 + (c - '0');
         ++psz;
      }
      ((char*)&ul)[nByte++] = n;
       if (nByte == 4 || *psz != '.')
         break;
       ++psz;
   }   if (nByte < 4 || ISALNUM(*psz))
      ul = 0xFFFFFFFF;    // Invalid address
   return ul;
}

How can I use ISockPort_Listen(), then write something to a specific IP address.  To turn on listening I cannot bind to a specific IP address?  I would like to be able to listen all the time and occationally write to a specific IP address.

How can I use ISockPort_Listen(), then write something to a specific IP address.  To turn on listening I cannot bind to a specific IP address?  I would like to be able to listen all the time and occationally write to a specific IP address.

ISockPort - Writing a TCP server application
This section will demonstrate a TCP server application that exchanges data with clients over an ISockPort object. The application implements a rudimentary echo server. The steps demonstrated are as follows:

 

Data initialization.

Creating and opening an ISockPort object.

Binding a Sockport.

Listening on a Sockport.

Accepting new connections.

Reading data from a client.

Writing data to a client.

Closing connections.

The server application should define the following:
// define port number of the server
#define SERVER_PORT 7

// define the pending connections backlog size
#define BACKLOG_SIZE 3

// define message length
#define BUFFER_SIZE 100
The application will use the following structures to organize data needed for socket communication
// struct representing a single client-server connection
struct TCPConnection
{
CApp* pme; // pointer to the application
ISockPort* pSock; // the socket used for this connection
AEECallback ReadSockCB; // AEECallback for the connection's read operations
AEECallback WriteSockCB; // AEECallback for the connection's write operations
char szBuf[BUFFER_SIZE]; // data buffer
uint32 nTotalBytesToWrite; // num of bytes received from the client.
// which is also num of bytes the
// server should echo
uint32 nBytesWritten; // number of bytes already written to client

TCPConnection* pNext; // pointer to the next element in the list.
};

// struct representing the server socket
struct TCPServerSockPort
{
ISockPort* pListenSocket; // the SockPort itself
AEECallback ListenSocketCB; // callback for the socket
AEESockAddrStorage Sockaddr; // socket address struct
};
Among others, the applet should have the follwoing members:
IShell* m_pIShell, // IShell pointer
TCPServerSockPort m_TCPServerSockPort; // pointer to a TCPServerSockPort object
TCPConnection* m_pHead; // head of singly-linked list of connections
Initialization of the address structure should be also carried out:
// initialize the addresses.
pme->m_TCPServerSockPort.Sockaddr.wFamily = AEE_AF_INET; // IPv4 socket
pme->m_TCPServerSockPort.Sockaddr.inet.port = HTONS(SERVER_PORT); // set port number
pme->m_TCPServerSockPort.Sockaddr.inet.addr = HTONL(AEE_INADDR_ANY); // set IP address to any available address.
For having a functional ISockport object, the following stages must be performed:

 

Calling IShell_CreateInstance(), to create an ISockPort object.

Calling ISockPort_OpenEx(), to open the SockPort.

 
void CApp_StartTCPServer(void* po)
{
int ret;
CApp* pme = (CApp*)po;
TCPServerSockPort* pSock = &(pme->m_TCPServerSockPort);

// create the ISockPort object.
ret = ISHELL_CreateInstance(pSock->pIShell, AEECLSID_SOCKPORT, (void**)&(pSock->pListenSocket));
if (SUCCESS != ret) {
// handle the error
...
return;
}

// open the SockPort.
ret = ISOCKPORT_OpenEx(pSock->pListenSocket, // ISockPort pointer
AEE_AF_INET, // wFamily = IPv4
AEE_SOCKPORT_STREAM, // socket type = TCP
0 // Protocol type:
// Use 0 (recommended) to let the system select its default
// protocol for the given address family and socket type
);
if (SUCCESS != ret) {
// handle the error
...
return;
}
}
The server SockPort has to be bound. The example function CApp_TryBind() attempts to bind the SockPort, using ISOCKPORT_Bind(). It then handles all the possible values ISOCKPORT_Bind() may return:

 

AEEPORT_WAIT - the operation cannot be completed at present. Often, this is because the system needs to establish a data connection between the phone and the cellular network on which the TCP data can be transmitted. In this case - call ISOCKPORT_WriteableEx() and register CApp_TryBind() as a callback, to be called again when the bind operation can make a progress.

ret != SUCCESS - an error occurred. ret holds the error code.

ret == SUCCESS - operation succeeded.

Note that ISOCKPORT_Bind() returns the error code, and there is no need to explicitly get it using ISOCKPORT_GetLastError().
void CApp_TryBind(void* po)
{
int ret;
CApp* pme = (CApp*)po;
TCPServerSockPort* pSock = &(pme->m_TCPServerSockPort);

// use AEE_INADDR_ANY for binding
ret = ISOCKPORT_Bind(pSock->pListenSocket, &(pSock->Sockaddr));
if (AEEPORT_WAIT == ret) {
ISOCKPORT_WriteableEx(pSock->pListenSocket, &pSock->ListenSocketCB, CApp_TryBind, pme);
return;
}
else if (SUCCESS != ret) {
// ret holds the error code
// release resources
CApp_ServerEnd(pSock);
...
return;
}

// the SockPort is bound, try to listen.
CApp_TryListen(pme);
...
}

Note that in TCPServerSockPort.Sockaddr, inet.addr was set to AEE_INADDR_ANY. Currently, this is the only supported option for bind operation. Once the SockPort is bound, it may listen to incoming connections. Once bound to an address, the SockPort may listen for incoming connections requests. CApp_TryListen() calls ISOCKPORT_Listen(), and then handles all the possible values ISOCKPORT_Listen() may return:

 

AEEPORT_WAIT - the operation cannot be completed at present. Often, this is because the system needs to establish a data connection between the phone and the cellular network on which the TCP data can be transmitted. In this case - call ISOCKPORT_WriteableEx() and register CApp_TryListen() as a callback, to be called again when the listen operation can make a progress.

ret != SUCCESS - an error occurred. ret holds the error code.

ret == SUCCESS - operation succeeded.

When the SockPort is listening, it may attempt to accept incoming connections.
void CApp_TryListen(void* po)
{
int ret;
CApp* pme = (CApp*)po;
TCPServerSockPort* pSock = &(pme->m_TCPServerSockPort);

ret = ISOCKPORT_Listen(pSock->pListenSocket, BACKLOG_SIZE);
if (AEEPORT_WAIT == ret) {
ISOCKPORT_WriteableEx(pSock->pListenSocket, &pSock->ListenSocketCB, CApp_TryListen, pme);
return;
}

if (SUCCESS != ret)
{
// ret holds the error code
// release resources
CApp_ServerEnd(pSock);
...
return;
}

// try accepting new connections
CApp_TryAccept(pme);
}
The server socket is now ready to accept clients' "connect" requests. The example function CApp_TryAccept() uses ISOCKPORT_Accept() for accepting incomming "connect" requests. If AEEPORT_WAIT is returned, it registers itself as a callback to be called when the accept operation may progress. After a connection was established, the server application may exchange data with the client through the new SockPort created during ISOCKPORT_Accept(). Before doing so, CApp_TryAccept() does two things:

 

It calls ISOCKPORT_ReadableEx() again, thus registering itself for accepting subsequent "connect" requests. Since Brew applications must not block, the user should use the callback mechanism to wait for incoming "connect" requests.

It allocates and initializes the data structures representing the new connection.

In this example, the application will attempt to read data from the client, and write it back to the client (echo).
void CApp_TryAccept(void* po)
{
int ret;
ISockPort* pTmpSocket;
TCPConnection* pConnection;
CApp* pme = (CApp*)po;
TCPServerSockPort* pServerSock = &(pme->m_TCPServerSockPort);

// accept a request. pTmpSocket will point to the newly created socket
ret = ISOCKPORT_Accept(pServerSock->pListenSocket, &pTmpSocket);
if (AEEPORT_WAIT == ret) {

// the request is blocked. Register CApp_TryAccept() as a callback
// to be called again when accept operation may progress.
ISOCKPORT_ReadableEx(pServerSock->pListenSocket, &pServerSock->ListenSocketCB, CApp_TryAccept, pme);
return;
}

if (SUCCESS != ret) {

// operation failed, release resources
CApp_ServerEnd(pServerSock);

// ret holds the error code, handle it
...
return;
}

// ISOCKPORT_Accept() succeeded.
// Register CApp_TryAccept() as a callback, for accepting further incoming "connect" requests.
ISOCKPORT_ReadableEx(pServerSock->pListenSocket, &pServerSock->ListenSocketCB, CApp_TryAccept, pme);

// allocate struct for holding the new connection's data
pConnection = MALLOCREC(TCPConnection);
if (!pConnection) {
// allocation failed - reject the connection
ISOCKPORT_Release(pTmpSocket);
return;
}

// init the connection's struct
pConnection->pme = pme;
pConnection->pSock = pTmpSocket;
pConnection->nBytesWritten = 0;
pConnection->nTotalBytesToWrite = 0;

// insert the new connection at head of the server's connections list
pConnection->pNext = pme->m_pHead;
pme->m_pHead = pConnection;

// wait for an incoming data on this connection.
CApp_TryRead(pConnection);
}
The example function - CApp_TryRead() - shown below, attempts to read data from a client, using ISOCKPORT_Read(). It then handles all the possible values ISOCKPORT_Read() may return:

 

nRead == AEEPORT_WAIT - the system can't read data at this time. Often, this is because the system needs to establish a data connection between the phone and the cellular network on which the TCP data can be received. In this case - call ISOCKPORT_ReadableEx() and register ISOCKPORT_Read() as a callback, to be called again when the read operation can make a progress.

nRead == AEEPORT_ERROR - an error occurred. Check the error code.

nRead == AEEPORT_CLOSED - no more data to be read, connection was closed by the client.

nRead > 0 - data bytes were read. Write them back to the client.

 
void CApp_TryRead(TCPConnection* pConnection)
{
int32 nRead;

// read the data
nRead = ISOCKPORT_Read(pConnection->pSock,
pConnection->szBuf,
sizeof(pConnection->szBuf));

if (AEEPORT_WAIT == nRead) {
ISOCKPORT_ReadableEx(pConnection->pSock, &pConnection->ReadSockCB, CApp_TryRead, pConnection);
return;
}

// an error occurred
if (AEEPORT_ERROR == nRead) {
// get the error code and close the connection
nRead = ISOCKPORT_GetLastError(pConnection->pSock);
CApp_ConnClose(pConnection);
...
return;
}

// connection was closed by the distant socket
if (AEEPORT_CLOSED == nRead) {
// close the connection
CApp_ConnClose(pConnection);
...
return;
}

// increment num of bytes read from the connection
pConnection->nTotalBytesToWrite = nRead;
pConnection->nBytesWritten = 0;

// echo the data back to the client
CApp_TryWrite(pConnection);
}
The example function - CApp_TryWrite() - shown below, attempts to write data to a client, using ISOCKPORT_Write(). It then handles all the possible values ISOCKPORT_Write() may return:

 

nWrite == AEEPORT_WAIT - the system can't write data at this time. Often, this is because the system needs to establish a data connection between the phone and the cellular network on which the TCP data can be transmitted. In this case - call ISOCKPORT_WriteableEx() and register CApp_TryWrite() as a callback, to be called again when the write operation can make a progress.

nWrite == AEEPORT_ERROR - an error occurred. Check the error code.

nWrite == AEEPORT_CLOSED - connection was closed by the client.

nWrite > 0 - Data bytes were written. If not all the data was written - wait until a further write may progress. If all the bytes were written - try to read data from the client.

 
void CApp_TryWrite(TCPConnection* pConnection)
{
int32 nWrite;

// write the data
nWrite = ISOCKPORT_Write(pConnection->pSock,
(pConnection->szBuf + pConnection->nBytesWritten),
(pConnection->nTotalBytesToWrite - pConnection->nBytesWritten)
);

if (AEEPORT_WAIT == nWrite) {
ISOCKPORT_WriteableEx(pConnection->pSock, &pConnection->WriteSockCB, CApp_TryWrite, pConnection);
return;
}

// an error occurred
if (AEEPORT_ERROR == nWrite) {
// get the error code and close the connection
nWrite = ISOCKPORT_GetLastError(pConnection->pSock);
CApp_ConnClose(pConnection);
...
return;
}

// connection was closed by the distant socket
if (AEEPORT_CLOSED == nWrite) {
// close the connection
CApp_ConnClose(pConnection);
...
return;
}

// update num of bytes written.
pConnection->nBytesWritten += nWrite;

// in case of partial write register a callback to be called when further write can progress.
if (pConnection->nBytesWritten < pConnection->nTotalBytesToWrite) {
ISOCKPORT_WriteableEx(pConnection->pSock, &pConnection->WriteSockCB, CApp_TryWrite, pConnection);
return;
}

// all bytes were written.
// wait for an incoming packet
ISOCKPORT_ReadableEx(pConnection->pSock, &pConnection->ReadSockCB, CApp_TryRead, pConnection);
}
The following functions demonstrate how to gracefully close connections and free resources. RELEASEIF macro will be used to release the object. It will call ISOCKPORT_Release(), which will implicitly close the socket in the background if it is open.
#define RELEASEIF(pi) { if (pi) { IBASE_Release((IBase*)(pi)); (pi)=0; }}
CApp_ServerEnd() releases the server socket.
void CApp_ServerEnd(TCPServerSockPort* pServerSock)
{
CALLBACK_Cancel(&pServerSock->ListenSocketCB);
RELEASEIF(pServerSock->pListenSocket);
RELEASEIF(pServerSock->pIShell);
}
CApp_ConnClose() detaches one connection from the application's connection list, and releases it.
void CApp_ConnClose(TCPConnection* pConnection)
{
TCPConnection* pCurr = NULL;
TCPConnection* pPrev = NULL;

// release the connection's data
CALLBACK_Cancel(&pConnection->ReadSockCB);
CALLBACK_Cancel(&pConnection->WriteSockCB);
ISOCKPORT_Release(pConnection->pSock);

// remove this connection from the server's list
for (pCurr = pConnection->pme->m_pHead; pCurr != NULL; pCurr = pCurr->pNext)
{
if (pCurr == pConnection) {
if (NULL == pPrev) {
// the connection is in the head of the list
pConnection->pme->m_pHead = pCurr->pNext;
}
else {
pPrev->pNext = pCurr->pNext;
}
break;
}
pPrev = pCurr;
}

FREE(pConnection);
}

ISockPort - Writing a TCP server application
This section will demonstrate a TCP server application that exchanges data with clients over an ISockPort object. The application implements a rudimentary echo server. The steps demonstrated are as follows:

 

Data initialization.

Creating and opening an ISockPort object.

Binding a Sockport.

Listening on a Sockport.

Accepting new connections.

Reading data from a client.

Writing data to a client.

Closing connections.

The server application should define the following:
// define port number of the server
#define SERVER_PORT 7

// define the pending connections backlog size
#define BACKLOG_SIZE 3

// define message length
#define BUFFER_SIZE 100
The application will use the following structures to organize data needed for socket communication
// struct representing a single client-server connection
struct TCPConnection
{
CApp* pme; // pointer to the application
ISockPort* pSock; // the socket used for this connection
AEECallback ReadSockCB; // AEECallback for the connection's read operations
AEECallback WriteSockCB; // AEECallback for the connection's write operations
char szBuf[BUFFER_SIZE]; // data buffer
uint32 nTotalBytesToWrite; // num of bytes received from the client.
// which is also num of bytes the
// server should echo
uint32 nBytesWritten; // number of bytes already written to client

TCPConnection* pNext; // pointer to the next element in the list.
};

// struct representing the server socket
struct TCPServerSockPort
{
ISockPort* pListenSocket; // the SockPort itself
AEECallback ListenSocketCB; // callback for the socket
AEESockAddrStorage Sockaddr; // socket address struct
};
Among others, the applet should have the follwoing members:
IShell* m_pIShell, // IShell pointer
TCPServerSockPort m_TCPServerSockPort; // pointer to a TCPServerSockPort object
TCPConnection* m_pHead; // head of singly-linked list of connections
Initialization of the address structure should be also carried out:
// initialize the addresses.
pme->m_TCPServerSockPort.Sockaddr.wFamily = AEE_AF_INET; // IPv4 socket
pme->m_TCPServerSockPort.Sockaddr.inet.port = HTONS(SERVER_PORT); // set port number
pme->m_TCPServerSockPort.Sockaddr.inet.addr = HTONL(AEE_INADDR_ANY); // set IP address to any available address.
For having a functional ISockport object, the following stages must be performed:

 

Calling IShell_CreateInstance(), to create an ISockPort object.

Calling ISockPort_OpenEx(), to open the SockPort.

 
void CApp_StartTCPServer(void* po)
{
int ret;
CApp* pme = (CApp*)po;
TCPServerSockPort* pSock = &(pme->m_TCPServerSockPort);

// create the ISockPort object.
ret = ISHELL_CreateInstance(pSock->pIShell, AEECLSID_SOCKPORT, (void**)&(pSock->pListenSocket));
if (SUCCESS != ret) {
// handle the error
...
return;
}

// open the SockPort.
ret = ISOCKPORT_OpenEx(pSock->pListenSocket, // ISockPort pointer
AEE_AF_INET, // wFamily = IPv4
AEE_SOCKPORT_STREAM, // socket type = TCP
0 // Protocol type:
// Use 0 (recommended) to let the system select its default
// protocol for the given address family and socket type
);
if (SUCCESS != ret) {
// handle the error
...
return;
}
}
The server SockPort has to be bound. The example function CApp_TryBind() attempts to bind the SockPort, using ISOCKPORT_Bind(). It then handles all the possible values ISOCKPORT_Bind() may return:

 

AEEPORT_WAIT - the operation cannot be completed at present. Often, this is because the system needs to establish a data connection between the phone and the cellular network on which the TCP data can be transmitted. In this case - call ISOCKPORT_WriteableEx() and register CApp_TryBind() as a callback, to be called again when the bind operation can make a progress.

ret != SUCCESS - an error occurred. ret holds the error code.

ret == SUCCESS - operation succeeded.

Note that ISOCKPORT_Bind() returns the error code, and there is no need to explicitly get it using ISOCKPORT_GetLastError().
void CApp_TryBind(void* po)
{
int ret;
CApp* pme = (CApp*)po;
TCPServerSockPort* pSock = &(pme->m_TCPServerSockPort);

// use AEE_INADDR_ANY for binding
ret = ISOCKPORT_Bind(pSock->pListenSocket, &(pSock->Sockaddr));
if (AEEPORT_WAIT == ret) {
ISOCKPORT_WriteableEx(pSock->pListenSocket, &pSock->ListenSocketCB, CApp_TryBind, pme);
return;
}
else if (SUCCESS != ret) {
// ret holds the error code
// release resources
CApp_ServerEnd(pSock);
...
return;
}

// the SockPort is bound, try to listen.
CApp_TryListen(pme);
...
}

Note that in TCPServerSockPort.Sockaddr, inet.addr was set to AEE_INADDR_ANY. Currently, this is the only supported option for bind operation. Once the SockPort is bound, it may listen to incoming connections. Once bound to an address, the SockPort may listen for incoming connections requests. CApp_TryListen() calls ISOCKPORT_Listen(), and then handles all the possible values ISOCKPORT_Listen() may return:

 

AEEPORT_WAIT - the operation cannot be completed at present. Often, this is because the system needs to establish a data connection between the phone and the cellular network on which the TCP data can be transmitted. In this case - call ISOCKPORT_WriteableEx() and register CApp_TryListen() as a callback, to be called again when the listen operation can make a progress.

ret != SUCCESS - an error occurred. ret holds the error code.

ret == SUCCESS - operation succeeded.

When the SockPort is listening, it may attempt to accept incoming connections.
void CApp_TryListen(void* po)
{
int ret;
CApp* pme = (CApp*)po;
TCPServerSockPort* pSock = &(pme->m_TCPServerSockPort);

ret = ISOCKPORT_Listen(pSock->pListenSocket, BACKLOG_SIZE);
if (AEEPORT_WAIT == ret) {
ISOCKPORT_WriteableEx(pSock->pListenSocket, &pSock->ListenSocketCB, CApp_TryListen, pme);
return;
}

if (SUCCESS != ret)
{
// ret holds the error code
// release resources
CApp_ServerEnd(pSock);
...
return;
}

// try accepting new connections
CApp_TryAccept(pme);
}
The server socket is now ready to accept clients' "connect" requests. The example function CApp_TryAccept() uses ISOCKPORT_Accept() for accepting incomming "connect" requests. If AEEPORT_WAIT is returned, it registers itself as a callback to be called when the accept operation may progress. After a connection was established, the server application may exchange data with the client through the new SockPort created during ISOCKPORT_Accept(). Before doing so, CApp_TryAccept() does two things:

 

It calls ISOCKPORT_ReadableEx() again, thus registering itself for accepting subsequent "connect" requests. Since Brew applications must not block, the user should use the callback mechanism to wait for incoming "connect" requests.

It allocates and initializes the data structures representing the new connection.

In this example, the application will attempt to read data from the client, and write it back to the client (echo).
void CApp_TryAccept(void* po)
{
int ret;
ISockPort* pTmpSocket;
TCPConnection* pConnection;
CApp* pme = (CApp*)po;
TCPServerSockPort* pServerSock = &(pme->m_TCPServerSockPort);

// accept a request. pTmpSocket will point to the newly created socket
ret = ISOCKPORT_Accept(pServerSock->pListenSocket, &pTmpSocket);
if (AEEPORT_WAIT == ret) {

// the request is blocked. Register CApp_TryAccept() as a callback
// to be called again when accept operation may progress.
ISOCKPORT_ReadableEx(pServerSock->pListenSocket, &pServerSock->ListenSocketCB, CApp_TryAccept, pme);
return;
}

if (SUCCESS != ret) {

// operation failed, release resources
CApp_ServerEnd(pServerSock);

// ret holds the error code, handle it
...
return;
}

// ISOCKPORT_Accept() succeeded.
// Register CApp_TryAccept() as a callback, for accepting further incoming "connect" requests.
ISOCKPORT_ReadableEx(pServerSock->pListenSocket, &pServerSock->ListenSocketCB, CApp_TryAccept, pme);

// allocate struct for holding the new connection's data
pConnection = MALLOCREC(TCPConnection);
if (!pConnection) {
// allocation failed - reject the connection
ISOCKPORT_Release(pTmpSocket);
return;
}

// init the connection's struct
pConnection->pme = pme;
pConnection->pSock = pTmpSocket;
pConnection->nBytesWritten = 0;
pConnection->nTotalBytesToWrite = 0;

// insert the new connection at head of the server's connections list
pConnection->pNext = pme->m_pHead;
pme->m_pHead = pConnection;

// wait for an incoming data on this connection.
CApp_TryRead(pConnection);
}
The example function - CApp_TryRead() - shown below, attempts to read data from a client, using ISOCKPORT_Read(). It then handles all the possible values ISOCKPORT_Read() may return:

 

nRead == AEEPORT_WAIT - the system can't read data at this time. Often, this is because the system needs to establish a data connection between the phone and the cellular network on which the TCP data can be received. In this case - call ISOCKPORT_ReadableEx() and register ISOCKPORT_Read() as a callback, to be called again when the read operation can make a progress.

nRead == AEEPORT_ERROR - an error occurred. Check the error code.

nRead == AEEPORT_CLOSED - no more data to be read, connection was closed by the client.

nRead > 0 - data bytes were read. Write them back to the client.

 
void CApp_TryRead(TCPConnection* pConnection)
{
int32 nRead;

// read the data
nRead = ISOCKPORT_Read(pConnection->pSock,
pConnection->szBuf,
sizeof(pConnection->szBuf));

if (AEEPORT_WAIT == nRead) {
ISOCKPORT_ReadableEx(pConnection->pSock, &pConnection->ReadSockCB, CApp_TryRead, pConnection);
return;
}

// an error occurred
if (AEEPORT_ERROR == nRead) {
// get the error code and close the connection
nRead = ISOCKPORT_GetLastError(pConnection->pSock);
CApp_ConnClose(pConnection);
...
return;
}

// connection was closed by the distant socket
if (AEEPORT_CLOSED == nRead) {
// close the connection
CApp_ConnClose(pConnection);
...
return;
}

// increment num of bytes read from the connection
pConnection->nTotalBytesToWrite = nRead;
pConnection->nBytesWritten = 0;

// echo the data back to the client
CApp_TryWrite(pConnection);
}
The example function - CApp_TryWrite() - shown below, attempts to write data to a client, using ISOCKPORT_Write(). It then handles all the possible values ISOCKPORT_Write() may return:

 

nWrite == AEEPORT_WAIT - the system can't write data at this time. Often, this is because the system needs to establish a data connection between the phone and the cellular network on which the TCP data can be transmitted. In this case - call ISOCKPORT_WriteableEx() and register CApp_TryWrite() as a callback, to be called again when the write operation can make a progress.

nWrite == AEEPORT_ERROR - an error occurred. Check the error code.

nWrite == AEEPORT_CLOSED - connection was closed by the client.

nWrite > 0 - Data bytes were written. If not all the data was written - wait until a further write may progress. If all the bytes were written - try to read data from the client.

 
void CApp_TryWrite(TCPConnection* pConnection)
{
int32 nWrite;

// write the data
nWrite = ISOCKPORT_Write(pConnection->pSock,
(pConnection->szBuf + pConnection->nBytesWritten),
(pConnection->nTotalBytesToWrite - pConnection->nBytesWritten)
);

if (AEEPORT_WAIT == nWrite) {
ISOCKPORT_WriteableEx(pConnection->pSock, &pConnection->WriteSockCB, CApp_TryWrite, pConnection);
return;
}

// an error occurred
if (AEEPORT_ERROR == nWrite) {
// get the error code and close the connection
nWrite = ISOCKPORT_GetLastError(pConnection->pSock);
CApp_ConnClose(pConnection);
...
return;
}

// connection was closed by the distant socket
if (AEEPORT_CLOSED == nWrite) {
// close the connection
CApp_ConnClose(pConnection);
...
return;
}

// update num of bytes written.
pConnection->nBytesWritten += nWrite;

// in case of partial write register a callback to be called when further write can progress.
if (pConnection->nBytesWritten < pConnection->nTotalBytesToWrite) {
ISOCKPORT_WriteableEx(pConnection->pSock, &pConnection->WriteSockCB, CApp_TryWrite, pConnection);
return;
}

// all bytes were written.
// wait for an incoming packet
ISOCKPORT_ReadableEx(pConnection->pSock, &pConnection->ReadSockCB, CApp_TryRead, pConnection);
}
The following functions demonstrate how to gracefully close connections and free resources. RELEASEIF macro will be used to release the object. It will call ISOCKPORT_Release(), which will implicitly close the socket in the background if it is open.
#define RELEASEIF(pi) { if (pi) { IBASE_Release((IBase*)(pi)); (pi)=0; }}
CApp_ServerEnd() releases the server socket.
void CApp_ServerEnd(TCPServerSockPort* pServerSock)
{
CALLBACK_Cancel(&pServerSock->ListenSocketCB);
RELEASEIF(pServerSock->pListenSocket);
RELEASEIF(pServerSock->pIShell);
}
CApp_ConnClose() detaches one connection from the application's connection list, and releases it.
void CApp_ConnClose(TCPConnection* pConnection)
{
TCPConnection* pCurr = NULL;
TCPConnection* pPrev = NULL;

// release the connection's data
CALLBACK_Cancel(&pConnection->ReadSockCB);
CALLBACK_Cancel(&pConnection->WriteSockCB);
ISOCKPORT_Release(pConnection->pSock);

// remove this connection from the server's list
for (pCurr = pConnection->pme->m_pHead; pCurr != NULL; pCurr = pCurr->pNext)
{
if (pCurr == pConnection) {
if (NULL == pPrev) {
// the connection is in the head of the list
pConnection->pme->m_pHead = pCurr->pNext;
}
else {
pPrev->pNext = pCurr->pNext;
}
break;
}
pPrev = pCurr;
}

FREE(pConnection);
}

I will try this code, but there is something I do not understand. In the ISockPort_CreateInstance(), pSock->piShell is used.  But the TCPServerSockPort structure does not have a piShell.  This also used in the ServerEnd().  Should I create the instance with the piShell of my app? Or was the IShell * left out of the TCPServerSockPort structure?

I will try this code, but there is something I do not understand. In the ISockPort_CreateInstance(), pSock->piShell is used.  But the TCPServerSockPort structure does not have a piShell.  This also used in the ServerEnd().  Should I create the instance with the piShell of my app? Or was the IShell * left out of the TCPServerSockPort structure?

looks like its a mistake. It should be pme->m_pIShell in both places.
also note as a general rule that IShell is sought of Kernal core interface/class, instance of it is provided at the start of the Applet by Brew & the same should be used for any other operations that require the IShell instace.

looks like its a mistake. It should be pme->m_pIShell in both places.
also note as a general rule that IShell is sought of Kernal core interface/class, instance of it is provided at the start of the Applet by Brew & the same should be used for any other operations that require the IShell instace.