summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/ipc/tcp_connection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/ipc/tcp_connection.cpp')
-rw-r--r--src/osd/modules/ipc/tcp_connection.cpp414
1 files changed, 0 insertions, 414 deletions
diff --git a/src/osd/modules/ipc/tcp_connection.cpp b/src/osd/modules/ipc/tcp_connection.cpp
deleted file mode 100644
index bfb8b6d5461..00000000000
--- a/src/osd/modules/ipc/tcp_connection.cpp
+++ /dev/null
@@ -1,414 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Inaki Baz Castillo,Miodrag Milanovic
-
-#include "emu.h"
-#include "tcp_connection.h"
-#include <cstdint> // uint8_t, etc
-#include <cstdlib> // std::malloc(), std::free()
-
-/* Static methods for UV callbacks. */
-
-static inline void on_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
-{
- static_cast<tcp_connection*>(handle->data)->on_uv_read_alloc(suggested_size, buf);
-}
-
-static inline void on_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
-{
- static_cast<tcp_connection*>(handle->data)->on_uv_read(nread, buf);
-}
-
-static inline void on_write(uv_write_t* req, int status)
-{
- tcp_connection::tcp_uv_write_data* write_data = static_cast<tcp_connection::tcp_uv_write_data*>(req->data);
- tcp_connection* connection = write_data->connection;
-
- // Delete the UvWriteData struct (which includes the uv_req_t and the store char[]).
- std::free(write_data);
-
- // Just notify the TCPConnection when error.
- if (status)
- connection->on_uv_write_error(status);
-}
-
-static inline void on_shutdown(uv_shutdown_t* req, int status)
-{
- static_cast<tcp_connection*>(req->data)->on_uv_shutdown(req, status);
-}
-
-static inline void on_close(uv_handle_t* handle)
-{
- static_cast<tcp_connection*>(handle->data)->on_uv_closed();
-}
-
-/* Instance methods. */
-
-tcp_connection::tcp_connection(size_t bufferSize) :
- m_listener(nullptr),
- m_local_addr(nullptr),
- m_is_closing(false),
- m_is_closed_by_peer(false),
- m_has_error(false),
- m_buffer_size(bufferSize),
- m_buffer(nullptr),
- m_buffer_data_len(0),
- m_local_port(0),
- m_peer_port(0)
-{
- m_uv_handle = new uv_tcp_t;
- m_uv_handle->data = (void*)this;
-
- // NOTE: Don't allocate the buffer here. Instead wait for the first uv_alloc_cb().
-}
-
-tcp_connection::~tcp_connection()
-{
- if (m_uv_handle)
- delete m_uv_handle;
- if (m_buffer)
- delete[] m_buffer;
-}
-
-void tcp_connection::setup(uv_loop_t* loop, listener* listener, struct sockaddr_storage* localAddr, const std::string &localIP, uint16_t localPort)
-{
- int err;
-
- // Set the UV handle.
- err = uv_tcp_init(loop, m_uv_handle);
- if (err)
- {
- delete m_uv_handle;
- m_uv_handle = nullptr;
- throw emu_fatalerror("uv_tcp_init() failed: %s", uv_strerror(err));
- }
-
- // Set the listener.
- m_listener = listener;
-
- // Set the local address.
- m_local_addr = localAddr;
- m_local_ip = localIP;
- m_local_port = localPort;
-}
-
-void tcp_connection::close()
-{
- if (m_is_closing)
- return;
-
- int err;
-
- m_is_closing = true;
-
- // Don't read more.
- err = uv_read_stop((uv_stream_t*)m_uv_handle);
- if (err)
- throw emu_fatalerror("uv_read_stop() failed: %s", uv_strerror(err));
-
- // If there is no error and the peer didn't close its connection side then close gracefully.
- if (!m_has_error && !m_is_closed_by_peer)
- {
- // Use uv_shutdown() so pending data to be written will be sent to the peer
- // before closing.
- uv_shutdown_t* req = new uv_shutdown_t;
- req->data = (void*)this;
- err = uv_shutdown(req, (uv_stream_t*)m_uv_handle, (uv_shutdown_cb)on_shutdown);
- if (err)
- throw emu_fatalerror("uv_shutdown() failed: %s", uv_strerror(err));
- }
- // Otherwise directly close the socket.
- else
- {
- uv_close((uv_handle_t*)m_uv_handle, (uv_close_cb)on_close);
- }
-}
-
-void tcp_connection::terminate()
-{
- if (m_is_closing)
- return;
- m_is_closing = true;
- uv_close((uv_handle_t*)m_uv_handle, (uv_close_cb)on_close);
-}
-
-void tcp_connection::dump()
-{
- osd_printf_verbose("[TCP, local:%s :%d, remote:%s :%d, status:%s]\r\n",
- m_local_ip.c_str(), (uint16_t)m_local_port,
- m_peer_ip.c_str(), (uint16_t)m_peer_port,
- (!m_is_closing) ? "open" : "closed");
-}
-
-void tcp_connection::start()
-{
- if (m_is_closing)
- return;
-
- int err;
-
- err = uv_read_start((uv_stream_t*)m_uv_handle, (uv_alloc_cb)on_alloc, (uv_read_cb)on_read);
- if (err)
- throw emu_fatalerror("uv_read_start() failed: %s", uv_strerror(err));
-
- // Get the peer address.
- if (!set_peer_address())
- throw emu_fatalerror("error setting peer IP and port");
-}
-
-void tcp_connection::write(const uint8_t* data, size_t len)
-{
- if (m_is_closing)
- return;
-
- if (len == 0)
- return;
-
- uv_buf_t buffer;
- int written;
- int err;
-
- // First try uv_try_write(). In case it can not directly write all the given
- // data then build a uv_req_t and use uv_write().
-
- buffer = uv_buf_init((char*)data, len);
- written = uv_try_write((uv_stream_t*)m_uv_handle, &buffer, 1);
-
- // All the data was written. Done.
- if (written == (int)len)
- {
- return;
- }
- // Cannot write any data at first time. Use uv_write().
- else if (written == UV_EAGAIN || written == UV_ENOSYS)
- {
- // Set written to 0 so pending_len can be properly calculated.
- written = 0;
- }
- // Error. Should not happen.
- else if (written < 0)
- {
- osd_printf_warning("uv_try_write() failed, closing the connection: %s\n", uv_strerror(written));
-
- close();
- return;
- }
-
- // osd_printf_info("could just write %zu bytes (%zu given) at first time, using uv_write() now", (size_t)written, len);
-
- size_t pending_len = len - written;
-
- // Allocate a special UvWriteData struct pointer.
- tcp_uv_write_data* write_data = (tcp_uv_write_data*)std::malloc(sizeof(tcp_uv_write_data) + pending_len);
-
- write_data->connection = this;
- std::memcpy(write_data->store, data + written, pending_len);
- write_data->req.data = (void*)write_data;
-
- buffer = uv_buf_init((char*)write_data->store, pending_len);
-
- err = uv_write(&write_data->req, (uv_stream_t*)m_uv_handle, &buffer, 1, (uv_write_cb)on_write);
- if (err)
- throw emu_fatalerror("uv_write() failed: %s", uv_strerror(err));
-}
-
-void tcp_connection::write(const uint8_t* data1, size_t len1, const uint8_t* data2, size_t len2)
-{
- if (m_is_closing)
- return;
-
- if (len1 == 0 && len2 == 0)
- return;
-
- size_t total_len = len1 + len2;
- uv_buf_t buffers[2];
- int written;
- int err;
-
- // First try uv_try_write(). In case it can not directly write all the given
- // data then build a uv_req_t and use uv_write().
-
- buffers[0] = uv_buf_init((char*)data1, len1);
- buffers[1] = uv_buf_init((char*)data2, len2);
- written = uv_try_write((uv_stream_t*)m_uv_handle, buffers, 2);
-
- // All the data was written. Done.
- if (written == (int)total_len)
- {
- return;
- }
- // Cannot write any data at first time. Use uv_write().
- else if (written == UV_EAGAIN || written == UV_ENOSYS)
- {
- // Set written to 0 so pending_len can be properly calculated.
- written = 0;
- }
- // Error. Should not happen.
- else if (written < 0)
- {
- osd_printf_warning("uv_try_write() failed, closing the connection: %s\n", uv_strerror(written));
-
- close();
- return;
- }
-
- // osd_printf_info("could just write %zu bytes (%zu given) at first time, using uv_write() now", (size_t)written, total_len);
-
- size_t pending_len = total_len - written;
-
- // Allocate a special UvWriteData struct pointer.
- tcp_uv_write_data* write_data = (tcp_uv_write_data*)std::malloc(sizeof(tcp_uv_write_data) + pending_len);
-
- write_data->connection = this;
- // If the first buffer was not entirely written then splice it.
- if ((size_t)written < len1)
- {
- std::memcpy(write_data->store, data1 + (size_t)written, len1 - (size_t)written);
- std::memcpy(write_data->store + (len1 - (size_t)written), data2, len2);
- }
- // Otherwise just take the pending data in the second buffer.
- else
- {
- std::memcpy(write_data->store, data2 + ((size_t)written - len1), len2 - ((size_t)written - len1));
- }
- write_data->req.data = (void*)write_data;
-
- uv_buf_t buffer = uv_buf_init((char*)write_data->store, pending_len);
-
- err = uv_write(&write_data->req, (uv_stream_t*)m_uv_handle, &buffer, 1, (uv_write_cb)on_write);
- if (err)
- throw emu_fatalerror("uv_write() failed: %s", uv_strerror(err));
-}
-
-void GetAddressInfo(const struct sockaddr* addr, int* family, std::string &ip, uint16_t* port)
-{
- char _ip[INET6_ADDRSTRLEN + 1];
- int err;
-
-
- err = uv_inet_ntop(AF_INET, &((struct sockaddr_in*)addr)->sin_addr, _ip, INET_ADDRSTRLEN);
- if (err)
- throw emu_fatalerror("uv_inet_ntop() failed: %s", uv_strerror(err));
- *port = (uint16_t)ntohs(((struct sockaddr_in*)addr)->sin_port);
-
- *family = addr->sa_family;
- ip.assign(_ip);
-}
-bool tcp_connection::set_peer_address()
-{
- int err;
- int len = sizeof(m_peer_addr);
-
- err = uv_tcp_getpeername(m_uv_handle, (struct sockaddr*)&m_peer_addr, &len);
- if (err)
- {
- osd_printf_error("uv_tcp_getpeername() failed: %s\n", uv_strerror(err));
-
- return false;
- }
-
- int family;
- GetAddressInfo((const struct sockaddr*)&m_peer_addr, &family, m_peer_ip, &m_peer_port);
-
- return true;
-}
-
-void tcp_connection::on_uv_read_alloc(size_t suggested_size, uv_buf_t* buf)
-{
- // If this is the first call to onUvReadAlloc() then allocate the receiving buffer now.
- if (!m_buffer)
- m_buffer = new uint8_t[m_buffer_size];
-
- // Tell UV to write after the last data byte in the buffer.
- buf->base = (char *)(m_buffer + m_buffer_data_len);
- // Give UV all the remaining space in the buffer.
- if (m_buffer_size > m_buffer_data_len)
- {
- buf->len = m_buffer_size - m_buffer_data_len;
- }
- else
- {
- buf->len = 0;
-
- osd_printf_warning("no available space in the buffer\n");
- }
-}
-
-void tcp_connection::on_uv_read(::ssize_t nread, const uv_buf_t* buf)
-{
- if (m_is_closing)
- return;
-
- if (nread == 0)
- return;
-
- // Data received.
- if (nread > 0)
- {
- // Update the buffer data length.
- m_buffer_data_len += (size_t)nread;
-
- // Notify the subclass.
- user_on_tcp_connection_read();
- }
- // Client disconneted.
- else if (nread == UV_EOF || nread == UV_ECONNRESET)
- {
- osd_printf_verbose("connection closed by peer, closing server side\n");
-
- m_is_closed_by_peer = true;
-
- // Close server side of the connection.
- close();
- }
- // Some error.
- else
- {
- osd_printf_verbose("read error, closing the connection: %s\n", uv_strerror(nread));
-
- m_has_error = true;
-
- // Close server side of the connection.
- close();
- }
-}
-
-void tcp_connection::on_uv_write_error(int error)
-{
- if (m_is_closing)
- return;
-
- if (error == UV_EPIPE || error == UV_ENOTCONN)
- {
- osd_printf_verbose("write error, closing the connection: %s\n", uv_strerror(error));
- }
- else
- {
- osd_printf_verbose("write error, closing the connection: %s\n", uv_strerror(error));
-
- m_has_error = true;
- }
-
- close();
-}
-
-void tcp_connection::on_uv_shutdown(uv_shutdown_t* req, int status)
-{
- delete req;
-
- if (status == UV_EPIPE || status == UV_ENOTCONN || status == UV_ECANCELED)
- osd_printf_verbose("shutdown error: %s\n", uv_strerror(status));
- else if (status)
- osd_printf_verbose("shutdown error: %s\n", uv_strerror(status));
-
- // Now do close the handle.
- uv_close((uv_handle_t*)m_uv_handle, (uv_close_cb)on_close);
-}
-
-void tcp_connection::on_uv_closed()
-{
- // Notify the listener.
- m_listener->on_tcp_connection_closed(this, m_is_closed_by_peer);
-
- // And delete this.
- delete this;
-}