aboutsummaryrefslogtreecommitdiffstats
path: root/metis/ccnx/forwarder/metis/io/metis_HopByHopFragmenter.h
diff options
context:
space:
mode:
Diffstat (limited to 'metis/ccnx/forwarder/metis/io/metis_HopByHopFragmenter.h')
-rw-r--r--metis/ccnx/forwarder/metis/io/metis_HopByHopFragmenter.h216
1 files changed, 216 insertions, 0 deletions
diff --git a/metis/ccnx/forwarder/metis/io/metis_HopByHopFragmenter.h b/metis/ccnx/forwarder/metis/io/metis_HopByHopFragmenter.h
new file mode 100644
index 00000000..6fd83f19
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/io/metis_HopByHopFragmenter.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file metis_HopByHopFragmenterer.h
+ * @brief Implements a fragmenter for a hop-by-hop protocol
+ *
+ * The hop-by-hop fragmenter can be though of as a bi-directional queue.
+ *
+ * The receive process takes fragmented packets from the wire and reassembles them. Once a packet is
+ * reassembed, it is put on end of the receive queue. The user can then pop a message of the top of
+ * the receive queue and process it normally.
+ *
+ * The send process takes a potentially large input packet and fragments it in to pieces that are places
+ * in order on the send queue. The caller can then pop messages of the head of the send queue and
+ * put them on the wire.
+ *
+ * In the next update, we probalby want to make the send queue and receive queue external so I/O and
+ * message processing threads can access them directly.
+ *
+ */
+
+#ifndef __Metis__metis_HopByHopFragmenter__
+#define __Metis__metis_HopByHopFragmenter__
+
+#include <stdbool.h>
+#include <ccnx/forwarder/metis/core/metis_Logger.h>
+#include <ccnx/forwarder/metis/core/metis_Message.h>
+
+struct metis_hopbyhop_fragment;
+typedef struct metis_hopbyhop_fragment MetisHopByHopFragmenter;
+
+/**
+ * Creates a fragmentation class for a specific session
+ *
+ * The fragmenter is specific to a given flow (i.e. source-destination-ethertype tuple).
+ * It is the responsibility of the caller to create the appropriate number of fragmenters
+ * and classify packets in to the right fragmenter.
+ *
+ * @param [in] logger The logger to use for output
+ * @param [in] mtu The MTU to use for send operations
+ *
+ * @return non-null An allocted MetisHopByHopFragmenter
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * MetisHopByHopFragmenter *fragmenter = metisHopByHopFragmenter_Create(logger, mtu);
+ * metisHopByHopFragmenter_Release(&fragmenter);
+ * }
+ * @endcode
+ */
+MetisHopByHopFragmenter *metisHopByHopFragmenter_Create(MetisLogger *logger, unsigned mtu);
+
+/**
+ * Release a reference to the fragmenter
+ *
+ * Will destroy any packets in the receive and send queues.
+ *
+ * @param [in,out] fragmenterPtr A pointer to an allocated MetisHopByHopFragmenter
+ *
+ * Example:
+ * @code
+ * {
+ * MetisHopByHopFragmenter *fragmenter = metisHopByHopFragmenter_Create(logger, mtu);
+ * metisHopByHopFragmenter_Release(&fragmenter);
+ * }
+ * @endcode
+ */
+void metisHopByHopFragmenter_Release(MetisHopByHopFragmenter **fragmenterPtr);
+
+/**
+ * Receives a message as part of the fragmentation session
+ *
+ * Receives a fragment. If this causes a reassembly to complete, the completed packet
+ * will be placed in the receive queue and may be accessed by metisHopByHopFragmenter_PopReceiveQueue().
+ * The caller is reponsible for releasing message.
+ *
+ * If a non-fragment packet is received, it is placed directly on the receive queue.
+ *
+ * The caller is responsible for releasing the message.
+ *
+ * @param [in] fragmenter An allocated MetisHopByHopFragmenter
+ * @param [in] message An allocated MetisMessage
+ *
+ * @return true The receive buffer has an assembled packet ready for read
+ * @return false the receive buffer does not have a complete packet ready.
+ *
+ * Example:
+ * @code
+ * {
+ * void
+ * acceptFragment(MetisHopByHopFragmenter *fragmenter, MetisMessage *message)
+ * {
+ * bool receiveQueueNotEmpty = metisHopByHopFragmenter_Receive(fragmenter, message);
+ * if (receiveQueueNotEmpty) {
+ * MetisMessage *assembled = NULL;
+ * while ((assembled = metisHopByHopFragmenter_PopReceiveQueue(fragmenter)) != NULL) {
+ * etherListener->stats.framesReassembled++;
+ * metisForwarder_Receive(etherListener->metis, assembled);
+ * }
+ * }
+ * }
+ * }
+ * @endcode
+ */
+bool metisHopByHopFragmenter_Receive(MetisHopByHopFragmenter *fragmenter, const MetisMessage *message);
+
+/**
+ * Pops the top assembed message from the receive queue
+ *
+ * Reads the top reassembled packet from the receive queue. The caller must
+ * release the returned message.
+ *
+ * @param [in] fragmenter An allocated MetisHopByHopFragmenter
+ *
+ * @return NULL The receive queue is empty (i.e. the current reassembly is not complete)
+ * @return non-null A re-assembed message
+ *
+ * Example:
+ * @code
+ * {
+ * void
+ * acceptFragment(MetisHopByHopFragmenter *fragmenter, MetisMessage *message)
+ * {
+ * bool receiveQueueNotEmpty = metisHopByHopFragmenter_Receive(fragmenter, message);
+ * if (receiveQueueNotEmpty) {
+ * MetisMessage *assembled = NULL;
+ * while ((assembled = metisHopByHopFragmenter_PopReceiveQueue(fragmenter)) != NULL) {
+ * etherListener->stats.framesReassembled++;
+ * metisForwarder_Receive(etherListener->metis, assembled);
+ * }
+ * }
+ * }
+ * }
+ * @endcode
+ */
+MetisMessage *metisHopByHopFragmenter_PopReceiveQueue(MetisHopByHopFragmenter *fragmenter);
+
+/**
+ * Adds a message to the send buffer
+ *
+ * This may make multiple references to the original message where each fragment is
+ * pointing as an extent in to the original message.
+ *
+ * @param [in] fragmenter An allocated MetisHopByHopFragmenter
+ * @param [in] message An allocated MetisMessage
+ *
+ * @return true The message was fragmented and put on the send queue
+ * @return false An error
+ *
+ * Example:
+ * @code
+ * {
+ * void sendFragments(MetisHopByHopFragmenter *fragmenter, const MetisMessage *message) {
+ * bool success = metisHopByHopFragmenter_Send(fragmenter, message);
+ *
+ * MetisMessage *fragment;
+ * while (success && (fragment = metisHopByHopFragmenter_PopSendQueue(fragmenter)) != NULL) {
+ * success = _sendFrame(fragment);
+ * metisMessage_Release(&fragment);
+ * }
+ *
+ * // if we failed, drain the other fragments
+ * if (!success) {
+ * while ((fragment = metisHopByHopFragmenter_PopSendQueue(fragmenter)) != NULL) {
+ * metisMessage_Release(&fragment);
+ * }
+ * }
+ * // caller must release message
+ * }
+ * @endcode
+ */
+bool metisHopByHopFragmenter_Send(MetisHopByHopFragmenter *fragmenter, MetisMessage *message);
+
+/**
+ * Pops the next message to send to the wire from the send queue
+ *
+ * Returns the front of the Send FIFO queue of fragments that should be
+ * sent on the wire.
+ *
+ * @param [in] fragmenter An allocated MetisHopByHopFragmenter
+ *
+ * @return null there is no message awaiting transmit
+ * @return non-null A message to send
+ *
+ * Example:
+ * @code
+ * {
+ * void sendIdleFragment(MetisHopByHopFragmenter *fragmenter) {
+ * bool success = metisHopByHopFragmenter_SendIdle(fragmenter);
+ *
+ * MetisMessage *fragment;
+ * while (success && (fragment = metisHopByHopFragmenter_PopSendQueue(fragmenter)) != NULL) {
+ * success = _sendFrame(fragment);
+ * metisMessage_Release(&fragment);
+ * }
+ * }
+ * }
+ * @endcode
+ */
+MetisMessage *metisHopByHopFragmenter_PopSendQueue(MetisHopByHopFragmenter *fragmenter);
+#endif /* defined(__Metis__metis_HopByHopFragmenter__) */