3@brief Implementation of QUIC stream handling classes.
4@details Contains Stream, StreamEndpointABC, StreamSender, and StreamReceiver classes
5 for managing data flow in QUIC connections.
8from abc
import ABC, abstractmethod
9from frame
import FrameStream
10from constants
import Constants
15 @brief Represents a QUIC stream that handles data transfer.
17 @details A Stream can be unidirectional or bidirectional, and handles
18 both sending and receiving data through dedicated endpoints.
21 def __init__(self, stream_id: int, is_uni: bool, is_s_initiated: bool):
23 @brief Initialize a Stream instance.
25 @param stream_id Unique identifier for the stream, generated already.
26 @param is_uni Specifies if the stream is unidirectional.
27 @param is_s_initiated Specifies if the stream was initiated by the server (receiver).
33 is_uni
and not is_s_initiated)
or not is_uni)
35 is_uni
and is_s_initiated)
or not is_uni)
39 @brief Check if there is any data to send or receive.
41 @return True if there is data in the sender or receiver buffer, False otherwise.
47 @brief Getter for stream ID.
49 @return The stream ID.
55 @brief Add data to the stream by delegation to StreamSender.
57 @param data Data to be added to the send buffer.
59 self.
_sender.add_data_to_buffer(data)
63 @brief Stream frames generation by delegation to StreamSender.
65 @details Generate stream frames for sending based on the maximum frame size.
67 @param max_size The size of the payload_size which is determined by size of
68 payload-packet/num of streams on that packet.
74 @brief Retrieve the next frame to be sent from the sender's list.
76 @return The next frame to be sent.
82 @brief Process a received frame by delegating it to the receiver.
84 @param frame The received frame.
90 @brief Retrieve the data received on the stream.
92 @return The data received on the stream.
94 return self.
_receiver.get_data_from_buffer()
98 @brief Check if the stream has finished sending and receiving data.
100 @return True if the stream is in a terminal state, False otherwise.
103 return self.
_receiver.is_terminal_state()
or self.
_sender.is_terminal_state()
105 return self.
_receiver.is_terminal_state()
107 return self.
_sender.is_terminal_state()
112 @brief Determine if a stream is unidirectional based on stream ID.
114 @param stream_id The stream ID.
115 @return True if the stream is unidirectional, False otherwise.
117 return bool(stream_id & Constants.DIRECTION_MASK)
122 @brief Determine if a stream was initiated by a server based on its stream ID.
124 @param stream_id The stream ID.
125 @return True if the stream was initiated by a server, False otherwise.
127 return bool(stream_id & Constants.INIT_BY_MASK)
132 @brief Abstract base class for stream endpoints.
134 @details Provides common functionality for sending and receiving endpoints
138 def __init__(self, stream_id: int, is_usable: bool):
140 @brief Abstract Constructor for StreamEndpointABC abstract class.
142 @param stream_id The stream ID of this endpoint.
143 @param is_usable Specifies if the stream endpoint is 'usable'.
145 self._stream_id: int = stream_id
146 self._curr_offset: int = Constants.ZERO
148 self.
_state: int = Constants.START
149 self._is_usable: bool = is_usable
153 @brief Set the state of the endpoint.
155 @param state New state.
156 @return True if _state was set successfully, False otherwise.
161 except Exception
as e:
162 print(f
'ERROR: Cannot set state to {state}. {e}')
168 @brief Add data to the buffer.
170 @param data The data to add to the buffer.
176 @brief Check if the buffer contains data.
178 @return True if the buffer has data, False otherwise.
184 @brief Check if the endpoint has reached a terminal state.
186 @return True if the state is DATA_RECVD, False otherwise.
188 return self.
_state == Constants.DATA_RECVD
or not self._is_usable
193 @brief Represents the sending endpoint of a QUIC stream.
195 @details Handles buffering of data to send, generation of stream frames,
196 and sending frames over the network.
199 def __init__(self, stream_id: int, is_usable: bool):
201 @brief Initialize a StreamSender instance.
203 @param stream_id The stream ID associated with this sender.
204 @param is_usable Whether this sender can be used for sending data.
206 super().
__init__(stream_id, is_usable)
211 @brief Add data to the sender's buffer.
213 @param data The data to add.
219 @brief Internal method to add data to the buffer.
221 @details Only adds data if the stream is in READY state.
223 @param data The data to add.
224 @throws ValueError If the stream is not in READY state.
229 raise ValueError(
"ERROR: cannot write. stream is not READY.")
233 @brief Generate frames for the data in the buffer.
235 @details Splits data into chunks if necessary.
237 @param max_size The maximum size of each frame.
240 if total_stream_frames > Constants.ONE:
241 for i
in range(total_stream_frames):
243 FrameStream(stream_id=self._stream_id, offset=self._curr_offset, length=max_size, fin=
False,
244 data=self.
_buffer_buffer[self._curr_offset:self._curr_offset + max_size]))
245 self._curr_offset += max_size
250 @brief Calculate the number of frames required for the data in the buffer.
252 @param max_size The maximum size of each frame.
253 @return The total number of frames.
262 @brief Generate a frame with the FIN bit set.
264 @details This indicates the end of the stream.
266 @return The final frame for the stream.
269 return FrameStream(stream_id=self._stream_id, offset=self._curr_offset,
277 @brief Send the next frame in the queue.
279 @return The next frame to be sent.
291 @brief Represents the receiving endpoint of a QUIC stream.
293 @details Handles reception of stream frames, ordering them by offset,
294 and assembling the complete stream data.
297 def __init__(self, stream_id: int, is_usable: bool):
299 @brief Initialize a StreamReceiver instance.
301 @param stream_id The stream ID associated with this receiver.
302 @param is_usable Whether this receiver can be used for receiving data.
304 super().
__init__(stream_id, is_usable)
309 @brief Process a received frame and add it to the receiver's buffer.
311 @param frame The received frame.
319 @brief Add a received frame to the receiver's dictionary.
321 @details Updates the current offset.
323 @param frame The received frame.
326 self._curr_offset += len(frame.data)
332 @brief Handle the reception of a FIN frame.
334 @details Indicates that all data has been received.
340 @brief Convert the received frames in the dictionary to a single buffer.
342 @details Sorts frames by offset.
351 @brief Add data to the buffer if the size is known.
353 @param data The data to add.
354 @throws ValueError If the stream size is not known.
359 raise ValueError(
"ERROR: cannot write. stream is not READY.")
363 @brief Retrieve the data from the buffer.
365 @return The data in the buffer.
366 @throws ValueError If the stream is closed.
374 raise ValueError(
"ERROR: cannot read. stream is closed.")
bool is_terminal_state(self)
bool _set_state(self, int state)
__init__(self, int stream_id, bool is_usable)
_add_data_to_buffer(self, bytes data)
bytes get_data_from_buffer(self)
stream_frame_recvd(self, FrameStream frame)
_add_frame_to_recv_dict(self, FrameStream frame)
_add_data_to_buffer(self, bytes data)
__init__(self, int stream_id, bool is_usable)
_convert_dict_to_buffer(self)
FrameStream generate_fin_frame(self)
_add_data_to_buffer(self, bytes data)
add_data_to_buffer(self, bytes data)
__init__(self, int stream_id, bool is_usable)
generate_stream_frames(self, int max_size)
FrameStream send_next_frame(self)
int _get_total_stream_frames_amount(self, int max_size)
generate_stream_frames(self, int max_size)
__init__(self, int stream_id, bool is_uni, bool is_s_initiated)
bytes get_data_received(self)
bool is_s_init_by_sid(int stream_id)
add_data_to_stream(self, bytes data)
bool is_uni_by_sid(int stream_id)
FrameStream send_next_frame(self)
receive_frame(self, FrameStream frame)