Logo Search packages:      
Sourcecode: tcpick version File versions  Download package

fragments.c

/*
 * fragments.c -- manages unacknowledged data
 * Part of the tcpick project
 *
 * Author: Francesco Stablum <duskdruid @ despammed.com>
 *
 * Copyright (C) 2003, 2004  Francesco Stablum
 * Licensed under the GPL
 *
 */

/*
 * 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

/* 
 * Explanation of this code (fragments.c)
 * ======================================
 *
 * The stream of data of the tcp connection will be saved on 
 * the file, but we know that tcp connection aren't datagram-oriented, 
 * but stream-oriented! This means we *must* rebuild the disordered
 * flow. The problem is: we cannot store entire tcp connections in
 * memory! This is simply crazy! What if somebody is downloading cd
 * iso images, or dvd films! They will surely be corrupted.
 * Solution: write the rebuilded part of tcp flow in the file when
 * there are no missing pieces; so we will be able to store in memory
 * a linked list that reorders the tcp data flow and then, when data
 * are acknowledged by a "ack" packet, these data will be written to
 * the output file.
 *
 * Phase 1:
 *     Picking up the packets containing data from the interface.
 * 
 * Packets containing data fragments are stored into the linked list
 * conn_ptr->unack, managed by the insfr(...) function
 * These data are not yet acknowledged with the "ack"
 * packet. Duplicates are discarded and the flow will be completely
 * rebuilt.
 * 
 * Phase 2:
 *     Acks are arriving!
 * 
 * When a "ack" packet arrives, the function flush_ack(...) writes the
 * acknowledged fragments to the output file, and deleletes them from
 * the linked list.
 */

#include "tcpick.h"
#include "extern.h"

#define MATCH_OFF(fr, oth) fr->off + fr->len == oth->off

#define ATTACH_FR(prev, this){                  \
                                    \
      this->next = prev->next;            \
      prev->next = this;                  \
                                    \
      if (MATCH_OFF(this, prev->next))    \
            this->flag = CONTINUE;        \
      else                          \
            this->flag = BREAK;             \
        }


#define FREE_FR(fr) S_free( fr->payload ); S_free( fr );

#define DELETE_FIRST_FR(list) {                         \
                        struct FRAGMENT * tmp;        \
                        tmp = * list;                   \
                        * list = ( * list )->next;      \
                        FREE_FR (tmp)                   \
                        }
__inline__ int 
addfr( struct FRAGMENT ** first,
       int wlen,
       u_int32_t data_off,
       u_char * payload,
       int payload_len )
/* called by established_packet().
 * Insert and reorder data fragments in a linked-list.
 * Duplicates are discarded.
 * 
 * return values: 
 * 0: fragment refused
 * 1: fragment accepted in the linked-list
 */

{
      struct FRAGMENT * new;
      struct FRAGMENT * curr;

      if ( data_off >= wlen ) {
 
            /* allocate and build the fragment */
            new = ( struct FRAGMENT * ) S_calloc ( 1, sizeof( struct FRAGMENT ));
            new->payload = ( u_char * ) S_calloc( 1, payload_len );
            new->off = data_off;
            memcpy( new->payload, payload, payload_len );
            new->len = payload_len;
            
            /* now insert the fragment in the flagged linked list */
            
            /* linked list was empty */
            if (! * first ) {
                  * first = new;
                  (* first)->next = NULL;
                  return 1;
            }
            
            /* replace first */
            if ( (* first)->off > new->off) { 
                  new->next = * first;
                  * first = new;
                  return 1;
            }
            
            curr = * first;
            
            while ( curr ) {
                  if( curr->flag == BREAK &&
                      MATCH_OFF(curr, new) ) {
                        /* the new data fragment is exactly next to curr */ 
                        ATTACH_FR( curr, new );
                        return 1;
                  }
                  else if ( curr->next ) {
                        if( curr->next->off > new->off ) {
                  /* the new data fragment is _not_ exactly next to curr,
                     but it must be there because the next
                     fragment has a bigger offset     */
                              ATTACH_FR( curr, new );
                              return 1;
                        }
                  } else {
                        /* it is the last */
                        curr->next = new;
                        return 1;
                  }
                  
                  curr = curr->next;
            }
            return 0;
      }
}

__inline__ int
flush_ack ( struct HOST_DESC * desc,
          struct CONN * conn_ptr,
          int ack_num )
/* called by established_packet
 * when a "ack" packet comes to the network device,
 * data that are unacknowledged will be acknowledged and immediatly
 * sent to the write engine wrebuild 
 */
{
#define LIST (desc->unack)
      
      while( LIST &&
             LIST->off <= ack_num ) {
            
            flowflush( conn_ptr, desc->oth, LIST->payload, LIST->len );

            debug("wrote off=%i wlen=%i len=%i ack=%i\n",
                  LIST->off, desc->wlen, LIST->len, ack_num);

            desc->wlen += LIST->len;
            DELETE_FIRST_FR ( & LIST );
      }
}

Generated by  Doxygen 1.6.0   Back to index