Tizen 2.0 Release
[external/libgnutls26.git] / lib / gnutls_buffers.c
1 /*
2  * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3  * 2009, 2010 Free Software Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 /* This is the only file that uses the berkeley sockets API.
27  * 
28  * Also holds all the buffering code used in gnutls.
29  * The buffering code works as:
30  *
31  * RECORD LAYER: 
32  *  1. uses a buffer to hold data (application/handshake),
33  *    we got but they were not requested, yet.
34  *  (see gnutls_record_buffer_put(), gnutls_record_buffer_get_size() etc.)
35  *
36  *  2. uses a buffer to hold data that were incomplete (ie the read/write
37  *    was interrupted)
38  *  (see _gnutls_io_read_buffered(), _gnutls_io_write_buffered() etc.)
39  * 
40  * HANDSHAKE LAYER:
41  *  1. Uses a buffer to hold data that was not sent or received
42  *  complete. (E.g. sent 10 bytes of a handshake packet that is 20 bytes
43  *  long).
44  * (see _gnutls_handshake_send_int(), _gnutls_handshake_recv_int())
45  *
46  *  2. Uses buffer to hold the last received handshake message.
47  *  (see _gnutls_handshake_buffer_put() etc.)
48  *
49  */
50
51 #include <gnutls_int.h>
52 #include <gnutls_errors.h>
53 #include <gnutls_num.h>
54 #include <gnutls_record.h>
55 #include <gnutls_buffers.h>
56 #include <gnutls_mbuffers.h>
57 #include <system.h>
58
59 #include <errno.h>
60 #ifdef _WIN32
61 # include <windows.h>
62 #endif
63
64 #ifndef EAGAIN
65 #define EAGAIN EWOULDBLOCK
66 #endif
67
68 /* this is the maximum number of messages allowed to queue.
69  */
70 #define MAX_QUEUE 16
71
72 /**
73  * gnutls_transport_set_errno:
74  * @session: is a #gnutls_session_t structure.
75  * @err: error value to store in session-specific errno variable.
76  *
77  * Store @err in the session-specific errno variable.  Useful values
78  * for @err is EAGAIN and EINTR, other values are treated will be
79  * treated as real errors in the push/pull function.
80  *
81  * This function is useful in replacement push/pull functions set by
82  * gnutls_transport_set_push_function and
83  * gnutls_transport_set_pullpush_function under Windows, where the
84  * replacement push/pull may not have access to the same @errno
85  * variable that is used by GnuTLS (e.g., the application is linked to
86  * msvcr71.dll and gnutls is linked to msvcrt.dll).
87  *
88  * If you don't have the @session variable easily accessible from the
89  * push/pull function, and don't worry about thread conflicts, you can
90  * also use gnutls_transport_set_global_errno().
91  **/
92 void
93 gnutls_transport_set_errno (gnutls_session_t session, int err)
94 {
95   session->internals.errnum = err;
96 }
97
98 /**
99  * gnutls_transport_set_global_errno:
100  * @err: error value to store in global errno variable.
101  *
102  * Store @err in the global errno variable.  Useful values for @err is
103  * EAGAIN and EINTR, other values are treated will be treated as real
104  * errors in the push/pull function.
105  *
106  * This function is useful in replacement push/pull functions set by
107  * gnutls_transport_set_push_function and
108  * gnutls_transport_set_pullpush_function under Windows, where the
109  * replacement push/pull may not have access to the same @errno
110  * variable that is used by GnuTLS (e.g., the application is linked to
111  * msvcr71.dll and gnutls is linked to msvcrt.dll).
112  *
113  * Whether this function is thread safe or not depends on whether the
114  * global variable errno is thread safe, some system libraries make it
115  * a thread-local variable.  When feasible, using the guaranteed
116  * thread-safe gnutls_transport_set_errno() may be better.
117  **/
118 void
119 gnutls_transport_set_global_errno (int err)
120 {
121 #ifdef _WIN32
122   /* Keep this in sync with system_errno */
123   switch (err)
124     {
125     case EAGAIN:
126       SetLastError (WSAEWOULDBLOCK);
127       break;
128     case EINTR:
129       SetLastError (WSAEINTR);
130       break;
131     default:
132       /* We don't care about anything else */
133       SetLastError (NO_ERROR);
134       break;
135     }
136 #else
137   errno = err;
138 #endif
139 }
140
141 /* Buffers received packets of type APPLICATION DATA and
142  * HANDSHAKE DATA.
143  */
144 int
145 _gnutls_record_buffer_put (content_type_t type,
146                            gnutls_session_t session, opaque * data,
147                            size_t length)
148 {
149   gnutls_buffer_st *buf;
150
151   if (length == 0)
152     return 0;
153
154   switch (type)
155     {
156     case GNUTLS_APPLICATION_DATA:
157       buf = &session->internals.application_data_buffer;
158       _gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n",
159                            (int) length, (int) type);
160       break;
161
162     case GNUTLS_HANDSHAKE:
163       buf = &session->internals.handshake_data_buffer;
164       _gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data(%d)\n",
165                            (int) length, (int) type);
166       break;
167
168     case GNUTLS_INNER_APPLICATION:
169       buf = &session->internals.ia_data_buffer;
170       _gnutls_buffers_log ("BUF[IA]: Inserted %d bytes of Data(%d)\n",
171                            (int) length, (int) type);
172       break;
173
174     default:
175       gnutls_assert ();
176       return GNUTLS_E_INVALID_REQUEST;
177     }
178
179   if (_gnutls_buffer_append_data (buf, data, length) < 0)
180     {
181       gnutls_assert ();
182       return GNUTLS_E_MEMORY_ERROR;
183     }
184
185   return 0;
186 }
187
188 int
189 _gnutls_record_buffer_get_size (content_type_t type, gnutls_session_t session)
190 {
191   switch (type)
192     {
193     case GNUTLS_APPLICATION_DATA:
194       return session->internals.application_data_buffer.length;
195
196     case GNUTLS_HANDSHAKE:
197       return session->internals.handshake_data_buffer.length;
198
199     case GNUTLS_INNER_APPLICATION:
200       return session->internals.ia_data_buffer.length;
201
202     default:
203       return GNUTLS_E_INVALID_REQUEST;
204     }
205 }
206
207 /**
208  * gnutls_record_check_pending:
209  * @session: is a #gnutls_session_t structure.
210  *
211  * This function checks if there are any data to receive in the gnutls
212  * buffers.
213  *
214  * Returns: the size of that data or 0.
215  **/
216 size_t
217 gnutls_record_check_pending (gnutls_session_t session)
218 {
219   return _gnutls_record_buffer_get_size (GNUTLS_APPLICATION_DATA, session);
220 }
221
222 int
223 _gnutls_record_buffer_get (content_type_t type,
224                            gnutls_session_t session, opaque * data,
225                            size_t length)
226 {
227   if (length == 0 || data == NULL)
228     {
229       gnutls_assert ();
230       return GNUTLS_E_INVALID_REQUEST;
231     }
232
233   switch (type)
234     {
235     case GNUTLS_APPLICATION_DATA:
236       _gnutls_buffer_pop_data (&session->internals.application_data_buffer,
237                                data, &length);
238       _gnutls_buffers_log ("BUFFER[REC][AD]: Read %d bytes of Data(%d)\n",
239                            (int) length, (int) type);
240       break;
241
242     case GNUTLS_HANDSHAKE:
243       _gnutls_buffer_pop_data (&session->internals.handshake_data_buffer,
244                                data, &length);
245       _gnutls_buffers_log ("BUF[REC][HD]: Read %d bytes of Data(%d)\n",
246                            (int) length, (int) type);
247       break;
248
249     case GNUTLS_INNER_APPLICATION:
250
251       _gnutls_buffer_pop_data (&session->internals.ia_data_buffer, data,
252                                &length);
253       _gnutls_buffers_log ("BUF[REC][IA]: Read %d bytes of Data(%d)\n",
254                            (int) length, (int) type);
255       break;
256
257     default:
258       gnutls_assert ();
259       return GNUTLS_E_INVALID_REQUEST;
260     }
261
262
263   return length;
264 }
265
266 inline static void
267 reset_errno (gnutls_session_t session)
268 {
269   session->internals.errnum = 0;
270 }
271
272 inline static int
273 get_errno (gnutls_session_t session)
274 {
275   if (session->internals.errnum != 0)
276     return session->internals.errnum;
277   else
278     return session->internals.errno_func (session->
279                                           internals.transport_recv_ptr);
280 }
281
282
283 /* This function is like read. But it does not return -1 on error.
284  * It does return gnutls_errno instead.
285  *
286  * Flags are only used if the default recv() function is being used.
287  */
288 static ssize_t
289 _gnutls_read (gnutls_session_t session, mbuffer_st ** bufel,
290               size_t size, gnutls_pull_func pull_func)
291 {
292   size_t left;
293   ssize_t i = 0;
294   char *ptr;
295   gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
296
297   if (!bufel)
298     {
299       gnutls_assert ();
300       return GNUTLS_E_INTERNAL_ERROR;
301     }
302
303   *bufel = _mbuffer_alloc (0, size);
304   if (!*bufel)
305     {
306       gnutls_assert ();
307       return GNUTLS_E_MEMORY_ERROR;
308     }
309   ptr = (*bufel)->msg.data;
310
311   session->internals.direction = 0;
312
313   left = size;
314   while (left > 0)
315     {
316       reset_errno (session);
317
318       i = pull_func (fd, &ptr[size - left], left);
319
320       if (i < 0)
321         {
322           int err = get_errno (session);
323
324           _gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n",
325                             (int) i, fd, errno, session->internals.errnum);
326
327           if (err == EAGAIN || err == EINTR)
328             {
329               if (size - left > 0)
330                 {
331
332                   _gnutls_read_log ("READ: returning %d bytes from %p\n",
333                                     (int) (size - left), fd);
334
335                   goto finish;
336                 }
337
338               if (err == EAGAIN)
339                 return GNUTLS_E_AGAIN;
340               return GNUTLS_E_INTERRUPTED;
341             }
342           else
343             {
344               gnutls_assert ();
345               return GNUTLS_E_PULL_ERROR;
346             }
347         }
348       else
349         {
350
351           _gnutls_read_log ("READ: Got %d bytes from %p\n", (int) i, fd);
352
353           if (i == 0)
354             break;              /* EOF */
355         }
356
357       left -= i;
358       (*bufel)->msg.size += i;
359     }
360
361 finish:
362
363   if (_gnutls_log_level >= 7)
364     {
365       _gnutls_read_log ("READ: read %d bytes from %p\n",
366                         (int) (size - left), fd);
367
368     }
369
370   return (size - left);
371 }
372
373
374
375 static ssize_t
376 _gnutls_writev_emu (gnutls_session_t session, const giovec_t * giovec,
377                     int giovec_cnt)
378 {
379   int ret = 0, j = 0;
380   gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
381   void *iptr;
382   size_t sizeOfPtr;
383   size_t total = 0;
384
385   for (j = 0; j < giovec_cnt; j++)
386     {
387       sizeOfPtr = giovec[j].iov_len;
388       iptr = giovec[j].iov_base;
389
390       ret = session->internals.push_func (fd, iptr, sizeOfPtr);
391
392       if (ret == -1)
393         break;
394
395       total += ret;
396
397       if (ret != giovec[j].iov_len)
398         break;
399     }
400
401   if (total > 0)
402     return total;
403
404   return ret;
405 }
406
407 static ssize_t
408 _gnutls_writev (gnutls_session_t session, const giovec_t * giovec,
409                 int giovec_cnt)
410 {
411   int i;
412   gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
413
414   reset_errno (session);
415
416   if (session->internals.push_func != NULL)
417     i = _gnutls_writev_emu (session, giovec, giovec_cnt);
418   else
419     i = session->internals.vec_push_func (fd, giovec, giovec_cnt);
420
421   if (i == -1)
422     {
423       int err = get_errno (session);
424       _gnutls_debug_log ("errno: %d\n", err);
425       if (err == EAGAIN)
426         return GNUTLS_E_AGAIN;
427       else if (err == EINTR)
428         return GNUTLS_E_INTERRUPTED;
429       else
430         {
431           gnutls_assert ();
432           return GNUTLS_E_PUSH_ERROR;
433         }
434     }
435   return i;
436 }
437
438 #define RCVLOWAT session->internals.lowat
439
440 /* This function is only used with berkeley style sockets.
441  * Clears the peeked data (read with MSG_PEEK).
442  */
443 int
444 _gnutls_io_clear_peeked_data (gnutls_session_t session)
445 {
446   mbuffer_st *peekdata;
447   int ret, sum;
448
449   if (session->internals.have_peeked_data == 0 || RCVLOWAT == 0)
450     return 0;
451
452   /* this was already read by using MSG_PEEK - so it shouldn't fail */
453   sum = 0;
454   do
455     {                           /* we need this to finish now */
456       ret =
457         _gnutls_read (session, &peekdata, RCVLOWAT - sum,
458                       session->internals.pull_func);
459       if (ret > 0)
460         sum += ret;
461       _mbuffer_xfree (&peekdata);
462     }
463   while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN
464          || sum < RCVLOWAT);
465
466   if (ret < 0)
467     {
468       gnutls_assert ();
469       return ret;
470     }
471
472   session->internals.have_peeked_data = 0;
473
474   return 0;
475 }
476
477 /* This function is like recv(with MSG_PEEK). But it does not return -1 on error.
478  * It does return gnutls_errno instead.
479  * This function reads data from the socket and keeps them in a buffer, of up to
480  * MAX_RECV_SIZE. 
481  *
482  * This is not a general purpose function. It returns EXACTLY the data requested,
483  * which are stored in a local (in the session) buffer.
484  *
485  */
486 ssize_t
487 _gnutls_io_read_buffered (gnutls_session_t session, size_t total,
488                           content_type_t recv_type)
489 {
490   ssize_t ret = 0, ret2 = 0;
491   size_t min;
492   mbuffer_st *bufel = NULL;
493   size_t recvlowat, recvdata, readsize;
494
495   if (total > MAX_RECV_SIZE || total == 0)
496     {
497       gnutls_assert ();         /* internal error */
498       return GNUTLS_E_INVALID_REQUEST;
499     }
500
501   /* If an external pull function is used, then do not leave
502    * any data into the kernel buffer.
503    */
504   if (session->internals.pull_func != system_read)
505     {
506       recvlowat = 0;
507     }
508   else
509     {
510       /* leave peeked data to the kernel space only if application data
511        * is received and we don't have any peeked 
512        * data in gnutls session.
513        */
514       if (recv_type != GNUTLS_APPLICATION_DATA
515           && session->internals.have_peeked_data == 0)
516         recvlowat = 0;
517       else
518         recvlowat = RCVLOWAT;
519     }
520
521
522
523   /* calculate the actual size, ie. get the minimum of the
524    * buffered data and the requested data.
525    */
526   min = MIN (session->internals.record_recv_buffer.byte_length, total);
527   if (min > 0)
528     {
529       /* if we have enough buffered data
530        * then just return them.
531        */
532       if (min == total)
533         {
534           return min;
535         }
536     }
537
538   /* min is over zero. recvdata is the data we must
539    * receive in order to return the requested data.
540    */
541   recvdata = total - min;
542   readsize = recvdata - recvlowat;
543
544   /* Check if the previously read data plus the new data to
545    * receive are longer than the maximum receive buffer size.
546    */
547   if ((session->internals.record_recv_buffer.byte_length + recvdata) >
548       MAX_RECV_SIZE)
549     {
550       gnutls_assert ();         /* internal error */
551       return GNUTLS_E_INVALID_REQUEST;
552     }
553
554   if (ret < 0)
555     {
556       gnutls_assert ();
557       return ret;
558     }
559
560   /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer.
561    */
562   if (readsize > 0)
563     {
564       ret =
565         _gnutls_read (session, &bufel, readsize,
566                       session->internals.pull_func);
567
568       /* return immediately if we got an interrupt or eagain
569        * error.
570        */
571       if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
572         {
573           _mbuffer_xfree (&bufel);
574           return ret;
575         }
576     }
577
578   /* copy fresh data to our buffer.
579    */
580   if (ret > 0)
581     {
582       _gnutls_read_log
583         ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
584          (int) session->internals.record_recv_buffer.byte_length, (int) ret);
585       _gnutls_read_log ("RB: Requested %d bytes\n", (int) total);
586
587       _mbuffer_enqueue (&session->internals.record_recv_buffer, bufel);
588     }
589   else
590     _mbuffer_xfree (&bufel);
591
592
593   /* This is hack in order for select to work. Just leave recvlowat data,
594    * into the kernel buffer (using a read with MSG_PEEK), thus making
595    * select think, that the socket is ready for reading.
596    * MSG_PEEK is only used with berkeley style sockets.
597    */
598   if (ret == readsize && recvlowat > 0)
599     {
600       ret2 = _gnutls_read (session, &bufel, recvlowat, system_read_peek);
601
602       if (ret2 < 0 && gnutls_error_is_fatal (ret2) == 0)
603         {
604           _mbuffer_xfree (&bufel);
605           return ret2;
606         }
607
608       if (ret2 > 0)
609         {
610           _gnutls_read_log ("RB-PEEK: Read %d bytes in PEEK MODE.\n",
611                             (int) ret2);
612           _gnutls_read_log
613             ("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n",
614              (int) session->internals.record_recv_buffer.byte_length,
615              (int) ret2, (int) total);
616           session->internals.have_peeked_data = 1;
617           _mbuffer_enqueue (&session->internals.record_recv_buffer, bufel);
618         }
619       else
620         _mbuffer_xfree (&bufel);
621     }
622
623   if (ret < 0 || ret2 < 0)
624     {
625       gnutls_assert ();
626       /* that's because they are initialized to 0 */
627       return MIN (ret, ret2);
628     }
629
630   ret += ret2;
631
632   if (ret > 0 && ret < recvlowat)
633     {
634       gnutls_assert ();
635       return GNUTLS_E_AGAIN;
636     }
637
638   if (ret == 0)
639     {                           /* EOF */
640       gnutls_assert ();
641       return 0;
642     }
643
644   ret = session->internals.record_recv_buffer.byte_length;
645
646   if ((ret > 0) && ((size_t) ret < total))
647     {
648       /* Short Read */
649       gnutls_assert ();
650       return GNUTLS_E_AGAIN;
651     }
652   else
653     {
654       return ret;
655     }
656 }
657
658 /* This function is like write. But it does not return -1 on error.
659  * It does return gnutls_errno instead.
660  *
661  * This function takes full responsibility of freeing msg->data.
662  *
663  * In case of E_AGAIN and E_INTERRUPTED errors, you must call
664  * gnutls_write_flush(), until it returns ok (0).
665  *
666  * We need to push exactly the data in msg->size, since we cannot send
667  * less data. In TLS the peer must receive the whole packet in order
668  * to decrypt and verify the integrity.
669  *
670  */
671 ssize_t
672 _gnutls_io_write_buffered (gnutls_session_t session,
673                            mbuffer_st * bufel, unsigned int mflag)
674 {
675   mbuffer_head_st *const send_buffer = &session->internals.record_send_buffer;
676
677   /* to know where the procedure was interrupted.
678    */
679   session->internals.direction = 1;
680
681   _mbuffer_enqueue (send_buffer, bufel);
682
683   _gnutls_write_log
684     ("WRITE: enqueued %d bytes for %p. Total %d bytes.\n",
685      (int) bufel->msg.size, session->internals.transport_recv_ptr,
686      (int) send_buffer->byte_length);
687
688   if (mflag == MBUFFER_FLUSH)
689     return _gnutls_io_write_flush (session);
690   else
691     return bufel->msg.size;
692 }
693
694 typedef ssize_t (*send_func) (gnutls_session_t, const giovec_t *, int);
695
696 /* This function writes the data that are left in the
697  * TLS write buffer (ie. because the previous write was
698  * interrupted.
699  */
700 ssize_t
701 _gnutls_io_write_flush (gnutls_session_t session)
702 {
703   gnutls_datum_t msg;
704   mbuffer_head_st *send_buffer = &session->internals.record_send_buffer;
705   int ret;
706   ssize_t sent = 0, tosend = 0;
707   giovec_t iovec[MAX_QUEUE];
708   int i = 0;
709   mbuffer_st *cur;
710
711   _gnutls_write_log ("WRITE FLUSH: %d bytes in buffer.\n",
712                      (int) send_buffer->byte_length);
713
714   for (cur = _mbuffer_get_first (send_buffer, &msg);
715        cur != NULL; cur = _mbuffer_get_next (cur, &msg))
716     {
717       iovec[i].iov_base = msg.data;
718       iovec[i++].iov_len = msg.size;
719       tosend += msg.size;
720
721       /* we buffer up to MAX_QUEUE messages */
722       if (i >= sizeof (iovec) / sizeof (iovec[0]))
723         {
724           gnutls_assert ();
725           return GNUTLS_E_INTERNAL_ERROR;
726         }
727     }
728
729   if (tosend == 0)
730     {
731       gnutls_assert();
732       return 0;
733     }
734
735   ret = _gnutls_writev (session, iovec, i);
736   if (ret >= 0)
737     {
738       _mbuffer_remove_bytes (send_buffer, ret);
739       _gnutls_write_log ("WRITE: wrote %d bytes, %d bytes left.\n",
740                          ret, (int) send_buffer->byte_length);
741
742       sent += ret;
743     }
744   else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
745     {
746       _gnutls_write_log ("WRITE interrupted: %d bytes left.\n",
747                          (int) send_buffer->byte_length);
748       return ret;
749     }
750   else
751     {
752       _gnutls_write_log ("WRITE error: code %d, %d bytes left.\n",
753                          ret, (int) send_buffer->byte_length);
754
755       gnutls_assert ();
756       return ret;
757     }
758
759   if (sent < tosend)
760     {
761       gnutls_assert ();
762       return GNUTLS_E_AGAIN;
763     }
764
765   return sent;
766 }
767
768 /* This function writes the data that are left in the
769  * Handshake write buffer (ie. because the previous write was
770  * interrupted.
771  *
772  */
773 ssize_t
774 _gnutls_handshake_io_write_flush (gnutls_session_t session)
775 {
776   mbuffer_head_st *const send_buffer =
777     &session->internals.handshake_send_buffer;
778   gnutls_datum_t msg;
779   int ret;
780   ssize_t total = 0;
781   mbuffer_st *cur;
782
783   _gnutls_write_log ("HWRITE FLUSH: %d bytes in buffer.\n",
784                      (int) send_buffer->byte_length);
785
786   for (cur = _mbuffer_get_first (send_buffer, &msg);
787        cur != NULL; cur = _mbuffer_get_first (send_buffer, &msg))
788     {
789       ret = _gnutls_send_int (session, GNUTLS_HANDSHAKE,
790                               session->internals.handshake_send_buffer_htype,
791                               EPOCH_WRITE_CURRENT,
792                               msg.data, msg.size, 0 /* do not flush */ );
793
794       if (ret >= 0)
795         {
796           _mbuffer_remove_bytes (send_buffer, ret);
797
798           _gnutls_write_log ("HWRITE: wrote %d bytes, %d bytes left.\n",
799                              ret, (int) send_buffer->byte_length);
800
801           total += ret;
802         }
803       else
804         {
805           _gnutls_write_log ("HWRITE error: code %d, %d bytes left.\n",
806                              ret, (int) send_buffer->byte_length);
807
808           gnutls_assert ();
809           return ret;
810         }
811     }
812
813   return _gnutls_io_write_flush (session);
814
815 }
816
817
818 /* This is a send function for the gnutls handshake 
819  * protocol. Just makes sure that all data have been sent.
820  *
821  */
822 void
823 _gnutls_handshake_io_cache_int (gnutls_session_t session,
824                                 gnutls_handshake_description_t htype,
825                                 mbuffer_st * bufel)
826 {
827   mbuffer_head_st *const send_buffer =
828     &session->internals.handshake_send_buffer;
829
830   _mbuffer_enqueue (send_buffer, bufel);
831   session->internals.handshake_send_buffer_htype = htype;
832
833   _gnutls_write_log
834     ("HWRITE: enqueued %d. Total %d bytes.\n",
835      (int) bufel->msg.size, (int) send_buffer->byte_length);
836
837   return;
838 }
839
840 /* This is a receive function for the gnutls handshake 
841  * protocol. Makes sure that we have received all data.
842  */
843 ssize_t
844 _gnutls_handshake_io_recv_int (gnutls_session_t session,
845                                content_type_t type,
846                                gnutls_handshake_description_t htype,
847                                void *iptr, size_t sizeOfPtr)
848 {
849   size_t left;
850   ssize_t i;
851   opaque *ptr;
852   size_t dsize;
853
854   ptr = iptr;
855   left = sizeOfPtr;
856
857   if (sizeOfPtr == 0 || iptr == NULL)
858     {
859       gnutls_assert ();
860       return GNUTLS_E_INVALID_REQUEST;
861     }
862
863   if (session->internals.handshake_recv_buffer.length > 0)
864     {
865       size_t tmp;
866
867       /* if we have already received some data */
868       if (sizeOfPtr <= session->internals.handshake_recv_buffer.length)
869         {
870           /* if requested less data then return it.
871            */
872           gnutls_assert ();
873
874           tmp = sizeOfPtr;
875           _gnutls_buffer_pop_data (&session->internals.handshake_recv_buffer,
876                                    iptr, &tmp);
877           return tmp;
878         }
879       gnutls_assert ();
880
881       tmp = sizeOfPtr;
882       _gnutls_buffer_pop_data (&session->internals.handshake_recv_buffer,
883                                iptr, &tmp);
884       left -= tmp;
885
886       htype = session->internals.handshake_recv_buffer_htype;
887       type = session->internals.handshake_recv_buffer_type;
888     }
889
890   while (left > 0)
891     {
892       dsize = sizeOfPtr - left;
893       i = _gnutls_recv_int (session, type, htype, &ptr[dsize], left);
894       if (i < 0)
895         {
896
897           if (dsize > 0 && (i == GNUTLS_E_INTERRUPTED || i == GNUTLS_E_AGAIN))
898             {
899               gnutls_assert ();
900
901               _gnutls_buffer_append_data (&session->internals.
902                                           handshake_recv_buffer, iptr, dsize);
903
904               session->internals.handshake_recv_buffer_htype = htype;
905               session->internals.handshake_recv_buffer_type = type;
906             }
907
908           return i;
909         }
910       else
911         {
912           if (i == 0)
913             break;              /* EOF */
914         }
915
916       left -= i;
917
918     }
919
920   session->internals.handshake_recv_buffer.length = 0;
921
922   return sizeOfPtr - left;
923 }
924
925 /* Buffer for handshake packets. Keeps the packets in order
926  * for finished messages to use them. Used in HMAC calculation
927  * and finished messages.
928  */
929 int
930 _gnutls_handshake_buffer_put (gnutls_session_t session, opaque * data,
931                               size_t length)
932 {
933
934   if (length == 0)
935     return 0;
936
937   if ((session->internals.max_handshake_data_buffer_size > 0) &&
938       ((length + session->internals.handshake_hash_buffer.length) >
939        session->internals.max_handshake_data_buffer_size))
940     {
941       gnutls_assert ();
942       return GNUTLS_E_HANDSHAKE_TOO_LARGE;
943     }
944
945   _gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data\n", (int) length);
946   if (_gnutls_buffer_append_data (&session->internals.handshake_hash_buffer,
947                                   data, length) < 0)
948     {
949       gnutls_assert ();
950       return GNUTLS_E_MEMORY_ERROR;
951     }
952
953   return 0;
954 }
955
956 int
957 _gnutls_handshake_buffer_get_size (gnutls_session_t session)
958 {
959
960   return session->internals.handshake_hash_buffer.length;
961 }
962
963 /* this function does not touch the buffer
964  * and returns data from it (peek mode!)
965  */
966 int
967 _gnutls_handshake_buffer_get_ptr (gnutls_session_t session,
968                                   opaque ** data_ptr, size_t * length)
969 {
970   if (length != NULL)
971     *length = session->internals.handshake_hash_buffer.length;
972
973   _gnutls_buffers_log ("BUF[HSK]: Peeked %d bytes of Data\n",
974                        (int) session->internals.handshake_hash_buffer.length);
975
976   if (data_ptr != NULL)
977     *data_ptr = session->internals.handshake_hash_buffer.data;
978
979   return 0;
980 }
981
982 /* Does not free the buffer
983  */
984 int
985 _gnutls_handshake_buffer_empty (gnutls_session_t session)
986 {
987
988   _gnutls_buffers_log ("BUF[HSK]: Emptied buffer\n");
989
990   session->internals.handshake_hash_buffer.length = 0;
991
992   return 0;
993 }
994
995
996 int
997 _gnutls_handshake_buffer_clear (gnutls_session_t session)
998 {
999
1000   _gnutls_buffers_log ("BUF[HSK]: Cleared Data from buffer\n");
1001   _gnutls_buffer_clear (&session->internals.handshake_hash_buffer);
1002
1003   return 0;
1004 }
1005
1006 /**
1007  * gnutls_transport_set_pull_function:
1008  * @session: is a #gnutls_session_t structure.
1009  * @pull_func: a callback function similar to read()
1010  *
1011  * This is the function where you set a function for gnutls to receive
1012  * data.  Normally, if you use berkeley style sockets, do not need to
1013  * use this function since the default (recv(2)) will probably be ok.
1014  *
1015  * PULL_FUNC is of the form,
1016  * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);
1017  **/
1018 void
1019 gnutls_transport_set_pull_function (gnutls_session_t session,
1020                                     gnutls_pull_func pull_func)
1021 {
1022   session->internals.pull_func = pull_func;
1023 }
1024
1025 /**
1026  * gnutls_transport_set_push_function:
1027  * @session: is a #gnutls_session_t structure.
1028  * @push_func: a callback function similar to write()
1029  *
1030  * This is the function where you set a push function for gnutls to
1031  * use in order to send data.  If you are going to use berkeley style
1032  * sockets, you do not need to use this function since the default
1033  * (send(2)) will probably be ok.  Otherwise you should specify this
1034  * function for gnutls to be able to send data.
1035  *
1036  * PUSH_FUNC is of the form,
1037  * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
1038  **/
1039 void
1040 gnutls_transport_set_push_function (gnutls_session_t session,
1041                                     gnutls_push_func push_func)
1042 {
1043   session->internals.push_func = push_func;
1044   session->internals.vec_push_func = NULL;
1045 }
1046
1047 /**
1048  * gnutls_transport_set_vec_push_function:
1049  * @session: is a #gnutls_session_t structure.
1050  * @vec_func: a callback function similar to writev()
1051  *
1052  * This is the function where you set a push function for gnutls to
1053  * use in order to send data.  If you are going to use berkeley style
1054  * sockets, you do not need to use this function since the default
1055  * (send(2)) will probably be ok.  Otherwise you should specify this
1056  * function for gnutls to be able to send data.
1057  *
1058  * PUSH_FUNC is of the form,
1059  * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
1060  **/
1061 void
1062 gnutls_transport_set_vec_push_function (gnutls_session_t session,
1063                                      gnutls_vec_push_func vec_func)
1064 {
1065   session->internals.push_func = NULL;
1066   session->internals.vec_push_func = vec_func;
1067 }
1068
1069 /**
1070  * gnutls_transport_set_errno_function:
1071  * @session: is a #gnutls_session_t structure.
1072  * @errno_func: a callback function similar to write()
1073  *
1074  * This is the function where you set a function to retrieve errno
1075  * after a failed push or pull operation.
1076  *
1077  * errno_func is of the form,
1078  * int (*gnutls_errno_func)(gnutls_transport_ptr_t);
1079  * and should return the errno.
1080  **/
1081 void
1082 gnutls_transport_set_errno_function (gnutls_session_t session,
1083                                      gnutls_errno_func errno_func)
1084 {
1085   session->internals.errno_func = errno_func;
1086 }