home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mksockrw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  12.2 KB  |  472 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "mkutils.h"
  20. #include "mktcp.h"
  21. #include "mkparse.h"
  22. #include "mkgeturl.h"  /* for error codes */
  23. #include "fe_proto.h" /* for externs */
  24. #include "merrors.h"
  25. #include "ssl.h"
  26.  
  27. #include "xp_error.h"
  28.  
  29. extern int MK_HTTP_TYPE_CONFLICT;
  30. extern int XP_ERRNO_EWOULDBLOCK;
  31.  
  32. #ifdef XP_UNIX
  33. /* #### WARNING, this is duplicated in mkconect.c
  34.  */
  35. # include <sys/ioctl.h>
  36. /*
  37.  * mcom_db.h is only included here to set BYTE_ORDER !!!
  38.  * MAXDNAME is pilfered right out of arpa/nameser.h.
  39.  */
  40. # include "mcom_db.h"
  41.  
  42. # if defined(__hpux) || defined(_HPUX_SOURCE)
  43. #  define BYTE_ORDER BIG_ENDIAN
  44. #  define MAXDNAME        256             /* maximum domain name */
  45. # else
  46. #  include <arpa/nameser.h>
  47. # endif
  48.  
  49. #include <resolv.h>
  50.  
  51. #if !defined(__osf__) && !defined(AIXV3) && !defined(_HPUX_SOURCE) && !defined(__386BSD__) && !defined(__linux) && !defined(SCO_SV)
  52. #include <sys/filio.h>
  53. #endif
  54.  
  55. #endif /* XP_UNIX */
  56.  
  57. #ifdef PROFILE
  58. #pragma profile on
  59. #endif
  60.  
  61. /* Global TCP Read/Write variables
  62.  */
  63. PUBLIC char * NET_Socket_Buffer=0;
  64. PUBLIC int    NET_Socket_Buffer_Size=0;
  65.  
  66. #if defined(XP_UNIX) && defined(XP_BSD_UNIX)
  67.  
  68. PRIVATE char * net_real_socket_buffer_ptr=0;
  69.  
  70. #include <unistd.h>
  71. #include <malloc.h>
  72.  
  73. typedef unsigned int intptr_t;
  74.  
  75. char *GetPageAlignedBuffer(int size)
  76. {
  77.     char *rv;
  78.     static int pageSize = 0;
  79.  
  80.     if (pageSize == 0) 
  81.       {
  82.         /* Cache this value to avoid syscall next time */
  83.         pageSize = getpagesize();
  84.       }
  85.  
  86.     net_real_socket_buffer_ptr = 0;
  87.  
  88.     /* Allocate too much memory */
  89.     rv = (char *) XP_ALLOC(size + pageSize - 1);
  90.     if (rv) 
  91.       {
  92.         intptr_t r = (intptr_t) rv;
  93.         intptr_t offset = r & (pageSize - 1);
  94.  
  95.         net_real_socket_buffer_ptr = rv;
  96.  
  97.         if (offset) 
  98.           {
  99.             /* Have to round up address */
  100.             r = r + pageSize - offset;
  101.           } 
  102.         else 
  103.           {
  104.             /*
  105.             ** Could be generous here and realloc to shrink since we
  106.             ** don't need the extra space...
  107.             */
  108.           }
  109.         rv = (char*) r;
  110.       }
  111.     return rv;
  112. }
  113. #endif /* XP_UNIX */
  114.  
  115. /* allocate memory for the TCP socket
  116.  * buffer
  117.  */
  118. PUBLIC int
  119. NET_ChangeSocketBufferSize (int size)
  120. {
  121.     NET_Socket_Buffer_Size = 0;
  122.  
  123.     if(size < 1)
  124.         size = 10*1024; /* default */
  125.  
  126.     if(size > 31*1024)
  127.         size = 31*1024;
  128.  
  129. #if defined(XP_UNIX) && defined(XP_BSD_UNIX)
  130.     FREEIF(net_real_socket_buffer_ptr);
  131.     NET_Socket_Buffer = GetPageAlignedBuffer(size);
  132. #else
  133.     FREEIF(NET_Socket_Buffer);
  134.     NET_Socket_Buffer = (char *) XP_ALLOC(size);
  135. #endif /* XP_UNIX */
  136.  
  137.    if(!NET_Socket_Buffer)
  138.       return(0); 
  139.  
  140.    /* else */
  141.    NET_Socket_Buffer_Size = size;
  142.    return(1);
  143. }
  144.  
  145. /* this is a very standard network write routine.
  146.  * 
  147.  * the only thing special about it is that
  148.  * it returns MK_HTTP_TYPE_CONFLICT on special error codes
  149.  *
  150.  */
  151. PUBLIC int NET_HTTPNetWrite (PRFileDesc *fildes, CONST void * buf, unsigned int nbyte)
  152. {
  153.     static int status;
  154.   
  155.     status = (int) NET_BlockingWrite(fildes, buf, nbyte);
  156.  
  157. #ifdef XP_UNIX
  158.     /* these status codes only work on UNIX
  159.      */
  160.     if ((status < 0) 
  161.          && (status == PR_NOT_CONNECTED_ERROR || status == PR_CONNECT_RESET_ERROR || status == PR_PIPE_ERROR)) 
  162.         return MK_HTTP_TYPE_CONFLICT;
  163. #endif /* XP_UNIX */
  164.  
  165.     /* else */
  166.     return(status);
  167. }
  168.  
  169. PUBLIC int32 NET_BlockingWrite (PRFileDesc *filedes, CONST void * buf, unsigned int nbyte)
  170. {
  171.     int32 length_written = 1;
  172.     unsigned int tot_len_written = 0; 
  173.  
  174.     while(nbyte > 0 && length_written > -1)
  175.       {
  176.         length_written = PR_Write(filedes, (const char*) buf+tot_len_written, nbyte);
  177.         
  178.         if(length_written > -1)
  179.           {
  180.             nbyte -= (unsigned int) length_written;
  181.             tot_len_written += (unsigned int) length_written;
  182.           }
  183.         else
  184.           {
  185.             int rv = PR_GetError();
  186.             if(rv == PR_WOULD_BLOCK_ERROR)
  187.              {
  188. #if defined(XP_WIN) && defined(MOZILLA_CLIENT)
  189.                FEU_StayingAlive();
  190. #endif
  191.                length_written = 1; /* this will let it continue looping */
  192.              }
  193.             else
  194.               {
  195.                 return (rv < 0) ? rv : (-rv);
  196.               }
  197.           }
  198.       }
  199.  
  200.     return(length_written); /* postive or negative */
  201. }
  202.  
  203. #ifdef DEBUG
  204. /* only a debugging routine!
  205.  * Prints the output to stderr as well as the socket
  206.  */
  207. MODULE_PRIVATE int 
  208. NET_DebugNetWrite (PRFileDesc *fildes, CONST void *buf, unsigned nbyte)
  209. {
  210.   if(MKLib_trace_flag && nbyte > 0)
  211.     {
  212. #ifdef XP_UNIX
  213.        write(2, "Tx: ", 4);
  214.        write(2, buf, nbyte);
  215.        write(2, "\n", 1);
  216. #endif
  217.     }
  218.  
  219.   return(PR_Write(fildes, buf, nbyte));
  220. }
  221.  
  222. /* This is a pretty standard read routine for debugging
  223.  *
  224.  * It prints whatever it reads to stderr for debugging purposes
  225.  */
  226. MODULE_PRIVATE int
  227. NET_DebugNetRead (PRFileDesc *fildes, void * buf, unsigned nbyte)
  228. {
  229.   static int status;  /* read return code */
  230.  
  231.   status = PR_Read (fildes, buf, nbyte);
  232.  
  233.   if(MKLib_trace_flag && status != PR_SUCCESS)
  234.     {
  235. #ifdef XP_UNIX
  236.       write(2,"Rx: ", 4);
  237.       write(2, (const char *)buf, status);
  238.       write(2, "\n", 1);
  239. #endif
  240.     }
  241.  
  242.   return(status);
  243. }
  244. #endif /* DEBUG */
  245.  
  246.  
  247. /* This is a pretty standard read routine
  248.  *
  249.  * The only special thing that is does is
  250.  * that it checks for the special errors encountered
  251.  * in a HTTP 1/.9 conflict and returns MK_HTTP_TYPE_CONFLICT
  252.  * when encountered
  253.  */
  254. /* fix Mac warning of missing prototype */
  255. MODULE_PRIVATE int 
  256. NET_HTTPNetRead (PRFileDesc *fildes, void *buf, unsigned nbyte);
  257.  
  258. MODULE_PRIVATE int 
  259. NET_HTTPNetRead (PRFileDesc *fildes, void *buf, unsigned nbyte)
  260. {
  261.   static int status;  /* read return code */
  262.  
  263.   status = PR_Read (fildes, buf, nbyte);
  264.  
  265. #ifdef XP_UNIX
  266.     /* check for HTTP server type conflict 
  267.      */
  268.   if (status == ENOTCONN || status == ECONNRESET || status == EPIPE) 
  269.       return MK_HTTP_TYPE_CONFLICT;
  270. #endif /* XP_UNIX */
  271.  
  272.   /* else */
  273.   return(status);
  274. }
  275.  
  276. /* net_BufferedReadLine
  277.  *
  278.  * will do a single read on the passed in socket
  279.  * and try and grok a single line from it.
  280.  *
  281.  * a '\n' is the demarkation of the end of a line
  282.  *
  283.  * if a '\n' exists the line will be returned into 'line' as
  284.  * a separately malloc'd line.  Any extra data
  285.  * will be malloc'd into the passed in 'buffer' pointer.
  286.  *
  287.  * if a '\n' is not found the data read from the
  288.  * socket will be appended (realloc'd) to the end of
  289.  * the passed in buffer.
  290.  *
  291.  * the status of the socket read will be passed back
  292.  * as a return value
  293.  *
  294.  * if 'line' is non-zero then a line was available and
  295.  * was malloc'd
  296.  */
  297. #define LINE_BUFFER_SIZE 1024
  298.  
  299. MODULE_PRIVATE int
  300. NET_BufferedReadLine   (PRFileDesc *  sock, 
  301.                          char   ** line, 
  302.                          char   ** buffer, 
  303.                          int32   * buffer_size, 
  304.                          Bool    * pause_for_next_read)
  305. {
  306.     char *strptr, *linefeed=0;
  307.     int status=1;
  308.     static char line_buffer[LINE_BUFFER_SIZE];  /* maybe this should be static? */
  309.     int line_length;
  310.     char *far_end;
  311.  
  312.     *line = 0;  /* init */
  313.  
  314.     *pause_for_next_read = TRUE;  /* This is the default it may change */
  315.  
  316.  
  317.     /* scan for line in existing buffer */
  318.     if(*buffer_size > 0)
  319.       {
  320.         for(strptr = *buffer; strptr < *buffer+*buffer_size; strptr++)
  321.         if(*strptr == LF)
  322.           {
  323.             linefeed = strptr;
  324.             break;
  325.           }
  326.       }
  327.  
  328.     if(!linefeed)
  329.       {
  330.         /* get some more data from the socket */
  331.         int32 read_size = MIN(LINE_BUFFER_SIZE, NET_Socket_Buffer_Size);
  332.         status = PR_Read(sock, NET_Socket_Buffer, read_size);
  333.  
  334.         TRACEMSG(("Read %d bytes from socket %d", status, sock));
  335.  
  336.         if(status < 0)
  337.             {
  338.             int rv = PR_GetError();
  339.             if (rv == PR_WOULD_BLOCK_ERROR)
  340.               {
  341.                 /* defaults to  *pause_for_next_read = TRUE; */
  342.                 return(1);
  343.               }
  344.             *pause_for_next_read = FALSE;
  345.             return (rv < 0) ? rv : (-rv);
  346.             }
  347.     
  348.         TRACEMSG(("Read %d bytes from socket\n",status));
  349.  
  350.         if(status > 0)
  351.           {
  352.             BlockAllocCat(*buffer, *buffer_size, NET_Socket_Buffer, status);
  353.             *buffer_size += status;
  354.           }
  355.  
  356.         if(*buffer_size > 0)
  357.           {
  358.             for(strptr = *buffer; strptr < *buffer+*buffer_size; strptr++)
  359.             if(*strptr == LF)
  360.               {
  361.                 linefeed = strptr;
  362.                 break;
  363.               }
  364.           }
  365.       }
  366.     
  367.     if(linefeed)
  368.       {
  369.         int32 tot_buf_size;
  370.  
  371.         *linefeed = '\0';
  372.  
  373.         /* kill the '\r' if it exits */
  374.         if(linefeed > *buffer && *(linefeed-1) == '\r')
  375.            *(linefeed-1) = '\0';
  376.  
  377.  
  378.         /* the number of bytes that the line tekes up */
  379.         line_length = (linefeed+1) - *buffer;  
  380.  
  381.         /* the farthest end of the memory buffer */
  382.         far_end = *buffer+*buffer_size;  
  383.  
  384.         if(line_length == *buffer_size)
  385.             {
  386.              /* the line is the whole buffer
  387.               * no copying is required and we know that
  388.               * there can't be any new \n's in the buffer
  389.               * so lets return now
  390.               */
  391.              *buffer_size = 0;
  392.              *line = *buffer;
  393.              return(status);
  394.           }
  395.  
  396.         /* set the line pointer now since we know where it
  397.          * will end up
  398.          */
  399.         *line = far_end-line_length;
  400.  
  401.         /* I'm doing some optimization here to try and reduce malloc's
  402.          * I want to copy the line that the calling function needs
  403.          * to the end of the buffer and move the part of the buffer
  404.          * that needs saveing to the beginning of the buffer
  405.          * that way no mallocs are required.  Space will be compacted
  406.          * or enlarged by the AllocCat above.
  407.          *
  408.          * If the line_buffer isn't large enough to hold the whole
  409.          * line then we need to do the copy in segments and shift
  410.          * the contents of the remaining line segment and buffer
  411.          * to the left each time.  This is very inefficient
  412.          * but the line_buffer is large enough to handle every
  413.          * expected line size (since lines should always be less
  414.          * than 512).  The segmenting should only come into
  415.          * play in degenerate cases.
  416.          */
  417.         tot_buf_size = *buffer_size;
  418.  
  419.         while(line_length)
  420.           {
  421.  
  422.             if(line_length > LINE_BUFFER_SIZE)
  423.               {
  424.                 XP_MEMMOVE(line_buffer, *buffer, LINE_BUFFER_SIZE);
  425.                 *buffer_size -= LINE_BUFFER_SIZE;
  426.                 line_length -= LINE_BUFFER_SIZE;
  427.                 /* move everything over includeing the parts 
  428.                  * of the buffer already moved 
  429.                   */
  430.                 XP_MEMMOVE(*buffer, 
  431.                         (*buffer)+LINE_BUFFER_SIZE, 
  432.                         tot_buf_size-LINE_BUFFER_SIZE);
  433.                 XP_MEMMOVE(far_end-LINE_BUFFER_SIZE, line_buffer, LINE_BUFFER_SIZE);
  434.               }
  435.             else
  436.               {
  437.                 XP_MEMMOVE(line_buffer, *buffer, line_length);
  438.                 *buffer_size -= line_length;
  439.                 /* move everything over includeing the parts 
  440.                  * of the buffer already moved 
  441.                   */
  442.                 XP_MEMMOVE(*buffer, 
  443.                         (*buffer)+line_length, 
  444.                         tot_buf_size-line_length);
  445.                 XP_MEMMOVE(far_end-line_length, line_buffer, line_length);
  446.                 line_length = 0;
  447.               }
  448.           }
  449.  
  450.         /* check for another linefeed in the buffered data
  451.          * if there is one then we don't want to pause for
  452.          * read yet.
  453.          */
  454.         linefeed = 0;
  455.         for(strptr = *buffer; strptr <= *buffer+*buffer_size; strptr++)
  456.             if(*strptr == LF)
  457.               {
  458.                 linefeed = strptr;
  459.                 break;
  460.               }
  461.  
  462.         if(linefeed)
  463.            *pause_for_next_read = FALSE;
  464.       }
  465.  
  466.     return(status);
  467. }
  468.  
  469. #ifdef PROFILE
  470. #pragma profile off
  471. #endif
  472.