Hi all,

I'm having a problem with NetLibSend and NetLibReceive. I am using 
NetLibSend/Receive to talk to a web server. I have been able to use the HTTP 
POST method to send small amounts of data (about 100 bytes), but whenever I try 
to send lots of data (say 2k-4k), NetLibSend reports success, but NetLibReceive 
times out. 

According to my web server, I can see the access for the small POST, but the 
large POST doesn't even appear.

When I run the program on the Palm simulator, all posts succeed! It is only on 
the device that large posts just don't work.

Is there a problem with sending out k's of data using NetLibSend, that it would 
report success but not really send the data? Is it a problem with just the Palm 
Treo (device I'm using)?

Here is the code I'm using to do the HTTP protocol. There's a lot of stuff 
here, but the main method is at the bottom, httpPost.

static string urlencode(char *s)
{
        string ret = s;
        char tmp[4];
        char hex[5];
        
        for (string::size_type i=0; i<ret.length(); i++)
        {
                if (TxtCharIsAlNum(ret[i]))
                        continue;
                StrPrintF(hex, "%4x", ret[i]);
                StrPrintF(tmp, "%%%s", hex+2); // skip over leading two zero's.
                ret.replace(i, 1, tmp);
                i++; // yeah, I know, we should skip over the hex digits, but 
I'm lazy.
        }
        
        return ret;
}

/******************************************************
 * 
 * Caches whether we have already opened the network
 * library, and whether it was opened successfully or
 * not.
 * 
 * Returns false if the network couldn't be found or
 * couldn't be opened.
 * 
 * Returns true if the network was successfully opened.
 * 
 * ****************************************************/
 
static Boolean isNetPresent()
{
        Err error;
        UInt16 ifErrs;
        
        if (netFeature == NO)
                return false;
        else if (netFeature == YES)
                return true;
                
        if (SysLibFind("Net.lib", &netLibRefNum))
        {
                netFeature = NO;
                return false;
        }
        
        error = NetLibOpen(netLibRefNum, &ifErrs);
        if (ifErrs || (error && error != netErrAlreadyOpen))    
        {
                netFeature = NO;
                return false;
        }

        netFeature = YES;       
        return true;
}

static NetSocketRef connectTo(const char *host, UInt16 port, Err* error,
                                                                UInt16 
statusFormID, UInt16 statusLabelID)
{
        NetSocketRef socket;
        NetSocketAddrINType destAddr;
        NetHostInfoBufType hostbuf;
        Int16 result;
        
        if (!isNetPresent())
        {
                *error = netErrNotOpen;
                return -1;
        }
        
        *error = 0;    
        connectionState = ConnectionState::SOCKET_OPEN;
        socket = NetLibSocketOpen(netLibRefNum,        // Network library
                              netSocketAddrINET,   // Address domain
                              netSocketTypeStream, // Socket type
                              netSocketProtoIPTCP, // Protocol
                              SysTicksPerSecond()/2,   // Timeout
                              error               // Error result
                              );
                              
    if (*error)
                return -1;
    
    if (statusFormID != 0)
            ShowResult(LOGIN_GETHOST, statusFormID, statusLabelID);
    
        *error = 0;    
        connectionState = ConnectionState::FIND_HOST;
    NetLibGetHostByName(netLibRefNum,
                                        host,
                                        &hostbuf,
                                        SysTicksPerSecond()*3,          // 
Timeout
                                        error);
                                                           
    if (*error)
                return -1;    
    
    MemSet(&destAddr, sizeof(destAddr), 0);
        destAddr.family = netSocketAddrINET; // This should match the second 
argument to NetLibSocketOpen
        destAddr.port = port;
        destAddr.addr = hostbuf.address[0];
        
    if (statusFormID != 0)
                ShowResult(LOGIN_CONNECT, statusFormID, statusLabelID);
        
        *error = 0;    
        connectionState = ConnectionState::SOCKET_CONNECT;
    result = NetLibSocketConnect(netLibRefNum,                  // Network 
library
                                 socket,                        // Socket 
reference
                                 (NetSocketAddrType*)&destAddr, // Destination 
address
                                 sizeof(destAddr),              // Length of 
destAddr
                                 SysTicksPerSecond()*CONNECT_TIMEOUT,        // 
Timeout
                                 error                         // Error result
                                 );
    
    if (result)
    {
        return -1;
    }

        return socket;    
}

static void closeSocket(NetSocketRef socket)
{
        Err ignore;
        
        NetLibSocketClose(netLibRefNum, socket, -1, &ignore);
}


static char readBuffer[256];
static UInt16 bufferSize;
static UInt16 readPtr;

static void initializeBufferedRead()
{
        bufferSize = 0;
        readPtr = 0;
}


// This is done just because when the PalmOS Simulator runs the code, 
NetLibReceive
// does not time out if there is no data.

static Int16 _NetLibReceive(UInt16 libRefNum, NetSocketRef socket, 
        void *bufP, UInt16 bufLen, UInt16 flags, void *fromAddrP, 
        UInt16 *fromLenP, Int32 timeout, Err *errP)
{
        NetFDSetType none;
        NetFDSetType readfds;
        Int16 numfds;
        
        netFDZero(&none);
        netFDZero(&readfds);
        netFDSet(socket, &readfds);
        
        numfds = NetLibSelect(libRefNum,
                                                        socket+1,
                                                        &readfds,
                                                        &none,
                                                        &none,
                                                        timeout,
                                                        errP);
                                                        
        if (numfds == 0)
        {
                *errP = netErrTimeout;
                return -1;
        }
        
        if (numfds == -1)
                return -1;
        
        return NetLibReceive(libRefNum,
                                                   socket,
                                                   bufP,
                                                   bufLen,
                                                   flags,             // flags
                                                   fromAddrP,
                                                   fromLenP,
                                                   0, // timeout
                                                   errP);
}

/*******************************************************
 * 
 * Read one character from a socket.
 * 
 * Returns the character read, or -1 if there was an error
 * (and error contains the error) or if the socket closed
 * (and error is 0 -- end of stream)
 * ******************************************************/
 
static int bufferedRead(NetSocketRef socket, Err *error, Int16 timeout)
{
        *error = 0;
        
        if (readPtr == bufferSize)
        {
                // refill buffer
                
                NetSocketAddrType senderAddr;
                UInt16 senderAddrLen = sizeof(senderAddr);
                Int16 result;
                
                // Use _NetLibReceive for emulator
                // Use NetLibReceive for release
                
                connectionState = ConnectionState::READ_RESPONSE;
                result = NetLibReceive(netLibRefNum,
                                                           socket,
                                                           readBuffer,
                                                           sizeof(readBuffer),
                                                           0,             // 
flags
                                                           &senderAddr,
                                                           &senderAddrLen,
                                                           timeout,
                                                           error);

                if (result == -1 || result == 0)
                        return -1;
                        
                bufferSize = result;
                readPtr = 0;            
        }
        
        return readBuffer[readPtr++];
}

/*************************************
 * 
 * Read a block of data.
 * 
 * Returns number of characters actually read. If the number of characters
 * actually read is less than the requested size, check error
 * ************************************/
 
static int bufferedReadArray(NetSocketRef socket, char *buf, int size, 
                                                        Err *error, Int16 
timeout)
{
        int i;
        *error = 0;
        
        for (i=0; i<size; i++)
        {
                int c;
                c = bufferedRead(socket, error, timeout);
                if (c == -1)
                        return i;
                buf[i] = c;
        }
        return i;
}


Boolean httpPost(Err *error, char *host, UInt16 port, char *resource,
                                        char *postData, UInt16 postSize,
                                        MemHandle *response,
                                        Int16 responseTimeout,
                                        UInt16 statusFormID, UInt16 
statusLabelID,
                                        string *sresponse = NULL)
{
        NetSocketRef socket;
        Int16 result;
        UInt16 sentBytes;
        UInt16 bufLen;
        char buf[512];
        
        
        socket = connectTo(host, port, error, statusFormID, statusLabelID);
        
        if (socket == -1)
                return false;
                        
        if (statusFormID != 0)
                ShowResult(LOGIN_SEND_REQUEST, statusFormID, statusLabelID);
        
        StrPrintF(buf, "POST %s HTTP/1.0\r\n"
                       "User-Agent: Palm Hacked HTTP/0.0\r\n"
                       "Host: %s\r\n"
                       "Content-Length: %u\r\n\r\n",
                       resource, host, postSize);
                       
        connectionState = ConnectionState::WRITE_REQUEST;
                       
        bufLen = StrLen(buf);
        sentBytes = 0;  
    while (sentBytes < bufLen) {
      result = NetLibSend (netLibRefNum,       // Network library
                           socket,             // Socket reference
                           buf + sentBytes,    // Buffer to send
                           bufLen - sentBytes, // Bytes to send from buffer
                           0,                  // Flags
                           NULL,               // Destination address -- does 
not apply to TCP sockets
                           0,                  // Length of destination address
                           SysTicksPerSecond()*3,   // Timeout
                           error              // Error result
                           );
      if (result == -1)
      {
        closeSocket(socket);
        return false;
      }

      sentBytes += result;
        }
        
        bufLen = postSize;
        sentBytes = 0;  
    while (sentBytes < bufLen) {
      result = NetLibSend (netLibRefNum,       // Network library
                           socket,             // Socket reference
                           postData + sentBytes,    // Buffer to send
                           bufLen - sentBytes, // Bytes to send from buffer
                           0,                  // Flags
                           NULL,               // Destination address -- does 
not apply to TCP sockets
                           0,                  // Length of destination address
                           SysTicksPerSecond()*3, // Timeout
                           error              // Error result
                           );
      if (result == -1)
      {
        closeSocket(socket);
        return false;
      }

      sentBytes += result;
      
          if (statusFormID != 0)
          {
                char tmpbuf[32];
                StrPrintF(tmpbuf, "Sent %d of %d bytes", sentBytes, postSize);
                ShowCustomResult(statusFormID, statusLabelID, tmpbuf);
          }
        }
        
        if (statusFormID != 0)
                ShowResult(LOGIN_WAIT_RESPONSE, statusFormID, statusLabelID);
        
        // Get status line, ignore reason phrase
        
        initializeBufferedRead();
        if (bufferedReadArray(socket, buf, 12, error, responseTimeout) != 12)
        {
                closeSocket(socket);
                return false;
        }
        
        if (statusFormID != 0)
                ShowCustomResult(statusFormID, statusLabelID, "Receiving 
response...");
                
        // make sure response is 200
        
        buf[12] = 0;
        if (StrCompare(buf+9, "200"))
        {
                closeSocket(socket);
                return false;
        }
        
        // ignore headers, get to the data
        
        while (true) {
                int c;
                
                c = bufferedRead(socket, error, responseTimeout);
                if (c == -1)
                {
                closeSocket(socket);
                        return false;
                }
                
                if (c == '\r')
                {
                        // see if next 3 characters are \n\r\n
                        
                        if (bufferedReadArray(socket, buf, 3, error, 
                                                                        
SysTicksPerSecond()) != 3)
                        {
                                closeSocket(socket);
                                return false;
                        }
                        
                        buf[3] = 0;
                        if (!StrCompare("\n\r\n", buf))
                                break;
                }               
                
        }
        
        // read the data, concat into response string
        
        if (sresponse == NULL)
                *response = 0;
        
        string str;
        int total = 0;
        
        while ( (bufLen = bufferedReadArray(socket, buf, sizeof(buf)-1,
                                                        error, 
responseTimeout)) > 0)
        {
                buf[bufLen] = 0;
                str += buf;
                total += bufLen;
                if (statusFormID != 0)
                {
                        StrPrintF(buf, "Read %d bytes", total);
                        ShowCustomResult(statusFormID, statusLabelID, buf);
                }
        }
        
        if (*error != 0)
        {
                closeSocket(socket);
                return false;
        }
        
        if (sresponse == NULL)
        {
                *response = MemHandleNew(str.length()+1);
                char *ptr = (char *)MemHandleLock(*response);
                StrCopy(ptr, str.c_str());
                MemHandleUnlock(*response);
        }
        else
                *sresponse = str;
        
        closeSocket(socket);
        return true;
}

-- 
For information on using the Palm Developer Forums, or to unsubscribe, please 
see http://www.palmos.com/dev/support/forums/

Reply via email to