summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/ipc/rtc_tcp_connection.cpp
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2016-04-10 14:02:31 +0200
committer Miodrag Milanovic <mmicko@gmail.com>2016-04-10 17:03:51 +0200
commitffbe0c66becfa5cf65aca3fef451cf162b251b4b (patch)
tree577722328262e22472133225072fd0a6a57018b3 /src/osd/modules/ipc/rtc_tcp_connection.cpp
parentdd89b30c63a9d4a426d1be88a55a88c6c0109047 (diff)
Basic TCP server based on libuv [Inaki Baz Castillo,Miodrag Milanovic]
Diffstat (limited to 'src/osd/modules/ipc/rtc_tcp_connection.cpp')
-rw-r--r--src/osd/modules/ipc/rtc_tcp_connection.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/osd/modules/ipc/rtc_tcp_connection.cpp b/src/osd/modules/ipc/rtc_tcp_connection.cpp
new file mode 100644
index 00000000000..1cc800b7d77
--- /dev/null
+++ b/src/osd/modules/ipc/rtc_tcp_connection.cpp
@@ -0,0 +1,150 @@
+// license:BSD-3-Clause
+// copyright-holders:Inaki Baz Castillo,Miodrag Milanovic
+#include "emu.h"
+#include "rtc_tcp_connection.h"
+
+/* Instance methods. */
+
+rtc_tcp_connection::rtc_tcp_connection(listener* listener, size_t bufferSize) :
+ tcp_connection(bufferSize),
+ m_listener(listener),
+ m_frame_start(0)
+{
+}
+
+rtc_tcp_connection::~rtc_tcp_connection()
+{
+}
+
+inline uint16_t get2bytes(const uint8_t* data, size_t i)
+{
+ return (uint16_t)(data[i + 1]) | ((uint16_t)(data[i])) << 8;
+}
+
+inline void set2bytes(uint8_t* data, size_t i, uint16_t value)
+{
+ data[i + 1] = (uint8_t)(value);
+ data[i] = (uint8_t)(value >> 8);
+}
+
+
+void rtc_tcp_connection::user_on_tcp_connection_read()
+{
+ /*
+ * Framing RFC 4571
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * ---------------------------------------------------------------
+ * | LENGTH | STUN / DTLS / RTP / RTCP |
+ * ---------------------------------------------------------------
+ *
+ * A 16-bit unsigned integer LENGTH field, coded in network byte order
+ * (big-endian), begins the frame. If LENGTH is non-zero, an RTP or
+ * RTCP packet follows the LENGTH field. The value coded in the LENGTH
+ * field MUST equal the number of octets in the RTP or RTCP packet.
+ * Zero is a valid value for LENGTH, and it codes the null packet.
+ */
+
+ // Be ready to parse more than a single frame in a single TCP chunk.
+ while (true)
+ {
+ // We may receive multiple packets in the same TCP chunk. If one of them is
+ // a DTLS Close Alert this would be closed (Close() called) so we cannot call
+ // our listeners anymore.
+ if (is_closing())
+ return;
+
+ size_t data_len = m_buffer_data_len - m_frame_start;
+ size_t packet_len = 0;
+
+ if (data_len >= 2)
+ packet_len = (size_t)get2bytes(m_buffer + m_frame_start, 0);
+
+ // We have packet_len bytes.
+ if ((data_len >= 2) && data_len >= 2 + packet_len)
+ {
+ const uint8_t* packet = m_buffer + m_frame_start + 2;
+
+ // Notify the listener.
+ if (packet_len != 0)
+ {
+ m_listener->on_packet_recv(this, packet, packet_len);
+ }
+
+ // If there is no more space available in the buffer and that is because
+ // the latest parsed frame filled it, then empty the full buffer.
+ if ((m_frame_start + 2 + packet_len) == m_buffer_size)
+ {
+ osd_printf_error("no more space in the buffer, emptying the buffer data");
+
+ m_frame_start = 0;
+ m_buffer_data_len = 0;
+ }
+ // If there is still space in the buffer, set the beginning of the next
+ // frame to the next position after the parsed frame.
+ else
+ {
+ m_frame_start += 2 + packet_len;
+ }
+
+ // If there is more data in the buffer after the parsed frame then
+ // parse again. Otherwise break here and wait for more data.
+ if (m_buffer_data_len > m_frame_start)
+ {
+ // osd_printf_error("there is more data after the parsed frame, continue parsing");
+
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else // Incomplete packet.
+ {
+ // Check if the buffer is full.
+ if (m_buffer_data_len == m_buffer_size)
+ {
+ // First case: the incomplete frame does not begin at position 0 of
+ // the buffer, so move the frame to the position 0.
+ if (m_frame_start != 0)
+ {
+ // osd_printf_error("no more space in the buffer, moving parsed bytes to the beginning of the buffer and wait for more data");
+
+ std::memmove(m_buffer, m_buffer + m_frame_start, m_buffer_size - m_frame_start);
+ m_buffer_data_len = m_buffer_size - m_frame_start;
+ m_frame_start = 0;
+ }
+ // Second case: the incomplete frame begins at position 0 of the buffer.
+ // The frame is too big, so close the connection.
+ else
+ {
+ osd_printf_error("no more space in the buffer for the unfinished frame being parsed, closing the connection");
+
+ // Close the socket.
+ close();
+ }
+ }
+ // The buffer is not full.
+ else
+ {
+ osd_printf_verbose("frame not finished yet, waiting for more data");
+ }
+
+ // Exit the parsing loop.
+ break;
+ }
+ }
+}
+
+void rtc_tcp_connection::send(const uint8_t* data, size_t len)
+{
+ // Write according to Framing RFC 4571.
+
+ uint8_t frame_len[2];
+
+ set2bytes(frame_len, 0, len);
+
+ write(frame_len, 2, data, len);
+}