⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 reliable.c

📁 OpenVPN is a robust and highly flexible tunneling application that uses all of the encryption, authe
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  OpenVPN -- An application to securely tunnel IP networks *             over a single UDP port, with support for SSL/TLS-based *             session authentication and key exchange, *             packet encryption, packet authentication, and *             packet compression. * *  Copyright (C) 2002-2004 James Yonan <jim@yonan.net> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program (see the file COPYING included with this *  distribution); if not, write to the Free Software Foundation, Inc., *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *//* * These routines implement a reliability layer on top of UDP, * so that SSL/TLS can be run over UDP. */#ifdef WIN32#include "config-win32.h"#else#include "config.h"#endif#if defined(USE_CRYPTO) && defined(USE_SSL)#include "syshead.h"#include "buffer.h"#include "error.h"#include "common.h"#include "reliable.h"#include "memdbg.h"/* check if a particular packet_id is present in ack */static inline boolreliable_ack_packet_id_present (struct reliable_ack *ack, packet_id_type pid){  int i;  for (i = 0; i < ack->len; ++i)    if (ack->packet_id[i] == pid)      return true;  return false;}/* get a packet_id from buf */boolreliable_ack_read_packet_id (struct buffer *buf, packet_id_type *pid){  packet_id_type net_pid;  if (buf_read (buf, &net_pid, sizeof (net_pid)))    {      *pid = ntohpid (net_pid);      msg (D_REL_DEBUG, "ACK read ID " packet_id_format " (buf->len=%d)",	   (packet_id_print_type)*pid, buf->len);      return true;    }  msg (D_REL_LOW, "ACK read ID FAILED (buf->len=%d)", buf->len);  return false;}/* acknowledge a packet_id by adding it to a struct reliable_ack */boolreliable_ack_acknowledge_packet_id (struct reliable_ack *ack, packet_id_type pid){  if (!reliable_ack_packet_id_present (ack, pid) && ack->len < RELIABLE_ACK_SIZE)    {      ack->packet_id[ack->len++] = pid;      msg (D_REL_DEBUG, "ACK acknowledge ID " packet_id_format " (ack->len=%d)",	   (packet_id_print_type)pid, ack->len);      return true;    }  msg (D_REL_LOW, "ACK acknowledge ID " packet_id_format " FAILED (ack->len=%d)",       (packet_id_print_type)pid, ack->len);  return false;}/* read a packet ID acknowledgement record from buf into ack */boolreliable_ack_read (struct reliable_ack * ack,		   struct buffer * buf, const struct session_id * sid){  struct gc_arena gc = gc_new ();  int i;  uint8_t count;  packet_id_type net_pid;  packet_id_type pid;  struct session_id session_id_remote;  if (!buf_read (buf, &count, sizeof (count)))    goto error;  for (i = 0; i < count; ++i)    {      if (!buf_read (buf, &net_pid, sizeof (net_pid)))	goto error;      if (ack->len >= RELIABLE_ACK_SIZE)	goto error;      pid = ntohpid (net_pid);      ack->packet_id[ack->len++] = pid;    }  if (count)    {      if (!session_id_read (&session_id_remote, buf))	goto error;      if (!session_id_defined (&session_id_remote) ||	  !session_id_equal (&session_id_remote, sid))	{	  msg (D_REL_LOW,	       "ACK read BAD SESSION-ID FROM REMOTE, local=%s, remote=%s",	       session_id_print (sid, &gc), session_id_print (&session_id_remote, &gc));	  goto error;	}    }  gc_free (&gc);  return true;error:  gc_free (&gc);  return false;}#define ACK_SIZE(n) (sizeof (uint8_t) + ((n) ? SID_SIZE : 0) + sizeof (packet_id_type) * (n))/* write a packet ID acknowledgement record to buf, *//* removing all acknowledged entries from ack */boolreliable_ack_write (struct reliable_ack * ack,		    struct buffer * buf,		    const struct session_id * sid, int max, bool prepend){  int i, j;  uint8_t n;  struct buffer sub;  n = ack->len;  if (n > max)    n = max;  sub = buf_sub (buf, ACK_SIZE(n), prepend);  if (!BDEF (&sub))    goto error;  ASSERT (buf_write (&sub, &n, sizeof (n)));  for (i = 0; i < n; ++i)    {      packet_id_type pid = ack->packet_id[i];      packet_id_type net_pid = htonpid (pid);      ASSERT (buf_write (&sub, &net_pid, sizeof (net_pid)));      msg (D_REL_DEBUG, "ACK write ID " packet_id_format " (ack->len=%d, n=%d)", (packet_id_print_type)pid, ack->len, n);    }  if (n)    {      ASSERT (session_id_defined (sid));      ASSERT (session_id_write (sid, &sub));      for (i = 0, j = n; j < ack->len;)	ack->packet_id[i++] = ack->packet_id[j++];      ack->len = i;    }  return true;error:  return false;}/* add to extra_frame the maximum number of bytes we will need for reliable_ack_write */voidreliable_ack_adjust_frame_parameters (struct frame* frame, int max){  frame_add_to_extra_frame (frame, ACK_SIZE (max));}/* print a reliable ACK record coming off the wire */const char *reliable_ack_print (struct buffer *buf, bool verbose, struct gc_arena *gc){  int i;  uint8_t n_ack;  struct session_id sid_ack;  packet_id_type pid;  struct buffer out = alloc_buf_gc (256, gc);  buf_printf (&out, "[");  if (!buf_read (buf, &n_ack, sizeof (n_ack)))    goto done;  for (i = 0; i < n_ack; ++i)    {      if (!buf_read (buf, &pid, sizeof (pid)))	goto done;      pid = ntohpid (pid);      buf_printf (&out, " " packet_id_format, (packet_id_print_type)pid);    }  if (n_ack)    {      if (!session_id_read (&sid_ack, buf))	goto done;      if (verbose)	buf_printf (&out, " sid=%s", session_id_print (&sid_ack, gc));    } done:  buf_printf (&out, " ]");  return BSTR (&out);}/* * struct reliable member functions. */voidreliable_init (struct reliable *rel, int buf_size, int offset, int array_size){  int i;  CLEAR (*rel);  ASSERT (array_size > 0 && array_size <= RELIABLE_CAPACITY);  rel->size = array_size;  rel->offset = offset;  for (i = 0; i < rel->size; ++i)    {      struct reliable_entry *e = &rel->array[i];      e->buf = alloc_buf (buf_size);      ASSERT (buf_init (&e->buf, offset));    }}voidreliable_free (struct reliable *rel){  int i;  for (i = 0; i < rel->size; ++i)    {      struct reliable_entry *e = &rel->array[i];      free_buf (&e->buf);    }}/* no active buffers? */boolreliable_empty (const struct reliable *rel){  int i;  for (i = 0; i < rel->size; ++i)    {      const struct reliable_entry *e = &rel->array[i];      if (e->active)	return false;    }  return true;}/* del acknowledged items from send buf */voidreliable_send_purge (struct reliable *rel, struct reliable_ack *ack){  int i, j;  for (i = 0; i < ack->len; ++i)    {      packet_id_type pid = ack->packet_id[i];      for (j = 0; j < rel->size; ++j)	{	  struct reliable_entry *e = &rel->array[j];	  if (e->active && e->packet_id == pid)	    {	      msg (D_REL_DEBUG,		   "ACK received for pid " packet_id_format ", deleting from send buffer",		   (packet_id_print_type)pid);#if 0	      /* DEBUGGING -- how close were we timing out on ACK failure and resending? */	      {		if (e->next_try)		  {		    const interval_t wake = e->next_try - now;		    msg (M_INFO, "ACK " packet_id_format ", wake=%d", pid, wake);		  }	      }#endif	      e->active = false;	      break;	    }	}    }}/* print the current sequence of active packet IDs */static const char *reliable_print_ids (const struct reliable *rel, struct gc_arena *gc){  struct buffer out = alloc_buf_gc (512, gc);  int i;  buf_printf (&out, "[" packet_id_format "]", (packet_id_print_type)rel->packet_id);  for (i = 0; i < rel->size; ++i)    {      const struct reliable_entry *e = &rel->array[i];      if (e->active)	buf_printf (&out, " " packet_id_format, (packet_id_print_type)e->packet_id);    }  return BSTR (&out);}/* true if at least one free buffer available */boolreliable_can_get (const struct reliable *rel){  struct gc_arena gc = gc_new ();  int i;  for (i = 0; i < rel->size; ++i)    {      const struct reliable_entry *e = &rel->array[i];      if (!e->active)	return true;    }  msg (D_REL_LOW, "ACK no free receive buffer available: %s", reliable_print_ids (rel, &gc));  gc_free (&gc);  return false;}/* make sure that incoming packet ID isn't a replay */boolreliable_not_replay (const struct reliable *rel, packet_id_type id){  struct gc_arena gc = gc_new ();  int i;  if (id < rel->packet_id)    goto bad;  for (i = 0; i < rel->size; ++i)    {      const struct reliable_entry *e = &rel->array[i];      if (e->active && e->packet_id == id)	goto bad;    }  gc_free (&gc);  return true; bad:  msg (D_REL_DEBUG, "ACK " packet_id_format " is a replay: %s", (packet_id_print_type)id, reliable_print_ids (rel, &gc));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -