SCTP Discussions

Text archives Help


Re: [SCTP-Discussion] Bug in bundling .c


Chronological Thread 
  • From: Andreas Jungmaier <ajung AT exp-math.uni-essen.de>
  • To: discussion AT sctp.de, Schruefer Wolfgang <Wolfgang.Schruefer AT icn.siemens.de>
  • Subject: Re: [SCTP-Discussion] Bug in bundling .c
  • Date: Thu Apr 5 11:33:02 2001
  • List-id: SCTP Discussions <discussion.sctp.de>
  • Organization: University of Essen, Germany

Hi all,

what Wolfgang reported here is indeed a bug.
In a more recent release I split bundling.c in two
modules, sbundling.c and rbundling.c - for sending and
receiving respectively.
I fixed the initialization issue in the corresponding file
sbundling.c, and attached it to this mail.

Wolfgang, you would also need to reset the
ptr->got_send_address Flag in bu_sendAllChunks(),
where all the other flags are reset, too.
(but you will see yourself from the attached file).

Thanks a lot, regards,

Andreas

> I had problems when sending because the datastructure of the
> bundling_instance in bundlung.c was not initialized (here it was
> bu_ptr->got_send_address). So I inserted the following lines in function
> bu_new() ...
>
> ptr->ctrl_position = 0;
> ptr->sack_position = 0;
> ptr->data_position = 0;
> ptr->treating_received_chunks = FALSE;
> ptr->got_sack_request = FALSE;
> ptr->got_send_address = FALSE;
> ptr->got_sack = FALSE;
> ptr->got_shutdown = FALSE;
> ptr->requested_destination = 0;

--

Andreas Jungmaier

