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   MHD_gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
00226 
00227   session->internals.direction = 0;
00228 
00229   left = sizeOfPtr;
00230   while (left > 0)
00231     {
00232       session->internals.errnum = 0;
00233       if (session->internals.MHD__gnutls_pull_func == NULL)
00234         {
00235           i =
00236             recv (GNUTLS_POINTER_TO_INT (fd), &ptr[sizeOfPtr - left], left,
00237                   flags);
00238 #if HAVE_WINSOCK
00239           if (i < 0)
00240             {
00241               int tmperr = WSAGetLastError ();
00242               switch (tmperr)
00243                 {
00244                 case WSAEWOULDBLOCK:
00245                   session->internals.errnum = EAGAIN;
00246                   break;
00247 
00248                 case WSAEINTR:
00249                   session->internals.errnum = EINTR;
00250                   break;
00251 
00252                 default:
00253                   session->internals.errnum = EIO;
00254                   break;
00255                 }
00256               WSASetLastError (tmperr);
00257             }
00258 #endif
00259         }
00260       else
00261         i = session->internals.MHD__gnutls_pull_func (fd,
00262                                                       &ptr[sizeOfPtr - left],
00263                                                       left);
00264       if (i < 0)
00265         {
00266           int err = session->internals.errnum ? session->internals.errnum
00267             : errno;
00268           if ( (err == EAGAIN) || (err == EINTR) )
00269             {
00270               if (sizeOfPtr - left > 0)
00271                 goto finish;       
00272               MHD_gnutls_assert ();         
00273               if (err == EAGAIN)
00274                 return GNUTLS_E_AGAIN;
00275               return GNUTLS_E_INTERRUPTED;
00276             }
00277           else
00278             {
00279               MHD_gnutls_assert ();
00280               return GNUTLS_E_PULL_ERROR;
00281             }
00282         }
00283       else
00284         {
00285           if (i == 0)
00286             break;              /* EOF */
00287         }
00288       left -= i;
00289     }
00290 
00291 finish:
00292   return (sizeOfPtr - left);
00293 }
00294 
00295 #define RCVLOWAT session->internals.lowat
00296 
00297 /* This function is only used with berkeley style sockets.
00298  * Clears the peeked data (read with MSG_PEEK).
00299  */
00300 int
00301 MHD_gtls_io_clear_peeked_data (MHD_gtls_session_t session)
00302 {
00303   char *peekdata;
00304   int ret, sum;
00305 
00306   if (session->internals.have_peeked_data == 0 || RCVLOWAT == 0)
00307     return 0;
00308 
00309   peekdata = MHD_gnutls_alloca (RCVLOWAT);
00310   if (peekdata == NULL)
00311     {
00312       MHD_gnutls_assert ();
00313       return GNUTLS_E_MEMORY_ERROR;
00314     }
00315 
00316   /* this was already read by using MSG_PEEK - so it shouldn't fail */
00317   sum = 0;
00318   do
00319     {                           /* we need this to finish now */
00320       ret = MHD__gnutls_read (session, peekdata, RCVLOWAT - sum, 0);
00321       if (ret > 0)
00322         sum += ret;
00323     }
00324   while ( (ret == GNUTLS_E_INTERRUPTED) || 
00325           (ret == GNUTLS_E_AGAIN) || 
00326           (sum < RCVLOWAT) );
00327 
00328   MHD_gnutls_afree (peekdata);
00329 
00330   if (ret < 0)
00331     {
00332       MHD_gnutls_assert ();
00333       return ret;
00334     }
00335 
00336   session->internals.have_peeked_data = 0;
00337 
00338   return 0;
00339 }
00340 
00341 void
00342 MHD_gtls_io_clear_read_buffer (MHD_gtls_session_t session)
00343 {
00344   session->internals.record_recv_buffer.length = 0;
00345 }
00346 
00347 /* This function is like recv(with MSG_PEEK). But it does not return -1 on error.
00348  * It does return MHD_gnutls_errno instead.
00349  * This function reads data from the socket and keeps them in a buffer, of up to
00350  * MAX_RECV_SIZE.
00351  *
00352  * This is not a general purpose function. It returns EXACTLY the data requested,
00353  * which are stored in a local (in the session) buffer. A pointer (iptr) to this buffer is returned.
00354  *
00355  */
00356 ssize_t
00357 MHD_gtls_io_read_buffered (MHD_gtls_session_t session, opaque ** iptr,
00358                            size_t sizeOfPtr, content_type_t recv_type)
00359 {
00360   ssize_t ret = 0, ret2 = 0;
00361   size_t min;
00362   int buf_pos;
00363   opaque *buf;
00364   int recvlowat;
00365   int recvdata, alloc_size;
00366 
00367   *iptr = session->internals.record_recv_buffer.data;
00368 
00369   if (sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0)
00370     {
00371       MHD_gnutls_assert ();     /* internal error */
00372       return GNUTLS_E_INVALID_REQUEST;
00373     }
00374 
00375   /* If an external pull function is used, then do not leave
00376    * any data into the kernel buffer.
00377    */
00378   if (session->internals.MHD__gnutls_pull_func != NULL)
00379     {
00380       recvlowat = 0;
00381     }
00382   else
00383     {
00384       /* leave peeked data to the kernel space only if application data
00385        * is received and we don't have any peeked
00386        * data in gnutls session.
00387        */
00388       if (recv_type != GNUTLS_APPLICATION_DATA
00389           && session->internals.have_peeked_data == 0)
00390         recvlowat = 0;
00391       else
00392         recvlowat = RCVLOWAT;
00393     }
00394 
00395   /* calculate the actual size, ie. get the minimum of the
00396    * buffered data and the requested data.
00397    */
00398   min = MIN (session->internals.record_recv_buffer.length, sizeOfPtr);
00399   if (min > 0)
00400     {
00401       /* if we have enough buffered data
00402        * then just return them.
00403        */
00404       if (min == sizeOfPtr)
00405         {
00406           return min;
00407         }
00408     }
00409 
00410   /* min is over zero. recvdata is the data we must
00411    * receive in order to return the requested data.
00412    */
00413   recvdata = sizeOfPtr - min;
00414 
00415   /* Check if the previously read data plus the new data to
00416    * receive are longer than the maximum receive buffer size.
00417    */
00418   if ((session->internals.record_recv_buffer.length + recvdata)
00419       > MAX_RECV_SIZE)
00420     {
00421       MHD_gnutls_assert ();     /* internal error */
00422       return GNUTLS_E_INVALID_REQUEST;
00423     }
00424 
00425   /* Allocate the data required to store the new packet.
00426    */
00427   alloc_size = recvdata + session->internals.record_recv_buffer.length;
00428   session->internals.record_recv_buffer.data =
00429     MHD_gtls_realloc_fast (session->internals.record_recv_buffer.data,
00430                            alloc_size);
00431   if (session->internals.record_recv_buffer.data == NULL)
00432     {
00433       MHD_gnutls_assert ();
00434       return GNUTLS_E_MEMORY_ERROR;
00435     }
00436 
00437   buf_pos = session->internals.record_recv_buffer.length;
00438   buf = session->internals.record_recv_buffer.data;
00439   *iptr = buf;
00440 
00441   /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer. */
00442   if (recvdata - recvlowat > 0)
00443     {
00444       ret =
00445         MHD__gnutls_read (session, &buf[buf_pos], recvdata - recvlowat, 0);
00446 
00447       /* return immediately if we got an interrupt or eagain
00448        * error.
00449        */
00450       if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0)
00451         {
00452           return ret;
00453         }
00454     }
00455 
00456   /* copy fresh data to our buffer.
00457    */
00458   if (ret > 0)
00459     {
00460       MHD__gnutls_read_log
00461         ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
00462          session->internals.record_recv_buffer.length, ret);
00463       MHD__gnutls_read_log ("RB: Requested %d bytes\n", sizeOfPtr);
00464       session->internals.record_recv_buffer.length += ret;
00465     }
00466 
00467   buf_pos = session->internals.record_recv_buffer.length;
00468 
00469   /* This is a hack placed in order for select to work. Just leave recvlowat data,
00470    * into the kernel buffer (using a read with MSG_PEEK), thus making
00471    * select think, that the socket is ready for reading.
00472    * MSG_PEEK is only used with berkeley style sockets.
00473    */
00474   if (ret == (recvdata - recvlowat) && recvlowat > 0)
00475     {
00476       ret2 = MHD__gnutls_read (session, &buf[buf_pos], recvlowat, MSG_PEEK);
00477 
00478       if (ret2 < 0 && MHD_gtls_error_is_fatal (ret2) == 0)
00479         {
00480           return ret2;
00481         }
00482 
00483       if (ret2 > 0)
00484         {
00485           MHD__gnutls_read_log ("RB-PEEK: Read %d bytes in PEEK MODE.\n",
00486                                 ret2);
00487           MHD__gnutls_read_log
00488             ("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n",
00489              session->internals.record_recv_buffer.length, ret2, sizeOfPtr);
00490           session->internals.have_peeked_data = 1;
00491           session->internals.record_recv_buffer.length += ret2;
00492 
00493         }
00494     }
00495 
00496   if (ret < 0 || ret2 < 0)
00497     {
00498       MHD_gnutls_assert ();
00499       /* that's because they are initialized to 0 */
00500       return MIN (ret, ret2);
00501     }
00502 
00503   ret += ret2;
00504 
00505   if (ret > 0 && ret < recvlowat)
00506     {
00507       MHD_gnutls_assert ();
00508       return GNUTLS_E_AGAIN;
00509     }
00510 
00511   if (ret == 0)
00512     {                           /* EOF */
00513       MHD_gnutls_assert ();
00514       return 0;
00515     }
00516 
00517   ret = session->internals.record_recv_buffer.length;
00518 
00519   if ((ret > 0) && ((size_t) ret < sizeOfPtr))
00520     {
00521       /* Short Read */
00522       MHD_gnutls_assert ();
00523       return GNUTLS_E_AGAIN;
00524     }
00525   else
00526     {
00527       return ret;
00528     }
00529 }
00530 
00531 /* These two functions are used to insert data to the send buffer of the handshake or
00532  * record protocol. The send buffer is kept if a send is interrupted and we need to keep
00533  * the data left to sent, in order to send them later.
00534  */
00535 
00536 #define MEMSUB(x,y) ((ssize_t)((ptrdiff_t)x-(ptrdiff_t)y))
00537 
00538 inline static int
00539 MHD__gnutls_buffer_insert (MHD_gtls_buffer * buffer,
00540                            const opaque * _data, size_t data_size)
00541 {
00542 
00543   if ((MEMSUB (_data, buffer->data) >= 0)
00544       && (MEMSUB (_data, buffer->data) < (ssize_t) buffer->length))
00545     {
00546       /* the given _data is part of the buffer.
00547        */
00548       if (data_size > buffer->length)
00549         {
00550           MHD_gnutls_assert ();
00551           /* this shouldn't have happened */
00552           return GNUTLS_E_INTERNAL_ERROR;
00553         }
00554 
00555       if (_data == buffer->data)
00556         {                       /* then don't even memmove */
00557           buffer->length = data_size;
00558           return 0;
00559         }
00560 
00561       memmove (buffer->data, _data, data_size);
00562       buffer->length = data_size;
00563 
00564       return 0;
00565 
00566     }
00567 
00568   if (MHD_gtls_buffer_append (buffer, _data, data_size) < 0)
00569     {
00570       MHD_gnutls_assert ();
00571       return GNUTLS_E_MEMORY_ERROR;
00572     }
00573 
00574   return 0;
00575 }
00576 
00577 inline static int
00578 MHD__gnutls_buffer_get (MHD_gtls_buffer * buffer,
00579                         const opaque ** ptr, size_t * ptr_size)
00580 {
00581   *ptr_size = buffer->length;
00582   *ptr = buffer->data;
00583 
00584   return 0;
00585 }
00586 
00587 /* This function is like write. But it does not return -1 on error.
00588  * It does return MHD_gnutls_errno instead.
00589  *
00590  * In case of E_AGAIN and E_INTERRUPTED errors, you must call MHD_gnutls_write_flush(),
00591  * until it returns ok (0).
00592  *
00593  * We need to push exactly the data in n, since we cannot send less
00594  * data. In TLS the peer must receive the whole packet in order
00595  * to decrypt and verify the integrity.
00596  *
00597  */
00598 ssize_t
00599 MHD_gtls_io_write_buffered (MHD_gtls_session_t session,
00600                             const void *iptr, size_t n)
00601 {
00602   size_t left;
00603   unsigned j, x, sum = 0;
00604   ssize_t retval, i;
00605   const opaque *ptr;
00606   int ret;
00607   MHD_gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
00608 
00609   /* to know where the procedure was interrupted.
00610    */
00611   session->internals.direction = 1;
00612 
00613   ptr = iptr;
00614 
00615   /* In case the previous write was interrupted, check if the
00616    * iptr != NULL and we have data in the buffer.
00617    * If this is true then return an error.
00618    */
00619   if (session->internals.record_send_buffer.length > 0 && iptr != NULL)
00620     {
00621       MHD_gnutls_assert ();
00622       return GNUTLS_E_INVALID_REQUEST;
00623     }
00624 
00625   /* If data in the buffer exist
00626    */
00627   if (iptr == NULL)
00628     {
00629       /* checking is handled above */
00630       ret =
00631         MHD__gnutls_buffer_get (&session->internals.record_send_buffer, &ptr,
00632                                 &n);
00633       if (ret < 0)
00634         {
00635           MHD_gnutls_assert ();
00636           return ret;
00637         }
00638 
00639       MHD__gnutls_write_log
00640         ("WRITE: Restoring old write. (%d bytes to send)\n", n);
00641     }
00642 
00643   MHD__gnutls_write_log ("WRITE: Will write %d bytes to %d.\n", n, fd);
00644 
00645   i = 0;
00646   left = n;
00647   while (left > 0)
00648     {
00649 
00650       session->internals.errnum = 0;
00651 
00652       if (session->internals.MHD__gnutls_push_func == NULL)
00653         {
00654           i = send (GNUTLS_POINTER_TO_INT (fd), &ptr[n - left], left, 0);
00655 #if HAVE_WINSOCK
00656           if (i < 0)
00657             {
00658               int tmperr = WSAGetLastError ();
00659               switch (tmperr)
00660                 {
00661                 case WSAEWOULDBLOCK:
00662                   session->internals.errnum = EAGAIN;
00663                   break;
00664 
00665                 case WSAEINTR:
00666                   session->internals.errnum = EINTR;
00667                   break;
00668 
00669                 default:
00670                   session->internals.errnum = EIO;
00671                   break;
00672                 }
00673               WSASetLastError (tmperr);
00674             }
00675 #endif
00676         }
00677       else
00678         i = session->internals.MHD__gnutls_push_func (fd, &ptr[n - left], left);
00679       if (i == -1)
00680         {
00681           int err = session->internals.errnum ? session->internals.errnum
00682             : errno;
00683 
00684           if ( (err == EAGAIN) || (err == EINTR) )
00685             {
00686               session->internals.record_send_buffer_prev_size += n - left;
00687 
00688               retval =
00689                 MHD__gnutls_buffer_insert (&session->
00690                                            internals.record_send_buffer,
00691                                            &ptr[n - left], left);
00692               if (retval < 0)
00693                 {
00694                   MHD_gnutls_assert ();
00695                   return retval;
00696                 }
00697               if (err == EAGAIN)
00698                 return GNUTLS_E_AGAIN;
00699               return GNUTLS_E_INTERRUPTED;
00700             }
00701           else
00702             {
00703               MHD_gnutls_assert ();
00704               return GNUTLS_E_PUSH_ERROR;
00705             }
00706         }
00707       left -= i;
00708 
00709       if (MHD__gnutls_log_level >= 7)
00710         {
00711           char line[128];
00712           char tmp[16];
00713 
00714           MHD__gnutls_write_log
00715             ("WRITE: wrote %d bytes to %d. Left %d bytes. Total %d bytes.\n",
00716              i, fd, left, n);
00717           for (x = 0; x < (unsigned) ((i) / 16) + 1; x++)
00718             {
00719               line[0] = 0;
00720 
00721               if (sum > n - left)
00722                 break;
00723 
00724               sprintf (tmp, "%.4x - ", x);
00725               MHD_gtls_str_cat (line, sizeof (line), tmp);
00726 
00727               for (j = 0; j < 16; j++)
00728                 {
00729                   if (sum < n - left)
00730                     {
00731                       sprintf (tmp, "%.2x ", ((unsigned char *) ptr)[sum++]);
00732                       MHD_gtls_str_cat (line, sizeof (line), tmp);
00733                     }
00734                   else
00735                     break;
00736                 }
00737               MHD__gnutls_write_log ("%s\n", line);
00738             }
00739         }
00740     }
00741 
00742   retval = n + session->internals.record_send_buffer_prev_size;
00743 
00744   session->internals.record_send_buffer.length = 0;
00745   session->internals.record_send_buffer_prev_size = 0;
00746 
00747   return retval;
00748 
00749 }
00750 
00751 /* This function writes the data that are left in the
00752  * TLS write buffer (ie. because the previous write was
00753  * interrupted.
00754  */
00755 ssize_t
00756 MHD_gtls_io_write_flush (MHD_gtls_session_t session)
00757 {
00758   ssize_t ret;
00759 
00760   if (session->internals.record_send_buffer.length == 0)
00761     return 0;                   /* done */
00762 
00763   ret = MHD_gtls_io_write_buffered (session, NULL, 0);
00764   MHD__gnutls_write_log ("WRITE FLUSH: %d [buffer: %d]\n", ret,
00765                          session->internals.record_send_buffer.length);
00766 
00767   return ret;
00768 }
00769 
00770 /* This function writes the data that are left in the
00771  * Handshake write buffer (ie. because the previous write was
00772  * interrupted.
00773  */
00774 ssize_t
00775 MHD_gtls_handshake_io_write_flush (MHD_gtls_session_t session)
00776 {
00777   ssize_t ret;
00778   ret = MHD_gtls_handshake_io_send_int (session, 0, 0, NULL, 0);
00779   if (ret < 0)
00780     {
00781       MHD_gnutls_assert ();
00782       return ret;
00783     }
00784 
00785   MHD__gnutls_write_log ("HANDSHAKE_FLUSH: written[1] %d bytes\n", ret);
00786 
00787   if (session->internals.handshake_send_buffer.length == 0)
00788     {
00789       ret = session->internals.handshake_send_buffer_prev_size; /* done */
00790       session->internals.handshake_send_buffer_prev_size = 0;
00791     }
00792 
00793   return ret;
00794 }
00795 
00796 /* This is a send function for the gnutls handshake
00797  * protocol. Just makes sure that all data have been sent.
00798  */
00799 ssize_t
00800 MHD_gtls_handshake_io_send_int (MHD_gtls_session_t session,
00801                                 content_type_t type,
00802                                 MHD_gnutls_handshake_description_t htype,
00803                                 const void *iptr, size_t n)
00804 {
00805   size_t left;
00806   ssize_t ret = 0;
00807   const opaque *ptr;
00808   ssize_t retval = 0;
00809 
00810   ptr = iptr;
00811 
00812   if (session->internals.handshake_send_buffer.length > 0 && ptr == NULL && n
00813       == 0)
00814     {
00815       /* resuming previously interrupted write
00816        */
00817       MHD_gnutls_assert ();
00818       ret = MHD__gnutls_buffer_get (&session->internals.handshake_send_buffer,
00819                                     &ptr, &n);
00820       if (ret < 0)
00821         {
00822           MHD_gnutls_assert ();
00823           return retval;
00824         }
00825 
00826       type = session->internals.handshake_send_buffer_type;
00827       htype = session->internals.handshake_send_buffer_htype;
00828 
00829     }
00830   else if (session->internals.handshake_send_buffer.length > 0)
00831     {
00832       MHD_gnutls_assert ();
00833       return GNUTLS_E_INTERNAL_ERROR;
00834     }
00835 #ifdef WRITE_DEBUG
00836   else
00837     {
00838       size_t sum = 0, x, j;
00839 
00840       MHD__gnutls_write_log ("HWRITE: will write %d bytes to %d.\n", n,
00841                              MHD_gnutls_transport_get_ptr (session));
00842       for (x = 0; x < ((n) / 16) + 1; x++)
00843         {
00844           if (sum > n)
00845             break;
00846 
00847           MHD__gnutls_write_log ("%.4x - ", x);
00848           for (j = 0; j < 16; j++)
00849             {
00850               if (sum < n)
00851                 {
00852                   MHD__gnutls_write_log ("%.2x ",
00853                                          ((unsigned char *) ptr)[sum++]);
00854                 }
00855               else
00856                 break;
00857             }
00858           MHD__gnutls_write_log ("\n");
00859         }
00860       MHD__gnutls_write_log ("\n");
00861     }
00862 #endif
00863 
00864   if (n == 0)
00865     {                           /* if we have no data to send */
00866       MHD_gnutls_assert ();
00867       return 0;
00868     }
00869   else if (ptr == NULL)
00870     {
00871       MHD_gnutls_assert ();
00872       return GNUTLS_E_INTERNAL_ERROR;
00873     }
00874 
00875   left = n;
00876   while (left > 0)
00877     {
00878       ret = MHD_gtls_send_int (session, type, htype, &ptr[n - left], left);
00879 
00880       if (ret <= 0)
00881         {
00882           if (ret == 0)
00883             {
00884               MHD_gnutls_assert ();
00885               ret = GNUTLS_E_INTERNAL_ERROR;
00886             }
00887 
00888           if (left > 0 && (ret == GNUTLS_E_INTERRUPTED || ret
00889                            == GNUTLS_E_AGAIN))
00890             {
00891               MHD_gnutls_assert ();
00892 
00893               retval =
00894                 MHD__gnutls_buffer_insert (&session->internals.
00895                                            handshake_send_buffer,
00896                                            &ptr[n - left], left);
00897               if (retval < 0)
00898                 {
00899                   MHD_gnutls_assert ();
00900                   return retval;
00901                 }
00902 
00903               session->internals.handshake_send_buffer_prev_size += n - left;
00904 
00905               session->internals.handshake_send_buffer_type = type;
00906               session->internals.handshake_send_buffer_htype = htype;
00907 
00908             }
00909           else
00910             {
00911               session->internals.handshake_send_buffer_prev_size = 0;
00912               session->internals.handshake_send_buffer.length = 0;
00913             }
00914 
00915           MHD_gnutls_assert ();
00916           return ret;
00917         }
00918       left -= ret;
00919     }
00920 
00921   retval = n + session->internals.handshake_send_buffer_prev_size;
00922 
00923   session->internals.handshake_send_buffer.length = 0;
00924   session->internals.handshake_send_buffer_prev_size = 0;
00925 
00926   return retval;
00927 
00928 }
00929 
00930 /* This is a receive function for the gnutls handshake
00931  * protocol. Makes sure that we have received all data.
00932  */
00933 ssize_t
00934 MHD_gtls_handshake_io_recv_int (MHD_gtls_session_t session,
00935                                 content_type_t type,
00936                                 MHD_gnutls_handshake_description_t htype,
00937                                 void *iptr, size_t sizeOfPtr)
00938 {
00939   size_t left;
00940   ssize_t i;
00941   opaque *ptr;
00942   size_t dsize;
00943 
00944   ptr = iptr;
00945   left = sizeOfPtr;
00946 
00947   if (sizeOfPtr == 0 || iptr == NULL)
00948     {
00949       MHD_gnutls_assert ();
00950       return GNUTLS_E_INVALID_REQUEST;
00951     }
00952 
00953   if (session->internals.handshake_recv_buffer.length > 0)
00954     {
00955       /* if we have already received some data */
00956       if (sizeOfPtr <= session->internals.handshake_recv_buffer.length)
00957         {
00958           /* if requested less data then return it.
00959            */
00960           MHD_gnutls_assert ();
00961           memcpy (iptr, session->internals.handshake_recv_buffer.data,
00962                   sizeOfPtr);
00963 
00964           session->internals.handshake_recv_buffer.length -= sizeOfPtr;
00965 
00966           memmove (session->internals.handshake_recv_buffer.data,
00967                    &session->internals.handshake_recv_buffer.data[sizeOfPtr],
00968                    session->internals.handshake_recv_buffer.length);
00969 
00970           return sizeOfPtr;
00971         }
00972       MHD_gnutls_assert ();
00973       memcpy (iptr, session->internals.handshake_recv_buffer.data,
00974               session->internals.handshake_recv_buffer.length);
00975 
00976       htype = session->internals.handshake_recv_buffer_htype;
00977       type = session->internals.handshake_recv_buffer_type;
00978 
00979       left -= session->internals.handshake_recv_buffer.length;
00980 
00981       session->internals.handshake_recv_buffer.length = 0;
00982     }
00983 
00984   while (left > 0)
00985     {
00986       dsize = sizeOfPtr - left;
00987       i = MHD_gtls_recv_int (session, type, htype, &ptr[dsize], left);
00988       if (i < 0)
00989         {
00990 
00991           if (dsize > 0 && (i == GNUTLS_E_INTERRUPTED || i == GNUTLS_E_AGAIN))
00992             {
00993               MHD_gnutls_assert ();
00994 
00995               session->internals.handshake_recv_buffer.data
00996                 =
00997                 MHD_gtls_realloc_fast (session->internals.
00998                                        handshake_recv_buffer.data, dsize);
00999               if (session->internals.handshake_recv_buffer.data == NULL)
01000                 {
01001                   MHD_gnutls_assert ();
01002                   return GNUTLS_E_MEMORY_ERROR;
01003                 }
01004 
01005               memcpy (session->internals.handshake_recv_buffer.data, iptr,
01006                       dsize);
01007 
01008               session->internals.handshake_recv_buffer_htype = htype;
01009               session->internals.handshake_recv_buffer_type = type;
01010 
01011               session->internals.handshake_recv_buffer.length = dsize;
01012             }
01013           else
01014             session->internals.handshake_recv_buffer.length = 0;
01015 
01016           MHD_gnutls_assert ();
01017 
01018           return i;
01019         }
01020       else
01021         {
01022           if (i == 0)
01023             break;              /* EOF */
01024         }
01025 
01026       left -= i;
01027 
01028     }
01029 
01030   session->internals.handshake_recv_buffer.length = 0;
01031 
01032   return sizeOfPtr - left;
01033 }
01034 
01035 /* Buffer for handshake packets. Keeps the packets in order
01036  * for finished messages to use them. Used in HMAC calculation
01037  * and finished messages.
01038  */
01039 int
01040 MHD_gtls_handshake_buffer_put (MHD_gtls_session_t session, opaque * data,
01041                                size_t length)
01042 {
01043 
01044   if (length == 0)
01045     return 0;
01046 
01047   if ((session->internals.max_handshake_data_buffer_size > 0) && ((length
01048                                                                    +
01049                                                                    session->
01050                                                                    internals.
01051                                                                    handshake_hash_buffer.
01052                                                                    length) >
01053                                                                   session->
01054                                                                   internals.
01055                                                                   max_handshake_data_buffer_size))
01056     {
01057       MHD_gnutls_assert ();
01058       return GNUTLS_E_MEMORY_ERROR;
01059     }
01060 
01061   MHD__gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data\n", length);
01062 
01063   if (MHD_gtls_buffer_append (&session->internals.handshake_hash_buffer, data,
01064                               length) < 0)
01065     {
01066       MHD_gnutls_assert ();
01067       return GNUTLS_E_MEMORY_ERROR;
01068     }
01069 
01070   return 0;
01071 }
01072 
01073 /* this function does not touch the buffer
01074  * and returns data from it (peek mode!)
01075  */
01076 int
01077 MHD_gtls_handshake_buffer_get_ptr (MHD_gtls_session_t session,
01078                                    opaque ** data_ptr, size_t * length)
01079 {
01080   if (length != NULL)
01081     *length = session->internals.handshake_hash_buffer.length;
01082 
01083   MHD__gnutls_buffers_log ("BUF[HSK]: Peeked %d bytes of Data\n",
01084                            session->internals.handshake_hash_buffer.length);
01085 
01086   if (data_ptr != NULL)
01087     *data_ptr = session->internals.handshake_hash_buffer.data;
01088 
01089   return 0;
01090 }
01091 
01092 /* Does not free the buffer
01093  */
01094 int
01095 MHD_gtls_handshake_buffer_empty (MHD_gtls_session_t session)
01096 {
01097 
01098   MHD__gnutls_buffers_log ("BUF[HSK]: Emptied buffer\n");
01099 
01100   session->internals.handshake_hash_buffer.length = 0;
01101 
01102   return 0;
01103 }
01104 
01105 int
01106 MHD_gtls_handshake_buffer_clear (MHD_gtls_session_t session)
01107 {
01108   MHD__gnutls_buffers_log ("BUF[HSK]: Cleared Data from buffer\n");
01109   MHD_gtls_buffer_clear (&session->internals.handshake_hash_buffer);
01110   return 0;
01111 }
Generated by  doxygen 1.6.2-20100208