a8/a8/udplistener.cc
2023-04-17 02:34:21 +00:00

162 lines
3.8 KiB
C++

#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <memory.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <netinet/tcp.h>
#include <string>
#include <functional>
#include <thread>
#include <a8/udplistener.h>
namespace a8
{
long long UdpPacket::GetRemoteKey()
{
return 0;
}
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) {
#if 0
master->OnSocketRead(recv_buf, ret);
#endif
}
}
}
};
UdpListener::UdpListener()
{
impl_ = new a8::UdpListenerImpl();
impl_->master = this;
}
UdpListener::~UdpListener()
{
delete impl_;
impl_ = nullptr;
}
void UdpListener::Open()
{
if (!IsActive()) {
impl_->SetActive(true);
}
}
void UdpListener::Close()
{
if (IsActive()) {
impl_->SetActive(false);
}
}
bool UdpListener::IsActive()
{
return impl_->IsActive();
}
void UdpListener::SendUdpPacket(UdpPacket* pkt)
{
}
}