----------------------------------------------------------------------------
void hamlet()
{#define question=((bb)||(!bb))}
----------------------------------------------------------------------------
Andreas Jungmaier, Dipl.-Ing.
University of Essen email:
ajung AT exp-math.uni-essen.de
Computer Networking Technology Group Tel. : +49 (0201) 183-7636
----------------------------------------------------------------------------
PGP Public Key and Fingerprint: see http://www.exp-math.uni-essen.de/~ajung
----------------------------------------------------------------------------
/*
 *  $Id: sbundling.c,v 1.6 2001/04/05 09:17:37 ajung Exp $
 *
 * SCTP implementation according to RFC 2960.
 * Copyright (C) 2000 by Siemens AG, Munich, Germany.
 *
 * Realized in co-operation between Siemens AG
 * and University of Essen, Institute of Computer Networking Technology.
 *
 * 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.
 *
 * There are two mailinglists available at http://www.sctp.de which should be
 * used for any discussion related to this implementation.
 *
 * Contact: discussion AT sctp.de
 *          Michael.Tuexen AT icn.siemens.de
 *          ajung AT exp-math.uni-essen.de
 *
 * Purpose: This module bundels chunks chunks to be send into UDP-datagramms. Chunks are accepted
 *          with the putChunk function until sendChunk is called, which causes the transmission of
 *          all chunks accumulated so far.
 *          In the receive direction, this module gets UDP-dataparts from SCTP message-distribution,
 *          which are disassambled (debundled) into chunks. Depending on the chunk-type, the chunk
 *          are distributed to SCTP-control, RX-control, pathmanagement or reliable transfer.
 */

#include <stdio.h>
#include <stdlib.h>
#include "bundling.h"
#include "messages.h"
#include "dll_main.h"
#include "distribution.h"
#include "recvctrl.h"
#include "reltransfer.h"
#include "errorhandler.h"

#define TOTAL_SIZE(buf)		((buf)->ctrl_position+(buf)->sack_position+(buf)->data_position- 2*sizeof(SCTP_common_header))

/**
 * this struct contains all data belonging to a bundling module
 */
typedef struct bundling_instance_struct
{
    //@{
    /// buffer for control chunks
    guchar ctrl_buf[MAX_MTU_SIZE];
    /// buffer for sack chunks
    guchar sack_buf[MAX_MTU_SIZE];
    /// buffer for data chunks
    guchar data_buf[MAX_MTU_SIZE];
    /* Leave some space for the SCTP common header */
    ///  current position in the buffer for control chunks
    guint ctrl_position;
    ///  current position in the buffer for sack chunks
    guint sack_position;
    ///  current position in the buffer for data chunks
    guint data_position;
    /// is there data to be sent in the buffer ?
    gboolean data_in_buffer;
    ///  is there a control chunk  to be sent in the buffer ?
    gboolean ctrl_chunk_in_buffer;
    ///  is there a sack chunk  to be sent in the buffer ?
    gboolean sack_in_buffer;
    ///
    gboolean got_send_request;
    ///
    gboolean got_send_address;
    ///
    gboolean locked;
    ///
    guint requested_destination;
    //@}

}
bundling_instance;

/**
 *  one static variable for a buffer that is used, if no bundling instance has been
 *  allocated and initialized yet
 */
static bundling_instance *global_buffer;


void bu_init_bundling(void)
{
    global_buffer = bu_new();
}

/**
 * Creates a new bundling instance and returns a pointer to its data.
 * @return pointer to an instance of the bundling data
 */
gpointer bu_new(void)
{
    /* Alloc new bundling_instance data struct */
    bundling_instance *ptr;

    ptr = malloc(sizeof(bundling_instance));
    if (!ptr) {
        error_log(ERROR_MAJOR, "Malloc failed");
        return 0;
    }
    ptr->ctrl_position = sizeof(SCTP_common_header); /* start adding data after that header ! */
    ptr->data_position = sizeof(SCTP_common_header); /* start adding data after that header ! */
    ptr->sack_position = sizeof(SCTP_common_header); /* start adding data after that header ! */

    ptr->data_in_buffer = FALSE;
    ptr->ctrl_chunk_in_buffer = FALSE;
    ptr->sack_in_buffer = FALSE;
    ptr->got_send_request = FALSE;
    ptr->got_send_address = FALSE;
    ptr->locked = FALSE;
    ptr->requested_destination = 0;
    return ptr;
}

/**
 * Deletes a bundling instance
 *
 * @param Pointer which was returned by bu_new()
 */
void bu_delete(gpointer buPtr)
{
    event_log(INTERNAL_EVENT_0, "deleting bundling");
    free(buPtr);
}



/**
 * Keep sender from sending data right away - wait after received chunks have
 * been diassembled completely.
 */
void bu_lock_sender()
{
    bundling_instance *bu_ptr;
    event_log(VERBOSE, "bu_lock_sender() was called... ");

    bu_ptr = (bundling_instance *) mdi_readBundling();
    if (!bu_ptr) {              /* Assume that no association exists, so we take the global bundling buffer */
        event_log(VERBOSE, "Setting global bundling buffer ");
        bu_ptr = global_buffer;
    }
    bu_ptr->locked = TRUE;
    bu_ptr->got_send_request = FALSE;
}

/**
 * Enable sending again - wait after received chunks have
 * been diassembled completely.
 */
void bu_unlock_sender(guint* ad_idx)
{
    bundling_instance *bu_ptr;
    event_log(VERBOSE, "bu_unlock_sender() was called... ");

    bu_ptr = (bundling_instance *) mdi_readBundling();
    if (!bu_ptr) {              /* Assume that no association exists, so we take the global bundling buffer */
        event_log(VERBOSE, "Setting global bundling buffer ");
        bu_ptr = global_buffer;
    }
    bu_ptr->locked = FALSE;
    if (bu_ptr->got_send_request == TRUE) bu_sendAllChunks(ad_idx);

}

/**
 * Called by recvcontrol, when a SACK must be piggy-backed
 * TODO : Handle multiple calls to this function between two send events
 *
 * @param chunk pointer to chunk, that is to be put in the bundling buffer
 * @return error value, 0 on success, -1 on error
 */
gint bu_put_SACK_Chunk(SCTP_sack_chunk * chunk)
{
    gint result;
    bundling_instance *bu_ptr;
    gboolean lock;

    event_log(INTERNAL_EVENT_0, "bu_put_SACK_Chunk() was called ");

    bu_ptr = (bundling_instance *) mdi_readBundling();

    if (!bu_ptr) {              /* Assume that no association exists, so we take the global bundling buffer */
        event_log(VERBOSE, "Copying SACK to global bundling buffer ");
        bu_ptr = global_buffer;
    }

    if (TOTAL_SIZE(bu_ptr) + CHUNKP_LENGTH((SCTP_chunk_header *) chunk) >= MAX_SCTP_PDU) {
        lock = bu_ptr->locked;
        error_log(ERROR_MAJOR,
                  "Chunk Length exceeded MAX_SCTP_PDU : sending chunk to default address !");
        if (lock) bu_ptr->locked = FALSE;
        result = bu_sendAllChunks(NULL);
        if (lock) bu_ptr->locked = TRUE;
    }

    if (bu_ptr->sack_in_buffer == TRUE) { /* multiple calls in between */
        event_log(INTERNAL_EVENT_0,
                  "bu_put_SACK_Chunk was called a second time, deleting first chunk");
        bu_ptr->sack_position = sizeof(SCTP_common_header);
    }

    memcpy(&(bu_ptr->sack_buf[bu_ptr->sack_position]), chunk,
           CHUNKP_LENGTH((SCTP_chunk_header *) chunk));

    event_logii(VERBOSE,
                "Put SACK Chunk Length : %u , Total buffer size : %u\n",
                CHUNKP_LENGTH((SCTP_chunk_header *) chunk), TOTAL_SIZE(bu_ptr));

    /* SACK always multiple of 32 bytes, do not care about padding */
    bu_ptr->sack_position += CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
    bu_ptr->sack_in_buffer = TRUE;
    return 0;
}

/**
 * this function used for bundling of control chunks
 * Used by SCTP-control and Path management
 *
 * @param chunk pointer to chunk, that is to be put in the bundling buffer
 * @return TODO : error value, 0 on success
 */
gint bu_put_Ctrl_Chunk(SCTP_simple_chunk * chunk)
{
    gint result;
    bundling_instance *bu_ptr;
    gint count;
    gboolean lock;

    event_log(INTERNAL_EVENT_0, "bu_put_Ctrl_Chunk() was called");

    bu_ptr = (bundling_instance *) mdi_readBundling();

    if (!bu_ptr) {              /* Assume that no association exists, so we take the global bundling buffer */
        event_log(VERBOSE, "Copying Control Chunk to global bundling buffer ");
        bu_ptr = global_buffer;
    }

    if (TOTAL_SIZE(bu_ptr) + CHUNKP_LENGTH((SCTP_chunk_header *) chunk) >= MAX_SCTP_PDU) {
        lock = bu_ptr->locked;
        error_log(ERROR_MAJOR,
                  "Chunk Length exceeded MAX_SCTP_PDU : sending chunk to default address !");
        if (lock) bu_ptr->locked = FALSE;
        result = bu_sendAllChunks(NULL);
        if (lock) bu_ptr->locked = TRUE;
    }
    memcpy(&(bu_ptr->ctrl_buf[bu_ptr->ctrl_position]), chunk,
           CHUNKP_LENGTH((SCTP_chunk_header *) chunk));
    event_logii(VERBOSE,
                "Put Control Chunk Length : %u , Total buffer size : %u\n",
                CHUNKP_LENGTH((SCTP_chunk_header *) chunk), TOTAL_SIZE(bu_ptr));

    bu_ptr->ctrl_position += CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
    /* insert padding, if necessary */
    if ((CHUNKP_LENGTH((SCTP_chunk_header *) chunk) % 4) != 0) {
        for (count = 0; count < (4 - (CHUNKP_LENGTH((SCTP_chunk_header *) chunk) % 4)); count++) {
            bu_ptr->ctrl_buf[bu_ptr->ctrl_position] = 0;
            bu_ptr->ctrl_position++;
        }
    }
    bu_ptr->ctrl_chunk_in_buffer = TRUE;
    return 0;
}

/**
 * this function used for putting data chunks into the buffer
 * Used only in the flow control module
 *
 * @param chunk pointer to chunk, that is to be put in the bundling buffer
 * @return TODO : error value, 0 on success
 */
gint bu_put_Data_Chunk(SCTP_simple_chunk * chunk)
{
    gint result;
    bundling_instance *bu_ptr;
    gint count;
    gboolean lock;

    event_log(INTERNAL_EVENT_0, "bu_put_Data_Chunk() was called ");

    bu_ptr = (bundling_instance *) mdi_readBundling();

    if (!bu_ptr) {              /* Assume that no association exists, so we take the global bundling buffer */
        event_log(VERBOSE, "Copying data to global bundling buffer ");
        bu_ptr = global_buffer;
    }

    if (TOTAL_SIZE(bu_ptr) + CHUNKP_LENGTH((SCTP_chunk_header *) chunk) >= MAX_SCTP_PDU) {
        lock = bu_ptr->locked;
        error_log(ERROR_MAJOR,
                  "Chunk Length exceeded MAX_SCTP_PDU : sending chunk to default address !");
        if (lock) bu_ptr->locked = FALSE;
        result = bu_sendAllChunks(NULL);
        if (lock) bu_ptr->locked = TRUE;
    }
    memcpy(&(bu_ptr->data_buf[bu_ptr->data_position]), chunk,
           CHUNKP_LENGTH((SCTP_chunk_header *) chunk));
    bu_ptr->data_position += CHUNKP_LENGTH((SCTP_chunk_header *) chunk);

    event_logii(VERBOSE,
                "Put Data Chunk Length : %u , Total buffer size : %u\n",
                CHUNKP_LENGTH((SCTP_chunk_header *) chunk), TOTAL_SIZE(bu_ptr));

    /* insert padding, if necessary */
    if ((CHUNKP_LENGTH((SCTP_chunk_header *) chunk) % 4) != 0) {
        for (count = 0; count < (4 - (CHUNKP_LENGTH((SCTP_chunk_header *) chunk) % 4)); count++) {
            bu_ptr->data_buf[bu_ptr->data_position] = 0;
            bu_ptr->data_position++;
        }
    }
    event_log(VERBOSE, "bu_put_Data_Chunk() : Added Padding bytes");
    bu_ptr->data_in_buffer = TRUE;
    return 0;
}

/**
 * Trigger sending of all chunks previously entered with put_Chunk functions
 *  Chunks sent are deleted afterwards.
 *
 *  @return                 Errorcode (0 for good case: length bytes sent; 1 or -1 for error)
 *  @param   ad_idx     pointer to address index or NULL if data is to be sent to default address
 */
gint bu_sendAllChunks(guint * ad_idx)
{
    gint result, send_len = 0;
    guchar *send_buffer = NULL;
    bundling_instance *bu_ptr;
    gshort idx = 0;

    bu_ptr = (bundling_instance *) mdi_readBundling();

    event_log(INTERNAL_EVENT_0, "bu_sendAllChunks() is being executed...");

    if (!bu_ptr) {
        event_log(VERBOSE, "Sending data from global bundling buffer ");
        bu_ptr = global_buffer;
    }
    if (bu_ptr->locked) {
        bu_ptr->got_send_request = TRUE;
        if (ad_idx) {
            bu_ptr->got_send_address = TRUE;
            bu_ptr->requested_destination = *ad_idx;
        }
        event_log(INTERNAL_EVENT_0, "bu_sendAllChunks : sender is LOCKED ---> returning ");
        return 1;
    }

    /* TODO : more intelligent path selection strategy */
    /*         should take into account PM_INACTIVE */
    if (ad_idx) {
        if (*ad_idx > 0xFFFF) {
            error_log(ERROR_FATAL, "address_index too big !");
        } else {
            idx = (short) *ad_idx;
        }
    } else {
        if (bu_ptr->got_send_address) idx = (short)bu_ptr->requested_destination;
        else {
            idx = pm_readPrimaryPath();
            if (pm_readPrimaryPath() == -1) {
                error_log(ERROR_MINOR,
                          "Primary Path returned was -1 in bu_sendAllChunks(), using PATH 0");
                idx = 0;
            }
        }
    }

    event_logi(VVERBOSE, "bu_sendAllChunks : send to path %d ", idx);

    if (bu_ptr->sack_in_buffer)             send_buffer = bu_ptr->sack_buf;
    else if (bu_ptr->ctrl_chunk_in_buffer)  send_buffer = bu_ptr->ctrl_buf;
    else if (bu_ptr->data_in_buffer)        send_buffer = bu_ptr->data_buf;
    else {
        error_log(ERROR_MINOR, "Nothing to send, but bu_sendAllChunks was called !");
        return 1;
    }

    if (bu_ptr->sack_in_buffer) {
        rxc_stop_sack_timer();
        /* SACKs by default go to the last active address, from which data arrived */
        idx = rxc_read_last_active_address();
        send_len = bu_ptr->sack_position; /* at least sizeof(SCTP_common_header) */
        /* at most pointing to the end of SACK chunk */
        if (bu_ptr->ctrl_chunk_in_buffer) {
            memcpy(&send_buffer[send_len],
                   &(bu_ptr->ctrl_buf[sizeof(SCTP_common_header)]),
                   (bu_ptr->ctrl_position - sizeof(SCTP_common_header)));
            send_len += bu_ptr->ctrl_position - sizeof(SCTP_common_header);
        }
        if (bu_ptr->data_in_buffer) {
            memcpy(&send_buffer[send_len],
                   &(bu_ptr->data_buf[sizeof(SCTP_common_header)]),
                   (bu_ptr->data_position - sizeof(SCTP_common_header)));
            send_len += bu_ptr->data_position - sizeof(SCTP_common_header);
        }
    } else if (bu_ptr->ctrl_chunk_in_buffer) {
        send_len = bu_ptr->ctrl_position;
        if (bu_ptr->data_in_buffer) {
            memcpy(&send_buffer[send_len],
                   &(bu_ptr->data_buf[sizeof(SCTP_common_header)]),
                   (bu_ptr->data_position - sizeof(SCTP_common_header)));
            send_len += bu_ptr->data_position - sizeof(SCTP_common_header);
        }

    } else if (bu_ptr->data_in_buffer) send_len = bu_ptr->data_position;

    if (bu_ptr->data_in_buffer) pm_chunksSentOn(idx);

    event_logii(VERBOSE, "bu_sendAllChunks() : sending message len==%u to adress idx=%u", send_len, idx);

    result = mdi_send_message((SCTP_message *) send_buffer, send_len, idx);

    event_logi(VVERBOSE, "bu_sendAllChunks(): result==%d ", result);

    /* reset all positions */
    bu_ptr->sack_in_buffer = FALSE;
    bu_ptr->ctrl_chunk_in_buffer = FALSE;
    bu_ptr->data_in_buffer = FALSE;
    bu_ptr->got_send_request = FALSE;
    bu_ptr->got_send_address = FALSE;

    bu_ptr->data_position = sizeof(SCTP_common_header);
    bu_ptr->ctrl_position = sizeof(SCTP_common_header);
    bu_ptr->sack_position = sizeof(SCTP_common_header);

    return result;
}



Archive powered by MHonArc 2.6.19+.

Top of page