gnutls_buffers.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
00003  *
00004  * Author: Nikos Mavrogiannopoulos
00005  *
00006  * This file is part of GNUTLS.
00007  *
00008  * The GNUTLS library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00021  * USA
00022  *
00023  */
00024 
00025 /* This is the only file that uses the berkeley sockets API.
00026  *
00027  * Also holds all the buffering code used in gnutls.
00028  * The buffering code works as:
00029  *
00030  * RECORD LAYER:
00031  *  1. uses a buffer to hold data (application/handshake),
00032  *    we got but they were not requested, yet.
00033  *  (see MHD_gnutls_record_buffer_put(), MHD_gnutls_record_buffer_get_size() etc.)
00034  *
00035  *  2. uses a buffer to hold data that were incomplete (ie the read/write
00036  *    was interrupted)
00037  *  (see MHD_gtls_io_read_buffered(), MHD_gtls_io_write_buffered() etc.)
00038  *
00039  * HANDSHAKE LAYER:
00040  *  1. Uses a buffer to hold data that was not sent or received
00041  *  complete. (E.g. sent 10 bytes of a handshake packet that is 20 bytes
00042  *  long).
00043  * (see MHD__gnutls_handshake_send_int(), MHD__gnutls_handshake_recv_int())
00044  *
00045  *  2. Uses buffer to hold the last received handshake message.
00046  *  (see MHD_gtls_handshake_buffer_put() etc.)
00047  *
00048  */
00049 
00050 #include <gnutls_int.h>
00051 #include <gnutls_errors.h>
00052 #include <gnutls_num.h>
00053 #include <gnutls_record.h>
00054 #include <gnutls_buffers.h>
00055 
00056 #include <errno.h>
00057 
00058 #ifdef _WIN32
00059 # include <winsock2.h>
00060 #endif
00061 
00062 #ifndef EAGAIN
00063 # define EAGAIN EWOULDBLOCK
00064 #endif
00065 
00066 /* Buffers received packets of type APPLICATION DATA and
00067  * HANDSHAKE DATA.
00068  */
00069 int
00070 MHD_gnutls_record_buffer_put (content_type_t type,
00071                               MHD_gtls_session_t session, opaque * data,
00072                               size_t length)
00073 {
00074   MHD_gtls_buffer *buf;
00075 
00076   if (length == 0)
00077     return 0;
00078 
00079   switch (type)
00080     {
00081     case GNUTLS_APPLICATION_DATA:
00082       buf = &session->internals.application_data_buffer;
00083       MHD__gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n",
00084                                length, type);
00085       break;
00086 
00087     case GNUTLS_HANDSHAKE:
00088       buf = &session->internals.handshake_data_buffer;
00089       MHD__gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data(%d)\n",
00090                                length, type);
00091       break;
00092 
00093     case GNUTLS_INNER_APPLICATION:
00094       buf = &session->internals.ia_data_buffer;
00095       MHD__gnutls_buffers_log ("BUF[IA]: Inserted %d bytes of Data(%d)\n",
00096                                length, type);
00097       break;
00098 
00099     default:
00100       MHD_gnutls_assert ();
00101       return GNUTLS_E_INVALID_REQUEST;
00102     }
00103 
00104   if (MHD_gtls_buffer_append (buf, data, length) < 0)
00105     {
00106       MHD_gnutls_assert ();
00107       return GNUTLS_E_MEMORY_ERROR;
00108     }
00109 
00110   return 0;
00111 }
00112 
00113 int
00114 MHD_gnutls_record_buffer_get_size (content_type_t type,
00115                                    MHD_gtls_session_t session)
00116 {
00117   switch (type)
00118     {
00119     case GNUTLS_APPLICATION_DATA:
00120       return session->internals.application_data_buffer.length;
00121 
00122     case GNUTLS_HANDSHAKE:
00123       return session->internals.handshake_data_buffer.length;
00124 
00125     case GNUTLS_INNER_APPLICATION:
00126       return session->internals.ia_data_buffer.length;
00127 
00128     default:
00129       return GNUTLS_E_INVALID_REQUEST;
00130     }
00131 }
00132 
00133 int
00134 MHD_gtls_record_buffer_get (content_type_t type, MHD_gtls_session_t session,
00135                             opaque * data, size_t length)
00136 {
00137   if (length == 0 || data == NULL)
00138     {
00139       MHD_gnutls_assert ();
00140       return GNUTLS_E_INVALID_REQUEST;
00141     }
00142 
00143   switch (type)
00144     {
00145     case GNUTLS_APPLICATION_DATA:
00146 
00147       if (length > session->internals.application_data_buffer.length)
00148         {
00149           length = session->internals.application_data_buffer.length;
00150         }
00151 
00152       MHD__gnutls_buffers_log ("BUFFER[REC][AD]: Read %d bytes of Data(%d)\n",
00153                                length, type);
00154 
00155       session->internals.application_data_buffer.length -= length;
00156       memcpy (data, session->internals.application_data_buffer.data, length);
00157 
00158       /* overwrite buffer */
00159       memmove (session->internals.application_data_buffer.data,
00160                &session->internals.application_data_buffer.data[length],
00161                session->internals.application_data_buffer.length);
00162 
00163       /* we do no longer realloc the application_data_buffer.data,
00164        * since it serves no practical reason. It also decreases
00165        * performance.
00166        */
00167       break;
00168 
00169     case GNUTLS_HANDSHAKE:
00170       if (length > session->internals.handshake_data_buffer.length)
00171         {
00172           length = session->internals.handshake_data_buffer.length;
00173         }
00174 
00175       MHD__gnutls_buffers_log ("BUF[REC][HD]: Read %d bytes of Data(%d)\n",
00176                                length, type);
00177 
00178       session->internals.handshake_data_buffer.length -= length;
00179       memcpy (data, session->internals.handshake_data_buffer.data, length);
00180 
00181       /* overwrite buffer */
00182       memmove (session->internals.handshake_data_buffer.data,
00183                &session->internals.handshake_data_buffer.data[length],
00184                session->internals.handshake_data_buffer.length);
00185 
00186       break;
00187 
00188     case GNUTLS_INNER_APPLICATION:
00189       if (length > session->internals.ia_data_buffer.length)
00190         length = session->internals.ia_data_buffer.length;
00191 
00192       MHD__gnutls_buffers_log ("BUF[REC][IA]: Read %d bytes of Data(%d)\n",
00193                                length, type);
00194 
00195       session->internals.ia_data_buffer.length -= length;
00196       memcpy (data, session->internals.ia_data_buffer.data, length);
00197 
00198       /* overwrite buffer */
00199       memmove (session->internals.ia_data_buffer.data,
00200                &session->internals.ia_data_buffer.data[length],
00201                session->internals.ia_data_buffer.length);
00202 
00203       break;
00204 
00205     default:
00206       MHD_gnutls_assert ();
00207       return GNUTLS_E_INVALID_REQUEST;
00208     }
00209 
00210   return length;
00211 }
00212 
00213 /* This function is like read. But it does not return -1 on error.
00214  * It does return MHD_gnutls_errno instead.
00215  *
00216  * Flags are only used if the default recv() function is being used.
00217  */
00218 static ssize_t
00219 MHD__gnutls_read (MHD_gtls_session_t session, void *iptr,
00220                   size_t sizeOfPtr, int flags)
00221 {
00222   size_t left;
00223   ssize_t i = 0;
00224   char *ptr = iptr;
00225   unsigned j, x, sum = 0;
00226   MHD_gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
00227 
00228   session->internals.direction = 0;
00229 
00230   left = sizeOfPtr;
00231   while (left > 0)
00232     {
00233       session->internals.errnum = 0;
00234       if (session->internals.MHD__gnutls_pull_func == NULL)
00235         {
00236           i =
00237             recv (GNUTLS_POINTER_TO_INT (fd), &ptr[sizeOfPtr - left], left,
00238                   flags);
00239 #if HAVE_WINSOCK
00240           if (i < 0)
00241             {
00242               int tmperr = WSAGetLastError ();
00243               switch (tmperr)
00244                 {
00245                 case WSAEWOULDBLOCK:
00246                   session->internals.errnum = EAGAIN;
00247                   break;
00248 
00249                 case WSAEINTR:
00250                   session->internals.errnum = EINTR;
00251                   break;
00252 
00253                 default:
00254                   session->internals.errnum = EIO;
00255                   break;
00256                 }
00257               WSASetLastError (tmperr);
00258             }
00259 #endif
00260         }
00261       else
00262         i = session->internals.MHD__gnutls_pull_func (fd,
00263                                                       &ptr[sizeOfPtr - left],
00264                                                       left);
00265 
00266       if (i < 0)
00267         {
00268           int err = session->internals.errnum ? session->internals.errnum
00269             : errno;
00270 
00271           MHD__gnutls_read_log
00272             ("READ: %d returned from %d, errno=%d gerrno=%d\n", i, fd, errno,
00273              session->internals.errnum);
00274 
00275           if (err == EAGAIN || err == EINTR)
00276             {
00277               if (sizeOfPtr - left > 0)
00278                 {
00279 
00280                   MHD__gnutls_read_log ("READ: returning %d bytes from %d\n",
00281                                         sizeOfPtr - left, fd);
00282 
00283                   goto finish;
00284                 }
00285               MHD_gnutls_assert ();
00286 
00287               if (err == EAGAIN)
00288                 return GNUTLS_E_AGAIN;
00289               return GNUTLS_E_INTERRUPTED;
00290             }
00291           else
00292             {
00293               MHD_gnutls_assert ();
00294               return GNUTLS_E_PULL_ERROR;
00295             }
00296         }
00297       else
00298         {
00299 
00300           MHD__gnutls_read_log ("READ: Got %d bytes from %d\n", i, fd);
00301 
00302           if (i == 0)
00303             break;              /* EOF */
00304         }
00305 
00306       left -= i;
00307 
00308     }
00309 
00310 finish:
00311 
00312   if (MHD__gnutls_log_level >= 7)
00313     {
00314       char line[128];
00315       char tmp[16];
00316 
00317       MHD__gnutls_read_log ("READ: read %d bytes from %d\n",
00318                             (sizeOfPtr - left), fd);
00319 
00320       for (x = 0; x < ((sizeOfPtr - left) / 16) + 1; x++)
00321         {
00322           line[0] = 0;
00323 
00324           sprintf (tmp, "%.4x - ", x);
00325           MHD_gtls_str_cat (line, sizeof (line), tmp);
00326 
00327           for (j = 0; j < 16; j++)
00328             {
00329               if (sum < (sizeOfPtr - left))
00330                 {
00331                   sprintf (tmp, "%.2x ", ((unsigned char *) ptr)[sum++]);
00332                   MHD_gtls_str_cat (line, sizeof (line), tmp);
00333                 }
00334             }
00335           MHD__gnutls_read_log ("%s\n", line);
00336         }
00337     }
00338 
00339   return (sizeOfPtr - left);
00340 }
00341 
00342 #define RCVLOWAT session->internals.lowat
00343 
00344 /* This function is only used with berkeley style sockets.
00345  * Clears the peeked data (read with MSG_PEEK).
00346  */
00347 int
00348 MHD_gtls_io_clear_peeked_data (MHD_gtls_session_t session)
00349 {
00350   char *peekdata;
00351   int ret, sum;
00352 
00353   if (session->internals.have_peeked_data == 0 || RCVLOWAT == 0)
00354     return 0;
00355 
00356   peekdata = MHD_gnutls_alloca (RCVLOWAT);
00357   if (peekdata == NULL)
00358     {
00359       MHD_gnutls_assert ();
00360       return GNUTLS_E_MEMORY_ERROR;
00361     }
00362 
00363   /* this was already read by using MSG_PEEK - so it shouldn't fail */
00364   sum = 0;
00365   do
00366     {                           /* we need this to finish now */
00367       ret = MHD__gnutls_read (session, peekdata, RCVLOWAT - sum, 0);
00368       if (ret > 0)
00369         sum += ret;
00370     }
00371   while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN || sum
00372          < RCVLOWAT);
00373 
00374   MHD_gnutls_afree (peekdata);
00375 
00376   if (ret < 0)
00377     {
00378       MHD_gnutls_assert ();
00379       return ret;
00380     }
00381 
00382   session->internals.have_peeked_data = 0;
00383 
00384   return 0;
00385 }
00386 
00387 void
00388 MHD_gtls_io_clear_read_buffer (MHD_gtls_session_t session)
00389 {
00390   session->internals.record_recv_buffer.length = 0;
00391 }
00392 
00393 /* This function is like recv(with MSG_PEEK). But it does not return -1 on error.
00394  * It does return MHD_gnutls_errno instead.
00395  * This function reads data from the socket and keeps them in a buffer, of up to
00396  * MAX_RECV_SIZE.
00397  *
00398  * This is not a general purpose function. It returns EXACTLY the data requested,
00399  * which are stored in a local (in the session) buffer. A pointer (iptr) to this buffer is returned.
00400  *
00401  */
00402 ssize_t
00403 MHD_gtls_io_read_buffered (MHD_gtls_session_t session, opaque ** iptr,
00404                            size_t sizeOfPtr, content_type_t recv_type)
00405 {
00406   ssize_t ret = 0, ret2 = 0;
00407   size_t min;
00408   int buf_pos;
00409   opaque *buf;
00410   int recvlowat;
00411   int recvdata, alloc_size;
00412 
00413   *iptr = session->internals.record_recv_buffer.data;
00414 
00415   if (sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0)
00416     {
00417       MHD_gnutls_assert ();     /* internal error */
00418       return GNUTLS_E_INVALID_REQUEST;
00419     }
00420 
00421   /* If an external pull function is used, then do not leave
00422    * any data into the kernel buffer.
00423    */
00424   if (session->internals.MHD__gnutls_pull_func != NULL)
00425     {
00426       recvlowat = 0;
00427     }
00428   else
00429     {
00430       /* leave peeked data to the kernel space only if application data
00431        * is received and we don't have any peeked
00432        * data in gnutls session.
00433        */
00434       if (recv_type != GNUTLS_APPLICATION_DATA
00435           && session->internals.have_peeked_data == 0)
00436         recvlowat = 0;
00437       else
00438         recvlowat = RCVLOWAT;
00439     }
00440 
00441   /* calculate the actual size, ie. get the minimum of the
00442    * buffered data and the requested data.
00443    */
00444   min = MIN (session->internals.record_recv_buffer.length, sizeOfPtr);
00445   if (min > 0)
00446     {
00447       /* if we have enough buffered data
00448        * then just return them.
00449        */
00450       if (min == sizeOfPtr)
00451         {
00452           return min;
00453         }
00454     }
00455 
00456   /* min is over zero. recvdata is the data we must
00457    * receive in order to return the requested data.
00458    */
00459   recvdata = sizeOfPtr - min;
00460 
00461   /* Check if the previously read data plus the new data to
00462    * receive are longer than the maximum receive buffer size.
00463    */
00464   if ((session->internals.record_recv_buffer.length + recvdata)
00465       > MAX_RECV_SIZE)
00466     {
00467       MHD_gnutls_assert ();     /* internal error */
00468       return GNUTLS_E_INVALID_REQUEST;
00469     }
00470 
00471   /* Allocate the data required to store the new packet.
00472    */
00473   alloc_size = recvdata + session->internals.record_recv_buffer.length;
00474   session->internals.record_recv_buffer.data =
00475     MHD_gtls_realloc_fast (session->internals.record_recv_buffer.data,
00476                            alloc_size);
00477   if (session->internals.record_recv_buffer.data == NULL)
00478     {
00479       MHD_gnutls_assert ();
00480       return GNUTLS_E_MEMORY_ERROR;
00481     }
00482 
00483   buf_pos = session->internals.record_recv_buffer.length;
00484   buf = session->internals.record_recv_buffer.data;
00485   *iptr = buf;
00486 
00487   /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer. */
00488   if (recvdata - recvlowat > 0)
00489     {
00490       ret =
00491         MHD__gnutls_read (session, &buf[buf_pos], recvdata - recvlowat, 0);
00492 
00493       /* return immediately if we got an interrupt or eagain
00494        * error.
00495        */
00496       if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0)
00497         {
00498           return ret;
00499         }
00500     }
00501 
00502   /* copy fresh data to our buffer.
00503    */
00504   if (ret > 0)
00505     {
00506       MHD__gnutls_read_log
00507         ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
00508          session->internals.record_recv_buffer.length, ret);
00509       MHD__gnutls_read_log ("RB: Requested %d bytes\n", sizeOfPtr);
00510       session->internals.record_recv_buffer.length += ret;
00511     }
00512 
00513   buf_pos = session->internals.record_recv_buffer.length;
00514 
00515   /* This is a hack placed in order for select to work. Just leave recvlowat data,
00516    * into the kernel buffer (using a read with MSG_PEEK), thus making
00517    * select think, that the socket is ready for reading.
00518    * MSG_PEEK is only used with berkeley style sockets.
00519    */
00520   if (ret == (recvdata - recvlowat) && recvlowat > 0)
00521     {
00522       ret2 = MHD__gnutls_read (session, &buf[buf_pos], recvlowat, MSG_PEEK);
00523 
00524       if (ret2 < 0 && MHD_gtls_error_is_fatal (ret2) == 0)
00525         {
00526           return ret2;
00527         }
00528 
00529       if (ret2 > 0)
00530         {
00531           MHD__gnutls_read_log ("RB-PEEK: Read %d bytes in PEEK MODE.\n",
00532                                 ret2);
00533           MHD__gnutls_read_log
00534             ("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n",
00535              session->internals.record_recv_buffer.length, ret2, sizeOfPtr);
00536           session->internals.have_peeked_data = 1;
00537           session->internals.record_recv_buffer.length += ret2;
00538 
00539         }
00540     }
00541 
00542   if (ret < 0 || ret2 < 0)
00543     {
00544       MHD_gnutls_assert ();
00545       /* that's because they are initialized to 0 */
00546       return MIN (ret, ret2);
00547     }
00548 
00549   ret += ret2;
00550 
00551   if (ret > 0 && ret < recvlowat)
00552     {
00553       MHD_gnutls_assert ();
00554       return GNUTLS_E_AGAIN;
00555     }
00556 
00557   if (ret == 0)
00558     {                           /* EOF */
00559       MHD_gnutls_assert ();
00560       return 0;
00561     }
00562 
00563   ret = session->internals.record_recv_buffer.length;
00564 
00565   if ((ret > 0) && ((size_t) ret < sizeOfPtr))
00566     {
00567       /* Short Read */
00568       MHD_gnutls_assert ();
00569       return GNUTLS_E_AGAIN;
00570     }
00571   else
00572     {
00573       return ret;
00574     }
00575 }
00576 
00577 /* These two functions are used to insert data to the send buffer of the handshake or
00578  * record protocol. The send buffer is kept if a send is interrupted and we need to keep
00579  * the data left to sent, in order to send them later.
00580  */
00581 
00582 #define MEMSUB(x,y) ((ssize_t)((ptrdiff_t)x-(ptrdiff_t)y))
00583 
00584 inline static int
00585 MHD__gnutls_buffer_insert (MHD_gtls_buffer * buffer,
00586                            const opaque * _data, size_t data_size)
00587 {
00588 
00589   if ((MEMSUB (_data, buffer->data) >= 0)
00590       && (MEMSUB (_data, buffer->data) < (ssize_t) buffer->length))
00591     {
00592       /* the given _data is part of the buffer.
00593        */
00594       if (data_size > buffer->length)
00595         {
00596           MHD_gnutls_assert ();
00597           /* this shouldn't have happened */
00598           return GNUTLS_E_INTERNAL_ERROR;
00599         }
00600 
00601       if (_data == buffer->data)
00602         {                       /* then don't even memmove */
00603           buffer->length = data_size;
00604           return 0;
00605         }
00606 
00607       memmove (buffer->data, _data, data_size);
00608       buffer->length = data_size;
00609 
00610       return 0;
00611 
00612     }
00613 
00614   if (MHD_gtls_buffer_append (buffer, _data, data_size) < 0)
00615     {
00616       MHD_gnutls_assert ();
00617       return GNUTLS_E_MEMORY_ERROR;
00618     }
00619 
00620   return 0;
00621 }
00622 
00623 inline static int
00624 MHD__gnutls_buffer_get (MHD_gtls_buffer * buffer,
00625                         const opaque ** ptr, size_t * ptr_size)
00626 {
00627   *ptr_size = buffer->length;
00628   *ptr = buffer->data;
00629 
00630   return 0;
00631 }
00632 
00633 /* This function is like write. But it does not return -1 on error.
00634  * It does return MHD_gnutls_errno instead.
00635  *
00636  * In case of E_AGAIN and E_INTERRUPTED errors, you must call MHD_gnutls_write_flush(),
00637  * until it returns ok (0).
00638  *
00639  * We need to push exactly the data in n, since we cannot send less
00640  * data. In TLS the peer must receive the whole packet in order
00641  * to decrypt and verify the integrity.
00642  *
00643  */
00644 ssize_t
00645 MHD_gtls_io_write_buffered (MHD_gtls_session_t session,
00646                             const void *iptr, size_t n)
00647 {
00648   size_t left;
00649   unsigned j, x, sum = 0;
00650   ssize_t retval, i;
00651   const opaque *ptr;
00652   int ret;
00653   MHD_gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
00654 
00655   /* to know where the procedure was interrupted.
00656    */
00657   session->internals.direction = 1;
00658 
00659   ptr = iptr;
00660 
00661   /* In case the previous write was interrupted, check if the
00662    * iptr != NULL and we have data in the buffer.
00663    * If this is true then return an error.
00664    */
00665   if (session->internals.record_send_buffer.length > 0 && iptr != NULL)
00666     {
00667       MHD_gnutls_assert ();
00668       return GNUTLS_E_INVALID_REQUEST;
00669     }
00670 
00671   /* If data in the buffer exist
00672    */
00673   if (iptr == NULL)
00674     {
00675       /* checking is handled above */
00676       ret =
00677         MHD__gnutls_buffer_get (&session->internals.record_send_buffer, &ptr,
00678                                 &n);
00679       if (ret < 0)
00680         {
00681           MHD_gnutls_assert ();
00682           return ret;
00683         }
00684 
00685       MHD__gnutls_write_log
00686         ("WRITE: Restoring old write. (%d bytes to send)\n", n);
00687     }
00688 
00689   MHD__gnutls_write_log ("WRITE: Will write %d bytes to %d.\n", n, fd);
00690 
00691   i = 0;
00692   left = n;
00693   while (left > 0)
00694     {
00695 
00696       session->internals.errnum = 0;
00697 
00698       if (session->internals.MHD__gnutls_push_func == NULL)
00699         {
00700           i = send (GNUTLS_POINTER_TO_INT (fd), &ptr[n - left], left, 0);
00701 #if HAVE_WINSOCK
00702           if (i < 0)
00703             {
00704               int tmperr = WSAGetLastError ();
00705               switch (tmperr)
00706                 {
00707                 case WSAEWOULDBLOCK:
00708                   session->internals.errnum = EAGAIN;
00709                   break;
00710 
00711                 case WSAEINTR:
00712                   session->internals.errnum = EINTR;
00713                   break;
00714 
00715                 default:
00716                   session->internals.errnum = EIO;
00717                   break;
00718                 }
00719               WSASetLastError (tmperr);
00720             }
00721 #endif
00722         }
00723       else
00724         i =
00725           session->internals.MHD__gnutls_push_func (fd, &ptr[n - left], left);
00726 
00727       if (i == -1)
00728         {
00729           int err = session->internals.errnum ? session->internals.errnum
00730             : errno;
00731 
00732           if (err == EAGAIN || err == EINTR)
00733             {
00734               session->internals.record_send_buffer_prev_size += n - left;
00735 
00736               retval =
00737                 MHD__gnutls_buffer_insert (&session->
00738                                            internals.record_send_buffer,
00739                                            &ptr[n - left], left);
00740               if (retval < 0)
00741                 {
00742                   MHD_gnutls_assert ();
00743                   return retval;
00744                 }
00745 
00746               MHD__gnutls_write_log
00747                 ("WRITE: Interrupted. Stored %d bytes to buffer. Already sent %d bytes.\n",
00748                  left, n - left);
00749 
00750               if (err == EAGAIN)
00751                 return GNUTLS_E_AGAIN;
00752               return GNUTLS_E_INTERRUPTED;
00753             }
00754           else
00755             {
00756               MHD_gnutls_assert ();
00757               return GNUTLS_E_PUSH_ERROR;
00758             }
00759         }
00760       left -= i;
00761 
00762       if (MHD__gnutls_log_level >= 7)
00763         {
00764           char line[128];
00765           char tmp[16];
00766 
00767           MHD__gnutls_write_log
00768             ("WRITE: wrote %d bytes to %d. Left %d bytes. Total %d bytes.\n",
00769              i, fd, left, n);
00770           for (x = 0; x < (unsigned) ((i) / 16) + 1; x++)
00771             {
00772               line[0] = 0;
00773 
00774               if (sum > n - left)
00775                 break;
00776 
00777               sprintf (tmp, "%.4x - ", x);
00778               MHD_gtls_str_cat (line, sizeof (line), tmp);
00779 
00780               for (j = 0; j < 16; j++)
00781                 {
00782                   if (sum < n - left)
00783                     {
00784                       sprintf (tmp, "%.2x ", ((unsigned char *) ptr)[sum++]);
00785                       MHD_gtls_str_cat (line, sizeof (line), tmp);
00786                     }
00787                   else
00788                     break;
00789                 }
00790               MHD__gnutls_write_log ("%s\n", line);
00791             }
00792         }
00793     }
00794 
00795   retval = n + session->internals.record_send_buffer_prev_size;
00796 
00797   session->internals.record_send_buffer.length = 0;
00798   session->internals.record_send_buffer_prev_size = 0;
00799 
00800   return retval;
00801 
00802 }
00803 
00804 /* This function writes the data that are left in the
00805  * TLS write buffer (ie. because the previous write was
00806  * interrupted.
00807  */
00808 ssize_t
00809 MHD_gtls_io_write_flush (MHD_gtls_session_t session)
00810 {
00811   ssize_t ret;
00812 
00813   if (session->internals.record_send_buffer.length == 0)
00814     return 0;                   /* done */
00815 
00816   ret = MHD_gtls_io_write_buffered (session, NULL, 0);
00817   MHD__gnutls_write_log ("WRITE FLUSH: %d [buffer: %d]\n", ret,
00818                          session->internals.record_send_buffer.length);
00819 
00820   return ret;
00821 }
00822 
00823 /* This function writes the data that are left in the
00824  * Handshake write buffer (ie. because the previous write was
00825  * interrupted.
00826  */
00827 ssize_t
00828 MHD_gtls_handshake_io_write_flush (MHD_gtls_session_t session)
00829 {
00830   ssize_t ret;
00831   ret = MHD_gtls_handshake_io_send_int (session, 0, 0, NULL, 0);
00832   if (ret < 0)
00833     {
00834       MHD_gnutls_assert ();
00835       return ret;
00836     }
00837 
00838   MHD__gnutls_write_log ("HANDSHAKE_FLUSH: written[1] %d bytes\n", ret);
00839 
00840   if (session->internals.handshake_send_buffer.length == 0)
00841     {
00842       ret = session->internals.handshake_send_buffer_prev_size; /* done */
00843       session->internals.handshake_send_buffer_prev_size = 0;
00844     }
00845 
00846   return ret;
00847 }
00848 
00849 /* This is a send function for the gnutls handshake
00850  * protocol. Just makes sure that all data have been sent.
00851  */
00852 ssize_t
00853 MHD_gtls_handshake_io_send_int (MHD_gtls_session_t session,
00854                                 content_type_t type,
00855                                 MHD_gnutls_handshake_description_t htype,
00856                                 const void *iptr, size_t n)
00857 {
00858   size_t left;
00859   ssize_t ret = 0;
00860   const opaque *ptr;
00861   ssize_t retval = 0;
00862 
00863   ptr = iptr;
00864 
00865   if (session->internals.handshake_send_buffer.length > 0 && ptr == NULL && n
00866       == 0)
00867     {
00868       /* resuming previously interrupted write
00869        */
00870       MHD_gnutls_assert ();
00871       ret = MHD__gnutls_buffer_get (&session->internals.handshake_send_buffer,
00872                                     &ptr, &n);
00873       if (ret < 0)
00874         {
00875           MHD_gnutls_assert ();
00876           return retval;
00877         }
00878 
00879       type = session->internals.handshake_send_buffer_type;
00880       htype = session->internals.handshake_send_buffer_htype;
00881 
00882     }
00883   else if (session->internals.handshake_send_buffer.length > 0)
00884     {
00885       MHD_gnutls_assert ();
00886       return GNUTLS_E_INTERNAL_ERROR;
00887     }
00888 #ifdef WRITE_DEBUG
00889   else
00890     {
00891       size_t sum = 0, x, j;
00892 
00893       MHD__gnutls_write_log ("HWRITE: will write %d bytes to %d.\n", n,
00894                              MHD_gnutls_transport_get_ptr (session));
00895       for (x = 0; x < ((n) / 16) + 1; x++)
00896         {
00897           if (sum > n)
00898             break;
00899 
00900           MHD__gnutls_write_log ("%.4x - ", x);
00901           for (j = 0; j < 16; j++)
00902             {
00903               if (sum < n)
00904                 {
00905                   MHD__gnutls_write_log ("%.2x ",
00906                                          ((unsigned char *) ptr)[sum++]);
00907                 }
00908               else
00909                 break;
00910             }
00911           MHD__gnutls_write_log ("\n");
00912         }
00913       MHD__gnutls_write_log ("\n");
00914     }
00915 #endif
00916 
00917   if (n == 0)
00918     {                           /* if we have no data to send */
00919       MHD_gnutls_assert ();
00920       return 0;
00921     }
00922   else if (ptr == NULL)
00923     {
00924       MHD_gnutls_assert ();
00925       return GNUTLS_E_INTERNAL_ERROR;
00926     }
00927 
00928   left = n;
00929   while (left > 0)
00930     {
00931       ret = MHD_gtls_send_int (session, type, htype, &ptr[n - left], left);
00932 
00933       if (ret <= 0)
00934         {
00935           if (ret == 0)
00936             {
00937               MHD_gnutls_assert ();
00938               ret = GNUTLS_E_INTERNAL_ERROR;
00939             }
00940 
00941           if (left > 0 && (ret == GNUTLS_E_INTERRUPTED || ret
00942                            == GNUTLS_E_AGAIN))
00943             {
00944               MHD_gnutls_assert ();
00945 
00946               retval =
00947                 MHD__gnutls_buffer_insert (&session->internals.
00948                                            handshake_send_buffer,
00949                                            &ptr[n - left], left);
00950               if (retval < 0)
00951                 {
00952                   MHD_gnutls_assert ();
00953                   return retval;
00954                 }
00955 
00956               session->internals.handshake_send_buffer_prev_size += n - left;
00957 
00958               session->internals.handshake_send_buffer_type = type;
00959               session->internals.handshake_send_buffer_htype = htype;
00960 
00961             }
00962           else
00963             {
00964               session->internals.handshake_send_buffer_prev_size = 0;
00965               session->internals.handshake_send_buffer.length = 0;
00966             }
00967 
00968           MHD_gnutls_assert ();
00969           return ret;
00970         }
00971       left -= ret;
00972     }
00973 
00974   retval = n + session->internals.handshake_send_buffer_prev_size;
00975 
00976   session->internals.handshake_send_buffer.length = 0;
00977   session->internals.handshake_send_buffer_prev_size = 0;
00978 
00979   return retval;
00980 
00981 }
00982 
00983 /* This is a receive function for the gnutls handshake
00984  * protocol. Makes sure that we have received all data.
00985  */
00986 ssize_t
00987 MHD_gtls_handshake_io_recv_int (MHD_gtls_session_t session,
00988                                 content_type_t type,
00989                                 MHD_gnutls_handshake_description_t htype,
00990                                 void *iptr, size_t sizeOfPtr)
00991 {
00992   size_t left;
00993   ssize_t i;
00994   opaque *ptr;
00995   size_t dsize;
00996 
00997   ptr = iptr;
00998   left = sizeOfPtr;
00999 
01000   if (sizeOfPtr == 0 || iptr == NULL)
01001     {
01002       MHD_gnutls_assert ();
01003       return GNUTLS_E_INVALID_REQUEST;
01004     }
01005 
01006   if (session->internals.handshake_recv_buffer.length > 0)
01007     {
01008       /* if we have already received some data */
01009       if (sizeOfPtr <= session->internals.handshake_recv_buffer.length)
01010         {
01011           /* if requested less data then return it.
01012            */
01013           MHD_gnutls_assert ();
01014           memcpy (iptr, session->internals.handshake_recv_buffer.data,
01015                   sizeOfPtr);
01016 
01017           session->internals.handshake_recv_buffer.length -= sizeOfPtr;
01018 
01019           memmove (session->internals.handshake_recv_buffer.data,
01020                    &session->internals.handshake_recv_buffer.data[sizeOfPtr],
01021                    session->internals.handshake_recv_buffer.length);
01022 
01023           return sizeOfPtr;
01024         }
01025       MHD_gnutls_assert ();
01026       memcpy (iptr, session->internals.handshake_recv_buffer.data,
01027               session->internals.handshake_recv_buffer.length);
01028 
01029       htype = session->internals.handshake_recv_buffer_htype;
01030       type = session->internals.handshake_recv_buffer_type;
01031 
01032       left -= session->internals.handshake_recv_buffer.length;
01033 
01034       session->internals.handshake_recv_buffer.length = 0;
01035     }
01036 
01037   while (left > 0)
01038     {
01039       dsize = sizeOfPtr - left;
01040       i = MHD_gtls_recv_int (session, type, htype, &ptr[dsize], left);
01041       if (i < 0)
01042         {
01043 
01044           if (dsize > 0 && (i == GNUTLS_E_INTERRUPTED || i == GNUTLS_E_AGAIN))
01045             {
01046               MHD_gnutls_assert ();
01047 
01048               session->internals.handshake_recv_buffer.data
01049                 =
01050                 MHD_gtls_realloc_fast (session->internals.
01051                                        handshake_recv_buffer.data, dsize);
01052               if (session->internals.handshake_recv_buffer.data == NULL)
01053                 {
01054                   MHD_gnutls_assert ();
01055                   return GNUTLS_E_MEMORY_ERROR;
01056                 }
01057 
01058               memcpy (session->internals.handshake_recv_buffer.data, iptr,
01059                       dsize);
01060 
01061               session->internals.handshake_recv_buffer_htype = htype;
01062               session->internals.handshake_recv_buffer_type = type;
01063 
01064               session->internals.handshake_recv_buffer.length = dsize;
01065             }
01066           else
01067             session->internals.handshake_recv_buffer.length = 0;
01068 
01069           MHD_gnutls_assert ();
01070 
01071           return i;
01072         }
01073       else
01074         {
01075           if (i == 0)
01076             break;              /* EOF */
01077         }
01078 
01079       left -= i;
01080 
01081     }
01082 
01083   session->internals.handshake_recv_buffer.length = 0;
01084 
01085   return sizeOfPtr - left;
01086 }
01087 
01088 /* Buffer for handshake packets. Keeps the packets in order
01089  * for finished messages to use them. Used in HMAC calculation
01090  * and finished messages.
01091  */
01092 int
01093 MHD_gtls_handshake_buffer_put (MHD_gtls_session_t session, opaque * data,
01094                                size_t length)
01095 {
01096 
01097   if (length == 0)
01098     return 0;
01099 
01100   if ((session->internals.max_handshake_data_buffer_size > 0) && ((length
01101                                                                    +
01102                                                                    session->
01103                                                                    internals.
01104                                                                    handshake_hash_buffer.
01105                                                                    length) >
01106                                                                   session->
01107                                                                   internals.
01108                                                                   max_handshake_data_buffer_size))
01109     {
01110       MHD_gnutls_assert ();
01111       return GNUTLS_E_MEMORY_ERROR;
01112     }
01113 
01114   MHD__gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data\n", length);
01115 
01116   if (MHD_gtls_buffer_append (&session->internals.handshake_hash_buffer, data,
01117                               length) < 0)
01118     {
01119       MHD_gnutls_assert ();
01120       return GNUTLS_E_MEMORY_ERROR;
01121     }
01122 
01123   return 0;
01124 }
01125 
01126 /* this function does not touch the buffer
01127  * and returns data from it (peek mode!)
01128  */
01129 int
01130 MHD_gtls_handshake_buffer_get_ptr (MHD_gtls_session_t session,
01131                                    opaque ** data_ptr, size_t * length)
01132 {
01133   if (length != NULL)
01134     *length = session->internals.handshake_hash_buffer.length;
01135 
01136   MHD__gnutls_buffers_log ("BUF[HSK]: Peeked %d bytes of Data\n",
01137                            session->internals.handshake_hash_buffer.length);
01138 
01139   if (data_ptr != NULL)
01140     *data_ptr = session->internals.handshake_hash_buffer.data;
01141 
01142   return 0;
01143 }
01144 
01145 /* Does not free the buffer
01146  */
01147 int
01148 MHD_gtls_handshake_buffer_empty (MHD_gtls_session_t session)
01149 {
01150 
01151   MHD__gnutls_buffers_log ("BUF[HSK]: Emptied buffer\n");
01152 
01153   session->internals.handshake_hash_buffer.length = 0;
01154 
01155   return 0;
01156 }
01157 
01158 int
01159 MHD_gtls_handshake_buffer_clear (MHD_gtls_session_t session)
01160 {
01161   MHD__gnutls_buffers_log ("BUF[HSK]: Cleared Data from buffer\n");
01162   MHD_gtls_buffer_clear (&session->internals.handshake_hash_buffer);
01163   return 0;
01164 }

Generated on Fri Feb 27 18:31:19 2009 for GNU libmicrohttpd by  doxygen 1.5.7.1