home *** CD-ROM | disk | FTP | other *** search
/ Palm Utilities / Palm_Utilities_CD-ROM_2001_2001.iso / files / internet misc / GetTLE 1.0 / GetTLE.exe / Src / tcpip.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-04-18  |  9.6 KB  |  348 lines

  1. /*
  2.     tcpip.c - Handling of TCP/IP networking
  3.     Copyright ⌐2000 Andreas Schneider
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. */
  19.  
  20. /*  This is a general purpose implementaion of TCP/IP networking
  21.     utility routines for PalmOS that I found quite useful for my
  22.     own programs. They are designed in a way that you can compile and
  23.     test them under Linux. It is far from complete and only contains
  24.     routines that I personally find useful. Feel free to add useful
  25.     stuff, but do remember that this software is distributed under
  26.     the GNU GPL licence. Any improvements you make to this code
  27.     must therefore be made available as source code. Why not send 
  28.     a patch file or something like that to andreas@riverrun.co.uk?
  29. */
  30.  
  31. #ifdef linux
  32. // includes and defines to compile with Linux
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <sys/socket.h>
  36. #include <netinet/in.h>
  37. #include <arpa/inet.h>   
  38. #include <netdb.h>
  39. #include <unistd.h>
  40. #include <errno.h>
  41. #include "tcpip.h" // Stuff for this file
  42. #else
  43. // The includes for PalmOS
  44. #include <PalmOs.h>
  45. #include <sys_socket.h> // Use Berkeley sockets headers, not NetLib
  46. #include <unix_stdarg.h>
  47. #include "tcpip.h" // Stuff for this file
  48. #endif
  49.  
  50. static const char CR = '\r';
  51. static const char LF = '\n';
  52.  
  53. static tcpipStatusCallback status_callback=NULL;
  54. static tcpipErrorCallback error_callback=NULL;
  55. static tcpipDebugCallback debug_callback=NULL;
  56. // first the functions for callbacks
  57. extern void TcpipSetStatusCallback(tcpipStatusCallback function)
  58. {
  59.   status_callback=function;
  60.   return;
  61. }
  62.  
  63. extern void TcpipSetErrorCallback(tcpipErrorCallback function)
  64. {
  65.   error_callback=function;
  66.   return;
  67. }
  68.  
  69. extern void TcpipSetDebugCallback(tcpipDebugCallback function)
  70. {
  71.   debug_callback=function;
  72.   return;
  73. }
  74.  
  75. // now 3 functions with safeguards
  76. #if 0 // not needed yet
  77. static void PrintStatus(char *message)
  78. {
  79.   if (status_callback)
  80.   {
  81.     (*status_callback)(message);
  82.   }
  83.   return;
  84. }
  85. #endif
  86.  
  87. static void PrintError(char *error,char *more)
  88. {
  89.   if (error_callback)
  90.   {
  91.     (*error_callback)(error,more);
  92.   }
  93. }
  94.  
  95. static void PrintDebug(char *format,...)
  96. {
  97.   va_list args;
  98.   
  99.   if (debug_callback)
  100.   {
  101.     va_start(args,format);
  102.     (*debug_callback)(format,args);
  103.     va_end(args);
  104.   }
  105.   return;
  106. }
  107.  
  108. // first a few utility functions:
  109.  
  110. // Converts a service name into a port number
  111. static int ServiceToPort(char *service,char *protocol)
  112. {
  113.   int port=-1;
  114.     struct servent *serv=NULL;
  115.     
  116.     serv=getservbyname(service,protocol);
  117.     if (serv!=NULL)
  118.     {
  119.       port=serv->s_port;
  120.     }
  121. #ifndef linux
  122.   // in PalmOS http is not a valid service name
  123.   // we must therefore handle that case ourselves
  124.   // maybe I should add afew more here or even better
  125.   // have a SetService(string,port) function? Later...
  126.   if (StrCompare(service,"http")==0)
  127.   {
  128.     port=80;
  129.   }
  130. #endif
  131.     return port;
  132. }
  133.  
  134. // Converts ascii text to in_addr struct.  
  135. // NULL is returned if the address can not be found.
  136. static struct in_addr *StrToAddr(char *address)
  137. {
  138.   struct hostent *host;
  139.   static struct in_addr saddr;
  140.  
  141.   // First try it as aaa.bbb.ccc.ddd.
  142.   saddr.s_addr = inet_addr(address);
  143.   if (saddr.s_addr != -1)
  144.   {
  145.     PrintDebug("Address was an IP\n");
  146.     return &saddr;
  147.   }
  148.   // that didn't work - look it up
  149.   host = gethostbyname(address);
  150.   if (host != NULL)
  151.   {
  152.       PrintDebug("Address was a hostname\n");
  153.     return (struct in_addr *) *host->h_addr_list;
  154.   }
  155.   // didn't work either - probably doesn't exist
  156.     PrintDebug("Address couldn't be resolved\n");
  157.   return NULL;
  158. }
  159.  
  160. // Make a connection to a given server/protocol/service.
  161. // The function returns a socket.
  162. // It's basically the usual Berkeley socket stuff
  163. // buffer is an optional buffer to buffer received data in a buffer :-)
  164. extern Socket MakeConnection(char *service,char *protocol,char *host_address,
  165.                char *buffer,size_t buffer_len)
  166. {
  167.   Socket sock={0};
  168.   struct in_addr *addr;
  169.   int connected;
  170.   struct sockaddr_in address;
  171.     int port=-1;
  172.  
  173.   // initialize the socket field to 'no socket'
  174.   sock.socket=-1;
  175.   // first convert the hostname/IP to a struct in_addr
  176.   if((addr = StrToAddr(host_address))==NULL)
  177.   {
  178.     PrintError("MakeConnection: Invalid host address", host_address);
  179.     return sock;
  180.   }
  181.     // now convert the service name to a port number
  182.     if((port=ServiceToPort(service,protocol))<0)
  183.     {
  184.       PrintError("MakeConnection: Invalid service name",service);
  185.       return sock;
  186.     }
  187.   // now set up the structures for the socket() call
  188.   memset((char *) &address, 0, sizeof(address));
  189.   address.sin_family = AF_INET;
  190.   address.sin_port = port;
  191.   address.sin_addr.s_addr = addr->s_addr;
  192.   sock.buffer=buffer;
  193.   sock.buffer_len=buffer_len;
  194.   sock.buffer_content=0; // initially nothing in buffer
  195.   sock.buffer_index=0;
  196.   sock.socket = socket(AF_INET, SOCK_STREAM, 0);
  197.     if (sock.socket==-1)
  198.     {
  199.       PrintError("Call to socket() failed",NULL);
  200.         return sock;
  201.     }
  202.     PrintDebug("Socket is %i\n",sock.socket);
  203.     PrintDebug("Port is %i\n",port);
  204.   connected = connect(sock.socket, (struct sockaddr *) &address,sizeof(address));
  205.   if (connected < 0)
  206.   {
  207.     sock.socket=-1;
  208.       PrintDebug("connect failed: %i\n",errno);
  209.       PrintError("connect", NULL);
  210.     return sock;
  211.   }
  212.   return sock;
  213. }
  214.  
  215. // send num_bytes of buffer over socket sock
  216. // might send it in smaller chuncks if necessary
  217. extern int SocketWrite(Socket *sock, char *buffer, unsigned int num_bytes)
  218. {
  219.     unsigned int    num_left;
  220.     int    chunk;
  221.     int num_written;
  222.  
  223.     num_left = num_bytes;
  224.     while (num_left > 0)
  225.     {
  226.         if (num_left > 0x7000) // limit amount to send
  227.         {
  228.           chunk = 0x7000; // too big
  229.         }
  230.         else 
  231.         {
  232.           chunk = num_left; // can send all
  233.         }
  234.         num_written = write(sock->socket, buffer, chunk);
  235.         if (num_written <= 0)
  236.         {
  237.           //error
  238.             return(num_written);
  239.     }
  240.         num_left -= num_written;
  241.         buffer   += num_written;
  242.     }
  243.     return(num_bytes - num_left); // hopefully == num_bytes
  244. }
  245.  
  246. extern int SocketReadByte(Socket *sock, char *byte)
  247. {
  248.   int bytes_read=0;
  249.   if (sock->buffer==NULL)
  250.   {
  251.     // the easy case - no buffer, read 1 directly from the socket
  252.     bytes_read=read(sock->socket,byte,1);
  253.   }
  254.   else
  255.   {
  256.     // bit more tricky, but hopefully faster...
  257.     if (sock->buffer_index>=sock->buffer_content)
  258.     {
  259.       // buffer_index points beyond end of buffer content
  260.       // get more data
  261.       bytes_read=read(sock->socket,sock->buffer,sock->buffer_len);
  262.       PrintDebug("[%u]",bytes_read);
  263.       if (bytes_read<=0)
  264.       {
  265.         // something went wrong
  266.         return bytes_read;
  267.       }
  268.       // we got more data (at least one byte)
  269.       sock->buffer_content=bytes_read;
  270.       sock->buffer_index=0;
  271.     }
  272.     // now we can return a byte
  273.     *byte=sock->buffer[sock->buffer_index];
  274.     sock->buffer_index++;
  275.     bytes_read=1;
  276.   }
  277.   return bytes_read;
  278. }
  279.  
  280. // This function reads from a socket (a character at time) until it recieves
  281. // a linefeed character. It fills the 'buffer' up to the maximum size 'count'-1
  282. // Carriage returns and linefeeds are not included in the line.
  283. // A trailing \0 will be added to the line.
  284. // This function will return -1 if the socket is closed during the read.
  285. // Note that if a single line exceeds the length of count, the extra data
  286. // will be read but discarded.
  287. extern int SocketReadLine(Socket *sock, char *buffer, size_t buffer_size)
  288. {
  289.   int bytes_read;
  290.   int total_count = 0;
  291.   char *current_position;
  292.   char char_read = 0;
  293.  
  294.   // start at the beginning of the buffer
  295.   current_position = buffer;
  296.   // loop done at least once
  297.   while (char_read!=LF) // wait for \n or \r\n
  298.   {
  299.     // read a single character from the socket
  300.     bytes_read = SocketReadByte(sock, &char_read);
  301.     // check for error
  302.     if (bytes_read < 0)
  303.     {
  304.       // < 0 is an error code
  305.       PrintDebug("SocketReadLine error #%i\n",bytes_read);
  306.       return bytes_read;
  307.     }
  308.     else if (bytes_read==0)
  309.     {
  310.       // this happens if the connection was closed by the other side
  311.       // we return -1 to indicate a problem. We can't return 0 because
  312.       // that's what we return when we read an empty line
  313.       PrintDebug("SocketReadLine: connection closed\n");
  314.       return -1;
  315.     }
  316.     // check if we want to include the character in the line
  317.     if ((total_count < buffer_size-1) && // only if line not too long
  318.         (char_read!=LF) && (char_read!=CR)) // and no CR/LFs
  319.     {
  320.       // we want this character - store it
  321.       *current_position = char_read;
  322.       // PrintDebug("%c",char_read);
  323.       current_position++;
  324.       total_count++;
  325.     }
  326.     else
  327.     {
  328.       // well, nothing else - excess data and CR/LFs are discarded
  329.     }
  330.   }
  331.   // end of loop - we must have come across the end of the line
  332.   // now terminate the buffer with a \0
  333.   // PrintDebug("[EOL]");
  334.   *current_position = 0;
  335.   return total_count;
  336. }
  337.  
  338. extern void SocketClose(Socket *sock)
  339. {
  340.   // does what you think it does
  341.   if (sock->socket>0)
  342.     {
  343.       close(sock->socket);
  344.         sock->socket=-1;
  345.     }
  346.     return;
  347. }
  348.