From 50341c6846dbde4d0eadd9a9d4ed3ae1863c12b8 Mon Sep 17 00:00:00 2001 From: azw Date: Sat, 15 Apr 2023 01:13:39 +0000 Subject: [PATCH] 1 --- a8/udplistener.cc | 152 ++++++++++++++++++++++++++++++++++++++++++++++ a8/udplistener.h | 27 ++++++++ 2 files changed, 179 insertions(+) create mode 100644 a8/udplistener.cc create mode 100644 a8/udplistener.h diff --git a/a8/udplistener.cc b/a8/udplistener.cc new file mode 100644 index 0000000..5e8df4a --- /dev/null +++ b/a8/udplistener.cc @@ -0,0 +1,152 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace a8 +{ + struct UdpListenerImpl + { + a8::UdpListener* master = nullptr; + + int listen_socket = -1; + std::thread* worker_thread = nullptr; + + volatile bool shutdown = false; + + bool IsActive() + { + return listen_socket != -1; + } + + void SetActive(bool active) + { + if (active) { + if (IsActive()) { + return; + } + if (!worker_thread) { + shutdown = false; + worker_thread = new std::thread(&a8::UdpListenerImpl::WorkerThreadProc, this); + } + } else { + if (IsActive()) { + ActiveStop(); + } + } + } + + bool ActiveStart() + { + listen_socket = ::socket(AF_INET, SOCK_DGRAM, 0); + if (listen_socket == -1){ + if (master->on_error) { + master->on_error(master, errno); + } + return false; + } + // TIME_WAIT - argh + int on = 1; + if (::setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1 ){ + //return false; + } + sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = inet_addr(master->bind_address.c_str()); + sa.sin_port = htons(master->bind_port); + if (::bind(listen_socket, (sockaddr*)&sa, sizeof(sa)) < 0) { + if (master->on_error) { + master->on_error(master, errno); + } + ::close(listen_socket); + listen_socket = -1; + return false; + } + return true; + } + + void ActiveStop() + { + if(listen_socket != -1){ + ::close(listen_socket); + listen_socket = -1; + } + if (worker_thread) { + shutdown = true; + worker_thread->join(); + delete worker_thread; + worker_thread = NULL; + } + } + + void WorkerThreadProc() + { + if(!ActiveStart()) + return; + struct sockaddr_in destAddr; + socklen_t addrLen = sizeof(sockaddr_in); + char recv_buf[1024 * 64]; + int buflen = sizeof(recv_buf); + while (!shutdown) { + int ret = ::recvfrom(listen_socket, + recv_buf, + buflen, + 0, + (struct sockaddr*)&destAddr, + (socklen_t*)&addrLen); + if(ret > 0){ + master->OnSocketRead(recv_buf, ret); + } + } + } + + }; + + UdpListener::UdpListener() + { + impl_ = new a8::UdpListenerImpl(); + impl_->master = this; + } + + UdpListener::~UdpListener() + { + delete impl_; + impl_ = nullptr; + } + + void UdpListener::OnSocketRead(char*, unsigned int) + { + } + + void UdpListener::Open() + { + if (!IsActive()) { + impl_->SetActive(true); + } + } + + void UdpListener::Close() + { + if (IsActive()) { + impl_->SetActive(false); + } + } + + bool UdpListener::IsActive() + { + return impl_->IsActive(); + } + +} diff --git a/a8/udplistener.h b/a8/udplistener.h new file mode 100644 index 0000000..509d25e --- /dev/null +++ b/a8/udplistener.h @@ -0,0 +1,27 @@ +#pragma once + +namespace a8 +{ + + struct UdpListenerImpl; + class UdpListener + { + public: + std::function on_error; + std::string bind_address; + unsigned short bind_port = 0; + + public: + UdpListener(); + ~UdpListener(); + + virtual void OnSocketRead(char*, unsigned int); + void Open(); + void Close(); + bool IsActive(); + + private: + a8::UdpListenerImpl* impl_ = nullptr; + }; + +}