Removed the trantor module. I had to merge it with the drogon modules (temporarily).

This commit is contained in:
Relintai 2021-06-17 14:44:04 +02:00
parent e50dc2560d
commit cde728db20
100 changed files with 0 additions and 17034 deletions

View File

@ -1,27 +0,0 @@
#!/usr/bin/env python
Import("env_mod")
Import("env")
env_mod.core_sources = []
env_mod.add_source_files(env_mod.core_sources, "trantor/net/*.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/net/inner/*.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/net/inner/poller/*.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/AsyncFileLogger.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/ConcurrentTaskQueue.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/Date.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/Logger.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/LogStream.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/MsgBuffer.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/SerialTaskQueue.cc")
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/TimingWheel.cc")
#windows only
#env_mod.add_source_files(env_mod.core_sources, "third_party/wepoll/*.c")
#env_mod.add_source_files(env_mod.core_sources, "trantor/utils/WindowsSupport.cc")
# Build it all as a library
lib = env_mod.add_library("trantor", env_mod.core_sources)
env.Prepend(LIBS=[lib])

View File

@ -1,34 +0,0 @@
import os
import platform
import sys
def is_active():
return True
def get_name():
return "trantor"
def can_build():
return False
def get_opts():
return []
def get_flags():
return []
def configure(env):
#env.Append(CXX=["-std=c++17"])
env.Prepend(CPPPATH=["#modules/trantor"])
env.Prepend(CPPPATH=["#modules/trantor/trantor/net"])
env.Prepend(CPPPATH=["#modules/trantor/trantor/net/inner"])
env.Prepend(CPPPATH=["#modules/trantor/trantor/utils"])

View File

@ -1 +0,0 @@
255976d89866d556efd24264f65765f3e02bc32b

View File

@ -1,57 +0,0 @@
// Trantor - A non-blocking I/O based TCP network library, using C++14/17,
// Copyright (c) 2016-2021, Tao An. All rights reserved.
// https://github.com/an-tao/trantor
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Tao An nor the names of other contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Muduo - A reactor-based C++ network library for Linux
// Copyright (c) 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Shuo Chen nor the names of other contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,49 +0,0 @@
# TRANTOR
[![Build Status](https://travis-ci.org/an-tao/trantor.svg?branch=master)](https://travis-ci.org/an-tao/trantor)
[![Build status](https://ci.appveyor.com/api/projects/status/yn8xunsubn37pi1u/branch/master?svg=true)](https://ci.appveyor.com/project/an-tao/trantor/branch/master)
[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/an-tao/trantor.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/an-tao/trantor/context:cpp)
## Overview
A non-blocking I/O cross-platform TCP network library, using C++14.
Drawing on the design of Muduo Library
## suported platforms
- Linux
- MacOS
- UNIX(BSD)
- Windows
## Feature highlights
- non-blocking I/O
- cross-platform
- Thread pool
- Lock free design
- Support SSL
- Server and Client
## Build
```shell
git clone https://github.com/an-tao/trantor.git
cd trantor
cmake -Bbuild -H.
cd build
make -j
```
## Licensing
Trantor - A non-blocking I/O based TCP network library, using C++14.
Copyright (c) 2016-2021, Tao An. All rights reserved.
https://github.com/an-tao/trantor
For more information see [License](License)
## Community
[Gitter](https://gitter.im/drogon-web/community)
## Documentation
[DocsForge](https://trantor.docsforge.com/)

View File

@ -1,42 +0,0 @@
#ifndef TRANTOR_EXPORT_H
#define TRANTOR_EXPORT_H
#ifdef TRANTOR_STATIC_DEFINE
# define TRANTOR_EXPORT
# define TRANTOR_NO_EXPORT
#else
# ifndef TRANTOR_EXPORT
# ifdef trantor_EXPORTS
/* We are building this library */
# define TRANTOR_EXPORT
# else
/* We are using this library */
# define TRANTOR_EXPORT
# endif
# endif
# ifndef TRANTOR_NO_EXPORT
# define TRANTOR_NO_EXPORT
# endif
#endif
#ifndef TRANTOR_DEPRECATED
# define TRANTOR_DEPRECATED __attribute__ ((__deprecated__))
#endif
#ifndef TRANTOR_DEPRECATED_EXPORT
# define TRANTOR_DEPRECATED_EXPORT TRANTOR_EXPORT TRANTOR_DEPRECATED
#endif
#ifndef TRANTOR_DEPRECATED_NO_EXPORT
# define TRANTOR_DEPRECATED_NO_EXPORT TRANTOR_NO_EXPORT TRANTOR_DEPRECATED
#endif
#if 0 /* DEFINE_NO_DEPRECATED */
# ifndef TRANTOR_NO_DEPRECATED
# define TRANTOR_NO_DEPRECATED
# endif
#endif
#endif /* TRANTOR_EXPORT_H */

View File

@ -1,110 +0,0 @@
/**
*
* Channel.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include "Channel.h"
#include <trantor/net/EventLoop.h>
#ifdef _WIN32
#include "Wepoll.h"
#define POLLIN EPOLLIN
#define POLLPRI EPOLLPRI
#define POLLOUT EPOLLOUT
#define POLLHUP EPOLLHUP
#define POLLNVAL 0
#define POLLERR EPOLLERR
#else
#include <poll.h>
#endif
#include <iostream>
namespace trantor
{
const int Channel::kNoneEvent = 0;
const int Channel::kReadEvent = POLLIN | POLLPRI;
const int Channel::kWriteEvent = POLLOUT;
Channel::Channel(EventLoop *loop, int fd)
: loop_(loop), fd_(fd), events_(0), revents_(0), index_(-1), tied_(false)
{
}
void Channel::remove()
{
assert(events_ == kNoneEvent);
addedToLoop_ = false;
loop_->removeChannel(this);
}
void Channel::update()
{
loop_->updateChannel(this);
}
void Channel::handleEvent()
{
// LOG_TRACE<<"revents_="<<revents_;
if (tied_)
{
std::shared_ptr<void> guard = tie_.lock();
if (guard)
{
handleEventSafely();
}
}
else
{
handleEventSafely();
}
}
void Channel::handleEventSafely()
{
if (eventCallback_)
{
eventCallback_();
return;
}
if ((revents_ & POLLHUP) && !(revents_ & POLLIN))
{
// LOG_TRACE<<"handle close";
if (closeCallback_)
closeCallback_();
}
if (revents_ & (POLLNVAL | POLLERR))
{
// LOG_TRACE<<"handle error";
if (errorCallback_)
errorCallback_();
}
#ifdef __linux__
if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))
#else
if (revents_ & (POLLIN | POLLPRI))
#endif
{
// LOG_TRACE<<"handle read";
if (readCallback_)
readCallback_();
}
#ifdef _WIN32
if ((revents_ & POLLOUT) && !(revents_ & POLLHUP))
#else
if (revents_ & POLLOUT)
#endif
{
// LOG_TRACE<<"handle write";
if (writeCallback_)
writeCallback_();
}
}
} // namespace trantor

View File

@ -1,314 +0,0 @@
/**
*
* @file Channel.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/Logger.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/exports.h>
#include <functional>
#include <assert.h>
#include <memory>
namespace trantor
{
class EventLoop;
/**
* @brief This class is used to implement reactor pattern. A Channel object
* manages a socket fd. Users use a Channel object to receive write or read
* events on the socket it manages.
*
*/
class TRANTOR_EXPORT Channel : NonCopyable
{
public:
using EventCallback = std::function<void()>;
/**
* @brief Construct a new Channel instance.
*
* @param loop The event loop in which the channel works.
* @param fd The socket fd.
*/
Channel(EventLoop *loop, int fd);
/**
* @brief Set the read callback.
*
* @param cb The callback is called when read event occurs on the socket.
* @note One should call the enableReading() method to ensure that the
* callback would be called when some data is received on the socket.
*/
void setReadCallback(const EventCallback &cb)
{
readCallback_ = cb;
};
void setReadCallback(EventCallback &&cb)
{
readCallback_ = std::move(cb);
}
/**
* @brief Set the write callback.
*
* @param cb The callback is called when write event occurs on the socket.
* @note One should call the enableWriting() method to ensure that the
* callback would be called when the socket can be written.
*/
void setWriteCallback(const EventCallback &cb)
{
writeCallback_ = cb;
};
void setWriteCallback(EventCallback &&cb)
{
writeCallback_ = std::move(cb);
}
/**
* @brief Set the close callback.
*
* @param cb The callback is called when the socket is closed.
*/
void setCloseCallback(const EventCallback &cb)
{
closeCallback_ = cb;
}
void setCloseCallback(EventCallback &&cb)
{
closeCallback_ = std::move(cb);
}
/**
* @brief Set the error callback.
*
* @param cb The callback is called when an error occurs on the socket.
*/
void setErrorCallback(const EventCallback &cb)
{
errorCallback_ = cb;
}
void setErrorCallback(EventCallback &&cb)
{
errorCallback_ = std::move(cb);
}
/**
* @brief Set the event callback.
*
* @param cb The callback is called when any event occurs on the socket.
* @note If the event callback is set to the channel, any other callback
* wouldn't be called again.
*/
void setEventCallback(const EventCallback &cb)
{
eventCallback_ = cb;
}
void setEventCallback(EventCallback &&cb)
{
eventCallback_ = std::move(cb);
}
/**
* @brief Return the fd of the socket.
*
* @return int
*/
int fd() const
{
return fd_;
}
/**
* @brief Return the events enabled on the socket.
*
* @return int
*/
int events() const
{
return events_;
}
/**
* @brief Return the events that occurred on the socket.
*
* @return int
*/
int revents() const
{
return revents_;
}
/**
* @brief Check whether there is no event enabled on the socket.
*
* @return true
* @return false
*/
bool isNoneEvent() const
{
return events_ == kNoneEvent;
};
/**
* @brief Disable all events on the socket.
*
*/
void disableAll()
{
events_ = kNoneEvent;
update();
}
/**
* @brief Remove the socket from the poller in the event loop.
*
*/
void remove();
/**
* @brief Return the event loop.
*
* @return EventLoop*
*/
EventLoop *ownerLoop()
{
return loop_;
};
/**
* @brief Enable the read event on the socket.
*
*/
void enableReading()
{
events_ |= kReadEvent;
update();
}
/**
* @brief Disable the read event on the socket.
*
*/
void disableReading()
{
events_ &= ~kReadEvent;
update();
}
/**
* @brief Enable the write event on the socket.
*
*/
void enableWriting()
{
events_ |= kWriteEvent;
update();
}
/**
* @brief Disable the write event on the socket.
*
*/
void disableWriting()
{
events_ &= ~kWriteEvent;
update();
}
/**
* @brief Check whether the write event is enabled on the socket.
*
* @return true
* @return false
*/
bool isWriting() const
{
return events_ & kWriteEvent;
}
/**
* @brief Check whether the read event is enabled on the socket.
*
* @return true
* @return false
*/
bool isReading() const
{
return events_ & kReadEvent;
}
/**
* @brief Set and update the events enabled.
*
* @param events
*/
void updateEvents(int events)
{
events_ = events;
update();
}
/**
* @brief This method is used to ensure that the callback owner is valid
* when a callback is called.
*
* @param obj The callback owner. Usually, the owner is also the owner of
* the channel.
* @note The 'obj' is kept in a weak_ptr object, so this method does not
* cause a circular reference problem.
*/
void tie(const std::shared_ptr<void> &obj)
{
tie_ = obj;
tied_ = true;
}
static const int kNoneEvent;
static const int kReadEvent;
static const int kWriteEvent;
private:
friend class EventLoop;
friend class EpollPoller;
friend class KQueue;
void update();
void handleEvent();
void handleEventSafely();
int setRevents(int revt)
{
// LOG_TRACE<<"revents="<<revt;
revents_ = revt;
return revt;
};
int index()
{
return index_;
};
void setIndex(int index)
{
index_ = index;
};
EventLoop *loop_;
const int fd_;
int events_;
int revents_;
int index_;
bool addedToLoop_{false};
EventCallback readCallback_;
EventCallback writeCallback_;
EventCallback errorCallback_;
EventCallback closeCallback_;
EventCallback eventCallback_;
std::weak_ptr<void> tie_;
bool tied_;
};
} // namespace trantor

View File

@ -1,372 +0,0 @@
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
// Taken from Muduo and modified
// Copyright 2016, Tao An. All rights reserved.
// https://github.com/an-tao/trantor
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Tao An
#include <trantor/net/EventLoop.h>
#include <trantor/utils/Logger.h>
#include "Poller.h"
#include "TimerQueue.h"
#include "Channel.h"
#include <thread>
#include <assert.h>
#ifdef _WIN32
#include <io.h>
using ssize_t = long long;
#else
#include <poll.h>
#endif
#include <iostream>
#ifdef __linux__
#include <sys/eventfd.h>
#endif
#include <functional>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <algorithm>
#include <signal.h>
#include <fcntl.h>
namespace trantor
{
#ifdef __linux__
int createEventfd()
{
int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
if (evtfd < 0)
{
std::cout << "Failed in eventfd" << std::endl;
abort();
}
return evtfd;
}
const int kPollTimeMs = 10000;
#endif
thread_local EventLoop *t_loopInThisThread = nullptr;
EventLoop::EventLoop()
: looping_(false),
threadId_(std::this_thread::get_id()),
quit_(false),
poller_(Poller::newPoller(this)),
currentActiveChannel_(nullptr),
eventHandling_(false),
timerQueue_(new TimerQueue(this)),
#ifdef __linux__
wakeupFd_(createEventfd()),
wakeupChannelPtr_(new Channel(this, wakeupFd_)),
#endif
threadLocalLoopPtr_(&t_loopInThisThread)
{
if (t_loopInThisThread)
{
LOG_FATAL << "There is already an EventLoop in this thread";
exit(-1);
}
t_loopInThisThread = this;
#ifdef __linux__
wakeupChannelPtr_->setReadCallback(std::bind(&EventLoop::wakeupRead, this));
wakeupChannelPtr_->enableReading();
#elif !defined _WIN32
auto r = pipe(wakeupFd_);
(void)r;
assert(!r);
fcntl(wakeupFd_[0], F_SETFL, O_NONBLOCK | O_CLOEXEC);
fcntl(wakeupFd_[1], F_SETFL, O_NONBLOCK | O_CLOEXEC);
wakeupChannelPtr_ =
std::unique_ptr<Channel>(new Channel(this, wakeupFd_[0]));
wakeupChannelPtr_->setReadCallback(std::bind(&EventLoop::wakeupRead, this));
wakeupChannelPtr_->enableReading();
#else
poller_->setEventCallback([](uint64_t event) { assert(event == 1); });
#endif
}
#ifdef __linux__
void EventLoop::resetTimerQueue()
{
assertInLoopThread();
assert(!looping_);
timerQueue_->reset();
}
#endif
void EventLoop::resetAfterFork()
{
poller_->resetAfterFork();
}
EventLoop::~EventLoop()
{
quit();
assert(!looping_);
t_loopInThisThread = nullptr;
#ifdef __linux__
close(wakeupFd_);
#elif defined _WIN32
#else
close(wakeupFd_[0]);
close(wakeupFd_[1]);
#endif
}
EventLoop *EventLoop::getEventLoopOfCurrentThread()
{
return t_loopInThisThread;
}
void EventLoop::updateChannel(Channel *channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
poller_->updateChannel(channel);
}
void EventLoop::removeChannel(Channel *channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
if (eventHandling_)
{
assert(currentActiveChannel_ == channel ||
std::find(activeChannels_.begin(),
activeChannels_.end(),
channel) == activeChannels_.end());
}
poller_->removeChannel(channel);
}
void EventLoop::quit()
{
quit_ = true;
Func f;
while (funcsOnQuit_.dequeue(f))
{
f();
}
// There is a chance that loop() just executes while(!quit_) and exits,
// then EventLoop destructs, then we are accessing an invalid object.
// Can be fixed using mutex_ in both places.
if (!isInLoopThread())
{
wakeup();
}
}
void EventLoop::loop()
{
assert(!looping_);
assertInLoopThread();
looping_ = true;
quit_ = false;
while (!quit_)
{
activeChannels_.clear();
#ifdef __linux__
poller_->poll(kPollTimeMs, &activeChannels_);
#else
poller_->poll(static_cast<int>(timerQueue_->getTimeout()),
&activeChannels_);
timerQueue_->processTimers();
#endif
// TODO sort channel by priority
// std::cout<<"after ->poll()"<<std::endl;
eventHandling_ = true;
for (auto it = activeChannels_.begin(); it != activeChannels_.end();
++it)
{
currentActiveChannel_ = *it;
currentActiveChannel_->handleEvent();
}
currentActiveChannel_ = NULL;
eventHandling_ = false;
// std::cout << "looping" << endl;
doRunInLoopFuncs();
}
looping_ = false;
}
void EventLoop::abortNotInLoopThread()
{
LOG_FATAL << "It is forbidden to run loop on threads other than event-loop "
"thread";
exit(1);
}
void EventLoop::runInLoop(const Func &cb)
{
if (isInLoopThread())
{
cb();
}
else
{
queueInLoop(cb);
}
}
void EventLoop::runInLoop(Func &&cb)
{
if (isInLoopThread())
{
cb();
}
else
{
queueInLoop(std::move(cb));
}
}
void EventLoop::queueInLoop(const Func &cb)
{
funcs_.enqueue(cb);
if (!isInLoopThread() || !looping_)
{
wakeup();
}
}
void EventLoop::queueInLoop(Func &&cb)
{
funcs_.enqueue(std::move(cb));
if (!isInLoopThread() || !looping_)
{
wakeup();
}
}
TimerId EventLoop::runAt(const Date &time, const Func &cb)
{
auto microSeconds =
time.microSecondsSinceEpoch() - Date::now().microSecondsSinceEpoch();
std::chrono::steady_clock::time_point tp =
std::chrono::steady_clock::now() +
std::chrono::microseconds(microSeconds);
return timerQueue_->addTimer(cb, tp, std::chrono::microseconds(0));
}
TimerId EventLoop::runAt(const Date &time, Func &&cb)
{
auto microSeconds =
time.microSecondsSinceEpoch() - Date::now().microSecondsSinceEpoch();
std::chrono::steady_clock::time_point tp =
std::chrono::steady_clock::now() +
std::chrono::microseconds(microSeconds);
return timerQueue_->addTimer(std::move(cb),
tp,
std::chrono::microseconds(0));
}
TimerId EventLoop::runAfter(double delay, const Func &cb)
{
return runAt(Date::date().after(delay), cb);
}
TimerId EventLoop::runAfter(double delay, Func &&cb)
{
return runAt(Date::date().after(delay), std::move(cb));
}
TimerId EventLoop::runEvery(double interval, const Func &cb)
{
std::chrono::microseconds dur(
static_cast<std::chrono::microseconds::rep>(interval * 1000000));
auto tp = std::chrono::steady_clock::now() + dur;
return timerQueue_->addTimer(cb, tp, dur);
}
TimerId EventLoop::runEvery(double interval, Func &&cb)
{
std::chrono::microseconds dur(
static_cast<std::chrono::microseconds::rep>(interval * 1000000));
auto tp = std::chrono::steady_clock::now() + dur;
return timerQueue_->addTimer(std::move(cb), tp, dur);
}
void EventLoop::invalidateTimer(TimerId id)
{
if (isRunning() && timerQueue_)
timerQueue_->invalidateTimer(id);
}
void EventLoop::doRunInLoopFuncs()
{
callingFuncs_ = true;
{
// the destructor for the Func may itself insert a new entry into the
// queue
while (!funcs_.empty())
{
Func func;
while (funcs_.dequeue(func))
{
func();
}
}
}
callingFuncs_ = false;
}
void EventLoop::wakeup()
{
// if (!looping_)
// return;
uint64_t tmp = 1;
#ifdef __linux__
int ret = write(wakeupFd_, &tmp, sizeof(tmp));
(void)ret;
#elif defined _WIN32
poller_->postEvent(1);
#else
int ret = write(wakeupFd_[1], &tmp, sizeof(tmp));
(void)ret;
#endif
}
void EventLoop::wakeupRead()
{
ssize_t ret = 0;
#ifdef __linux__
uint64_t tmp;
ret = read(wakeupFd_, &tmp, sizeof(tmp));
#elif defined _WIN32
#else
uint64_t tmp;
ret = read(wakeupFd_[0], &tmp, sizeof(tmp));
#endif
if (ret < 0)
LOG_SYSERR << "wakeup read error";
}
void EventLoop::moveToCurrentThread()
{
if (isRunning())
{
LOG_FATAL << "EventLoop cannot be moved when running";
exit(-1);
}
if (isInLoopThread())
{
LOG_WARN << "This EventLoop is already in the current thread";
return;
}
if (t_loopInThisThread)
{
LOG_FATAL << "There is already an EventLoop in this thread, you cannot "
"move another in";
exit(-1);
}
*threadLocalLoopPtr_ = nullptr;
t_loopInThisThread = this;
threadLocalLoopPtr_ = &t_loopInThisThread;
threadId_ = std::this_thread::get_id();
}
void EventLoop::runOnQuit(Func &&cb)
{
funcsOnQuit_.enqueue(std::move(cb));
}
void EventLoop::runOnQuit(const Func &cb)
{
funcsOnQuit_.enqueue(cb);
}
} // namespace trantor

View File

@ -1,321 +0,0 @@
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
// Taken from Muduo and modified
// Copyright 2016, Tao An. All rights reserved.
// https://github.com/an-tao/trantor
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Tao An
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/Date.h>
#include <trantor/utils/LockFreeQueue.h>
#include <trantor/exports.h>
#include <thread>
#include <memory>
#include <vector>
#include <mutex>
#include <queue>
#include <functional>
#include <chrono>
#include <limits>
namespace trantor
{
class Poller;
class TimerQueue;
class Channel;
using ChannelList = std::vector<Channel *>;
using Func = std::function<void()>;
using TimerId = uint64_t;
enum
{
InvalidTimerId = 0
};
/**
* @brief As the name implies, this class represents an event loop that runs in
* a perticular thread. The event loop can handle network I/O events and timers
* in asynchronous mode.
* @note An event loop object always belongs to a separate thread, and there is
* one event loop object at most in a thread. We can call an event loop object
* the event loop of the thread it belongs to, or call that thread the thread of
* the event loop.
*/
class TRANTOR_EXPORT EventLoop : NonCopyable
{
public:
EventLoop();
~EventLoop();
/**
* @brief Run the event loop. This method will be blocked until the event
* loop exits.
*
*/
void loop();
/**
* @brief Let the event loop quit.
*
*/
void quit();
/**
* @brief Assertion that the current thread is the thread to which the event
* loop belongs. If the assertion fails, the program aborts.
*/
void assertInLoopThread()
{
if (!isInLoopThread())
{
abortNotInLoopThread();
}
};
#ifdef __linux__
/**
* @brief Make the timer queue works after calling the fork() function.
*
*/
void resetTimerQueue();
#endif
/**
* @brief Make the event loop works after calling the fork() function.
*
*/
void resetAfterFork();
/**
* @brief Return true if the current thread is the thread to which the event
* loop belongs.
*
* @return true
* @return false
*/
bool isInLoopThread() const
{
return threadId_ == std::this_thread::get_id();
};
/**
* @brief Get the event loop of the current thread. Return nullptr if there
* is no event loop in the current thread.
*
* @return EventLoop*
*/
static EventLoop *getEventLoopOfCurrentThread();
/**
* @brief Run the function f in the thread of the event loop.
*
* @param f
* @note If the current thread is the thread of the event loop, the function
* f is executed directly before the method exiting.
*/
void runInLoop(const Func &f);
void runInLoop(Func &&f);
/**
* @brief Run the function f in the thread of the event loop.
*
* @param f
* @note The difference between this method and the runInLoop() method is
* that the function f is executed after the method exiting no matter if the
* current thread is the thread of the event loop.
*/
void queueInLoop(const Func &f);
void queueInLoop(Func &&f);
/**
* @brief Run a function at a time point.
*
* @param time The time to run the function.
* @param cb The function to run.
* @return TimerId The ID of the timer.
*/
TimerId runAt(const Date &time, const Func &cb);
TimerId runAt(const Date &time, Func &&cb);
/**
* @brief Run a function after a period of time.
*
* @param delay Represent the period of time in seconds.
* @param cb The function to run.
* @return TimerId The ID of the timer.
*/
TimerId runAfter(double delay, const Func &cb);
TimerId runAfter(double delay, Func &&cb);
/**
* @brief Run a function after a period of time.
* @note Users could use chrono literals to represent a time duration
* For example:
* @code
runAfter(5s, task);
runAfter(10min, task);
@endcode
*/
TimerId runAfter(const std::chrono::duration<double> &delay, const Func &cb)
{
return runAfter(delay.count(), cb);
}
TimerId runAfter(const std::chrono::duration<double> &delay, Func &&cb)
{
return runAfter(delay.count(), std::move(cb));
}
/**
* @brief Repeatedly run a function every period of time.
*
* @param interval The duration in seconds.
* @param cb The function to run.
* @return TimerId The ID of the timer.
*/
TimerId runEvery(double interval, const Func &cb);
TimerId runEvery(double interval, Func &&cb);
/**
* @brief Repeatedly run a function every period of time.
* Users could use chrono literals to represent a time duration
* For example:
* @code
runEvery(5s, task);
runEvery(10min, task);
runEvery(0.1h, task);
@endcode
*/
TimerId runEvery(const std::chrono::duration<double> &interval,
const Func &cb)
{
return runEvery(interval.count(), cb);
}
TimerId runEvery(const std::chrono::duration<double> &interval, Func &&cb)
{
return runEvery(interval.count(), std::move(cb));
}
/**
* @brief Invalidate the timer identified by the given ID.
*
* @param id The ID of the timer.
*/
void invalidateTimer(TimerId id);
/**
* @brief Move the EventLoop to the current thread, this method must be
* called before the loop is running.
*
*/
void moveToCurrentThread();
/**
* @brief Update channel status. This method is usually used internally.
*
* @param chl
*/
void updateChannel(Channel *chl);
/**
* @brief Remove a channel from the event loop. This method is usually used
* internally.
*
* @param chl
*/
void removeChannel(Channel *chl);
/**
* @brief Return the index of the event loop.
*
* @return size_t
*/
size_t index()
{
return index_;
}
/**
* @brief Set the index of the event loop.
*
* @param index
*/
void setIndex(size_t index)
{
index_ = index;
}
/**
* @brief Return true if the event loop is running.
*
* @return true
* @return false
*/
bool isRunning()
{
return looping_ && (!quit_);
}
/**
* @brief Check if the event loop is calling a function.
*
* @return true
* @return false
*/
bool isCallingFunctions()
{
return callingFuncs_;
}
/**
* @brief Run functions when the event loop quits
*
* @param cb the function to run
* @note the function runs on the thread that quits the EventLoop
*/
void runOnQuit(Func &&cb);
void runOnQuit(const Func &cb);
private:
void abortNotInLoopThread();
void wakeup();
void wakeupRead();
bool looping_;
std::thread::id threadId_;
bool quit_;
std::unique_ptr<Poller> poller_;
ChannelList activeChannels_;
Channel *currentActiveChannel_;
bool eventHandling_;
MpscQueue<Func> funcs_;
std::unique_ptr<TimerQueue> timerQueue_;
MpscQueue<Func> funcsOnQuit_;
bool callingFuncs_{false};
#ifdef __linux__
int wakeupFd_;
std::unique_ptr<Channel> wakeupChannelPtr_;
#elif defined _WIN32
#else
int wakeupFd_[2];
std::unique_ptr<Channel> wakeupChannelPtr_;
#endif
void doRunInLoopFuncs();
#ifdef _WIN32
size_t index_{size_t(-1)};
#else
size_t index_{std::numeric_limits<size_t>::max()};
#endif
EventLoop **threadLocalLoopPtr_;
};
} // namespace trantor

View File

@ -1,72 +0,0 @@
/**
*
* @file EventLoopThread.cc
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/net/EventLoopThread.h>
#include <trantor/utils/Logger.h>
#ifdef __linux__
#include <sys/prctl.h>
#endif
using namespace trantor;
EventLoopThread::EventLoopThread(const std::string &threadName)
: loop_(nullptr),
loopThreadName_(threadName),
thread_([this]() { loopFuncs(); })
{
auto f = promiseForLoopPointer_.get_future();
loop_ = f.get();
}
EventLoopThread::~EventLoopThread()
{
run();
if (loop_)
{
loop_->quit();
}
if (thread_.joinable())
{
thread_.join();
}
}
// void EventLoopThread::stop() {
// if(loop_)
// loop_->quit();
//}
void EventLoopThread::wait()
{
thread_.join();
}
void EventLoopThread::loopFuncs()
{
#ifdef __linux__
::prctl(PR_SET_NAME, loopThreadName_.c_str());
#endif
EventLoop loop;
loop.queueInLoop([this]() { promiseForLoop_.set_value(1); });
promiseForLoopPointer_.set_value(&loop);
auto f = promiseForRun_.get_future();
(void)f.get();
loop.loop();
// LOG_DEBUG << "loop out";
loop_ = NULL;
}
void EventLoopThread::run()
{
std::call_once(once_, [this]() {
auto f = promiseForLoop_.get_future();
promiseForRun_.set_value(1);
// Make sure the event loop loops before returning.
(void)f.get();
});
}

View File

@ -1,72 +0,0 @@
/**
*
* @file EventLoopThread.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/net/EventLoop.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/exports.h>
#include <mutex>
#include <thread>
#include <memory>
#include <condition_variable>
#include <future>
namespace trantor
{
/**
* @brief This class represents an event loop thread.
*
*/
class TRANTOR_EXPORT EventLoopThread : NonCopyable
{
public:
explicit EventLoopThread(const std::string &threadName = "EventLoopThread");
~EventLoopThread();
/**
* @brief Wait for the event loop to exit.
* @note This method blocks the current thread until the event loop exits.
*/
void wait();
/**
* @brief Get the pointer of the event loop of the thread.
*
* @return EventLoop*
*/
EventLoop *getLoop() const
{
return loop_;
}
/**
* @brief Run the event loop of the thread. This method doesn't block the
* current thread.
*
*/
void run();
private:
EventLoop *loop_;
std::string loopThreadName_;
void loopFuncs();
std::promise<EventLoop *> promiseForLoopPointer_;
std::promise<int> promiseForRun_;
std::promise<int> promiseForLoop_;
std::once_flag once_;
std::thread thread_;
};
} // namespace trantor

View File

@ -1,72 +0,0 @@
/**
*
* EventLoopThreadPool.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/net/EventLoopThreadPool.h>
using namespace trantor;
EventLoopThreadPool::EventLoopThreadPool(size_t threadNum,
const std::string &name)
: loopIndex_(0)
{
for (size_t i = 0; i < threadNum; ++i)
{
loopThreadVector_.emplace_back(std::make_shared<EventLoopThread>(name));
}
}
void EventLoopThreadPool::start()
{
for (unsigned int i = 0; i < loopThreadVector_.size(); ++i)
{
loopThreadVector_[i]->run();
}
}
// void EventLoopThreadPool::stop(){
// for(unsigned int i=0;i<loopThreadVector_.size();i++)
// {
// loopThreadVector_[i].stop();
// }
//}
void EventLoopThreadPool::wait()
{
for (unsigned int i = 0; i < loopThreadVector_.size(); ++i)
{
loopThreadVector_[i]->wait();
}
}
EventLoop *EventLoopThreadPool::getNextLoop()
{
if (loopThreadVector_.size() > 0)
{
EventLoop *loop = loopThreadVector_[loopIndex_]->getLoop();
++loopIndex_;
if (loopIndex_ >= loopThreadVector_.size())
loopIndex_ = 0;
return loop;
}
return nullptr;
}
EventLoop *EventLoopThreadPool::getLoop(size_t id)
{
if (id < loopThreadVector_.size())
return loopThreadVector_[id]->getLoop();
return nullptr;
}
std::vector<EventLoop *> EventLoopThreadPool::getLoops() const
{
std::vector<EventLoop *> ret;
for (auto &loopThread : loopThreadVector_)
{
ret.push_back(loopThread->getLoop());
}
return ret;
}

View File

@ -1,92 +0,0 @@
/**
*
* @file EventLoopThreadPool.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/net/EventLoopThread.h>
#include <trantor/exports.h>
#include <vector>
#include <memory>
namespace trantor
{
/**
* @brief This class represents a pool of EventLoopThread objects
*
*/
class TRANTOR_EXPORT EventLoopThreadPool : NonCopyable
{
public:
EventLoopThreadPool() = delete;
/**
* @brief Construct a new event loop thread pool instance.
*
* @param threadNum The number of threads
* @param name The name of the EventLoopThreadPool object.
*/
EventLoopThreadPool(size_t threadNum,
const std::string &name = "EventLoopThreadPool");
/**
* @brief Run all event loops in the pool.
* @note This function doesn't block the current thread.
*/
void start();
/**
* @brief Wait for all event loops in the pool to quit.
*
* @note This function blocks the current thread.
*/
void wait();
/**
* @brief Return the number of the event loop.
*
* @return size_t
*/
size_t size()
{
return loopThreadVector_.size();
}
/**
* @brief Get the next event loop in the pool.
*
* @return EventLoop*
*/
EventLoop *getNextLoop();
/**
* @brief Get the event loop in the `id` position in the pool.
*
* @param id The id of the first event loop is zero. If the id >= the number
* of event loops, nullptr is returned.
* @return EventLoop*
*/
EventLoop *getLoop(size_t id);
/**
* @brief Get all event loops in the pool.
*
* @return std::vector<EventLoop *>
*/
std::vector<EventLoop *> getLoops() const;
private:
std::vector<std::shared_ptr<EventLoopThread>> loopThreadVector_;
size_t loopIndex_;
};
} // namespace trantor

View File

@ -1,232 +0,0 @@
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#include <trantor/net/InetAddress.h>
#include <trantor/utils/Logger.h>
//#include <muduo/net/Endian.h>
#ifdef _WIN32
struct in6_addr_uint
{
union
{
u_char Byte[16];
u_short Word[8];
uint32_t __s6_addr32[4];
} uext;
};
#else
#include <strings.h> // memset
#include <netinet/tcp.h>
#include <netdb.h>
#endif
// INADDR_ANY use (type)value casting.
static const in_addr_t kInaddrAny = INADDR_ANY;
static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK;
// /* Structure describing an Internet socket address. */
// struct sockaddr_in {
// sa_family_t sin_family; /* address family: AF_INET */
// uint16_t sin_port; /* port in network byte order */
// struct in_addr sin_addr; /* internet address */
// };
// /* Internet address. */
// typedef uint32_t in_addr_t;
// struct in_addr {
// in_addr_t s_addr; /* address in network byte order */
// };
// struct sockaddr_in6 {
// sa_family_t sin6_family; /* address family: AF_INET6 */
// uint16_t sin6_port; /* port in network byte order */
// uint32_t sin6_flowinfo; /* IPv6 flow information */
// struct in6_addr sin6_addr; /* IPv6 address */
// uint32_t sin6_scope_id; /* IPv6 scope-id */
// };
using namespace trantor;
/*
#ifdef __linux__
#if !(__GNUC_PREREQ(4, 6))
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#endif
#endif
*/
InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6)
: isIpV6_(ipv6)
{
if (ipv6)
{
memset(&addr6_, 0, sizeof(addr6_));
addr6_.sin6_family = AF_INET6;
in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any;
addr6_.sin6_addr = ip;
addr6_.sin6_port = htons(port);
}
else
{
memset(&addr_, 0, sizeof(addr_));
addr_.sin_family = AF_INET;
in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny;
addr_.sin_addr.s_addr = htonl(ip);
addr_.sin_port = htons(port);
}
isUnspecified_ = false;
}
InetAddress::InetAddress(const std::string &ip, uint16_t port, bool ipv6)
: isIpV6_(ipv6)
{
if (ipv6)
{
memset(&addr6_, 0, sizeof(addr6_));
addr6_.sin6_family = AF_INET6;
addr6_.sin6_port = htons(port);
if (::inet_pton(AF_INET6, ip.c_str(), &addr6_.sin6_addr) <= 0)
{
return;
}
}
else
{
memset(&addr_, 0, sizeof(addr_));
addr_.sin_family = AF_INET;
addr_.sin_port = htons(port);
if (::inet_pton(AF_INET, ip.c_str(), &addr_.sin_addr) <= 0)
{
return;
}
}
isUnspecified_ = false;
}
std::string InetAddress::toIpPort() const
{
char buf[64] = "";
uint16_t port = ntohs(addr_.sin_port);
snprintf(buf, sizeof(buf), ":%u", port);
return toIp() + std::string(buf);
}
bool InetAddress::isIntranetIp() const
{
if (addr_.sin_family == AF_INET)
{
uint32_t ip_addr = ntohl(addr_.sin_addr.s_addr);
if ((ip_addr >= 0x0A000000 && ip_addr <= 0x0AFFFFFF) ||
(ip_addr >= 0xAC100000 && ip_addr <= 0xAC1FFFFF) ||
(ip_addr >= 0xC0A80000 && ip_addr <= 0xC0A8FFFF) ||
ip_addr == 0x7f000001)
{
return true;
}
}
else
{
auto addrP = ip6NetEndian();
// Loopback ip
if (*addrP == 0 && *(addrP + 1) == 0 && *(addrP + 2) == 0 &&
ntohl(*(addrP + 3)) == 1)
return true;
// Privated ip is prefixed by FEC0::/10 or FE80::/10, need testing
auto i32 = (ntohl(*addrP) & 0xffc00000);
if (i32 == 0xfec00000 || i32 == 0xfe800000)
return true;
if (*addrP == 0 && *(addrP + 1) == 0 && ntohl(*(addrP + 2)) == 0xffff)
{
// the IPv6 version of an IPv4 IP address
uint32_t ip_addr = ntohl(*(addrP + 3));
if ((ip_addr >= 0x0A000000 && ip_addr <= 0x0AFFFFFF) ||
(ip_addr >= 0xAC100000 && ip_addr <= 0xAC1FFFFF) ||
(ip_addr >= 0xC0A80000 && ip_addr <= 0xC0A8FFFF) ||
ip_addr == 0x7f000001)
{
return true;
}
}
}
return false;
}
bool InetAddress::isLoopbackIp() const
{
if (!isIpV6())
{
uint32_t ip_addr = ntohl(addr_.sin_addr.s_addr);
if (ip_addr == 0x7f000001)
{
return true;
}
}
else
{
auto addrP = ip6NetEndian();
if (*addrP == 0 && *(addrP + 1) == 0 && *(addrP + 2) == 0 &&
ntohl(*(addrP + 3)) == 1)
return true;
// the IPv6 version of an IPv4 loopback address
if (*addrP == 0 && *(addrP + 1) == 0 && ntohl(*(addrP + 2)) == 0xffff &&
ntohl(*(addrP + 3)) == 0x7f000001)
return true;
}
return false;
}
std::string InetAddress::toIp() const
{
char buf[64];
if (addr_.sin_family == AF_INET)
{
#if defined _MSC_VER && _MSC_VER >= 1900
::inet_ntop(AF_INET, (PVOID)&addr_.sin_addr, buf, sizeof(buf));
#else
::inet_ntop(AF_INET, &addr_.sin_addr, buf, sizeof(buf));
#endif
}
else if (addr_.sin_family == AF_INET6)
{
#if defined _MSC_VER && _MSC_VER >= 1900
::inet_ntop(AF_INET6, (PVOID)&addr6_.sin6_addr, buf, sizeof(buf));
#else
::inet_ntop(AF_INET6, &addr6_.sin6_addr, buf, sizeof(buf));
#endif
}
return buf;
}
uint32_t InetAddress::ipNetEndian() const
{
// assert(family() == AF_INET);
return addr_.sin_addr.s_addr;
}
const uint32_t *InetAddress::ip6NetEndian() const
{
// assert(family() == AF_INET6);
#ifdef __linux__
return addr6_.sin6_addr.s6_addr32;
#elif defined _WIN32
// TODO is this OK ?
const struct in6_addr_uint *addr_temp =
reinterpret_cast<const struct in6_addr_uint *>(&addr6_.sin6_addr);
return (*addr_temp).uext.__s6_addr32;
#else
return addr6_.sin6_addr.__u6_addr.__u6_addr32;
#endif
}
uint16_t InetAddress::toPort() const
{
return ntohs(portNetEndian());
}

View File

@ -1,226 +0,0 @@
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is a public header file, it must only include public header files.
// Taken from Muduo and modified
// Copyright 2016, Tao An. All rights reserved.
// https://github.com/an-tao/trantor
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Tao An
#ifndef MUDUO_NET_INETADDRESS_H
#define MUDUO_NET_INETADDRESS_H
#include <trantor/utils/Date.h>
#include <trantor/exports.h>
#ifdef _WIN32
#include <ws2tcpip.h>
using sa_family_t = unsigned short;
using in_addr_t = uint32_t;
using uint16_t = unsigned short;
#else
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#include <string>
#include <unordered_map>
#include <mutex>
namespace trantor
{
/**
* @brief Wrapper of sockaddr_in. This is an POD interface class.
*
*/
class TRANTOR_EXPORT InetAddress
{
public:
/**
* @brief Constructs an endpoint with given port number. Mostly used in
* TcpServer listening.
*
* @param port
* @param loopbackOnly
* @param ipv6
*/
InetAddress(uint16_t port = 0,
bool loopbackOnly = false,
bool ipv6 = false);
/**
* @brief Constructs an endpoint with given ip and port.
*
* @param ip A IPv4 or IPv6 address.
* @param port
* @param ipv6
*/
InetAddress(const std::string &ip, uint16_t port, bool ipv6 = false);
/**
* @brief Constructs an endpoint with given struct `sockaddr_in`. Mostly
* used when accepting new connections
*
* @param addr
*/
explicit InetAddress(const struct sockaddr_in &addr)
: addr_(addr), isUnspecified_(false)
{
}
/**
* @brief Constructs an IPv6 endpoint with given struct `sockaddr_in6`.
* Mostly used when accepting new connections
*
* @param addr
*/
explicit InetAddress(const struct sockaddr_in6 &addr)
: addr6_(addr), isIpV6_(true), isUnspecified_(false)
{
}
/**
* @brief Return the sin_family of the endpoint.
*
* @return sa_family_t
*/
sa_family_t family() const
{
return addr_.sin_family;
}
/**
* @brief Return the IP string of the endpoint.
*
* @return std::string
*/
std::string toIp() const;
/**
* @brief Return the IP and port string of the endpoint.
*
* @return std::string
*/
std::string toIpPort() const;
/**
* @brief Return the port number of the endpoint.
*
* @return uint16_t
*/
uint16_t toPort() const;
/**
* @brief Check if the endpoint is IPv4 or IPv6.
*
* @return true
* @return false
*/
bool isIpV6() const
{
return isIpV6_;
}
/**
* @brief Return true if the endpoint is an intranet endpoint.
*
* @return true
* @return false
*/
bool isIntranetIp() const;
/**
* @brief Return true if the endpoint is a loopback endpoint.
*
* @return true
* @return false
*/
bool isLoopbackIp() const;
/**
* @brief Get the pointer to the sockaddr struct.
*
* @return const struct sockaddr*
*/
const struct sockaddr *getSockAddr() const
{
return static_cast<const struct sockaddr *>((void *)(&addr6_));
}
/**
* @brief Set the sockaddr_in6 struct in the endpoint.
*
* @param addr6
*/
void setSockAddrInet6(const struct sockaddr_in6 &addr6)
{
addr6_ = addr6;
isIpV6_ = (addr6_.sin6_family == AF_INET6);
isUnspecified_ = false;
}
/**
* @brief Return the integer value of the IP(v4) in net endian byte order.
*
* @return uint32_t
*/
uint32_t ipNetEndian() const;
/**
* @brief Return the pointer to the integer value of the IP(v6) in net
* endian byte order.
*
* @return const uint32_t*
*/
const uint32_t *ip6NetEndian() const;
/**
* @brief Return the port number in net endian byte order.
*
* @return uint16_t
*/
uint16_t portNetEndian() const
{
return addr_.sin_port;
}
/**
* @brief Set the port number in net endian byte order.
*
* @param port
*/
void setPortNetEndian(uint16_t port)
{
addr_.sin_port = port;
}
/**
* @brief Return true if the address is not initalized.
*/
inline bool isUnspecified() const
{
return isUnspecified_;
}
private:
union
{
struct sockaddr_in addr_;
struct sockaddr_in6 addr6_;
};
bool isIpV6_{false};
bool isUnspecified_{true};
};
} // namespace trantor
#endif // MUDUO_NET_INETADDRESS_H

View File

@ -1,57 +0,0 @@
// Copyright 2016, Tao An. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Tao An
#pragma once
#include <trantor/exports.h>
#include <memory>
#include <trantor/net/EventLoop.h>
#include <trantor/net/InetAddress.h>
namespace trantor
{
/**
* @brief This class represents an asynchronous DNS resolver.
* @note Although the c-ares library is not essential, it is recommended to
* install it for higher performance
*/
class TRANTOR_EXPORT Resolver
{
public:
using Callback = std::function<void(const trantor::InetAddress&)>;
/**
* @brief Create a new DNS resolver.
*
* @param loop The event loop in which the DNS resolver runs.
* @param timeout The timeout in seconds for DNS.
* @return std::shared_ptr<Resolver>
*/
static std::shared_ptr<Resolver> newResolver(EventLoop* loop = nullptr,
size_t timeout = 60);
/**
* @brief Resolve an address asynchronously.
*
* @param hostname
* @param callback
*/
virtual void resolve(const std::string& hostname,
const Callback& callback) = 0;
virtual ~Resolver()
{
}
/**
* @brief Check whether the c-ares library is used.
*
* @return true
* @return false
*/
static bool isCAresUsed();
};
} // namespace trantor

View File

@ -1,228 +0,0 @@
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// Taken from muduo and modified by an tao
#include <trantor/net/TcpClient.h>
#include <trantor/utils/Logger.h>
#include "Connector.h"
#include "inner/TcpConnectionImpl.h"
#include <trantor/net/EventLoop.h>
#include <functional>
#include <algorithm>
#include "Socket.h"
#include <stdio.h> // snprintf
using namespace trantor;
using namespace std::placeholders;
namespace trantor
{
// void removeConnector(const ConnectorPtr &)
// {
// // connector->
// }
#ifndef _WIN32
TcpClient::IgnoreSigPipe TcpClient::initObj;
#endif
static void defaultConnectionCallback(const TcpConnectionPtr &conn)
{
LOG_TRACE << conn->localAddr().toIpPort() << " -> "
<< conn->peerAddr().toIpPort() << " is "
<< (conn->connected() ? "UP" : "DOWN");
// do not call conn->forceClose(), because some users want to register
// message callback only.
}
static void defaultMessageCallback(const TcpConnectionPtr &, MsgBuffer *buf)
{
buf->retrieveAll();
}
} // namespace trantor
TcpClient::TcpClient(EventLoop *loop,
const InetAddress &serverAddr,
const std::string &nameArg)
: loop_(loop),
connector_(new Connector(loop, serverAddr, false)),
name_(nameArg),
connectionCallback_(defaultConnectionCallback),
messageCallback_(defaultMessageCallback),
retry_(false),
connect_(true)
{
connector_->setNewConnectionCallback(
std::bind(&TcpClient::newConnection, this, _1));
connector_->setErrorCallback([this]() {
if (connectionErrorCallback_)
{
connectionErrorCallback_();
}
});
LOG_TRACE << "TcpClient::TcpClient[" << name_ << "] - connector ";
}
TcpClient::~TcpClient()
{
LOG_TRACE << "TcpClient::~TcpClient[" << name_ << "] - connector ";
TcpConnectionImplPtr conn;
{
std::lock_guard<std::mutex> lock(mutex_);
conn = std::dynamic_pointer_cast<TcpConnectionImpl>(connection_);
}
if (conn)
{
assert(loop_ == conn->getLoop());
// TODO: not 100% safe, if we are in different thread
auto loop = loop_;
loop_->runInLoop([conn, loop]() {
conn->setCloseCallback([loop](const TcpConnectionPtr &connPtr) {
loop->queueInLoop([connPtr]() {
static_cast<TcpConnectionImpl *>(connPtr.get())
->connectDestroyed();
});
});
});
conn->forceClose();
}
else
{
/// TODO need test in this condition
connector_->stop();
}
}
void TcpClient::connect()
{
// TODO: check state
LOG_TRACE << "TcpClient::connect[" << name_ << "] - connecting to "
<< connector_->serverAddress().toIpPort();
connect_ = true;
connector_->start();
}
void TcpClient::disconnect()
{
connect_ = false;
{
std::lock_guard<std::mutex> lock(mutex_);
if (connection_)
{
connection_->shutdown();
}
}
}
void TcpClient::stop()
{
connect_ = false;
connector_->stop();
}
void TcpClient::newConnection(int sockfd)
{
loop_->assertInLoopThread();
InetAddress peerAddr(Socket::getPeerAddr(sockfd));
InetAddress localAddr(Socket::getLocalAddr(sockfd));
// TODO poll with zero timeout to double confirm the new connection
// TODO use make_shared if necessary
std::shared_ptr<TcpConnectionImpl> conn;
if (sslCtxPtr_)
{
#ifdef USE_OPENSSL
conn = std::make_shared<TcpConnectionImpl>(loop_,
sockfd,
localAddr,
peerAddr,
sslCtxPtr_,
false,
validateCert_,
SSLHostName_);
#else
LOG_FATAL << "OpenSSL is not found in your system!";
abort();
#endif
}
else
{
conn = std::make_shared<TcpConnectionImpl>(loop_,
sockfd,
localAddr,
peerAddr);
}
conn->setConnectionCallback(connectionCallback_);
conn->setRecvMsgCallback(messageCallback_);
conn->setWriteCompleteCallback(writeCompleteCallback_);
conn->setCloseCallback(std::bind(&TcpClient::removeConnection, this, _1));
{
std::lock_guard<std::mutex> lock(mutex_);
connection_ = conn;
}
conn->setSSLErrorCallback([this](SSLError err) {
if (sslErrorCallback_)
{
sslErrorCallback_(err);
}
});
conn->connectEstablished();
}
void TcpClient::removeConnection(const TcpConnectionPtr &conn)
{
loop_->assertInLoopThread();
assert(loop_ == conn->getLoop());
{
std::lock_guard<std::mutex> lock(mutex_);
assert(connection_ == conn);
connection_.reset();
}
loop_->queueInLoop(
std::bind(&TcpConnectionImpl::connectDestroyed,
std::dynamic_pointer_cast<TcpConnectionImpl>(conn)));
if (retry_ && connect_)
{
LOG_TRACE << "TcpClient::connect[" << name_ << "] - Reconnecting to "
<< connector_->serverAddress().toIpPort();
connector_->restart();
}
}
void TcpClient::enableSSL(
bool useOldTLS,
bool validateCert,
std::string hostname,
const std::vector<std::pair<std::string, std::string>> &sslConfCmds)
{
#ifdef USE_OPENSSL
/* Create a new OpenSSL context */
sslCtxPtr_ = newSSLContext(useOldTLS, validateCert, sslConfCmds);
validateCert_ = validateCert;
if (!hostname.empty())
{
std::transform(hostname.begin(),
hostname.end(),
hostname.begin(),
tolower);
SSLHostName_ = std::move(hostname);
}
#else
LOG_FATAL << "OpenSSL is not found in your system!";
abort();
#endif
}

View File

@ -1,247 +0,0 @@
// taken from muduo
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is a public header file, it must only include public header files.
// Copyright 2016, Tao An. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Tao An
#pragma once
#include <trantor/net/EventLoop.h>
#include <trantor/net/InetAddress.h>
#include <trantor/net/TcpConnection.h>
#include <trantor/exports.h>
#include <functional>
#include <thread>
#include <atomic>
#include <signal.h>
namespace trantor
{
class Connector;
using ConnectorPtr = std::shared_ptr<Connector>;
class SSLContext;
/**
* @brief This class represents a TCP client.
*
*/
class TRANTOR_EXPORT TcpClient : NonCopyable
{
public:
/**
* @brief Construct a new TCP client instance.
*
* @param loop The event loop in which the client runs.
* @param serverAddr The address of the server.
* @param nameArg The name of the client.
*/
TcpClient(EventLoop *loop,
const InetAddress &serverAddr,
const std::string &nameArg);
~TcpClient();
/**
* @brief Connect to the server.
*
*/
void connect();
/**
* @brief Disconnect from the server.
*
*/
void disconnect();
/**
* @brief Stop connecting to the server.
*
*/
void stop();
/**
* @brief Get the TCP connection to the server.
*
* @return TcpConnectionPtr
*/
TcpConnectionPtr connection() const
{
std::lock_guard<std::mutex> lock(mutex_);
return connection_;
}
/**
* @brief Get the event loop.
*
* @return EventLoop*
*/
EventLoop *getLoop() const
{
return loop_;
}
/**
* @brief Check whether the client re-connect to the server.
*
* @return true
* @return false
*/
bool retry() const
{
return retry_;
}
/**
* @brief Enable retrying.
*
*/
void enableRetry()
{
retry_ = true;
}
/**
* @brief Get the name of the client.
*
* @return const std::string&
*/
const std::string &name() const
{
return name_;
}
/**
* @brief Set the connection callback.
*
* @param cb The callback is called when the connection to the server is
* established or closed.
*/
void setConnectionCallback(const ConnectionCallback &cb)
{
connectionCallback_ = cb;
}
void setConnectionCallback(ConnectionCallback &&cb)
{
connectionCallback_ = std::move(cb);
}
/**
* @brief Set the connection error callback.
*
* @param cb The callback is called when an error occurs during connecting
* to the server.
*/
void setConnectionErrorCallback(const ConnectionErrorCallback &cb)
{
connectionErrorCallback_ = cb;
}
/**
* @brief Set the message callback.
*
* @param cb The callback is called when some data is received from the
* server.
*/
void setMessageCallback(const RecvMessageCallback &cb)
{
messageCallback_ = cb;
}
void setMessageCallback(RecvMessageCallback &&cb)
{
messageCallback_ = std::move(cb);
}
/// Set write complete callback.
/// Not thread safe.
/**
* @brief Set the write complete callback.
*
* @param cb The callback is called when data to send is written to the
* socket.
*/
void setWriteCompleteCallback(const WriteCompleteCallback &cb)
{
writeCompleteCallback_ = cb;
}
void setWriteCompleteCallback(WriteCompleteCallback &&cb)
{
writeCompleteCallback_ = std::move(cb);
}
/**
* @brief Set the callback for errors of SSL
* @param cb The callback is called when an SSL error occurs.
*/
void setSSLErrorCallback(const SSLErrorCallback &cb)
{
sslErrorCallback_ = cb;
}
void setSSLErrorCallback(SSLErrorCallback &&cb)
{
sslErrorCallback_ = std::move(cb);
}
/**
* @brief Enable SSL encryption.
* @param useOldTLS If true, the TLS 1.0 and 1.1 are supported by the
* client.
* @param validateCert If true, we try to validate if the peer's SSL cert
* is valid.
* @param hostname The server hostname for SNI. If it is empty, the SNI is
* not used.
* @param sslConfCmds The commands used to call the SSL_CONF_cmd function in
* OpenSSL.
* @note It's well known that TLS 1.0 and 1.1 are not considered secure in
* 2020. And it's a good practice to only use TLS 1.2 and above.
*/
void enableSSL(bool useOldTLS = false,
bool validateCert = true,
std::string hostname = "",
const std::vector<std::pair<std::string, std::string>>
&sslConfCmds = {});
private:
/// Not thread safe, but in loop
void newConnection(int sockfd);
/// Not thread safe, but in loop
void removeConnection(const TcpConnectionPtr &conn);
EventLoop *loop_;
ConnectorPtr connector_; // avoid revealing Connector
const std::string name_;
ConnectionCallback connectionCallback_;
ConnectionErrorCallback connectionErrorCallback_;
RecvMessageCallback messageCallback_;
WriteCompleteCallback writeCompleteCallback_;
SSLErrorCallback sslErrorCallback_;
std::atomic_bool retry_; // atomic
std::atomic_bool connect_; // atomic
// always in loop thread
mutable std::mutex mutex_;
TcpConnectionPtr connection_; // @GuardedBy mutex_
std::shared_ptr<SSLContext> sslCtxPtr_;
bool validateCert_{false};
std::string SSLHostName_;
#ifndef _WIN32
class IgnoreSigPipe
{
public:
IgnoreSigPipe()
{
::signal(SIGPIPE, SIG_IGN);
}
};
static IgnoreSigPipe initObj;
#endif
};
} // namespace trantor

View File

@ -1,261 +0,0 @@
/**
*
* @file TcpConnection.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/exports.h>
#include <trantor/net/EventLoop.h>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/MsgBuffer.h>
#include <trantor/net/callbacks.h>
#include <memory>
#include <functional>
#include <string>
namespace trantor
{
class SSLContext;
TRANTOR_EXPORT std::shared_ptr<SSLContext> newSSLServerContext(
const std::string &certPath,
const std::string &keyPath,
bool useOldTLS = false,
const std::vector<std::pair<std::string, std::string>> &sslConfCmds = {});
/**
* @brief This class represents a TCP connection.
*
*/
class TRANTOR_EXPORT TcpConnection
{
public:
TcpConnection() = default;
virtual ~TcpConnection(){};
/**
* @brief Send some data to the peer.
*
* @param msg
* @param len
*/
virtual void send(const char *msg, size_t len) = 0;
virtual void send(const void *msg, size_t len) = 0;
virtual void send(const std::string &msg) = 0;
virtual void send(std::string &&msg) = 0;
virtual void send(const MsgBuffer &buffer) = 0;
virtual void send(MsgBuffer &&buffer) = 0;
virtual void send(const std::shared_ptr<std::string> &msgPtr) = 0;
virtual void send(const std::shared_ptr<MsgBuffer> &msgPtr) = 0;
/**
* @brief Send a file to the peer.
*
* @param fileName
* @param offset
* @param length
*/
virtual void sendFile(const char *fileName,
size_t offset = 0,
size_t length = 0) = 0;
/**
* @brief Get the local address of the connection.
*
* @return const InetAddress&
*/
virtual const InetAddress &localAddr() const = 0;
/**
* @brief Get the remote address of the connection.
*
* @return const InetAddress&
*/
virtual const InetAddress &peerAddr() const = 0;
/**
* @brief Return true if the connection is established.
*
* @return true
* @return false
*/
virtual bool connected() const = 0;
/**
* @brief Return false if the connection is established.
*
* @return true
* @return false
*/
virtual bool disconnected() const = 0;
/**
* @brief Get the buffer in which the received data stored.
*
* @return MsgBuffer*
*/
virtual MsgBuffer *getRecvBuffer() = 0;
/**
* @brief Set the high water mark callback
*
* @param cb The callback is called when the data in sending buffer is
* larger than the water mark.
* @param markLen The water mark in bytes.
*/
virtual void setHighWaterMarkCallback(const HighWaterMarkCallback &cb,
size_t markLen) = 0;
/**
* @brief Set the TCP_NODELAY option to the socket.
*
* @param on
*/
virtual void setTcpNoDelay(bool on) = 0;
/**
* @brief Shutdown the connection.
* @note This method only closes the writing direction.
*/
virtual void shutdown() = 0;
/**
* @brief Close the connection forcefully.
*
*/
virtual void forceClose() = 0;
/**
* @brief Get the event loop in which the connection I/O is handled.
*
* @return EventLoop*
*/
virtual EventLoop *getLoop() = 0;
/**
* @brief Set the custom data on the connection.
*
* @param context
*/
void setContext(const std::shared_ptr<void> &context)
{
contextPtr_ = context;
}
void setContext(std::shared_ptr<void> &&context)
{
contextPtr_ = std::move(context);
}
/**
* @brief Get the custom data from the connection.
*
* @tparam T
* @return std::shared_ptr<T>
*/
template <typename T>
std::shared_ptr<T> getContext() const
{
return std::static_pointer_cast<T>(contextPtr_);
}
/**
* @brief Return true if the custom data is set by user.
*
* @return true
* @return false
*/
bool hasContext() const
{
return (bool)contextPtr_;
}
/**
* @brief Clear the custom data.
*
*/
void clearContext()
{
contextPtr_.reset();
}
/**
* @brief Call this method to avoid being kicked off by TcpServer, refer to
* the kickoffIdleConnections method in the TcpServer class.
*
*/
virtual void keepAlive() = 0;
/**
* @brief Return true if the keepAlive() method is called.
*
* @return true
* @return false
*/
virtual bool isKeepAlive() = 0;
/**
* @brief Return the number of bytes sent
*
* @return size_t
*/
virtual size_t bytesSent() const = 0;
/**
* @brief Return the number of bytes received.
*
* @return size_t
*/
virtual size_t bytesReceived() const = 0;
/**
* @brief Check whether the connection is SSL encrypted.
*
* @return true
* @return false
*/
virtual bool isSSLConnection() const = 0;
/**
* @brief Start the SSL encryption on the connection (as a client).
*
* @param callback The callback is called when the SSL connection is
* established.
* @param hostname The server hostname for SNI. If it is empty, the SNI is
* not used.
* @param sslConfCmds The commands used to call the SSL_CONF_cmd function in
* OpenSSL.
*/
virtual void startClientEncryption(
std::function<void()> callback,
bool useOldTLS = false,
bool validateCert = true,
std::string hostname = "",
const std::vector<std::pair<std::string, std::string>> &sslConfCmds =
{}) = 0;
/**
* @brief Start the SSL encryption on the connection (as a server).
*
* @param ctx The SSL context.
* @param callback The callback is called when the SSL connection is
* established.
*/
virtual void startServerEncryption(const std::shared_ptr<SSLContext> &ctx,
std::function<void()> callback) = 0;
protected:
bool validateCert_ = false;
private:
std::shared_ptr<void> contextPtr_;
};
} // namespace trantor

View File

@ -1,201 +0,0 @@
/**
*
* @file TcpServer.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/trantor
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
* Trantor
*
*/
#include "Acceptor.h"
#include "inner/TcpConnectionImpl.h"
#include <trantor/net/TcpServer.h>
#include <trantor/utils/Logger.h>
#include <functional>
#include <vector>
using namespace trantor;
using namespace std::placeholders;
TcpServer::TcpServer(EventLoop *loop,
const InetAddress &address,
const std::string &name,
bool reUseAddr,
bool reUsePort)
: loop_(loop),
acceptorPtr_(new Acceptor(loop, address, reUseAddr, reUsePort)),
serverName_(name),
recvMessageCallback_([](const TcpConnectionPtr &, MsgBuffer *buffer) {
LOG_ERROR << "unhandled recv message [" << buffer->readableBytes()
<< " bytes]";
buffer->retrieveAll();
})
{
acceptorPtr_->setNewConnectionCallback(
std::bind(&TcpServer::newConnection, this, _1, _2));
}
TcpServer::~TcpServer()
{
// loop_->assertInLoopThread();
LOG_TRACE << "TcpServer::~TcpServer [" << serverName_ << "] destructing";
}
void TcpServer::newConnection(int sockfd, const InetAddress &peer)
{
LOG_TRACE << "new connection:fd=" << sockfd
<< " address=" << peer.toIpPort();
// test code for blocking or nonblocking
// std::vector<char> str(1024*1024*100);
// for(int i=0;i<str.size();i++)
// str[i]='A';
// LOG_TRACE<<"vector size:"<<str.size();
// size_t n=write(sockfd,&str[0],str.size());
// LOG_TRACE<<"write "<<n<<" bytes";
loop_->assertInLoopThread();
EventLoop *ioLoop = NULL;
if (loopPoolPtr_ && loopPoolPtr_->size() > 0)
{
ioLoop = loopPoolPtr_->getNextLoop();
}
if (ioLoop == NULL)
ioLoop = loop_;
std::shared_ptr<TcpConnectionImpl> newPtr;
if (sslCtxPtr_)
{
#ifdef USE_OPENSSL
newPtr = std::make_shared<TcpConnectionImpl>(
ioLoop,
sockfd,
InetAddress(Socket::getLocalAddr(sockfd)),
peer,
sslCtxPtr_);
#else
LOG_FATAL << "OpenSSL is not found in your system!";
abort();
#endif
}
else
{
newPtr = std::make_shared<TcpConnectionImpl>(
ioLoop, sockfd, InetAddress(Socket::getLocalAddr(sockfd)), peer);
}
if (idleTimeout_ > 0)
{
assert(timingWheelMap_[ioLoop]);
newPtr->enableKickingOff(idleTimeout_, timingWheelMap_[ioLoop]);
}
newPtr->setRecvMsgCallback(recvMessageCallback_);
newPtr->setConnectionCallback(
[this](const TcpConnectionPtr &connectionPtr) {
if (connectionCallback_)
connectionCallback_(connectionPtr);
});
newPtr->setWriteCompleteCallback(
[this](const TcpConnectionPtr &connectionPtr) {
if (writeCompleteCallback_)
writeCompleteCallback_(connectionPtr);
});
newPtr->setCloseCallback(std::bind(&TcpServer::connectionClosed, this, _1));
connSet_.insert(newPtr);
newPtr->connectEstablished();
}
void TcpServer::start()
{
loop_->runInLoop([this]() {
assert(!started_);
started_ = true;
if (idleTimeout_ > 0)
{
timingWheelMap_[loop_] =
std::make_shared<TimingWheel>(loop_,
idleTimeout_,
1.0F,
idleTimeout_ < 500
? idleTimeout_ + 1
: 100);
if (loopPoolPtr_)
{
auto loopNum = loopPoolPtr_->size();
while (loopNum > 0)
{
// LOG_TRACE << "new Wheel loopNum=" << loopNum;
auto poolLoop = loopPoolPtr_->getNextLoop();
timingWheelMap_[poolLoop] =
std::make_shared<TimingWheel>(poolLoop,
idleTimeout_,
1.0F,
idleTimeout_ < 500
? idleTimeout_ + 1
: 100);
--loopNum;
}
}
}
LOG_TRACE << "map size=" << timingWheelMap_.size();
acceptorPtr_->listen();
});
}
void TcpServer::stop()
{
loop_->runInLoop([this]() { acceptorPtr_.reset(); });
for (auto connection : connSet_)
{
connection->forceClose();
}
loopPoolPtr_.reset();
for (auto &iter : timingWheelMap_)
{
std::promise<int> pro;
auto f = pro.get_future();
iter.second->getLoop()->runInLoop([&iter, &pro]() mutable {
iter.second.reset();
pro.set_value(1);
});
f.get();
}
}
void TcpServer::connectionClosed(const TcpConnectionPtr &connectionPtr)
{
LOG_TRACE << "connectionClosed";
// loop_->assertInLoopThread();
loop_->runInLoop([this, connectionPtr]() {
size_t n = connSet_.erase(connectionPtr);
(void)n;
assert(n == 1);
});
static_cast<TcpConnectionImpl *>(connectionPtr.get())->connectDestroyed();
}
const std::string TcpServer::ipPort() const
{
return acceptorPtr_->addr().toIpPort();
}
const trantor::InetAddress &TcpServer::address() const
{
return acceptorPtr_->addr();
}
void TcpServer::enableSSL(
const std::string &certPath,
const std::string &keyPath,
bool useOldTLS,
const std::vector<std::pair<std::string, std::string>> &sslConfCmds)
{
#ifdef USE_OPENSSL
/* Create a new OpenSSL context */
sslCtxPtr_ = newSSLServerContext(certPath, keyPath, useOldTLS, sslConfCmds);
#else
LOG_FATAL << "OpenSSL is not found in your system!";
abort();
#endif
}

View File

@ -1,250 +0,0 @@
/**
*
* @file TcpServer.h
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/trantor
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
* Trantor
*
*/
#pragma once
#include <trantor/net/callbacks.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThreadPool.h>
#include <trantor/net/InetAddress.h>
#include <trantor/net/TcpConnection.h>
#include <trantor/utils/TimingWheel.h>
#include <trantor/exports.h>
#include <string>
#include <memory>
#include <set>
#include <signal.h>
namespace trantor
{
class Acceptor;
class SSLContext;
/**
* @brief This class represents a TCP server.
*
*/
class TRANTOR_EXPORT TcpServer : NonCopyable
{
public:
/**
* @brief Construct a new TCP server instance.
*
* @param loop The event loop in which the acceptor of the server is
* handled.
* @param address The address of the server.
* @param name The name of the server.
* @param reUseAddr The SO_REUSEADDR option.
* @param reUsePort The SO_REUSEPORT option.
*/
TcpServer(EventLoop *loop,
const InetAddress &address,
const std::string &name,
bool reUseAddr = true,
bool reUsePort = true);
~TcpServer();
/**
* @brief Start the server.
*
*/
void start();
/**
* @brief Stop the server.
*
*/
void stop();
/**
* @brief Set the number of event loops in which the I/O of connections to
* the server is handled.
*
* @param num
*/
void setIoLoopNum(size_t num)
{
assert(!started_);
loopPoolPtr_ = std::make_shared<EventLoopThreadPool>(num);
loopPoolPtr_->start();
}
/**
* @brief Set the event loops pool in which the I/O of connections to
* the server is handled.
*
* @param pool
*/
void setIoLoopThreadPool(const std::shared_ptr<EventLoopThreadPool> &pool)
{
assert(pool->size() > 0);
assert(!started_);
loopPoolPtr_ = pool;
loopPoolPtr_->start();
}
/**
* @brief Set the message callback.
*
* @param cb The callback is called when some data is received on a
* connection to the server.
*/
void setRecvMessageCallback(const RecvMessageCallback &cb)
{
recvMessageCallback_ = cb;
}
void setRecvMessageCallback(RecvMessageCallback &&cb)
{
recvMessageCallback_ = std::move(cb);
}
/**
* @brief Set the connection callback.
*
* @param cb The callback is called when a connection is established or
* closed.
*/
void setConnectionCallback(const ConnectionCallback &cb)
{
connectionCallback_ = cb;
}
void setConnectionCallback(ConnectionCallback &&cb)
{
connectionCallback_ = std::move(cb);
}
/**
* @brief Set the write complete callback.
*
* @param cb The callback is called when data to send is written to the
* socket of a connection.
*/
void setWriteCompleteCallback(const WriteCompleteCallback &cb)
{
writeCompleteCallback_ = cb;
}
void setWriteCompleteCallback(WriteCompleteCallback &&cb)
{
writeCompleteCallback_ = std::move(cb);
}
/**
* @brief Get the name of the server.
*
* @return const std::string&
*/
const std::string &name() const
{
return serverName_;
}
/**
* @brief Get the IP and port string of the server.
*
* @return const std::string
*/
const std::string ipPort() const;
/**
* @brief Get the address of the server.
*
* @return const trantor::InetAddress&
*/
const trantor::InetAddress &address() const;
/**
* @brief Get the event loop of the server.
*
* @return EventLoop*
*/
EventLoop *getLoop() const
{
return loop_;
}
/**
* @brief Get the I/O event loops of the server.
*
* @return std::vector<EventLoop *>
*/
std::vector<EventLoop *> getIoLoops() const
{
return loopPoolPtr_->getLoops();
}
/**
* @brief An idle connection is a connection that has no read or write, kick
* off it after timeout seconds.
*
* @param timeout
*/
void kickoffIdleConnections(size_t timeout)
{
loop_->runInLoop([this, timeout]() {
assert(!started_);
idleTimeout_ = timeout;
});
}
/**
* @brief Enable SSL encryption.
*
* @param certPath The path of the certificate file.
* @param keyPath The path of the private key file.
* @param useOldTLS If true, the TLS 1.0 and 1.1 are supported by the
* server.
* @param sslConfCmds The commands used to call the SSL_CONF_cmd function in
* OpenSSL.
* @note It's well known that TLS 1.0 and 1.1 are not considered secure in
* 2020. And it's a good practice to only use TLS 1.2 and above.
*/
void enableSSL(const std::string &certPath,
const std::string &keyPath,
bool useOldTLS = false,
const std::vector<std::pair<std::string, std::string>>
&sslConfCmds = {});
private:
EventLoop *loop_;
std::unique_ptr<Acceptor> acceptorPtr_;
void newConnection(int fd, const InetAddress &peer);
std::string serverName_;
std::set<TcpConnectionPtr> connSet_;
RecvMessageCallback recvMessageCallback_;
ConnectionCallback connectionCallback_;
WriteCompleteCallback writeCompleteCallback_;
size_t idleTimeout_{0};
std::map<EventLoop *, std::shared_ptr<TimingWheel>> timingWheelMap_;
void connectionClosed(const TcpConnectionPtr &connectionPtr);
std::shared_ptr<EventLoopThreadPool> loopPoolPtr_;
#ifndef _WIN32
class IgnoreSigPipe
{
public:
IgnoreSigPipe()
{
::signal(SIGPIPE, SIG_IGN);
LOG_TRACE << "Ignore SIGPIPE";
}
};
IgnoreSigPipe initObj;
#endif
bool started_{false};
// OpenSSL SSL context Object;
std::shared_ptr<SSLContext> sslCtxPtr_;
};
} // namespace trantor

View File

@ -1,43 +0,0 @@
/**
*
* callbacks.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <functional>
#include <memory>
namespace trantor
{
enum class SSLError
{
kSSLHandshakeError,
kSSLInvalidCertificate
};
using TimerCallback = std::function<void()>;
// the data has been read to (buf, len)
class TcpConnection;
class MsgBuffer;
using TcpConnectionPtr = std::shared_ptr<TcpConnection>;
// tcp server and connection callback
using RecvMessageCallback =
std::function<void(const TcpConnectionPtr &, MsgBuffer *)>;
using ConnectionErrorCallback = std::function<void()>;
using ConnectionCallback = std::function<void(const TcpConnectionPtr &)>;
using CloseCallback = std::function<void(const TcpConnectionPtr &)>;
using WriteCompleteCallback = std::function<void(const TcpConnectionPtr &)>;
using HighWaterMarkCallback =
std::function<void(const TcpConnectionPtr &, const size_t)>;
using SSLErrorCallback = std::function<void(SSLError)>;
} // namespace trantor

View File

@ -1,97 +0,0 @@
/**
*
* Acceptor.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include "Acceptor.h"
using namespace trantor;
#ifndef O_CLOEXEC
#define O_CLOEXEC O_NOINHERIT
#endif
Acceptor::Acceptor(EventLoop *loop,
const InetAddress &addr,
bool reUseAddr,
bool reUsePort)
:
#ifndef _WIN32
idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)),
#endif
sock_(
Socket::createNonblockingSocketOrDie(addr.getSockAddr()->sa_family)),
addr_(addr),
loop_(loop),
acceptChannel_(loop, sock_.fd())
{
sock_.setReuseAddr(reUseAddr);
sock_.setReusePort(reUsePort);
sock_.bindAddress(addr_);
acceptChannel_.setReadCallback(std::bind(&Acceptor::readCallback, this));
if (addr_.toPort() == 0)
{
addr_ = InetAddress{Socket::getLocalAddr(sock_.fd())};
}
}
Acceptor::~Acceptor()
{
acceptChannel_.disableAll();
acceptChannel_.remove();
#ifndef _WIN32
::close(idleFd_);
#endif
}
void Acceptor::listen()
{
loop_->assertInLoopThread();
sock_.listen();
acceptChannel_.enableReading();
}
void Acceptor::readCallback()
{
InetAddress peer;
int newsock = sock_.accept(&peer);
if (newsock >= 0)
{
if (newConnectionCallback_)
{
newConnectionCallback_(newsock, peer);
}
else
{
#ifndef _WIN32
::close(newsock);
#else
closesocket(newsock);
#endif
}
}
else
{
LOG_SYSERR << "Accpetor::readCallback";
// Read the section named "The special problem of
// accept()ing when you can't" in libev's doc.
// By Marc Lehmann, author of libev.
/// errno is thread safe
#ifndef _WIN32
if (errno == EMFILE)
{
::close(idleFd_);
idleFd_ = sock_.accept(&peer);
::close(idleFd_);
idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
}
#endif
}
}

View File

@ -1,56 +0,0 @@
/**
*
* Acceptor.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/net/EventLoop.h>
#include <trantor/utils/NonCopyable.h>
#include "Socket.h"
#include <trantor/net/InetAddress.h>
#include "Channel.h"
#include <functional>
namespace trantor
{
using NewConnectionCallback = std::function<void(int fd, const InetAddress &)>;
class Acceptor : NonCopyable
{
public:
Acceptor(EventLoop *loop,
const InetAddress &addr,
bool reUseAddr = true,
bool reUsePort = true);
~Acceptor();
const InetAddress &addr() const
{
return addr_;
}
void setNewConnectionCallback(const NewConnectionCallback &cb)
{
newConnectionCallback_ = cb;
};
void listen();
protected:
#ifndef _WIN32
int idleFd_;
#endif
Socket sock_;
InetAddress addr_;
EventLoop *loop_;
NewConnectionCallback newConnectionCallback_;
Channel acceptChannel_;
void readCallback();
};
} // namespace trantor

View File

@ -1,258 +0,0 @@
// Copyright 2016, Tao An. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Tao An
#include "AresResolver.h"
#include <trantor/net/Channel.h>
#include <ares.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <netdb.h>
#include <arpa/inet.h> // inet_ntop
#include <netinet/in.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
using namespace trantor;
using namespace std::placeholders;
namespace
{
double getSeconds(struct timeval* tv)
{
if (tv)
return double(tv->tv_sec) + double(tv->tv_usec) / 1000000.0;
else
return -1.0;
}
const char* getSocketType(int type)
{
if (type == SOCK_DGRAM)
return "UDP";
else if (type == SOCK_STREAM)
return "TCP";
else
return "Unknown";
}
} // namespace
bool Resolver::isCAresUsed()
{
return true;
}
AresResolver::LibraryInitializer::LibraryInitializer()
{
ares_library_init(ARES_LIB_INIT_ALL);
}
AresResolver::LibraryInitializer::~LibraryInitializer()
{
ares_library_cleanup();
}
AresResolver::LibraryInitializer AresResolver::libraryInitializer_;
std::shared_ptr<Resolver> Resolver::newResolver(trantor::EventLoop* loop,
size_t timeout)
{
return std::make_shared<AresResolver>(loop, timeout);
}
AresResolver::AresResolver(EventLoop* loop, size_t timeout)
: loop_(loop), timeout_(timeout)
{
if (!loop)
{
loop_ = getLoop();
}
}
void AresResolver::init()
{
if (!ctx_)
{
struct ares_options options;
int optmask = ARES_OPT_FLAGS;
options.flags = ARES_FLAG_NOCHECKRESP;
options.flags |= ARES_FLAG_STAYOPEN;
options.flags |= ARES_FLAG_IGNTC; // UDP only
optmask |= ARES_OPT_SOCK_STATE_CB;
options.sock_state_cb = &AresResolver::ares_sock_statecallback_;
options.sock_state_cb_data = this;
optmask |= ARES_OPT_TIMEOUT;
options.timeout = 2;
// optmask |= ARES_OPT_LOOKUPS;
// options.lookups = lookups;
int status = ares_init_options(&ctx_, &options, optmask);
if (status != ARES_SUCCESS)
{
assert(0);
}
ares_set_socket_callback(ctx_,
&AresResolver::ares_sock_createcallback_,
this);
}
}
AresResolver::~AresResolver()
{
if (ctx_)
ares_destroy(ctx_);
}
void AresResolver::resolveInLoop(const std::string& hostname,
const Callback& cb)
{
loop_->assertInLoopThread();
#ifdef _WIN32
if (hostname == "localhost")
{
const static trantor::InetAddress localhost_{"127.0.0.1", 0};
cb(localhost_);
return;
}
#endif
init();
QueryData* queryData = new QueryData(this, cb, hostname);
ares_gethostbyname(ctx_,
hostname.c_str(),
AF_INET,
&AresResolver::ares_hostcallback_,
queryData);
struct timeval tv;
struct timeval* tvp = ares_timeout(ctx_, NULL, &tv);
double timeout = getSeconds(tvp);
// LOG_DEBUG << "timeout " << timeout << " active " << timerActive_;
if (!timerActive_ && timeout >= 0.0)
{
loop_->runAfter(timeout,
std::bind(&AresResolver::onTimer, shared_from_this()));
timerActive_ = true;
}
return;
}
void AresResolver::onRead(int sockfd)
{
ares_process_fd(ctx_, sockfd, ARES_SOCKET_BAD);
}
void AresResolver::onTimer()
{
assert(timerActive_ == true);
ares_process_fd(ctx_, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
struct timeval tv;
struct timeval* tvp = ares_timeout(ctx_, NULL, &tv);
double timeout = getSeconds(tvp);
if (timeout < 0)
{
timerActive_ = false;
}
else
{
loop_->runAfter(timeout,
std::bind(&AresResolver::onTimer, shared_from_this()));
}
}
void AresResolver::onQueryResult(int status,
struct hostent* result,
const std::string& hostname,
const Callback& callback)
{
LOG_TRACE << "onQueryResult " << status;
struct sockaddr_in addr;
memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = 0;
if (result)
{
addr.sin_addr = *reinterpret_cast<in_addr*>(result->h_addr);
}
InetAddress inet(addr);
{
std::lock_guard<std::mutex> lock(globalMutex());
auto& addrItem = globalCache()[hostname];
addrItem.first = addr.sin_addr;
addrItem.second = trantor::Date::date();
}
callback(inet);
}
void AresResolver::onSockCreate(int sockfd, int type)
{
(void)type;
loop_->assertInLoopThread();
assert(channels_.find(sockfd) == channels_.end());
Channel* channel = new Channel(loop_, sockfd);
channel->setReadCallback(std::bind(&AresResolver::onRead, this, sockfd));
channel->enableReading();
channels_[sockfd].reset(channel);
}
void AresResolver::onSockStateChange(int sockfd, bool read, bool write)
{
(void)write;
loop_->assertInLoopThread();
ChannelList::iterator it = channels_.find(sockfd);
assert(it != channels_.end());
if (read)
{
// update
// if (write) { } else { }
}
else
{
// remove
it->second->disableAll();
it->second->remove();
channels_.erase(it);
}
}
void AresResolver::ares_hostcallback_(void* data,
int status,
int timeouts,
struct hostent* hostent)
{
(void)timeouts;
QueryData* query = static_cast<QueryData*>(data);
query->owner_->onQueryResult(status,
hostent,
query->hostname_,
query->callback_);
delete query;
}
#ifdef _WIN32
int AresResolver::ares_sock_createcallback_(SOCKET sockfd, int type, void* data)
#else
int AresResolver::ares_sock_createcallback_(int sockfd, int type, void* data)
#endif
{
LOG_TRACE << "sockfd=" << sockfd << " type=" << getSocketType(type);
static_cast<AresResolver*>(data)->onSockCreate(sockfd, type);
return 0;
}
void AresResolver::ares_sock_statecallback_(void* data,
#ifdef _WIN32
SOCKET sockfd,
#else
int sockfd,
#endif
int read,
int write)
{
LOG_TRACE << "sockfd=" << sockfd << " read=" << read << " write=" << write;
static_cast<AresResolver*>(data)->onSockStateChange(sockfd, read, write);
}

View File

@ -1,148 +0,0 @@
// Copyright 2016, Tao An. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Tao An
#pragma once
#include <trantor/net/Resolver.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/EventLoopThread.h>
#include <map>
#include <memory>
#include <string.h>
extern "C"
{
struct hostent;
struct ares_channeldata;
using ares_channel = struct ares_channeldata*;
}
namespace trantor
{
class AresResolver : public Resolver,
public NonCopyable,
public std::enable_shared_from_this<AresResolver>
{
public:
AresResolver(trantor::EventLoop* loop, size_t timeout);
~AresResolver();
virtual void resolve(const std::string& hostname,
const Callback& cb) override
{
bool cached = false;
InetAddress inet;
{
std::lock_guard<std::mutex> lock(globalMutex());
auto iter = globalCache().find(hostname);
if (iter != globalCache().end())
{
auto& cachedAddr = iter->second;
if (timeout_ == 0 ||
cachedAddr.second.after(timeout_) > trantor::Date::date())
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr = cachedAddr.first;
inet = InetAddress(addr);
cached = true;
}
}
}
if (cached)
{
cb(inet);
return;
}
if (loop_->isInLoopThread())
{
resolveInLoop(hostname, cb);
}
else
{
loop_->queueInLoop([thisPtr = shared_from_this(), hostname, cb]() {
thisPtr->resolveInLoop(hostname, cb);
});
}
}
private:
struct QueryData
{
AresResolver* owner_;
Callback callback_;
std::string hostname_;
QueryData(AresResolver* o,
const Callback& cb,
const std::string& hostname)
: owner_(o), callback_(cb), hostname_(hostname)
{
}
};
void resolveInLoop(const std::string& hostname, const Callback& cb);
void init();
trantor::EventLoop* loop_;
ares_channel ctx_{nullptr};
bool timerActive_{false};
using ChannelList = std::map<int, std::unique_ptr<trantor::Channel>>;
ChannelList channels_;
static std::unordered_map<std::string,
std::pair<struct in_addr, trantor::Date>>&
globalCache()
{
static std::unordered_map<std::string,
std::pair<struct in_addr, trantor::Date>>
dnsCache;
return dnsCache;
}
static std::mutex& globalMutex()
{
static std::mutex mutex_;
return mutex_;
}
static EventLoop* getLoop()
{
static EventLoopThread loopThread;
loopThread.run();
return loopThread.getLoop();
}
const size_t timeout_{60};
void onRead(int sockfd);
void onTimer();
void onQueryResult(int status,
struct hostent* result,
const std::string& hostname,
const Callback& callback);
void onSockCreate(int sockfd, int type);
void onSockStateChange(int sockfd, bool read, bool write);
static void ares_hostcallback_(void* data,
int status,
int timeouts,
struct hostent* hostent);
#ifdef _WIN32
static int ares_sock_createcallback_(SOCKET sockfd, int type, void* data);
#else
static int ares_sock_createcallback_(int sockfd, int type, void* data);
#endif
static void ares_sock_statecallback_(void* data,
#ifdef _WIN32
SOCKET sockfd,
#else
int sockfd,
#endif
int read,
int write);
struct LibraryInitializer
{
LibraryInitializer();
~LibraryInitializer();
};
static LibraryInitializer libraryInitializer_;
};
} // namespace trantor

View File

@ -1,261 +0,0 @@
/**
*
* @file Connector.cc
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include "Connector.h"
#include "Channel.h"
#include "Socket.h"
using namespace trantor;
Connector::Connector(EventLoop *loop, const InetAddress &addr, bool retry)
: loop_(loop), serverAddr_(addr), retry_(retry)
{
}
Connector::Connector(EventLoop *loop, InetAddress &&addr, bool retry)
: loop_(loop), serverAddr_(std::move(addr)), retry_(retry)
{
}
void Connector::start()
{
connect_ = true;
loop_->runInLoop([this]() { startInLoop(); });
}
void Connector::restart()
{
}
void Connector::stop()
{
}
void Connector::startInLoop()
{
loop_->assertInLoopThread();
assert(status_ == Status::Disconnected);
if (connect_)
{
connect();
}
else
{
LOG_DEBUG << "do not connect";
}
}
void Connector::connect()
{
int sockfd = Socket::createNonblockingSocketOrDie(serverAddr_.family());
errno = 0;
int ret = Socket::connect(sockfd, serverAddr_);
int savedErrno = (ret == 0) ? 0 : errno;
switch (savedErrno)
{
case 0:
case EINPROGRESS:
case EINTR:
case EISCONN:
LOG_TRACE << "connecting";
connecting(sockfd);
break;
case EAGAIN:
case EADDRINUSE:
case EADDRNOTAVAIL:
case ECONNREFUSED:
case ENETUNREACH:
if (retry_)
{
retry(sockfd);
}
break;
case EACCES:
case EPERM:
case EAFNOSUPPORT:
case EALREADY:
case EBADF:
case EFAULT:
case ENOTSOCK:
LOG_SYSERR << "connect error in Connector::startInLoop "
<< savedErrno;
#ifndef _WIN32
::close(sockfd);
#else
closesocket(sockfd);
#endif
if (errorCallback_)
errorCallback_();
break;
default:
LOG_SYSERR << "Unexpected error in Connector::startInLoop "
<< savedErrno;
#ifndef _WIN32
::close(sockfd);
#else
closesocket(sockfd);
#endif
if (errorCallback_)
errorCallback_();
break;
}
}
void Connector::connecting(int sockfd)
{
status_ = Status::Connecting;
assert(!channelPtr_);
channelPtr_.reset(new Channel(loop_, sockfd));
channelPtr_->setWriteCallback(
std::bind(&Connector::handleWrite, shared_from_this()));
channelPtr_->setErrorCallback(
std::bind(&Connector::handleError, shared_from_this()));
channelPtr_->setCloseCallback(
std::bind(&Connector::handleError, shared_from_this()));
LOG_TRACE << "connecting:" << sockfd;
channelPtr_->enableWriting();
}
int Connector::removeAndResetChannel()
{
channelPtr_->disableAll();
channelPtr_->remove();
int sockfd = channelPtr_->fd();
// Can't reset channel_ here, because we are inside Channel::handleEvent
loop_->queueInLoop([this]() { channelPtr_.reset(); });
return sockfd;
}
void Connector::handleWrite()
{
if (status_ == Status::Connecting)
{
int sockfd = removeAndResetChannel();
int err = Socket::getSocketError(sockfd);
if (err)
{
LOG_WARN << "Connector::handleWrite - SO_ERROR = " << err << " "
<< strerror_tl(err);
if (retry_)
{
retry(sockfd);
}
else
{
#ifndef _WIN32
::close(sockfd);
#else
closesocket(sockfd);
#endif
}
if (errorCallback_)
{
errorCallback_();
}
}
else if (Socket::isSelfConnect(sockfd))
{
LOG_WARN << "Connector::handleWrite - Self connect";
if (retry_)
{
retry(sockfd);
}
else
{
#ifndef _WIN32
::close(sockfd);
#else
closesocket(sockfd);
#endif
}
if (errorCallback_)
{
errorCallback_();
}
}
else
{
status_ = Status::Connected;
if (connect_)
{
newConnectionCallback_(sockfd);
}
else
{
#ifndef _WIN32
::close(sockfd);
#else
closesocket(sockfd);
#endif
}
}
}
else
{
// what happened?
assert(status_ == Status::Disconnected);
}
}
void Connector::handleError()
{
if (status_ == Status::Connecting)
{
status_ = Status::Disconnected;
int sockfd = removeAndResetChannel();
int err = Socket::getSocketError(sockfd);
LOG_TRACE << "SO_ERROR = " << err << " " << strerror_tl(err);
if (retry_)
{
retry(sockfd);
}
else
{
#ifndef _WIN32
::close(sockfd);
#else
closesocket(sockfd);
#endif
}
if (errorCallback_)
{
errorCallback_();
}
}
}
void Connector::retry(int sockfd)
{
assert(retry_);
#ifndef _WIN32
::close(sockfd);
#else
closesocket(sockfd);
#endif
status_ = Status::Disconnected;
if (connect_)
{
LOG_INFO << "Connector::retry - Retry connecting to "
<< serverAddr_.toIpPort() << " in " << retryInterval_
<< " milliseconds. ";
loop_->runAfter(retryInterval_ / 1000.0,
std::bind(&Connector::startInLoop, shared_from_this()));
retryInterval_ = retryInterval_ * 2;
if (retryInterval_ > maxRetryInterval_)
retryInterval_ = maxRetryInterval_;
}
else
{
LOG_DEBUG << "do not connect";
}
}

View File

@ -1,88 +0,0 @@
/**
*
* Connector.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/net/EventLoop.h>
#include <trantor/net/InetAddress.h>
#include <atomic>
#include <memory>
namespace trantor
{
class Connector : public NonCopyable,
public std::enable_shared_from_this<Connector>
{
public:
using NewConnectionCallback = std::function<void(int sockfd)>;
using ConnectionErrorCallback = std::function<void()>;
Connector(EventLoop *loop, const InetAddress &addr, bool retry = true);
Connector(EventLoop *loop, InetAddress &&addr, bool retry = true);
void setNewConnectionCallback(const NewConnectionCallback &cb)
{
newConnectionCallback_ = cb;
}
void setNewConnectionCallback(NewConnectionCallback &&cb)
{
newConnectionCallback_ = std::move(cb);
}
void setErrorCallback(const ConnectionErrorCallback &cb)
{
errorCallback_ = cb;
}
void setErrorCallback(ConnectionErrorCallback &&cb)
{
errorCallback_ = std::move(cb);
}
const InetAddress &serverAddress() const
{
return serverAddr_;
}
void start();
void restart();
void stop();
private:
NewConnectionCallback newConnectionCallback_;
ConnectionErrorCallback errorCallback_;
enum class Status
{
Disconnected,
Connecting,
Connected
};
static constexpr int kMaxRetryDelayMs = 30 * 1000;
static constexpr int kInitRetryDelayMs = 500;
std::shared_ptr<Channel> channelPtr_;
EventLoop *loop_;
InetAddress serverAddr_;
std::atomic_bool connect_{false};
std::atomic<Status> status_{Status::Disconnected};
int retryInterval_{kInitRetryDelayMs};
int maxRetryInterval_{kMaxRetryDelayMs};
bool retry_;
void startInLoop();
void connect();
void connecting(int sockfd);
int removeAndResetChannel();
void handleWrite();
void handleError();
void retry(int sockfd);
};
} // namespace trantor

View File

@ -1,95 +0,0 @@
#include "NormalResolver.h"
#include <trantor/utils/Logger.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <strings.h> // memset
#endif
using namespace trantor;
std::shared_ptr<Resolver> Resolver::newResolver(trantor::EventLoop *,
size_t timeout)
{
return std::make_shared<NormalResolver>(timeout);
}
bool Resolver::isCAresUsed()
{
return false;
}
void NormalResolver::resolve(const std::string &hostname,
const Callback &callback)
{
{
std::lock_guard<std::mutex> guard(globalMutex());
auto iter = globalCache().find(hostname);
if (iter != globalCache().end())
{
auto &cachedAddr = iter->second;
if (timeout_ == 0 || cachedAddr.second.after(static_cast<double>(
timeout_)) > trantor::Date::date())
{
callback(cachedAddr.first);
return;
}
}
}
concurrentTaskQueue().runTaskInQueue(
[thisPtr = shared_from_this(), callback, hostname]() {
{
std::lock_guard<std::mutex> guard(thisPtr->globalMutex());
auto iter = thisPtr->globalCache().find(hostname);
if (iter != thisPtr->globalCache().end())
{
auto &cachedAddr = iter->second;
if (thisPtr->timeout_ == 0 ||
cachedAddr.second.after(static_cast<double>(
thisPtr->timeout_)) > trantor::Date::date())
{
callback(cachedAddr.first);
return;
}
}
}
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
auto error = getaddrinfo(hostname.data(), nullptr, &hints, &res);
if (error == -1 || res == nullptr)
{
LOG_SYSERR << "InetAddress::resolve";
callback(InetAddress{});
return;
}
InetAddress inet;
if (res->ai_family == AF_INET)
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof addr);
addr = *reinterpret_cast<struct sockaddr_in *>(res->ai_addr);
inet = InetAddress(addr);
}
else if (res->ai_family == AF_INET6)
{
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof addr);
addr = *reinterpret_cast<struct sockaddr_in6 *>(res->ai_addr);
inet = InetAddress(addr);
}
callback(inet);
{
std::lock_guard<std::mutex> guard(thisPtr->globalMutex());
auto &addrItem = thisPtr->globalCache()[hostname];
addrItem.first = inet;
addrItem.second = trantor::Date::date();
}
return;
});
}

View File

@ -1,62 +0,0 @@
// Copyright 2016, Tao An. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Tao An
#pragma once
#include <trantor/net/Resolver.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/ConcurrentTaskQueue.h>
#include <memory>
#include <vector>
#include <thread>
namespace trantor
{
constexpr size_t kResolveBufferLength{16 * 1024};
class NormalResolver : public Resolver,
public NonCopyable,
public std::enable_shared_from_this<NormalResolver>
{
public:
virtual void resolve(const std::string& hostname,
const Callback& callback) override;
explicit NormalResolver(size_t timeout)
: timeout_(timeout), resolveBuffer_(kResolveBufferLength)
{
}
virtual ~NormalResolver()
{
}
private:
static std::unordered_map<std::string,
std::pair<trantor::InetAddress, trantor::Date>>&
globalCache()
{
static std::unordered_map<
std::string,
std::pair<trantor::InetAddress, trantor::Date>>
dnsCache_;
return dnsCache_;
}
static std::mutex& globalMutex()
{
static std::mutex mutex_;
return mutex_;
}
static trantor::ConcurrentTaskQueue& concurrentTaskQueue()
{
static trantor::ConcurrentTaskQueue queue(
std::thread::hardware_concurrency() < 8
? 8
: std::thread::hardware_concurrency(),
"Dns Queue");
return queue;
}
const size_t timeout_;
std::vector<char> resolveBuffer_;
};
} // namespace trantor

View File

@ -1,32 +0,0 @@
/**
*
* Poller.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include "Poller.h"
#ifdef __linux__
#include "poller/EpollPoller.h"
#elif defined _WIN32
#include "Wepoll.h"
#include "poller/EpollPoller.h"
#else
#include "poller/KQueue.h"
#endif
using namespace trantor;
Poller *Poller::newPoller(EventLoop *loop)
{
#if defined __linux__ || defined _WIN32
return new EpollPoller(loop);
#else
return new KQueue(loop);
#endif
}

View File

@ -1,54 +0,0 @@
/**
*
* Poller.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include "NonCopyable.h"
#include "EventLoop.h"
#include <memory>
#include <map>
namespace trantor
{
class Channel;
#ifdef _WIN32
using EventCallback = std::function<void(uint64_t)>;
#endif
class Poller : NonCopyable
{
public:
explicit Poller(EventLoop *loop) : ownerLoop_(loop){};
virtual ~Poller()
{
}
void assertInLoopThread()
{
ownerLoop_->assertInLoopThread();
}
virtual void poll(int timeoutMs, ChannelList *activeChannels) = 0;
virtual void updateChannel(Channel *channel) = 0;
virtual void removeChannel(Channel *channel) = 0;
#ifdef _WIN32
virtual void postEvent(uint64_t event) = 0;
virtual void setEventCallback(const EventCallback &cb) = 0;
#endif
virtual void resetAfterFork()
{
}
static Poller *newPoller(EventLoop *loop);
private:
EventLoop *ownerLoop_;
};
} // namespace trantor

View File

@ -1,248 +0,0 @@
/**
*
* Socket.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/utils/Logger.h>
#include "Socket.h"
#include <assert.h>
#include <sys/types.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/tcp.h>
#endif
using namespace trantor;
bool Socket::isSelfConnect(int sockfd)
{
struct sockaddr_in6 localaddr = getLocalAddr(sockfd);
struct sockaddr_in6 peeraddr = getPeerAddr(sockfd);
if (localaddr.sin6_family == AF_INET)
{
const struct sockaddr_in *laddr4 =
reinterpret_cast<struct sockaddr_in *>(&localaddr);
const struct sockaddr_in *raddr4 =
reinterpret_cast<struct sockaddr_in *>(&peeraddr);
return laddr4->sin_port == raddr4->sin_port &&
laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr;
}
else if (localaddr.sin6_family == AF_INET6)
{
return localaddr.sin6_port == peeraddr.sin6_port &&
memcmp(&localaddr.sin6_addr,
&peeraddr.sin6_addr,
sizeof localaddr.sin6_addr) == 0;
}
else
{
return false;
}
}
void Socket::bindAddress(const InetAddress &localaddr)
{
assert(sockFd_ > 0);
int ret;
if (localaddr.isIpV6())
ret = ::bind(sockFd_, localaddr.getSockAddr(), sizeof(sockaddr_in6));
else
ret = ::bind(sockFd_, localaddr.getSockAddr(), sizeof(sockaddr_in));
if (ret == 0)
return;
else
{
LOG_SYSERR << ", Bind address failed at " << localaddr.toIpPort();
exit(1);
}
}
void Socket::listen()
{
assert(sockFd_ > 0);
int ret = ::listen(sockFd_, SOMAXCONN);
if (ret < 0)
{
LOG_SYSERR << "listen failed";
exit(1);
}
}
int Socket::accept(InetAddress *peeraddr)
{
struct sockaddr_in6 addr6;
memset(&addr6, 0, sizeof(addr6));
socklen_t size = sizeof(addr6);
#ifdef __linux__
int connfd = ::accept4(sockFd_,
(struct sockaddr *)&addr6,
&size,
SOCK_NONBLOCK | SOCK_CLOEXEC);
#else
int connfd =
static_cast<int>(::accept(sockFd_, (struct sockaddr *)&addr6, &size));
setNonBlockAndCloseOnExec(connfd);
#endif
if (connfd >= 0)
{
peeraddr->setSockAddrInet6(addr6);
}
return connfd;
}
void Socket::closeWrite()
{
#ifndef _WIN32
if (::shutdown(sockFd_, SHUT_WR) < 0)
#else
if (::shutdown(sockFd_, SD_SEND) < 0)
#endif
{
LOG_SYSERR << "sockets::shutdownWrite";
}
}
int Socket::read(char *buffer, uint64_t len)
{
#ifndef _WIN32
return ::read(sockFd_, buffer, len);
#else
return recv(sockFd_, buffer, static_cast<int>(len), 0);
#endif
}
struct sockaddr_in6 Socket::getLocalAddr(int sockfd)
{
struct sockaddr_in6 localaddr;
memset(&localaddr, 0, sizeof(localaddr));
socklen_t addrlen = static_cast<socklen_t>(sizeof localaddr);
if (::getsockname(sockfd,
static_cast<struct sockaddr *>((void *)(&localaddr)),
&addrlen) < 0)
{
LOG_SYSERR << "sockets::getLocalAddr";
}
return localaddr;
}
struct sockaddr_in6 Socket::getPeerAddr(int sockfd)
{
struct sockaddr_in6 peeraddr;
memset(&peeraddr, 0, sizeof(peeraddr));
socklen_t addrlen = static_cast<socklen_t>(sizeof peeraddr);
if (::getpeername(sockfd,
static_cast<struct sockaddr *>((void *)(&peeraddr)),
&addrlen) < 0)
{
LOG_SYSERR << "sockets::getPeerAddr";
}
return peeraddr;
}
void Socket::setTcpNoDelay(bool on)
{
#ifdef _WIN32
char optval = on ? 1 : 0;
#else
int optval = on ? 1 : 0;
#endif
::setsockopt(sockFd_,
IPPROTO_TCP,
TCP_NODELAY,
&optval,
static_cast<socklen_t>(sizeof optval));
// TODO CHECK
}
void Socket::setReuseAddr(bool on)
{
#ifdef _WIN32
char optval = on ? 1 : 0;
#else
int optval = on ? 1 : 0;
#endif
::setsockopt(sockFd_,
SOL_SOCKET,
SO_REUSEADDR,
&optval,
static_cast<socklen_t>(sizeof optval));
// TODO CHECK
}
void Socket::setReusePort(bool on)
{
#ifdef SO_REUSEPORT
#ifdef _WIN32
char optval = on ? 1 : 0;
#else
int optval = on ? 1 : 0;
#endif
int ret = ::setsockopt(sockFd_,
SOL_SOCKET,
SO_REUSEPORT,
&optval,
static_cast<socklen_t>(sizeof optval));
if (ret < 0 && on)
{
LOG_SYSERR << "SO_REUSEPORT failed.";
}
#else
if (on)
{
LOG_ERROR << "SO_REUSEPORT is not supported.";
}
#endif
}
void Socket::setKeepAlive(bool on)
{
#ifdef _WIN32
char optval = on ? 1 : 0;
#else
int optval = on ? 1 : 0;
#endif
::setsockopt(sockFd_,
SOL_SOCKET,
SO_KEEPALIVE,
&optval,
static_cast<socklen_t>(sizeof optval));
// TODO CHECK
}
int Socket::getSocketError()
{
#ifdef _WIN32
char optval;
#else
int optval;
#endif
socklen_t optlen = static_cast<socklen_t>(sizeof optval);
if (::getsockopt(sockFd_, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
{
return errno;
}
else
{
return optval;
}
}
Socket::~Socket()
{
LOG_TRACE << "Socket deconstructed:" << sockFd_;
if (sockFd_ >= 0)
#ifndef _WIN32
close(sockFd_);
#else
closesocket(sockFd_);
#endif
}

View File

@ -1,157 +0,0 @@
/**
*
* Socket.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/Logger.h>
#include <string>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <fcntl.h>
namespace trantor
{
class Socket : NonCopyable
{
public:
static int createNonblockingSocketOrDie(int family)
{
#ifdef __linux__
int sock = ::socket(family,
SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
IPPROTO_TCP);
#else
int sock = static_cast<int>(::socket(family, SOCK_STREAM, IPPROTO_TCP));
setNonBlockAndCloseOnExec(sock);
#endif
if (sock < 0)
{
LOG_SYSERR << "sockets::createNonblockingOrDie";
exit(1);
}
LOG_TRACE << "sock=" << sock;
return sock;
}
static int getSocketError(int sockfd)
{
int optval;
socklen_t optlen = static_cast<socklen_t>(sizeof optval);
#ifdef _WIN32
if (::getsockopt(
sockfd, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen) < 0)
#else
if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
#endif
{
return errno;
}
else
{
return optval;
}
}
static int connect(int sockfd, const InetAddress &addr)
{
if (addr.isIpV6())
return ::connect(sockfd,
addr.getSockAddr(),
static_cast<socklen_t>(
sizeof(struct sockaddr_in6)));
else
return ::connect(sockfd,
addr.getSockAddr(),
static_cast<socklen_t>(
sizeof(struct sockaddr_in)));
}
static bool isSelfConnect(int sockfd);
explicit Socket(int sockfd) : sockFd_(sockfd)
{
}
~Socket();
/// abort if address in use
void bindAddress(const InetAddress &localaddr);
/// abort if address in use
void listen();
int accept(InetAddress *peeraddr);
void closeWrite();
int read(char *buffer, uint64_t len);
int fd()
{
return sockFd_;
}
static struct sockaddr_in6 getLocalAddr(int sockfd);
static struct sockaddr_in6 getPeerAddr(int sockfd);
///
/// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm).
///
void setTcpNoDelay(bool on);
///
/// Enable/disable SO_REUSEADDR
///
void setReuseAddr(bool on);
///
/// Enable/disable SO_REUSEPORT
///
void setReusePort(bool on);
///
/// Enable/disable SO_KEEPALIVE
///
void setKeepAlive(bool on);
int getSocketError();
protected:
int sockFd_;
public:
// taken from muduo
static void setNonBlockAndCloseOnExec(int sockfd)
{
#ifdef _WIN32
// TODO how to set FD_CLOEXEC on windows? is it necessary?
u_long arg = 1;
auto ret = ioctlsocket(sockfd, (long)FIONBIO, &arg);
if (ret)
{
LOG_ERROR << "ioctlsocket error";
}
#else
// non-block
int flags = ::fcntl(sockfd, F_GETFL, 0);
flags |= O_NONBLOCK;
int ret = ::fcntl(sockfd, F_SETFL, flags);
// TODO check
// close-on-exec
flags = ::fcntl(sockfd, F_GETFD, 0);
flags |= FD_CLOEXEC;
ret = ::fcntl(sockfd, F_SETFD, flags);
// TODO check
(void)ret;
#endif
}
};
} // namespace trantor

File diff suppressed because it is too large Load Diff

View File

@ -1,344 +0,0 @@
/**
*
* @file TcpConnectionImpl.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/net/TcpConnection.h>
#include <trantor/utils/TimingWheel.h>
#include <list>
#include <mutex>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <thread>
#include <array>
namespace trantor
{
#ifdef USE_OPENSSL
enum class SSLStatus
{
Handshaking,
Connecting,
Connected,
DisConnecting,
DisConnected
};
class SSLContext;
class SSLConn;
std::shared_ptr<SSLContext> newSSLContext(
bool useOldTLS,
bool validateCert,
const std::vector<std::pair<std::string, std::string>> &sslConfCmds);
std::shared_ptr<SSLContext> newSSLServerContext(
const std::string &certPath,
const std::string &keyPath,
bool useOldTLS,
const std::vector<std::pair<std::string, std::string>> &sslConfCmds);
// void initServerSSLContext(const std::shared_ptr<SSLContext> &ctx,
// const std::string &certPath,
// const std::string &keyPath);
#endif
class Channel;
class Socket;
class TcpServer;
void removeConnection(EventLoop *loop, const TcpConnectionPtr &conn);
class TcpConnectionImpl : public TcpConnection,
public NonCopyable,
public std::enable_shared_from_this<TcpConnectionImpl>
{
friend class TcpServer;
friend class TcpClient;
friend void trantor::removeConnection(EventLoop *loop,
const TcpConnectionPtr &conn);
public:
class KickoffEntry
{
public:
explicit KickoffEntry(const std::weak_ptr<TcpConnection> &conn)
: conn_(conn)
{
}
void reset()
{
conn_.reset();
}
~KickoffEntry()
{
auto conn = conn_.lock();
if (conn)
{
conn->forceClose();
}
}
private:
std::weak_ptr<TcpConnection> conn_;
};
TcpConnectionImpl(EventLoop *loop,
int socketfd,
const InetAddress &localAddr,
const InetAddress &peerAddr);
#ifdef USE_OPENSSL
TcpConnectionImpl(EventLoop *loop,
int socketfd,
const InetAddress &localAddr,
const InetAddress &peerAddr,
const std::shared_ptr<SSLContext> &ctxPtr,
bool isServer = true,
bool validateCert = true,
const std::string &hostname = "");
#endif
virtual ~TcpConnectionImpl();
virtual void send(const char *msg, size_t len) override;
virtual void send(const void *msg, size_t len) override;
virtual void send(const std::string &msg) override;
virtual void send(std::string &&msg) override;
virtual void send(const MsgBuffer &buffer) override;
virtual void send(MsgBuffer &&buffer) override;
virtual void send(const std::shared_ptr<std::string> &msgPtr) override;
virtual void send(const std::shared_ptr<MsgBuffer> &msgPtr) override;
virtual void sendFile(const char *fileName,
size_t offset = 0,
size_t length = 0) override;
virtual const InetAddress &localAddr() const override
{
return localAddr_;
}
virtual const InetAddress &peerAddr() const override
{
return peerAddr_;
}
virtual bool connected() const override
{
return status_ == ConnStatus::Connected;
}
virtual bool disconnected() const override
{
return status_ == ConnStatus::Disconnected;
}
// virtual MsgBuffer* getSendBuffer() override{ return &writeBuffer_;}
virtual MsgBuffer *getRecvBuffer() override
{
return &readBuffer_;
}
// set callbacks
virtual void setHighWaterMarkCallback(const HighWaterMarkCallback &cb,
size_t markLen) override
{
highWaterMarkCallback_ = cb;
highWaterMarkLen_ = markLen;
}
virtual void keepAlive() override
{
idleTimeout_ = 0;
auto entry = kickoffEntry_.lock();
if (entry)
{
entry->reset();
}
}
virtual bool isKeepAlive() override
{
return idleTimeout_ == 0;
}
virtual void setTcpNoDelay(bool on) override;
virtual void shutdown() override;
virtual void forceClose() override;
virtual EventLoop *getLoop() override
{
return loop_;
}
virtual size_t bytesSent() const override
{
return bytesSent_;
}
virtual size_t bytesReceived() const override
{
return bytesReceived_;
}
virtual void startClientEncryption(
std::function<void()> callback,
bool useOldTLS = false,
bool validateCert = true,
std::string hostname = "",
const std::vector<std::pair<std::string, std::string>> &sslConfCmds =
{}) override;
virtual void startServerEncryption(const std::shared_ptr<SSLContext> &ctx,
std::function<void()> callback) override;
virtual bool isSSLConnection() const override
{
return isEncrypted_;
}
private:
/// Internal use only.
std::weak_ptr<KickoffEntry> kickoffEntry_;
std::weak_ptr<TimingWheel> timingWheelWeakPtr_;
size_t idleTimeout_{0};
Date lastTimingWheelUpdateTime_;
void enableKickingOff(size_t timeout,
const std::shared_ptr<TimingWheel> &timingWheel)
{
assert(timingWheel);
assert(timingWheel->getLoop() == loop_);
assert(timeout > 0);
auto entry = std::make_shared<KickoffEntry>(shared_from_this());
kickoffEntry_ = entry;
timingWheelWeakPtr_ = timingWheel;
idleTimeout_ = timeout;
timingWheel->insertEntry(timeout, entry);
}
void extendLife();
#ifndef _WIN32
void sendFile(int sfd, size_t offset = 0, size_t length = 0);
#else
void sendFile(FILE *fp, size_t offset = 0, size_t length = 0);
#endif
void setRecvMsgCallback(const RecvMessageCallback &cb)
{
recvMsgCallback_ = cb;
}
void setConnectionCallback(const ConnectionCallback &cb)
{
connectionCallback_ = cb;
}
void setWriteCompleteCallback(const WriteCompleteCallback &cb)
{
writeCompleteCallback_ = cb;
}
void setCloseCallback(const CloseCallback &cb)
{
closeCallback_ = cb;
}
void setSSLErrorCallback(const SSLErrorCallback &cb)
{
sslErrorCallback_ = cb;
}
void connectDestroyed();
virtual void connectEstablished();
protected:
struct BufferNode
{
#ifndef _WIN32
int sendFd_{-1};
off_t offset_;
#else
FILE *sendFp_{nullptr};
long long offset_;
#endif
ssize_t fileBytesToSend_;
std::shared_ptr<MsgBuffer> msgBuffer_;
~BufferNode()
{
#ifndef _WIN32
if (sendFd_ >= 0)
close(sendFd_);
#else
if (sendFp_)
fclose(sendFp_);
#endif
}
};
using BufferNodePtr = std::shared_ptr<BufferNode>;
enum class ConnStatus
{
Disconnected,
Connecting,
Connected,
Disconnecting
};
bool isEncrypted_{false};
EventLoop *loop_;
std::unique_ptr<Channel> ioChannelPtr_;
std::unique_ptr<Socket> socketPtr_;
MsgBuffer readBuffer_;
std::list<BufferNodePtr> writeBufferList_;
void readCallback();
void writeCallback();
InetAddress localAddr_, peerAddr_;
ConnStatus status_{ConnStatus::Connecting};
// callbacks
RecvMessageCallback recvMsgCallback_;
ConnectionCallback connectionCallback_;
CloseCallback closeCallback_;
WriteCompleteCallback writeCompleteCallback_;
HighWaterMarkCallback highWaterMarkCallback_;
SSLErrorCallback sslErrorCallback_;
void handleClose();
void handleError();
// virtual void sendInLoop(const std::string &msg);
void sendFileInLoop(const BufferNodePtr &file);
#ifndef _WIN32
void sendInLoop(const void *buffer, size_t length);
ssize_t writeInLoop(const void *buffer, size_t length);
#else
void sendInLoop(const char *buffer, size_t length);
ssize_t writeInLoop(const char *buffer, size_t length);
#endif
size_t highWaterMarkLen_;
std::string name_;
uint64_t sendNum_{0};
std::mutex sendNumMutex_;
size_t bytesSent_{0};
size_t bytesReceived_{0};
std::unique_ptr<std::vector<char>> fileBufferPtr_;
#ifdef USE_OPENSSL
private:
void doHandshaking();
bool validatePeerCertificate();
struct SSLEncryption
{
SSLStatus statusOfSSL_ = SSLStatus::Handshaking;
// OpenSSL
std::shared_ptr<SSLContext> sslCtxPtr_;
std::unique_ptr<SSLConn> sslPtr_;
std::unique_ptr<std::array<char, 8192>> sendBufferPtr_;
bool isServer_{false};
bool isUpgrade_{false};
std::function<void()> upgradeCallback_;
std::string hostname_;
};
std::unique_ptr<SSLEncryption> sslEncryptionPtr_;
void startClientEncryptionInLoop(
std::function<void()> &&callback,
bool useOldTLS,
bool validateCert,
const std::string &hostname,
const std::vector<std::pair<std::string, std::string>> &sslConfCmds);
void startServerEncryptionInLoop(const std::shared_ptr<SSLContext> &ctx,
std::function<void()> &&callback);
#endif
};
using TcpConnectionImplPtr = std::shared_ptr<TcpConnectionImpl>;
} // namespace trantor

View File

@ -1,64 +0,0 @@
/**
*
* Timer.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include "Timer.h"
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoop.h>
namespace trantor
{
std::atomic<TimerId> Timer::timersCreated_ = ATOMIC_VAR_INIT(InvalidTimerId);
Timer::Timer(const TimerCallback &cb,
const TimePoint &when,
const TimeInterval &interval)
: callback_(cb),
when_(when),
interval_(interval),
repeat_(interval.count() > 0),
id_(++timersCreated_)
{
}
Timer::Timer(TimerCallback &&cb,
const TimePoint &when,
const TimeInterval &interval)
: callback_(std::move(cb)),
when_(when),
interval_(interval),
repeat_(interval.count() > 0),
id_(++timersCreated_)
{
// LOG_TRACE<<"Timer move contrustor";
}
void Timer::run() const
{
callback_();
}
void Timer::restart(const TimePoint &now)
{
if (repeat_)
{
when_ = now + interval_;
}
else
when_ = std::chrono::steady_clock::now();
}
bool Timer::operator<(const Timer &t) const
{
return when_ < t.when_;
}
bool Timer::operator>(const Timer &t) const
{
return when_ > t.when_;
}
} // namespace trantor

View File

@ -1,68 +0,0 @@
/**
*
* Timer.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/callbacks.h>
#include <functional>
#include <atomic>
#include <iostream>
#include <chrono>
namespace trantor
{
using TimerId = uint64_t;
using TimePoint = std::chrono::steady_clock::time_point;
using TimeInterval = std::chrono::microseconds;
class Timer : public NonCopyable
{
public:
Timer(const TimerCallback &cb,
const TimePoint &when,
const TimeInterval &interval);
Timer(TimerCallback &&cb,
const TimePoint &when,
const TimeInterval &interval);
~Timer()
{
// std::cout<<"Timer unconstract!"<<std::endl;
}
void run() const;
void restart(const TimePoint &now);
bool operator<(const Timer &t) const;
bool operator>(const Timer &t) const;
const TimePoint &when() const
{
return when_;
}
bool isRepeat()
{
return repeat_;
}
TimerId id()
{
return id_;
}
private:
TimerCallback callback_;
TimePoint when_;
const TimeInterval interval_;
const bool repeat_;
const TimerId id_;
static std::atomic<TimerId> timersCreated_;
};
} // namespace trantor

View File

@ -1,294 +0,0 @@
/**
*
* @file TimerQueue.cc
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/net/EventLoop.h>
#include "TimerQueue.h"
#include "Channel.h"
#ifdef __linux__
#include <sys/timerfd.h>
#endif
#include <string.h>
#include <iostream>
#ifndef _WIN32
#include <unistd.h>
#endif
using namespace trantor;
#ifdef __linux__
static int createTimerfd()
{
int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (timerfd < 0)
{
std::cerr << "create timerfd failed!" << std::endl;
}
return timerfd;
}
static struct timespec howMuchTimeFromNow(const TimePoint &when)
{
auto microSeconds = std::chrono::duration_cast<std::chrono::microseconds>(
when - std::chrono::steady_clock::now())
.count();
if (microSeconds < 100)
{
microSeconds = 100;
}
struct timespec ts;
ts.tv_sec = static_cast<time_t>(microSeconds / 1000000);
ts.tv_nsec = static_cast<long>((microSeconds % 1000000) * 1000);
return ts;
}
static void resetTimerfd(int timerfd, const TimePoint &expiration)
{
// wake up loop by timerfd_settime()
struct itimerspec newValue;
struct itimerspec oldValue;
memset(&newValue, 0, sizeof(newValue));
memset(&oldValue, 0, sizeof(oldValue));
newValue.it_value = howMuchTimeFromNow(expiration);
int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
if (ret)
{
// LOG_SYSERR << "timerfd_settime()";
}
}
static void readTimerfd(int timerfd, const TimePoint &)
{
uint64_t howmany;
ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
if (n != sizeof howmany)
{
LOG_ERROR << "TimerQueue::handleRead() reads " << n
<< " bytes instead of 8";
}
}
void TimerQueue::handleRead()
{
loop_->assertInLoopThread();
const auto now = std::chrono::steady_clock::now();
readTimerfd(timerfd_, now);
std::vector<TimerPtr> expired = getExpired(now);
callingExpiredTimers_ = true;
// cancelingTimers_.clear();
// safe to callback outside critical section
for (auto const &timerPtr : expired)
{
if (timerIdSet_.find(timerPtr->id()) != timerIdSet_.end())
{
timerPtr->run();
}
}
callingExpiredTimers_ = false;
reset(expired, now);
}
#else
static int64_t howMuchTimeFromNow(const TimePoint &when)
{
auto microSeconds = std::chrono::duration_cast<std::chrono::microseconds>(
when - std::chrono::steady_clock::now())
.count();
if (microSeconds < 1000)
{
microSeconds = 1000;
}
return microSeconds / 1000;
}
void TimerQueue::processTimers()
{
loop_->assertInLoopThread();
const auto now = std::chrono::steady_clock::now();
std::vector<TimerPtr> expired = getExpired(now);
callingExpiredTimers_ = true;
// cancelingTimers_.clear();
// safe to callback outside critical section
for (auto const &timerPtr : expired)
{
if (timerIdSet_.find(timerPtr->id()) != timerIdSet_.end())
{
timerPtr->run();
}
}
callingExpiredTimers_ = false;
reset(expired, now);
}
#endif
///////////////////////////////////////
TimerQueue::TimerQueue(EventLoop *loop)
: loop_(loop),
#ifdef __linux__
timerfd_(createTimerfd()),
timerfdChannelPtr_(new Channel(loop, timerfd_)),
#endif
timers_(),
callingExpiredTimers_(false)
{
#ifdef __linux__
timerfdChannelPtr_->setReadCallback(
std::bind(&TimerQueue::handleRead, this));
// we are always reading the timerfd, we disarm it with timerfd_settime.
timerfdChannelPtr_->enableReading();
#endif
}
#ifdef __linux__
void TimerQueue::reset()
{
loop_->runInLoop([this]() {
timerfdChannelPtr_->disableAll();
timerfdChannelPtr_->remove();
close(timerfd_);
timerfd_ = createTimerfd();
timerfdChannelPtr_ = std::make_shared<Channel>(loop_, timerfd_);
timerfdChannelPtr_->setReadCallback(
std::bind(&TimerQueue::handleRead, this));
// we are always reading the timerfd, we disarm it with timerfd_settime.
timerfdChannelPtr_->enableReading();
if (!timers_.empty())
{
const auto nextExpire = timers_.top()->when();
resetTimerfd(timerfd_, nextExpire);
}
});
}
#endif
TimerQueue::~TimerQueue()
{
#ifdef __linux__
auto chlPtr = timerfdChannelPtr_;
auto fd = timerfd_;
loop_->runInLoop([chlPtr, fd]() {
chlPtr->disableAll();
chlPtr->remove();
::close(fd);
});
#endif
}
TimerId TimerQueue::addTimer(const TimerCallback &cb,
const TimePoint &when,
const TimeInterval &interval)
{
std::shared_ptr<Timer> timerPtr =
std::make_shared<Timer>(cb, when, interval);
loop_->runInLoop([this, timerPtr]() { addTimerInLoop(timerPtr); });
return timerPtr->id();
}
TimerId TimerQueue::addTimer(TimerCallback &&cb,
const TimePoint &when,
const TimeInterval &interval)
{
std::shared_ptr<Timer> timerPtr =
std::make_shared<Timer>(std::move(cb), when, interval);
loop_->runInLoop([this, timerPtr]() { addTimerInLoop(timerPtr); });
return timerPtr->id();
}
void TimerQueue::addTimerInLoop(const TimerPtr &timer)
{
loop_->assertInLoopThread();
timerIdSet_.insert(timer->id());
if (insert(timer))
{
// the earliest timer changed
#ifdef __linux__
resetTimerfd(timerfd_, timer->when());
#endif
}
}
void TimerQueue::invalidateTimer(TimerId id)
{
loop_->runInLoop([this, id]() { timerIdSet_.erase(id); });
}
bool TimerQueue::insert(const TimerPtr &timerPtr)
{
loop_->assertInLoopThread();
bool earliestChanged = false;
if (timers_.size() == 0 || *timerPtr < *timers_.top())
{
earliestChanged = true;
}
timers_.push(timerPtr);
// std::cout<<"after push new
// timer:"<<timerPtr->when().microSecondsSinceEpoch()/1000000<<std::endl;
return earliestChanged;
}
#ifndef __linux__
int64_t TimerQueue::getTimeout() const
{
loop_->assertInLoopThread();
if (timers_.empty())
{
return 10000;
}
else
{
return howMuchTimeFromNow(timers_.top()->when());
}
}
#endif
std::vector<TimerPtr> TimerQueue::getExpired(const TimePoint &now)
{
std::vector<TimerPtr> expired;
while (!timers_.empty())
{
if (timers_.top()->when() < now)
{
expired.push_back(timers_.top());
timers_.pop();
}
else
break;
}
return expired;
}
void TimerQueue::reset(const std::vector<TimerPtr> &expired,
const TimePoint &now)
{
loop_->assertInLoopThread();
for (auto const &timerPtr : expired)
{
auto iter = timerIdSet_.find(timerPtr->id());
if (iter != timerIdSet_.end())
{
if (timerPtr->isRepeat())
{
timerPtr->restart(now);
insert(timerPtr);
}
else
{
timerIdSet_.erase(iter);
}
}
}
#ifdef __linux__
if (!timers_.empty())
{
const auto nextExpire = timers_.top()->when();
resetTimerfd(timerfd_, nextExpire);
}
#endif
}

View File

@ -1,76 +0,0 @@
/**
*
* TimerQueue.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/callbacks.h>
#include "Timer.h"
#include <queue>
#include <memory>
#include <atomic>
#include <unordered_set>
namespace trantor
{
// class Timer;
class EventLoop;
class Channel;
using TimerPtr = std::shared_ptr<Timer>;
struct TimerPtrComparer
{
bool operator()(const TimerPtr &x, const TimerPtr &y) const
{
return *x > *y;
}
};
class TimerQueue : NonCopyable
{
public:
explicit TimerQueue(EventLoop *loop);
~TimerQueue();
TimerId addTimer(const TimerCallback &cb,
const TimePoint &when,
const TimeInterval &interval);
TimerId addTimer(TimerCallback &&cb,
const TimePoint &when,
const TimeInterval &interval);
void addTimerInLoop(const TimerPtr &timer);
void invalidateTimer(TimerId id);
#ifdef __linux__
void reset();
#else
int64_t getTimeout() const;
void processTimers();
#endif
protected:
EventLoop *loop_;
#ifdef __linux__
int timerfd_;
std::shared_ptr<Channel> timerfdChannelPtr_;
void handleRead();
#endif
std::priority_queue<TimerPtr, std::vector<TimerPtr>, TimerPtrComparer>
timers_;
bool callingExpiredTimers_;
bool insert(const TimerPtr &timePtr);
std::vector<TimerPtr> getExpired();
void reset(const std::vector<TimerPtr> &expired, const TimePoint &now);
std::vector<TimerPtr> getExpired(const TimePoint &now);
private:
std::unordered_set<uint64_t> timerIdSet_;
};
} // namespace trantor

View File

@ -1,241 +0,0 @@
/**
*
* EpollPoller.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/utils/Logger.h>
#include "Channel.h"
#include "EpollPoller.h"
#ifdef __linux__
#include <poll.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <assert.h>
#include <strings.h>
#include <iostream>
#elif defined _WIN32
#include "Wepoll.h"
#include <assert.h>
#include <iostream>
#include <winsock2.h>
#include <fcntl.h>
#define EPOLL_CLOEXEC _O_NOINHERIT
#endif
namespace trantor
{
#if defined __linux__ || defined _WIN32
#if defined __linux__
static_assert(EPOLLIN == POLLIN, "EPOLLIN != POLLIN");
static_assert(EPOLLPRI == POLLPRI, "EPOLLPRI != POLLPRI");
static_assert(EPOLLOUT == POLLOUT, "EPOLLOUT != POLLOUT");
static_assert(EPOLLRDHUP == POLLRDHUP, "EPOLLRDHUP != POLLRDHUP");
static_assert(EPOLLERR == POLLERR, "EPOLLERR != POLLERR");
static_assert(EPOLLHUP == POLLHUP, "EPOLLHUP != POLLHUP");
#endif
namespace
{
const int kNew = -1;
const int kAdded = 1;
const int kDeleted = 2;
} // namespace
EpollPoller::EpollPoller(EventLoop *loop)
: Poller(loop),
#ifdef _WIN32
// wepoll does not suppor flags
epollfd_(::epoll_create1(0)),
#else
epollfd_(::epoll_create1(EPOLL_CLOEXEC)),
#endif
events_(kInitEventListSize)
{
}
EpollPoller::~EpollPoller()
{
#ifdef _WIN32
epoll_close(epollfd_);
#else
close(epollfd_);
#endif
}
#ifdef _WIN32
void EpollPoller::postEvent(uint64_t event)
{
epoll_post_signal(epollfd_, event);
}
#endif
void EpollPoller::poll(int timeoutMs, ChannelList *activeChannels)
{
int numEvents = ::epoll_wait(epollfd_,
&*events_.begin(),
static_cast<int>(events_.size()),
timeoutMs);
int savedErrno = errno;
// Timestamp now(Timestamp::now());
if (numEvents > 0)
{
// LOG_TRACE << numEvents << " events happended";
fillActiveChannels(numEvents, activeChannels);
if (static_cast<size_t>(numEvents) == events_.size())
{
events_.resize(events_.size() * 2);
}
}
else if (numEvents == 0)
{
// std::cout << "nothing happended" << std::endl;
}
else
{
// error happens, log uncommon ones
if (savedErrno != EINTR)
{
errno = savedErrno;
LOG_SYSERR << "EPollEpollPoller::poll()";
}
}
return;
}
void EpollPoller::fillActiveChannels(int numEvents,
ChannelList *activeChannels) const
{
assert(static_cast<size_t>(numEvents) <= events_.size());
for (int i = 0; i < numEvents; ++i)
{
#ifdef _WIN32
if (events_[i].events == EPOLLEVENT)
{
eventCallback_(events_[i].data.u64);
continue;
}
#endif
Channel *channel = static_cast<Channel *>(events_[i].data.ptr);
#ifndef NDEBUG
int fd = channel->fd();
ChannelMap::const_iterator it = channels_.find(fd);
assert(it != channels_.end());
assert(it->second == channel);
#endif
channel->setRevents(events_[i].events);
activeChannels->push_back(channel);
}
// LOG_TRACE<<"active Channels num:"<<activeChannels->size();
}
void EpollPoller::updateChannel(Channel *channel)
{
assertInLoopThread();
const int index = channel->index();
// LOG_TRACE << "fd = " << channel->fd()
// << " events = " << channel->events() << " index = " << index;
if (index == kNew || index == kDeleted)
{
// a new one, add with EPOLL_CTL_ADD
#ifndef NDEBUG
int fd = channel->fd();
if (index == kNew)
{
assert(channels_.find(fd) == channels_.end());
channels_[fd] = channel;
}
else
{ // index == kDeleted
assert(channels_.find(fd) != channels_.end());
assert(channels_[fd] == channel);
}
#endif
channel->setIndex(kAdded);
update(EPOLL_CTL_ADD, channel);
}
else
{
// update existing one with EPOLL_CTL_MOD/DEL
#ifndef NDEBUG
int fd = channel->fd();
(void)fd;
assert(channels_.find(fd) != channels_.end());
assert(channels_[fd] == channel);
#endif
assert(index == kAdded);
if (channel->isNoneEvent())
{
update(EPOLL_CTL_DEL, channel);
channel->setIndex(kDeleted);
}
else
{
update(EPOLL_CTL_MOD, channel);
}
}
}
void EpollPoller::removeChannel(Channel *channel)
{
EpollPoller::assertInLoopThread();
#ifndef NDEBUG
int fd = channel->fd();
assert(channels_.find(fd) != channels_.end());
assert(channels_[fd] == channel);
size_t n = channels_.erase(fd);
(void)n;
assert(n == 1);
#endif
assert(channel->isNoneEvent());
int index = channel->index();
assert(index == kAdded || index == kDeleted);
if (index == kAdded)
{
update(EPOLL_CTL_DEL, channel);
}
channel->setIndex(kNew);
}
void EpollPoller::update(int operation, Channel *channel)
{
struct epoll_event event;
memset(&event, 0, sizeof(event));
event.events = channel->events();
event.data.ptr = channel;
int fd = channel->fd();
if (::epoll_ctl(epollfd_, operation, fd, &event) < 0)
{
if (operation == EPOLL_CTL_DEL)
{
// LOG_SYSERR << "epoll_ctl op =" << operationToString(operation) <<
// " fd =" << fd;
}
else
{
// LOG_SYSFATAL << "epoll_ctl op =" << operationToString(operation)
// << " fd =" << fd;
}
}
}
#else
EpollPoller::EpollPoller(EventLoop *loop) : Poller(loop)
{
assert(false);
}
EpollPoller::~EpollPoller()
{
}
void EpollPoller::poll(int, ChannelList *)
{
}
void EpollPoller::updateChannel(Channel *)
{
}
void EpollPoller::removeChannel(Channel *)
{
}
#endif
} // namespace trantor

View File

@ -1,64 +0,0 @@
/**
*
* EpollPoller.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include "../Poller.h"
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/EventLoop.h>
#if defined __linux__ || defined _WIN32
#include <memory>
#include <map>
using EventList = std::vector<struct epoll_event>;
#endif
namespace trantor
{
class Channel;
class EpollPoller : public Poller
{
public:
explicit EpollPoller(EventLoop *loop);
virtual ~EpollPoller();
virtual void poll(int timeoutMs, ChannelList *activeChannels) override;
virtual void updateChannel(Channel *channel) override;
virtual void removeChannel(Channel *channel) override;
#ifdef _WIN32
virtual void postEvent(uint64_t event) override;
virtual void setEventCallback(const EventCallback &cb) override
{
eventCallback_ = cb;
}
#endif
private:
#if defined __linux__ || defined _WIN32
static const int kInitEventListSize = 16;
#ifdef _WIN32
void *epollfd_;
EventCallback eventCallback_{[](uint64_t event) {}};
#else
int epollfd_;
#endif
EventList events_;
void update(int operation, Channel *channel);
#ifndef NDEBUG
using ChannelMap = std::map<int, Channel *>;
ChannelMap channels_;
#endif
void fillActiveChannels(int numEvents, ChannelList *activeChannels) const;
#endif
};
} // namespace trantor

View File

@ -1,249 +0,0 @@
#include "KQueue.h"
#include "Channel.h"
#ifdef USE_KQUEUE
#include <trantor/utils/Logger.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <unistd.h>
#include <poll.h>
#endif
namespace trantor
{
#ifdef USE_KQUEUE
namespace
{
const int kNew = -1;
const int kAdded = 1;
const int kDeleted = 2;
} // namespace
KQueue::KQueue(EventLoop *loop)
: Poller(loop), kqfd_(kqueue()), events_(kInitEventListSize)
{
assert(kqfd_ >= 0);
}
KQueue::~KQueue()
{
close(kqfd_);
}
void KQueue::resetAfterFork()
{
close(kqfd_);
kqfd_ = kqueue();
for (auto &ch : channels_)
{
ch.second.first = 0;
if (ch.second.second->isReading() || ch.second.second->isWriting())
{
update(ch.second.second);
}
}
}
void KQueue::poll(int timeoutMs, ChannelList *activeChannels)
{
struct timespec timeout;
timeout.tv_sec = timeoutMs / 1000;
timeout.tv_nsec = (timeoutMs % 1000) * 1000000;
int numEvents = kevent(kqfd_,
NULL,
0,
events_.data(),
static_cast<int>(events_.size()),
&timeout);
int savedErrno = errno;
// Timestamp now(Timestamp::now());
if (numEvents > 0)
{
// LOG_TRACE << numEvents << " events happended";
fillActiveChannels(numEvents, activeChannels);
if (static_cast<size_t>(numEvents) == events_.size())
{
events_.resize(events_.size() * 2);
}
}
else if (numEvents == 0)
{
// std::cout << "nothing happended" << std::endl;
}
else
{
// error happens, log uncommon ones
if (savedErrno != EINTR)
{
errno = savedErrno;
LOG_SYSERR << "KQueue::poll()";
}
}
return;
}
void KQueue::fillActiveChannels(int numEvents,
ChannelList *activeChannels) const
{
assert(static_cast<size_t>(numEvents) <= events_.size());
for (int i = 0; i < numEvents; ++i)
{
Channel *channel = static_cast<Channel *>(events_[i].udata);
assert(channels_.find(channel->fd()) != channels_.end());
int events = events_[i].filter;
if (events == EVFILT_READ)
{
channel->setRevents(POLLIN);
}
else if (events == EVFILT_WRITE)
{
channel->setRevents(POLLOUT);
}
else
{
LOG_ERROR << "events=" << events;
continue;
}
activeChannels->push_back(channel);
}
}
void KQueue::updateChannel(Channel *channel)
{
assertInLoopThread();
const int index = channel->index();
// LOG_TRACE << "fd = " << channel->fd()
// << " events = " << channel->events() << " index = " << index;
if (index == kNew || index == kDeleted)
{
if (index == kNew)
{
assert(channels_.find(channel->fd()) == channels_.end());
}
else
{ // index == kDeleted
assert(channels_.find(channel->fd()) != channels_.end());
assert(channels_[channel->fd()].second == channel);
}
update(channel);
channel->setIndex(kAdded);
}
else
{
// update existing one
int fd = channel->fd();
(void)fd;
assert(channels_.find(fd) != channels_.end());
assert(index == kAdded);
if (channel->isNoneEvent())
{
update(channel);
channel->setIndex(kDeleted);
}
else
{
update(channel);
}
}
}
void KQueue::removeChannel(Channel *channel)
{
assertInLoopThread();
int fd = channel->fd();
assert(channels_.find(fd) != channels_.end());
assert(channel->isNoneEvent());
int index = channel->index();
assert(index == kAdded || index == kDeleted);
if (index == kAdded)
{
update(channel);
}
size_t n = channels_.erase(fd);
(void)n;
assert(n == 1);
channel->setIndex(kNew);
}
void KQueue::update(Channel *channel)
{
struct kevent ev[2];
int n = 0;
auto events = channel->events();
int oldEvents = 0;
if (channels_.find(channel->fd()) != channels_.end())
{
oldEvents = channels_[channel->fd()].first;
}
auto fd = channel->fd();
channels_[fd] = {events, channel};
if ((events & Channel::kReadEvent) && (!(oldEvents & Channel::kReadEvent)))
{
EV_SET(&ev[n++],
fd,
EVFILT_READ,
EV_ADD | EV_ENABLE,
0,
0,
(void *)(intptr_t)channel);
}
else if ((!(events & Channel::kReadEvent)) &&
(oldEvents & Channel::kReadEvent))
{
EV_SET(&ev[n++],
fd,
EVFILT_READ,
EV_DELETE,
0,
0,
(void *)(intptr_t)channel);
}
if ((events & Channel::kWriteEvent) &&
(!(oldEvents & Channel::kWriteEvent)))
{
EV_SET(&ev[n++],
fd,
EVFILT_WRITE,
EV_ADD | EV_ENABLE,
0,
0,
(void *)(intptr_t)channel);
}
else if ((!(events & Channel::kWriteEvent)) &&
(oldEvents & Channel::kWriteEvent))
{
EV_SET(&ev[n++],
fd,
EVFILT_WRITE,
EV_DELETE,
0,
0,
(void *)(intptr_t)channel);
}
kevent(kqfd_, ev, n, NULL, 0, NULL);
}
#else
KQueue::KQueue(EventLoop *loop) : Poller(loop)
{
assert(false);
}
KQueue::~KQueue()
{
}
void KQueue::poll(int, ChannelList *)
{
}
void KQueue::updateChannel(Channel *)
{
}
void KQueue::removeChannel(Channel *)
{
}
void KQueue::resetAfterFork()
{
}
#endif
} // namespace trantor

View File

@ -1,55 +0,0 @@
/**
*
* KQueue.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/trantor
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
* Trantor
*
*/
#pragma once
#include "../Poller.h"
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/EventLoop.h>
#if (defined(__unix__) && !defined(__linux__)) || \
(defined(__APPLE__) && defined(__MACH__))
#define USE_KQUEUE
#include <memory>
#include <unordered_map>
#include <vector>
using EventList = std::vector<struct kevent>;
#endif
namespace trantor
{
class Channel;
class KQueue : public Poller
{
public:
explicit KQueue(EventLoop *loop);
virtual ~KQueue();
virtual void poll(int timeoutMs, ChannelList *activeChannels) override;
virtual void updateChannel(Channel *channel) override;
virtual void removeChannel(Channel *channel) override;
virtual void resetAfterFork() override;
private:
#ifdef USE_KQUEUE
static const int kInitEventListSize = 16;
int kqfd_;
EventList events_;
using ChannelMap = std::unordered_map<int, std::pair<int, Channel *>>;
ChannelMap channels_;
void fillActiveChannels(int numEvents, ChannelList *activeChannels) const;
void update(Channel *channel);
#endif
};
} // namespace trantor

View File

@ -1,45 +0,0 @@
#include <trantor/utils/Logger.h>
#include <trantor/utils/AsyncFileLogger.h>
#include <stdlib.h>
#include <thread>
int main()
{
trantor::AsyncFileLogger asyncFileLogger;
asyncFileLogger.setFileName("async_test");
asyncFileLogger.startLogging();
trantor::Logger::setOutputFunction(
[&](const char *msg, const uint64_t len) {
asyncFileLogger.output(msg, len);
},
[&]() { asyncFileLogger.flush(); });
asyncFileLogger.setFileSizeLimit(100000000);
// LOG_DEBUG<<"debug log!"<<1;
// LOG_TRACE<<"trace log!"<<2;
// LOG_INFO<<"info log!"<<3;
// LOG_WARN<<"warning log!"<<4;
// if(1)
// LOG_ERROR<<"error log!"<<5;
// std::thread thread_([](){
// LOG_FATAL<<"fatal log!"<<6;
// });
//
// FILE *fp=fopen("/notexistfile","rb");
// if(fp==NULL)
// {
// LOG_SYSERR<<"syserr log!"<<7;
// }
int i = 0;
while (i < 1000000)
{
++i;
if (i % 100 == 0)
{
LOG_ERROR << "this is the " << i << "th log";
continue;
}
LOG_INFO << "this is the " << i << "th log";
++i;
LOG_DEBUG << "this is the " << i << "th log";
}
}

View File

@ -1,33 +0,0 @@
#include <trantor/utils/Logger.h>
#include <trantor/utils/AsyncFileLogger.h>
#include <thread>
#include <chrono>
#include <stdlib.h>
using namespace std::chrono_literals;
int main()
{
trantor::AsyncFileLogger asyncFileLogger;
asyncFileLogger.setFileName("async_test");
asyncFileLogger.startLogging();
trantor::Logger::setOutputFunction(
[&](const char *msg, const uint64_t len) {
asyncFileLogger.output(msg, len);
},
[&]() { asyncFileLogger.flush(); });
asyncFileLogger.setFileSizeLimit(100000000);
int i = 0;
while (i < 1000000)
{
++i;
if (i % 100 == 0)
{
LOG_ERROR << "this is the " << i << "th log";
continue;
}
LOG_INFO << "this is the " << i << "th log";
++i;
LOG_DEBUG << "this is the " << i << "th log";
std::this_thread::sleep_for(1s);
}
}

View File

@ -1,51 +0,0 @@
add_executable(ssl_server_test SSLServerTest.cc)
add_executable(ssl_client_test SSLClientTest.cc)
add_executable(serial_task_queue_test1 SerialTaskQueueTest1.cc)
add_executable(serial_task_queue_test2 SerialTaskQueueTest2.cc)
add_executable(timer_test TimerTest.cc)
add_executable(timer_test1 TimerTest1.cc)
add_executable(run_in_loop_test1 RunInLoopTest1.cc)
add_executable(run_in_loop_test2 RunInLoopTest2.cc)
add_executable(logger_test LoggerTest.cc)
add_executable(async_file_logger_test AsyncFileLoggerTest.cc)
add_executable(tcp_server_test TcpServerTest.cc)
add_executable(concurrent_task_queue_test ConcurrentTaskQueueTest.cc)
add_executable(tcp_client_test TcpClientTest.cc)
add_executable(async_file_logger_test1 AsyncFileLoggerTest1.cc)
add_executable(sendfile_test SendfileTest.cc)
add_executable(timing_wheel_test TimingWheelTest.cc)
add_executable(kickoff_test KickoffTest.cc)
add_executable(dns_test DnsTest.cc)
add_executable(delayed_ssl_server_test DelayedSSLServerTest.cc)
add_executable(delayed_ssl_client_test DelayedSSLClientTest.cc)
add_executable(run_on_quit_test RunOnQuitTest.cc)
set(targets_list
ssl_server_test
ssl_client_test
serial_task_queue_test1
serial_task_queue_test2
timer_test
timer_test1
run_in_loop_test1
run_in_loop_test2
logger_test
async_file_logger_test
tcp_server_test
concurrent_task_queue_test
tcp_client_test
async_file_logger_test1
sendfile_test
timing_wheel_test
kickoff_test
dns_test
delayed_ssl_server_test
delayed_ssl_client_test
run_on_quit_test)
set_property(TARGET ${targets_list} PROPERTY CXX_STANDARD 14)
set_property(TARGET ${targets_list} PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET ${targets_list} PROPERTY CXX_EXTENSIONS OFF)
foreach(T ${targets_list})
target_link_libraries(${T} PRIVATE trantor)
endforeach()

View File

@ -1,37 +0,0 @@
#include <trantor/utils/ConcurrentTaskQueue.h>
#include <trantor/utils/Logger.h>
#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <time.h>
#include <stdio.h>
using namespace std::chrono_literals;
int main()
{
trantor::ConcurrentTaskQueue queue(5, "concurrT");
std::atomic_int sum;
sum = 0;
for (int i = 0; i < 4; ++i)
{
queue.runTaskInQueue([&sum]() {
LOG_DEBUG << "add sum";
for (int i = 0; i < 10000; ++i)
{
++sum;
}
});
}
queue.runTaskInQueue([&sum]() {
for (int i = 0; i < 20; ++i)
{
LOG_DEBUG << "sum=" << sum;
std::this_thread::sleep_for(100us);
}
});
getc(stdin);
LOG_DEBUG << "sum=" << sum;
}

View File

@ -1,64 +0,0 @@
#include <trantor/net/TcpClient.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <string>
#include <iostream>
#include <atomic>
using namespace trantor;
#define USE_IPV6 0
int main()
{
trantor::Logger::setLogLevel(trantor::Logger::kTrace);
LOG_DEBUG << "TcpClient class test!";
EventLoop loop;
#if USE_IPV6
InetAddress serverAddr("::1", 8888, true);
#else
InetAddress serverAddr("127.0.0.1", 8888);
#endif
std::shared_ptr<trantor::TcpClient> client[10];
std::atomic_int connCount;
connCount = 10;
for (int i = 0; i < 10; ++i)
{
client[i] = std::make_shared<trantor::TcpClient>(&loop,
serverAddr,
"tcpclienttest");
client[i]->setConnectionCallback(
[i, &loop, &connCount](const TcpConnectionPtr &conn) {
if (conn->connected())
{
}
else
{
LOG_DEBUG << i << " disconnected";
--connCount;
if (connCount == 0)
loop.quit();
}
});
client[i]->setMessageCallback(
[](const TcpConnectionPtr &conn, MsgBuffer *buf) {
auto msg = std::string(buf->peek(), buf->readableBytes());
LOG_INFO << msg;
if (msg == "hello")
{
buf->retrieveAll();
conn->startClientEncryption(
[conn]() {
LOG_INFO << "SSL established";
conn->send("Hello");
},
false,
false);
}
if (conn->isSSLConnection())
{
buf->retrieveAll();
}
});
client[i]->connect();
}
loop.loop();
}

View File

@ -1,46 +0,0 @@
#include <trantor/net/TcpServer.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <string>
#include <iostream>
using namespace trantor;
#define USE_IPV6 0
int main()
{
LOG_DEBUG << "test start";
Logger::setLogLevel(Logger::kTrace);
EventLoopThread loopThread;
loopThread.run();
#if USE_IPV6
InetAddress addr(8888, true, true);
#else
InetAddress addr(8888);
#endif
TcpServer server(loopThread.getLoop(), addr, "test");
auto ctx = newSSLServerContext("server.pem", "server.pem", {});
LOG_INFO << "start";
server.setRecvMessageCallback(
[](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) {
LOG_DEBUG << std::string{buffer->peek(), buffer->readableBytes()};
connectionPtr->send(*buffer);
buffer->retrieveAll();
connectionPtr->shutdown();
});
server.setConnectionCallback([ctx](const TcpConnectionPtr &connPtr) {
if (connPtr->connected())
{
LOG_DEBUG << "New connection";
connPtr->send("hello");
connPtr->startServerEncryption(ctx, [] {
LOG_INFO << "SSL established";
});
}
else if (connPtr->disconnected())
{
LOG_DEBUG << "connection disconnected";
}
});
server.setIoLoopNum(3);
server.start();
loopThread.wait();
}

View File

@ -1,48 +0,0 @@
#include <trantor/net/Resolver.h>
#include <iostream>
void dns(const std::shared_ptr<trantor::Resolver> &resolver)
{
auto now = trantor::Date::now();
resolver->resolve("www.baidu.com", [now](const trantor::InetAddress &addr) {
auto interval = trantor::Date::now().microSecondsSinceEpoch() -
now.microSecondsSinceEpoch();
std::cout << "baidu:" << addr.toIp() << " " << interval / 1000 << "ms"
<< std::endl;
});
resolver->resolve("www.google.com",
[now](const trantor::InetAddress &addr) {
auto interval =
trantor::Date::now().microSecondsSinceEpoch() -
now.microSecondsSinceEpoch();
std::cout << "google:" << addr.toIp() << " "
<< interval / 1000 << "ms" << std::endl;
});
resolver->resolve("www.sina.com", [now](const trantor::InetAddress &addr) {
auto interval = trantor::Date::now().microSecondsSinceEpoch() -
now.microSecondsSinceEpoch();
std::cout << "sina:" << addr.toIp() << " " << interval / 1000 << "ms"
<< std::endl;
});
resolver->resolve("www.xjfisfjaskfeiakdjfg.com",
[now](const trantor::InetAddress &addr) {
auto interval =
trantor::Date::now().microSecondsSinceEpoch() -
now.microSecondsSinceEpoch();
std::cout << "bad address:" << addr.toIp() << " "
<< interval / 1000 << "ms" << std::endl;
});
resolver->resolve("localhost", [now](const trantor::InetAddress &addr) {
auto interval = trantor::Date::now().microSecondsSinceEpoch() -
now.microSecondsSinceEpoch();
std::cout << "localhost:" << addr.toIp() << " " << interval / 1000
<< "ms" << std::endl;
});
}
int main()
{
trantor::EventLoop loop;
auto resolver = trantor::Resolver::newResolver(&loop);
dns(resolver);
loop.runAfter(1.0, [resolver]() { dns(resolver); });
loop.loop();
}

View File

@ -1,46 +0,0 @@
#include <trantor/net/TcpServer.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <string>
#include <iostream>
using namespace trantor;
#define USE_IPV6 0
int main()
{
LOG_DEBUG << "test start";
Logger::setLogLevel(Logger::kTrace);
EventLoop loop;
#if USE_IPV6
InetAddress addr(8888, true, true);
#else
InetAddress addr(8888);
#endif
TcpServer server(&loop, addr, "test");
server.kickoffIdleConnections(10);
server.setRecvMessageCallback(
[](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) {
// LOG_DEBUG<<"recv callback!";
std::cout << std::string(buffer->peek(), buffer->readableBytes());
connectionPtr->send(buffer->peek(), buffer->readableBytes());
buffer->retrieveAll();
});
int n = 0;
server.setConnectionCallback([&n](const TcpConnectionPtr &connPtr) {
if (connPtr->connected())
{
++n;
if (n % 2 == 0)
{
connPtr->keepAlive();
}
LOG_DEBUG << "New connection";
}
else if (connPtr->disconnected())
{
LOG_DEBUG << "connection disconnected";
}
});
server.setIoLoopNum(3);
server.start();
loop.loop();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +0,0 @@
//
// Created by antao on 1/14/17.
//
#include <trantor/net/EventLoop.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
int main()
{
trantor::EventLoop loop;
std::thread thread([&loop]() {
std::this_thread::sleep_for(3s);
loop.runInLoop([&loop]() {
std::cout << "runInLoop called in other thread" << std::endl;
loop.queueInLoop(
[]() { std::cout << "queueInLoop in runInLoop" << std::endl; });
});
});
loop.runInLoop([]() { std::cout << "runInLoop 1" << std::endl; });
loop.runInLoop([]() { std::cout << "runInLoop 2" << std::endl; });
loop.queueInLoop([]() { std::cout << "queueInLoop 1" << std::endl; });
loop.runAfter(1.5, []() { std::cout << "run after 1.5" << std::endl; });
loop.loop();
}

View File

@ -1,44 +0,0 @@
#include <trantor/net/EventLoopThread.h>
#include <iostream>
#include <atomic>
#include <future>
#ifndef _WIN32
#include <unistd.h>
#endif
int main()
{
std::atomic<uint64_t> counter;
counter = 0;
std::promise<int> pro;
auto ft = pro.get_future();
trantor::EventLoopThread loopThread;
auto loop = loopThread.getLoop();
loop->runInLoop([&counter, &pro, loop]() {
for (int i = 0; i < 10000; ++i)
{
loop->queueInLoop([&counter, &pro]() {
++counter;
if (counter.load() == 110000)
pro.set_value(1);
});
}
});
for (int i = 0; i < 10; ++i)
{
std::thread([&counter, loop, &pro]() {
for (int i = 0; i < 10000; ++i)
{
loop->runInLoop([&counter, &pro]() {
++counter;
if (counter.load() == 110000)
pro.set_value(1);
});
}
}).detach();
}
loopThread.run();
ft.get();
std::cout << "counter=" << counter.load() << std::endl;
}

View File

@ -1,27 +0,0 @@
#include <trantor/net/EventLoopThread.h>
#include <iostream>
#include <atomic>
#include <future>
#ifndef _WIN32
#include <unistd.h>
#endif
int main()
{
std::atomic<bool> flag(false);
{
trantor::EventLoopThread thr;
thr.getLoop()->runOnQuit([&]() { flag = true; });
thr.run();
thr.getLoop()->quit();
}
if (flag == false)
{
std::cerr << "Test failed\n";
}
else
{
std::cout << "Success\n";
}
}

View File

@ -1,54 +0,0 @@
#include <trantor/net/TcpClient.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <string>
#include <iostream>
#include <atomic>
using namespace trantor;
#define USE_IPV6 0
int main()
{
trantor::Logger::setLogLevel(trantor::Logger::kTrace);
LOG_DEBUG << "TcpClient class test!";
EventLoop loop;
#if USE_IPV6
InetAddress serverAddr("::1", 8888, true);
#else
InetAddress serverAddr("127.0.0.1", 8888);
#endif
std::shared_ptr<trantor::TcpClient> client[10];
std::atomic_int connCount;
connCount = 1;
for (int i = 0; i < connCount; ++i)
{
client[i] = std::make_shared<trantor::TcpClient>(&loop,
serverAddr,
"tcpclienttest");
client[i]->enableSSL(false, false);
client[i]->setConnectionCallback(
[i, &loop, &connCount](const TcpConnectionPtr &conn) {
if (conn->connected())
{
LOG_DEBUG << i << " connected!";
char tmp[20];
sprintf(tmp, "%d client!!", i);
conn->send(tmp);
}
else
{
LOG_DEBUG << i << " disconnected";
--connCount;
if (connCount == 0)
loop.quit();
}
});
client[i]->setMessageCallback(
[](const TcpConnectionPtr &conn, MsgBuffer *buf) {
LOG_DEBUG << std::string(buf->peek(), buf->readableBytes());
buf->retrieveAll();
conn->shutdown();
});
client[i]->connect();
}
loop.loop();
}

View File

@ -1,43 +0,0 @@
#include <trantor/net/TcpServer.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <string>
#include <iostream>
using namespace trantor;
#define USE_IPV6 0
int main()
{
LOG_DEBUG << "test start";
Logger::setLogLevel(Logger::kTrace);
EventLoopThread loopThread;
loopThread.run();
#if USE_IPV6
InetAddress addr(8888, true, true);
#else
InetAddress addr(8888);
#endif
TcpServer server(loopThread.getLoop(), addr, "test");
server.enableSSL("server.pem", "server.pem");
server.setRecvMessageCallback(
[](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) {
// LOG_DEBUG<<"recv callback!";
std::cout << std::string(buffer->peek(), buffer->readableBytes());
connectionPtr->send(buffer->peek(), buffer->readableBytes());
buffer->retrieveAll();
connectionPtr->forceClose();
});
server.setConnectionCallback([](const TcpConnectionPtr &connPtr) {
if (connPtr->connected())
{
LOG_DEBUG << "New connection";
connPtr->send("Hello world\r\n");
}
else if (connPtr->disconnected())
{
LOG_DEBUG << "connection disconnected";
}
});
server.setIoLoopNum(3);
server.start();
loopThread.wait();
}

View File

@ -1,91 +0,0 @@
#include <trantor/net/TcpServer.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <string>
#include <iostream>
#include <thread>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef _WIN32
#include <unistd.h>
#endif
using namespace trantor;
#define USE_IPV6 0
int main(int argc, char *argv[])
{
if (argc < 2)
{
std::cout << "usage:" << argv[0] << " filename" << std::endl;
return 1;
}
std::cout << "filename:" << argv[1] << std::endl;
struct stat filestat;
if (stat(argv[1], &filestat) < 0)
{
perror("");
exit(1);
}
std::cout << "file len=" << filestat.st_size << std::endl;
auto fp = fopen(argv[1], "rb");
if (fp == nullptr)
{
perror("");
exit(1);
}
fclose(fp);
LOG_DEBUG << "test start";
Logger::setLogLevel(Logger::kTrace);
EventLoopThread loopThread;
loopThread.run();
#if USE_IPV6
InetAddress addr(1207, true, true);
#else
InetAddress addr(1207);
#endif
TcpServer server(loopThread.getLoop(), addr, "test");
server.setRecvMessageCallback(
[](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) {
// LOG_DEBUG<<"recv callback!";
});
int counter = 0;
server.setConnectionCallback(
[argv, &counter](const TcpConnectionPtr &connPtr) {
if (connPtr->connected())
{
LOG_DEBUG << "New connection";
std::thread t([connPtr, argv, &counter]() {
for (int i = 0; i < 5; ++i)
{
connPtr->sendFile(argv[1]);
char str[64];
++counter;
sprintf(str, "\n%d files sent!\n", counter);
connPtr->send(str, strlen(str));
}
});
t.detach();
for (int i = 0; i < 3; ++i)
{
connPtr->sendFile(argv[1]);
char str[64];
++counter;
sprintf(str, "\n%d files sent!\n", counter);
connPtr->send(str, strlen(str));
}
}
else if (connPtr->disconnected())
{
LOG_DEBUG << "connection disconnected";
}
});
server.setIoLoopNum(3);
server.start();
loopThread.wait();
}

View File

@ -1,29 +0,0 @@
#include <trantor/utils/SerialTaskQueue.h>
#include <trantor/utils/Logger.h>
#include <iostream>
#include <thread>
#include <stdio.h>
using namespace std::chrono_literals;
int main()
{
trantor::Logger::setLogLevel(trantor::Logger::kTrace);
trantor::SerialTaskQueue queue1("test queue1");
trantor::SerialTaskQueue queue2("");
queue1.runTaskInQueue([&]() {
for (int i = 0; i < 5; ++i)
{
std::this_thread::sleep_for(1s);
printf("task(%s) i=%d\n", queue1.getName().c_str(), i);
}
});
queue2.runTaskInQueue([&]() {
for (int i = 0; i < 5; ++i)
{
std::this_thread::sleep_for(1s);
printf("task(%s) i=%d\n", queue2.getName().c_str(), i);
}
});
queue1.waitAllTasksFinished();
queue2.waitAllTasksFinished();
}

View File

@ -1,42 +0,0 @@
#include <trantor/utils/SerialTaskQueue.h>
#include <iostream>
#include <atomic>
#include <future>
#ifndef _WIN32
#include <unistd.h>
#endif
int main()
{
std::atomic<uint64_t> counter;
counter = 0;
std::promise<int> pro;
auto ft = pro.get_future();
trantor::SerialTaskQueue queue("");
queue.runTaskInQueue([&counter, &pro, &queue]() {
for (int i = 0; i < 10000; ++i)
{
queue.runTaskInQueue([&counter, &pro]() {
++counter;
if (counter.load() == 110000)
pro.set_value(1);
});
}
});
for (int i = 0; i < 10; ++i)
{
std::thread([&counter, &queue, &pro]() {
for (int i = 0; i < 10000; ++i)
{
queue.runTaskInQueue([&counter, &pro]() {
++counter;
if (counter.load() == 110000)
pro.set_value(1);
});
}
}).detach();
}
ft.get();
std::cout << "counter=" << counter.load() << std::endl;
}

View File

@ -1,53 +0,0 @@
#include <trantor/net/TcpClient.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <string>
#include <iostream>
#include <atomic>
using namespace trantor;
#define USE_IPV6 0
int main()
{
trantor::Logger::setLogLevel(trantor::Logger::kTrace);
LOG_DEBUG << "TcpClient class test!";
EventLoop loop;
#if USE_IPV6
InetAddress serverAddr("::1", 8888, true);
#else
InetAddress serverAddr("127.0.0.1", 8888);
#endif
std::shared_ptr<trantor::TcpClient> client[10];
std::atomic_int connCount;
connCount = 10;
for (int i = 0; i < 10; ++i)
{
client[i] = std::make_shared<trantor::TcpClient>(&loop,
serverAddr,
"tcpclienttest");
client[i]->setConnectionCallback(
[i, &loop, &connCount](const TcpConnectionPtr &conn) {
if (conn->connected())
{
LOG_DEBUG << i << " connected!";
char tmp[20];
sprintf(tmp, "%d client!!", i);
conn->send(tmp);
}
else
{
LOG_DEBUG << i << " disconnected";
--connCount;
if (connCount == 0)
loop.quit();
}
});
client[i]->setMessageCallback(
[](const TcpConnectionPtr &conn, MsgBuffer *buf) {
LOG_DEBUG << std::string(buf->peek(), buf->readableBytes());
buf->retrieveAll();
conn->shutdown();
});
client[i]->connect();
}
loop.loop();
}

View File

@ -1,41 +0,0 @@
#include <trantor/net/TcpServer.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <string>
#include <iostream>
using namespace trantor;
#define USE_IPV6 0
int main()
{
LOG_DEBUG << "test start";
Logger::setLogLevel(Logger::kTrace);
EventLoopThread loopThread;
loopThread.run();
#if USE_IPV6
InetAddress addr(8888, true, true);
#else
InetAddress addr(8888);
#endif
TcpServer server(loopThread.getLoop(), addr, "test");
server.setRecvMessageCallback(
[](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) {
// LOG_DEBUG<<"recv callback!";
std::cout << std::string(buffer->peek(), buffer->readableBytes());
connectionPtr->send(buffer->peek(), buffer->readableBytes());
buffer->retrieveAll();
// connectionPtr->forceClose();
});
server.setConnectionCallback([](const TcpConnectionPtr &connPtr) {
if (connPtr->connected())
{
LOG_DEBUG << "New connection";
}
else if (connPtr->disconnected())
{
LOG_DEBUG << "connection disconnected";
}
});
server.setIoLoopNum(3);
server.start();
loopThread.wait();
}

View File

@ -1,33 +0,0 @@
#include <trantor/net/EventLoop.h>
#include <trantor/utils/Logger.h>
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::literals;
int main()
{
trantor::Logger::setLogLevel(trantor::Logger::kTrace);
trantor::EventLoop loop;
auto id1 = loop.runAfter(1s, []() {
LOG_ERROR << "This info shouldn't be displayed!";
});
loop.invalidateTimer(id1);
auto id2 = loop.runEvery(0.3s, []() {
LOG_ERROR << "This timer will be invalidated after 3 second;";
});
std::thread thread([id2, &loop]() {
std::this_thread::sleep_for(3s);
loop.invalidateTimer(id2);
});
thread.detach();
loop.runEvery(3, []() { LOG_DEBUG << " runEvery 3s"; });
loop.runAt(trantor::Date::date().after(10),
[]() { LOG_DEBUG << "runAt 10s later"; });
loop.runAfter(5, []() { std::cout << "runAt 5s later" << std::endl; });
loop.runEvery(1, []() { std::cout << "runEvery 1s" << std::endl; });
loop.runAfter(4, []() { std::cout << "runAfter 4s" << std::endl; });
loop.runAfter(10min,
[]() { std::cout << "*********** run after 10 min\n"; });
loop.loop();
}

View File

@ -1,23 +0,0 @@
#include <trantor/net/EventLoop.h>
#include <trantor/utils/Logger.h>
#include <iostream>
int main()
{
trantor::EventLoop loop;
LOG_FATAL << trantor::Date::date().roundDay().microSecondsSinceEpoch();
trantor::Date begin = trantor::Date::date().roundSecond().after(2);
auto id = loop.runAt(begin, [begin, &loop]() {
LOG_DEBUG << "test begin:";
srand((unsigned int)time(NULL));
for (int i = 0; i < 10000; ++i)
{
int aa = rand() % 10000;
double s = (double)aa / 1000.0 + 1;
loop.runAt(begin.after(s),
[s]() { LOG_ERROR << "run After:" << s; });
}
LOG_DEBUG << "timer created!";
});
std::cout << "id=" << id << std::endl;
loop.loop();
}

View File

@ -1,48 +0,0 @@
#include <trantor/utils/TimingWheel.h>
#include <trantor/utils/Logger.h>
#include <memory>
class MyClass
{
public:
MyClass();
MyClass(MyClass &&) = default;
MyClass(const MyClass &) = default;
MyClass &operator=(MyClass &&) = default;
MyClass &operator=(const MyClass &) = default;
~MyClass();
private:
};
MyClass::MyClass()
{
}
MyClass::~MyClass()
{
LOG_DEBUG << "MyClass destructed!";
}
int main()
{
LOG_DEBUG << "start";
trantor::EventLoop loop;
std::weak_ptr<MyClass> weakEntry;
trantor::TimingWheel wheel(&loop, 75, 0.1, 100);
{
auto entry = std::shared_ptr<MyClass>(new MyClass);
wheel.insertEntry(75, entry);
weakEntry = entry;
}
// loop.runAfter(5.0, [&]() {
// wheel.insertEntry(10, weakEntry.lock());
// });
// loop.runAfter(0.5,[&](){
// wheel.insertEntry(28,weakEntry.lock());
// });
// loop.runEvery(1.0,[](){
// LOG_DEBUG<<"tick";
// });
loop.loop();
}

View File

@ -1,49 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/vLeZ4B80b22y
JSF9WoAEGo5D0GLlzSxL7rRZSd81h3YMKpsgFT4WkZxs9sqoRW/OTaqMGuEzGt6a
54RMwycQwJL+GGt/stZ+7AYHoLE6cQzP8iFcwy4mLFsX+gQjoE0UHr0RykKRl3Vw
qZST74AhAMlFvEDCfoMxTy9dy5ZjbLTFrH1kvo5CT9MEbyBLpxYrYYFjBAMIZdvV
82Mz3JftDLbx7t+96PaGLpDMLk9NgrV1kbUpzck/aCbZ5DgV7enTU33tVIcfMU5e
fZii044OkOvFNXibi6tdPORP8TBnrmEZjmDnFAgEijzpIcJ4VVPTrlCuxLUKcSDY
wYLro7gbAgMBAAECggEAesztcnoewkCTq0MovdZWo0o2z6wJi1DrC/7oNz+e2/PU
YVpwXA3+5AmCfC9cAIXoY+NOVclpbofJBsE89MUQoiQUgPU29GSgCE42VnBO0jVR
lWVohLblOcGy3hpcyEyE0VwWj+xQ0lqE9xFFfbIpB/ou7qDxgR/x+oTSu2oG+cmr
xv+Dj+k46QW0X2A3XHnlZkk0fQGb+Tf3fIJ4BBwF/UFQTDyZPZrsZfbpoEk1BnIf
VPcfM1/ca6h1t/oEnpD66H2TjxYzZC58mqZSZIZ+Pk+wocSsF5UcQLedcM137LDH
OR+fdscinr1xgMhV30RmAUP5tug9Km3oq8wf4Xl1IQKBgQDmDtYbwN7V1eA6Dbeq
HCk07t/llK+j4mvyuU+pVKfNHmnUUd+NPpDwREFrfoR6ilrZMJ4Obl7z53rja+9s
JqECBThhRzHxnUQgsu3DQeY7e2KxBBGGvhQBjRGtVRID3aFTTyMKvaOkTc7kL+x1
5DbtoVAA1kbYnjgZJyZosx+bmQKBgQDVW6lXxoLzC7npXdXOTMJifExcCIzXskc9
5b+rJTXgkqaPQSQ7nNmRReUY9r9UBsZKLduuYJZ3TLMCaU91/wBwc1ygkQvRz+8A
2QGMovlVOqwPAOEc1lMCXzQki9PcqmVX/e0oFmTtUgyF4RKEwL/q8A9fWy587rkQ
57MDNJ3h0wKBgQDNJgPFweq0EsGd4yeZuP0B59Wee0VYxgru6lLgM85iujEzFUNd
R6KlrqgLvElUoNW8gX8gbUmdBBlwfYqGDbhb/d212W/u/geHhSdCjBxLhI6QPYmH
dy6N54cQ4yBqdBNtH8+mv08SsBPDJf0db8GPi960sF+CwSxTObclfD2+WQKBgBgi
HxyLmsJNIEFSWN3V9uLW9ngui2fWhZJty2lbcyWs0ORBVQzdKArzof9Z4bhqb8Fy
QHgP+tURuunZ6aAKMQ2HLwIGhhS8dWdeJHu474UBdvbXfZ8aaxdIl4hOvK8oIwB5
+3peVho1/q6iD8suVkcH0mVR1gdRpWNRIgGJ0RX7AoGBAMzp0u3X3SEMWTlqFR7D
BJqmpiMvJJJSqex1i4PJoy+uJpqfl3b1jUMnFIS4GiscVCIEJkPpZaz3eSTt7aVQ
+7v0b/Cusv1qYX2c5v9j9x7nmUlfdwT5rY2g6RXI/xlhPD9elb1dxlzmhiO4VQtr
AdiFmu0poyPpEGwjpcLEZq6K
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDajCCAlICCQCXmD7IkkDArzANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJD
TjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHQmVpamluZzEPMA0GA1UECgwG
YW4tdGFvMQ8wDQYDVQQLDAZhbi10YW8xIjAgBgkqhkiG9w0BCQEWE2FudGFvMjAw
MkBnbWFpbC5jb20wHhcNMTgwNzIxMDEyMjEyWhcNMTkwNzIxMDEyMjEyWjB3MQsw
CQYDVQQGEwJDTjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHQmVpamluZzEP
MA0GA1UECgwGYW4tdGFvMQ8wDQYDVQQLDAZhbi10YW8xIjAgBgkqhkiG9w0BCQEW
E2FudGFvMjAwMkBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC/vLeZ4B80b22yJSF9WoAEGo5D0GLlzSxL7rRZSd81h3YMKpsgFT4WkZxs
9sqoRW/OTaqMGuEzGt6a54RMwycQwJL+GGt/stZ+7AYHoLE6cQzP8iFcwy4mLFsX
+gQjoE0UHr0RykKRl3VwqZST74AhAMlFvEDCfoMxTy9dy5ZjbLTFrH1kvo5CT9ME
byBLpxYrYYFjBAMIZdvV82Mz3JftDLbx7t+96PaGLpDMLk9NgrV1kbUpzck/aCbZ
5DgV7enTU33tVIcfMU5efZii044OkOvFNXibi6tdPORP8TBnrmEZjmDnFAgEijzp
IcJ4VVPTrlCuxLUKcSDYwYLro7gbAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAClA
Z6JHessY1mo0ObCp8Sh83gIiGu9M77xz6Gy2vUpUGE9N1hJwYH3uZPLbpnIuxZU0
uDXd9w5vCJmtqo/4X6sedqKA6Upi8DROawtCUJaGrHrb2vJONyL7A3OWpHyYgOAa
z+sl4jbrGGv4azSg9ef1mQZTDcEcdsYiKj9U4zoyDXteyt6NQK3x5BtziB0mJfeM
gjrltVcc59s8Z2jf3PI3qmWtMuJm7KGHlan2DUz12AZxY3sJrFyew3Vi1V2uvIZB
YwgcXbVa3r6PQU3RwFwkazxAe80ZgiQlVsEiBl8mre4zznt5XHF6mzAqvpHyXPCI
LfEO3waLkgB94mFha5A=
-----END CERTIFICATE-----

View File

@ -1,28 +0,0 @@
wepoll - epoll for Windows
https://github.com/piscisaureus/wepoll
Copyright 2012-2020, Bert Belder <bertbelder@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,41 +0,0 @@
## wepoll
This library is based on [wepoll v1.5.8](https://github.com/piscisaureus/wepoll/commit/0598a791bf9cbbf480793d778930fc635b044980).
An eventfd-like mechanism is added to it. After making the changes, we can wake up `trantor::EventLoop` from the epoll_wait() function.
## Modifications
```shell
diff wepoll.h Wepoll.h
53a54
> EPOLLEVENT = (int)(1U << 14),
67a69
> #define EPOLLEVENT (1U << 14)
111a114
> WEPOLL_EXPORT void epoll_post_signal(HANDLE ephnd, uint64_t event);
```
```shell
diff wepoll.c Wepoll.c
50a51
> EPOLLEVENT = (int)(1U << 14),
64a66
> #define EPOLLEVENT (1U << 14)
1262a1265,1271
> if (iocp_events[i].lpCompletionKey)
> {
> struct epoll_event* ev = &epoll_events[epoll_event_count++];
> ev->data.u64 = (uint64_t)iocp_events[i].lpCompletionKey;
> ev->events = EPOLLEVENT;
> continue;
> }
2441a2451,2457
> void epoll_post_signal(HANDLE port_handle, uint64_t event)
> {
> ULONG_PTR ev;
> ev = (ULONG_PTR)event;
> PostQueuedCompletionStatus(port_handle, 1, ev, NULL);
> }
>
```

File diff suppressed because it is too large Load Diff

View File

@ -1,120 +0,0 @@
/*
* wepoll - epoll for Windows
* https://github.com/piscisaureus/wepoll
*
* Copyright 2012-2020, Bert Belder <bertbelder@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEPOLL_H_
#define WEPOLL_H_
#ifndef WEPOLL_EXPORT
#define WEPOLL_EXPORT
#endif
#include <stdint.h>
enum EPOLL_EVENTS
{
EPOLLIN = (int)(1U << 0),
EPOLLPRI = (int)(1U << 1),
EPOLLOUT = (int)(1U << 2),
EPOLLERR = (int)(1U << 3),
EPOLLHUP = (int)(1U << 4),
EPOLLRDNORM = (int)(1U << 6),
EPOLLRDBAND = (int)(1U << 7),
EPOLLWRNORM = (int)(1U << 8),
EPOLLWRBAND = (int)(1U << 9),
EPOLLMSG = (int)(1U << 10), /* Never reported. */
EPOLLRDHUP = (int)(1U << 13),
EPOLLEVENT = (int)(1U << 14),
EPOLLONESHOT = (int)(1U << 31)
};
#define EPOLLIN (1U << 0)
#define EPOLLPRI (1U << 1)
#define EPOLLOUT (1U << 2)
#define EPOLLERR (1U << 3)
#define EPOLLHUP (1U << 4)
#define EPOLLRDNORM (1U << 6)
#define EPOLLRDBAND (1U << 7)
#define EPOLLWRNORM (1U << 8)
#define EPOLLWRBAND (1U << 9)
#define EPOLLMSG (1U << 10)
#define EPOLLRDHUP (1U << 13)
#define EPOLLEVENT (1U << 14)
#define EPOLLONESHOT (1U << 31)
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_MOD 2
#define EPOLL_CTL_DEL 3
typedef void* HANDLE;
typedef uintptr_t SOCKET;
typedef union epoll_data
{
void* ptr;
int fd;
uint32_t u32;
uint64_t u64;
SOCKET sock; /* Windows specific */
HANDLE hnd; /* Windows specific */
} epoll_data_t;
struct epoll_event
{
uint32_t events; /* Epoll events and flags */
epoll_data_t data; /* User data variable */
};
#ifdef __cplusplus
extern "C"
{
#endif
WEPOLL_EXPORT HANDLE epoll_create(int size);
WEPOLL_EXPORT HANDLE epoll_create1(int flags);
WEPOLL_EXPORT int epoll_close(HANDLE ephnd);
WEPOLL_EXPORT int epoll_ctl(HANDLE ephnd,
int op,
SOCKET sock,
struct epoll_event* event);
WEPOLL_EXPORT int epoll_wait(HANDLE ephnd,
struct epoll_event* events,
int maxevents,
int timeout);
WEPOLL_EXPORT void epoll_post_signal(HANDLE ephnd, uint64_t event);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WEPOLL_H_ */

View File

@ -1,19 +0,0 @@
find_package(GTest REQUIRED)
add_executable(msgbuffer_unittest MsgBufferUnittest.cc)
add_executable(inetaddress_unittest InetAddressUnittest.cc)
add_executable(date_unittest DateUnittest.cc)
add_executable(split_string_unittest splitStringUnittest.cc)
set(UNITTEST_TARGETS
msgbuffer_unittest
inetaddress_unittest
date_unittest
split_string_unittest)
set_property(TARGET ${UNITTEST_TARGETS} PROPERTY CXX_STANDARD 14)
set_property(TARGET ${UNITTEST_TARGETS} PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET ${UNITTEST_TARGETS} PROPERTY CXX_EXTENSIONS OFF)
include(GoogleTest)
foreach(T ${UNITTEST_TARGETS})
target_link_libraries(${T} PRIVATE trantor GTest::GTest)
gtest_discover_tests(${T})
endforeach()

View File

@ -1,43 +0,0 @@
#include <trantor/utils/Date.h>
#include <gtest/gtest.h>
#include <string>
#include <iostream>
using namespace trantor;
TEST(Date, constructorTest)
{
EXPECT_STREQ("1985-01-01 00:00:00",
trantor::Date(1985, 1, 1)
.toCustomedFormattedStringLocal("%Y-%m-%d %H:%M:%S")
.c_str());
EXPECT_STREQ("2004-02-29 00:00:00.000000",
trantor::Date(2004, 2, 29)
.toCustomedFormattedStringLocal("%Y-%m-%d %H:%M:%S", true)
.c_str());
EXPECT_STRNE("2001-02-29 00:00:00.000000",
trantor::Date(2001, 2, 29)
.toCustomedFormattedStringLocal("%Y-%m-%d %H:%M:%S", true)
.c_str());
EXPECT_STREQ("2018-01-01 00:00:00.000000",
trantor::Date(2018, 1, 1, 12, 12, 12, 2321)
.roundDay()
.toCustomedFormattedStringLocal("%Y-%m-%d %H:%M:%S", true)
.c_str());
}
TEST(Date, DatabaseStringTest)
{
auto now = trantor::Date::now();
EXPECT_EQ(now, trantor::Date::fromDbStringLocal(now.toDbStringLocal()));
std::string dbString = "2018-01-01 00:00:00.123";
auto dbDate = trantor::Date::fromDbStringLocal(dbString);
auto ms = (dbDate.microSecondsSinceEpoch() % 1000000) / 1000;
EXPECT_EQ(ms, 123);
dbString = "2018-01-01 00:00:00";
dbDate = trantor::Date::fromDbStringLocal(dbString);
ms = (dbDate.microSecondsSinceEpoch() % 1000000) / 1000;
EXPECT_EQ(ms, 0);
}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,22 +0,0 @@
#include <trantor/net/InetAddress.h>
#include <gtest/gtest.h>
#include <string>
#include <iostream>
using namespace trantor;
TEST(InetAddress, innerIpTest)
{
EXPECT_EQ(true, InetAddress("192.168.0.1", 0).isIntranetIp());
EXPECT_EQ(true, InetAddress("192.168.12.1", 0).isIntranetIp());
EXPECT_EQ(true, InetAddress("10.168.0.1", 0).isIntranetIp());
EXPECT_EQ(true, InetAddress("10.0.0.1", 0).isIntranetIp());
EXPECT_EQ(true, InetAddress("172.31.10.1", 0).isIntranetIp());
EXPECT_EQ(true, InetAddress("127.0.0.1", 0).isIntranetIp());
EXPECT_EQ(true, InetAddress("example.com", 0).isUnspecified());
EXPECT_EQ(false, InetAddress("127.0.0.2", 0).isUnspecified());
EXPECT_EQ(false, InetAddress("0.0.0.0", 0).isUnspecified());
}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,78 +0,0 @@
#include <trantor/utils/MsgBuffer.h>
#include <gtest/gtest.h>
#include <string>
#include <iostream>
using namespace trantor;
TEST(MsgBufferTest, readableTest)
{
MsgBuffer buffer;
EXPECT_EQ(0, buffer.readableBytes());
buffer.append(std::string(128, 'a'));
EXPECT_EQ(128, buffer.readableBytes());
buffer.retrieve(100);
EXPECT_EQ(28, buffer.readableBytes());
EXPECT_EQ('a', buffer.peekInt8());
buffer.retrieveAll();
EXPECT_EQ(0, buffer.readableBytes());
}
TEST(MsgBufferTest, writableTest)
{
MsgBuffer buffer(100);
EXPECT_EQ(100, buffer.writableBytes());
buffer.append("abcde");
EXPECT_EQ(95, buffer.writableBytes());
buffer.append(std::string(100, 'x'));
EXPECT_EQ(111, buffer.writableBytes());
buffer.retrieve(100);
EXPECT_EQ(111, buffer.writableBytes());
buffer.append(std::string(112, 'c'));
EXPECT_EQ(99, buffer.writableBytes());
buffer.retrieveAll();
EXPECT_EQ(216, buffer.writableBytes());
}
TEST(MsgBufferTest, addInFrontTest)
{
MsgBuffer buffer(100);
EXPECT_EQ(100, buffer.writableBytes());
buffer.addInFrontInt8('a');
EXPECT_EQ(100, buffer.writableBytes());
buffer.addInFrontInt64(123);
EXPECT_EQ(92, buffer.writableBytes());
buffer.addInFrontInt64(100);
EXPECT_EQ(84, buffer.writableBytes());
buffer.addInFrontInt8(1);
EXPECT_EQ(84, buffer.writableBytes());
}
TEST(MsgBuffer, MoveContrustor)
{
MsgBuffer buf1(100);
const char *bufptr1 = buf1.peek();
MsgBuffer buffnew1 = std::move(buf1);
EXPECT_EQ(bufptr1, buffnew1.peek());
MsgBuffer buf2(100);
const char *bufptr2 = buf2.peek();
MsgBuffer buffnew2(std::move(buf2));
EXPECT_EQ(bufptr2, buffnew2.peek());
}
TEST(Msgbuffer, MoveAssignmentOperator)
{
MsgBuffer buf(100);
const char *bufptr = buf.peek();
size_t writable = buf.writableBytes();
MsgBuffer buffnew(1000);
buffnew = std::move(buf);
EXPECT_EQ(bufptr, buffnew.peek());
EXPECT_EQ(writable, buffnew.writableBytes());
}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,159 +0,0 @@
#include <trantor/utils/Date.h>
#include <gtest/gtest.h>
#include <trantor/utils/Funcs.h>
#include <iostream>
using namespace trantor;
TEST(splitString, ACCEPT_EMPTY_STRING1)
{
std::string originString = "1,2,3";
auto out = splitString(originString, ",", true);
EXPECT_EQ(out.size(), 3);
}
TEST(splitString, ACCEPT_EMPTY_STRING2)
{
std::string originString = ",1,2,3";
auto out = splitString(originString, ",", true);
EXPECT_EQ(out.size(), 4);
EXPECT_TRUE(out[0].empty());
}
TEST(splitString, ACCEPT_EMPTY_STRING3)
{
std::string originString = ",1,2,3,";
auto out = splitString(originString, ",", true);
EXPECT_EQ(out.size(), 5);
EXPECT_TRUE(out[0].empty());
}
TEST(splitString, ACCEPT_EMPTY_STRING4)
{
std::string originString = ",1,2,3,";
auto out = splitString(originString, ":", true);
EXPECT_EQ(out.size(), 1);
EXPECT_STREQ(out[0].data(), ",1,2,3,");
}
TEST(splitString, ACCEPT_EMPTY_STRING5)
{
std::string originString = "trantor::splitString";
auto out = splitString(originString, "::", true);
EXPECT_EQ(out.size(), 2);
EXPECT_STREQ(out[0].data(), "trantor");
EXPECT_STREQ(out[1].data(), "splitString");
}
TEST(splitString, ACCEPT_EMPTY_STRING6)
{
std::string originString = "trantor::::splitString";
auto out = splitString(originString, "::", true);
EXPECT_EQ(out.size(), 3);
EXPECT_STREQ(out[0].data(), "trantor");
EXPECT_STREQ(out[1].data(), "");
EXPECT_STREQ(out[2].data(), "splitString");
}
TEST(splitString, ACCEPT_EMPTY_STRING7)
{
std::string originString = "trantor:::splitString";
auto out = splitString(originString, "::", true);
EXPECT_EQ(out.size(), 2);
EXPECT_STREQ(out[0].data(), "trantor");
EXPECT_STREQ(out[1].data(), ":splitString");
}
TEST(splitString, ACCEPT_EMPTY_STRING8)
{
std::string originString = "trantor:::splitString";
auto out = splitString(originString, "trantor:::splitString", true);
EXPECT_EQ(out.size(), 2);
EXPECT_STREQ(out[0].data(), "");
EXPECT_STREQ(out[1].data(), "");
}
TEST(splitString, ACCEPT_EMPTY_STRING9)
{
std::string originString = "";
auto out = splitString(originString, ",", true);
EXPECT_EQ(out.size(), 1);
EXPECT_STREQ(out[0].data(), "");
}
TEST(splitString, ACCEPT_EMPTY_STRING10)
{
std::string originString = "trantor";
auto out = splitString(originString, "", true);
EXPECT_EQ(out.size(), 0);
}
TEST(splitString, ACCEPT_EMPTY_STRING11)
{
std::string originString = "";
auto out = splitString(originString, "", true);
EXPECT_EQ(out.size(), 0);
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING1)
{
std::string originString = ",1,2,3";
auto out = splitString(originString, ",");
EXPECT_EQ(out.size(), 3);
EXPECT_STREQ(out[0].data(), "1");
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING2)
{
std::string originString = ",1,2,3,";
auto out = splitString(originString, ",");
EXPECT_EQ(out.size(), 3);
EXPECT_STREQ(out[0].data(), "1");
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING3)
{
std::string originString = ",1,2,3,";
auto out = splitString(originString, ":");
EXPECT_EQ(out.size(), 1);
EXPECT_STREQ(out[0].data(), ",1,2,3,");
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING4)
{
std::string originString = "trantor::splitString";
auto out = splitString(originString, "::");
EXPECT_EQ(out.size(), 2);
EXPECT_STREQ(out[0].data(), "trantor");
EXPECT_STREQ(out[1].data(), "splitString");
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING5)
{
std::string originString = "trantor::::splitString";
auto out = splitString(originString, "::");
EXPECT_EQ(out.size(), 2);
EXPECT_STREQ(out[0].data(), "trantor");
EXPECT_STREQ(out[1].data(), "splitString");
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING6)
{
std::string originString = "trantor:::splitString";
auto out = splitString(originString, "::");
EXPECT_EQ(out.size(), 2);
EXPECT_STREQ(out[0].data(), "trantor");
EXPECT_STREQ(out[1].data(), ":splitString");
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING7)
{
std::string originString = "trantor:::splitString";
auto out = splitString(originString, "trantor:::splitString");
EXPECT_EQ(out.size(), 0);
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING8)
{
std::string originString = "";
auto out = splitString(originString, ",");
EXPECT_EQ(out.size(), 0);
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING9)
{
std::string originString = "trantor";
auto out = splitString(originString, "");
EXPECT_EQ(out.size(), 0);
}
TEST(splitString, NO_ACCEPT_EMPTY_STRING10)
{
std::string originString = "";
auto out = splitString(originString, "");
EXPECT_EQ(out.size(), 0);
}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,253 +0,0 @@
/**
*
* AsyncFileLogger.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/utils/AsyncFileLogger.h>
#ifndef _WIN32
#include <unistd.h>
#ifdef __linux__
#include <sys/prctl.h>
#endif
#endif
#include <string.h>
#include <iostream>
#include <functional>
#include <chrono>
namespace trantor
{
static constexpr std::chrono::seconds kLogFlushTimeout{1};
static constexpr size_t kMemBufferSize{4 * 1024 * 1024};
extern const char *strerror_tl(int savedErrno);
} // namespace trantor
using namespace trantor;
AsyncFileLogger::AsyncFileLogger()
: logBufferPtr_(new std::string), nextBufferPtr_(new std::string)
{
logBufferPtr_->reserve(kMemBufferSize);
nextBufferPtr_->reserve(kMemBufferSize);
}
AsyncFileLogger::~AsyncFileLogger()
{
// std::cout << "~AsyncFileLogger" << std::endl;
stopFlag_ = true;
if (threadPtr_)
{
cond_.notify_all();
threadPtr_->join();
}
// std::cout << "thread exit" << std::endl;
{
std::lock_guard<std::mutex> guard_(mutex_);
if (logBufferPtr_->length() > 0)
{
writeBuffers_.push(logBufferPtr_);
}
while (!writeBuffers_.empty())
{
StringPtr tmpPtr = (StringPtr &&) writeBuffers_.front();
writeBuffers_.pop();
writeLogToFile(tmpPtr);
}
}
}
void AsyncFileLogger::output(const char *msg, const uint64_t len)
{
std::lock_guard<std::mutex> guard_(mutex_);
if (len > kMemBufferSize)
return;
if (!logBufferPtr_)
{
logBufferPtr_ = std::make_shared<std::string>();
logBufferPtr_->reserve(kMemBufferSize);
}
if (logBufferPtr_->capacity() - logBufferPtr_->length() < len)
{
swapBuffer();
cond_.notify_one();
}
if (writeBuffers_.size() > 25) // 100M bytes logs in buffer
{
++lostCounter_;
return;
}
if (lostCounter_ > 0)
{
char logErr[128];
auto strlen =
snprintf(logErr,
sizeof(logErr),
"%llu log information is lost\n",
static_cast<long long unsigned int>(lostCounter_));
lostCounter_ = 0;
logBufferPtr_->append(logErr, strlen);
}
logBufferPtr_->append(msg, len);
}
void AsyncFileLogger::flush()
{
std::lock_guard<std::mutex> guard_(mutex_);
if (logBufferPtr_->length() > 0)
{
// std::cout<<"flush log buffer
// len:"<<logBufferPtr_->length()<<std::endl;
swapBuffer();
cond_.notify_one();
}
}
void AsyncFileLogger::writeLogToFile(const StringPtr buf)
{
if (!loggerFilePtr_)
{
loggerFilePtr_ = std::unique_ptr<LoggerFile>(
new LoggerFile(filePath_, fileBaseName_, fileExtName_));
}
loggerFilePtr_->writeLog(buf);
if (loggerFilePtr_->getLength() > sizeLimit_)
{
loggerFilePtr_.reset();
}
}
void AsyncFileLogger::logThreadFunc()
{
#ifdef __linux__
prctl(PR_SET_NAME, "AsyncFileLogger");
#endif
while (!stopFlag_)
{
{
std::unique_lock<std::mutex> lock(mutex_);
while (writeBuffers_.size() == 0 && !stopFlag_)
{
if (cond_.wait_for(lock, kLogFlushTimeout) ==
std::cv_status::timeout)
{
if (logBufferPtr_->length() > 0)
{
swapBuffer();
}
break;
}
}
tmpBuffers_.swap(writeBuffers_);
}
while (!tmpBuffers_.empty())
{
StringPtr tmpPtr = (StringPtr &&) tmpBuffers_.front();
tmpBuffers_.pop();
writeLogToFile(tmpPtr);
tmpPtr->clear();
{
std::unique_lock<std::mutex> lock(mutex_);
nextBufferPtr_ = tmpPtr;
}
}
if (loggerFilePtr_)
loggerFilePtr_->flush();
}
}
void AsyncFileLogger::startLogging()
{
threadPtr_ = std::unique_ptr<std::thread>(
new std::thread(std::bind(&AsyncFileLogger::logThreadFunc, this)));
}
AsyncFileLogger::LoggerFile::LoggerFile(const std::string &filePath,
const std::string &fileBaseName,
const std::string &fileExtName)
: creationDate_(Date::date()),
filePath_(filePath),
fileBaseName_(fileBaseName),
fileExtName_(fileExtName)
{
fileFullName_ = filePath + fileBaseName + fileExtName;
#ifndef _MSC_VER
fp_ = fopen(fileFullName_.c_str(), "a");
#else
fp_ = _fsopen(fileFullName_.c_str(), "a+", _SH_DENYWR);
#endif
if (fp_ == nullptr)
{
std::cout << strerror_tl(errno) << std::endl;
}
}
uint64_t AsyncFileLogger::LoggerFile::fileSeq_{0};
void AsyncFileLogger::LoggerFile::writeLog(const StringPtr buf)
{
if (fp_)
{
// std::cout<<"write "<<buf->length()<<" bytes to file"<<std::endl;
fwrite(buf->c_str(), 1, buf->length(), fp_);
}
}
void AsyncFileLogger::LoggerFile::flush()
{
if (fp_)
{
fflush(fp_);
}
}
uint64_t AsyncFileLogger::LoggerFile::getLength()
{
if (fp_)
return ftell(fp_);
return 0;
}
AsyncFileLogger::LoggerFile::~LoggerFile()
{
if (fp_)
{
fclose(fp_);
char seq[12];
snprintf(seq,
sizeof(seq),
".%06llu",
static_cast<long long unsigned int>(fileSeq_ % 1000000));
++fileSeq_;
std::string newName =
filePath_ + fileBaseName_ + "." +
creationDate_.toCustomedFormattedString("%y%m%d-%H%M%S") +
std::string(seq) + fileExtName_;
rename(fileFullName_.c_str(), newName.c_str());
}
}
void AsyncFileLogger::swapBuffer()
{
writeBuffers_.push(logBufferPtr_);
if (nextBufferPtr_)
{
logBufferPtr_ = nextBufferPtr_;
nextBufferPtr_.reset();
logBufferPtr_->clear();
}
else
{
logBufferPtr_ = std::make_shared<std::string>();
logBufferPtr_->reserve(kMemBufferSize);
}
}

View File

@ -1,140 +0,0 @@
/**
*
* @file AsyncFileLogger.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/Date.h>
#include <trantor/exports.h>
#include <thread>
#include <mutex>
#include <string>
#include <condition_variable>
#include <sstream>
#include <memory>
#include <queue>
namespace trantor
{
using StringPtr = std::shared_ptr<std::string>;
using StringPtrQueue = std::queue<StringPtr>;
/**
* @brief This class implements utility functions for writing logs to files
* asynchronously.
*
*/
class TRANTOR_EXPORT AsyncFileLogger : NonCopyable
{
public:
/**
* @brief Write the message to the log file.
*
* @param msg
* @param len
*/
void output(const char *msg, const uint64_t len);
/**
* @brief Flush data from memory buffer to the log file.
*
*/
void flush();
/**
* @brief Start writing log files.
*
*/
void startLogging();
/**
* @brief Set the size limit of log files. When the log file size reaches
* the limit, the log file is switched.
*
* @param limit
*/
void setFileSizeLimit(uint64_t limit)
{
sizeLimit_ = limit;
}
/**
* @brief Set the log file name.
*
* @param baseName The base name of the log file.
* @param extName The extended name of the log file.
* @param path The location where the log file is stored.
*/
void setFileName(const std::string &baseName,
const std::string &extName = ".log",
const std::string &path = "./")
{
fileBaseName_ = baseName;
extName[0] == '.' ? fileExtName_ = extName
: fileExtName_ = std::string(".") + extName;
filePath_ = path;
if (filePath_.length() == 0)
filePath_ = "./";
if (filePath_[filePath_.length() - 1] != '/')
filePath_ = filePath_ + "/";
}
~AsyncFileLogger();
AsyncFileLogger();
protected:
std::mutex mutex_;
std::condition_variable cond_;
StringPtr logBufferPtr_;
StringPtr nextBufferPtr_;
StringPtrQueue writeBuffers_;
StringPtrQueue tmpBuffers_;
void writeLogToFile(const StringPtr buf);
std::unique_ptr<std::thread> threadPtr_;
bool stopFlag_{false};
void logThreadFunc();
std::string filePath_{"./"};
std::string fileBaseName_{"trantor"};
std::string fileExtName_{".log"};
uint64_t sizeLimit_{20 * 1024 * 1024};
class LoggerFile : NonCopyable
{
public:
LoggerFile(const std::string &filePath,
const std::string &fileBaseName,
const std::string &fileExtName);
~LoggerFile();
void writeLog(const StringPtr buf);
uint64_t getLength();
explicit operator bool() const
{
return fp_ != nullptr;
}
void flush();
protected:
FILE *fp_{nullptr};
Date creationDate_;
std::string fileFullName_;
std::string filePath_;
std::string fileBaseName_;
std::string fileExtName_;
static uint64_t fileSeq_;
};
std::unique_ptr<LoggerFile> loggerFilePtr_;
uint64_t lostCounter_{0};
void swapBuffer();
};
} // namespace trantor

View File

@ -1,95 +0,0 @@
/**
*
* ConcurrentTaskQueue.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/utils/ConcurrentTaskQueue.h>
#include <trantor/utils/Logger.h>
#include <assert.h>
#ifdef __linux__
#include <sys/prctl.h>
#endif
using namespace trantor;
ConcurrentTaskQueue::ConcurrentTaskQueue(size_t threadNum,
const std::string &name)
: queueCount_(threadNum), queueName_(name), stop_(false)
{
assert(threadNum > 0);
for (unsigned int i = 0; i < queueCount_; ++i)
{
threads_.push_back(
std::thread(std::bind(&ConcurrentTaskQueue::queueFunc, this, i)));
}
}
void ConcurrentTaskQueue::runTaskInQueue(const std::function<void()> &task)
{
LOG_TRACE << "copy task into queue";
std::lock_guard<std::mutex> lock(taskMutex_);
taskQueue_.push(task);
taskCond_.notify_one();
}
void ConcurrentTaskQueue::runTaskInQueue(std::function<void()> &&task)
{
LOG_TRACE << "move task into queue";
std::lock_guard<std::mutex> lock(taskMutex_);
taskQueue_.push(std::move(task));
taskCond_.notify_one();
}
void ConcurrentTaskQueue::queueFunc(int queueNum)
{
char tmpName[32];
snprintf(tmpName, sizeof(tmpName), "%s%d", queueName_.c_str(), queueNum);
#ifdef __linux__
::prctl(PR_SET_NAME, tmpName);
#endif
while (!stop_)
{
std::function<void()> r;
{
std::unique_lock<std::mutex> lock(taskMutex_);
while (!stop_ && taskQueue_.size() == 0)
{
taskCond_.wait(lock);
}
if (taskQueue_.size() > 0)
{
LOG_TRACE << "got a new task!";
r = std::move(taskQueue_.front());
taskQueue_.pop();
}
else
continue;
}
r();
}
}
size_t ConcurrentTaskQueue::getTaskCount()
{
std::lock_guard<std::mutex> guard(taskMutex_);
return taskQueue_.size();
}
void ConcurrentTaskQueue::stop()
{
if (!stop_)
{
stop_ = true;
taskCond_.notify_all();
for (auto &t : threads_)
t.join();
}
}
ConcurrentTaskQueue::~ConcurrentTaskQueue()
{
stop();
}

View File

@ -1,89 +0,0 @@
/**
*
* @file ConcurrentTaskQueue.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/TaskQueue.h>
#include <trantor/exports.h>
#include <list>
#include <memory>
#include <vector>
#include <queue>
#include <string>
namespace trantor
{
/**
* @brief This class implements a task queue running in parallel. Basically this
* can be called a threads pool.
*
*/
class TRANTOR_EXPORT ConcurrentTaskQueue : public TaskQueue
{
public:
/**
* @brief Construct a new concurrent task queue instance.
*
* @param threadNum The number of threads in the queue.
* @param name The name of the queue.
*/
ConcurrentTaskQueue(size_t threadNum, const std::string &name);
/**
* @brief Run a task in the queue.
*
* @param task
*/
virtual void runTaskInQueue(const std::function<void()> &task);
virtual void runTaskInQueue(std::function<void()> &&task);
/**
* @brief Get the name of the queue.
*
* @return std::string
*/
virtual std::string getName() const
{
return queueName_;
};
/**
* @brief Get the number of tasks to be executed in the queue.
*
* @return size_t
*/
size_t getTaskCount();
/**
* @brief Stop all threads in the queue.
*
*/
void stop();
~ConcurrentTaskQueue();
private:
size_t queueCount_;
std::string queueName_;
std::queue<std::function<void()>> taskQueue_;
std::vector<std::thread> threads_;
std::mutex taskMutex_;
std::condition_variable taskCond_;
std::atomic_bool stop_;
void queueFunc(int queueNum);
};
} // namespace trantor

View File

@ -1,359 +0,0 @@
/**
*
* Date.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include "Date.h"
#include "Funcs.h"
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <cstdlib>
#include <iostream>
#include <string.h>
#ifdef _WIN32
#include <WinSock2.h>
#include <time.h>
#endif
namespace trantor
{
#ifdef _WIN32
int gettimeofday(timeval *tp, void *tzp)
{
time_t clock;
struct tm tm;
SYSTEMTIME wtm;
GetLocalTime(&wtm);
tm.tm_year = wtm.wYear - 1900;
tm.tm_mon = wtm.wMonth - 1;
tm.tm_mday = wtm.wDay;
tm.tm_hour = wtm.wHour;
tm.tm_min = wtm.wMinute;
tm.tm_sec = wtm.wSecond;
tm.tm_isdst = -1;
clock = mktime(&tm);
tp->tv_sec = static_cast<long>(clock);
tp->tv_usec = wtm.wMilliseconds * 1000;
return (0);
}
#endif
const Date Date::date()
{
#ifndef _WIN32
struct timeval tv;
gettimeofday(&tv, NULL);
int64_t seconds = tv.tv_sec;
return Date(seconds * MICRO_SECONDS_PRE_SEC + tv.tv_usec);
#else
timeval tv;
gettimeofday(&tv, NULL);
int64_t seconds = tv.tv_sec;
return Date(seconds * MICRO_SECONDS_PRE_SEC + tv.tv_usec);
#endif
}
const Date Date::after(double second) const
{
return Date(static_cast<int64_t>(microSecondsSinceEpoch_ +
second * MICRO_SECONDS_PRE_SEC));
}
const Date Date::roundSecond() const
{
return Date(microSecondsSinceEpoch_ -
(microSecondsSinceEpoch_ % MICRO_SECONDS_PRE_SEC));
}
const Date Date::roundDay() const
{
struct tm t;
time_t seconds =
static_cast<time_t>(microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC);
#ifndef _WIN32
localtime_r(&seconds, &t);
#else
localtime_s(&t, &seconds);
#endif
t.tm_hour = 0;
t.tm_min = 0;
t.tm_sec = 0;
return Date(mktime(&t) * MICRO_SECONDS_PRE_SEC);
}
struct tm Date::tmStruct() const
{
time_t seconds =
static_cast<time_t>(microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC);
struct tm tm_time;
#ifndef _WIN32
gmtime_r(&seconds, &tm_time);
#else
gmtime_s(&tm_time, &seconds);
#endif
return tm_time;
}
std::string Date::toFormattedString(bool showMicroseconds) const
{
// std::cout<<"toFormattedString"<<std::endl;
char buf[128] = {0};
time_t seconds =
static_cast<time_t>(microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC);
struct tm tm_time;
#ifndef _WIN32
gmtime_r(&seconds, &tm_time);
#else
gmtime_s(&tm_time, &seconds);
#endif
if (showMicroseconds)
{
int microseconds =
static_cast<int>(microSecondsSinceEpoch_ % MICRO_SECONDS_PRE_SEC);
snprintf(buf,
sizeof(buf),
"%4d%02d%02d %02d:%02d:%02d.%06d",
tm_time.tm_year + 1900,
tm_time.tm_mon + 1,
tm_time.tm_mday,
tm_time.tm_hour,
tm_time.tm_min,
tm_time.tm_sec,
microseconds);
}
else
{
snprintf(buf,
sizeof(buf),
"%4d%02d%02d %02d:%02d:%02d",
tm_time.tm_year + 1900,
tm_time.tm_mon + 1,
tm_time.tm_mday,
tm_time.tm_hour,
tm_time.tm_min,
tm_time.tm_sec);
}
return buf;
}
std::string Date::toCustomedFormattedString(const std::string &fmtStr,
bool showMicroseconds) const
{
char buf[256] = {0};
time_t seconds =
static_cast<time_t>(microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC);
struct tm tm_time;
#ifndef _WIN32
gmtime_r(&seconds, &tm_time);
#else
gmtime_s(&tm_time, &seconds);
#endif
strftime(buf, sizeof(buf), fmtStr.c_str(), &tm_time);
if (!showMicroseconds)
return std::string(buf);
char decimals[12] = {0};
int microseconds =
static_cast<int>(microSecondsSinceEpoch_ % MICRO_SECONDS_PRE_SEC);
snprintf(decimals, sizeof(decimals), ".%06d", microseconds);
return std::string(buf) + decimals;
}
void Date::toCustomedFormattedString(const std::string &fmtStr,
char *str,
size_t len) const
{
// not safe
time_t seconds =
static_cast<time_t>(microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC);
struct tm tm_time;
#ifndef _WIN32
gmtime_r(&seconds, &tm_time);
#else
gmtime_s(&tm_time, &seconds);
#endif
strftime(str, len, fmtStr.c_str(), &tm_time);
}
std::string Date::toFormattedStringLocal(bool showMicroseconds) const
{
// std::cout<<"toFormattedString"<<std::endl;
char buf[128] = {0};
time_t seconds =
static_cast<time_t>(microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC);
struct tm tm_time;
#ifndef _WIN32
localtime_r(&seconds, &tm_time);
#else
localtime_s(&tm_time, &seconds);
#endif
if (showMicroseconds)
{
int microseconds =
static_cast<int>(microSecondsSinceEpoch_ % MICRO_SECONDS_PRE_SEC);
snprintf(buf,
sizeof(buf),
"%4d%02d%02d %02d:%02d:%02d.%06d",
tm_time.tm_year + 1900,
tm_time.tm_mon + 1,
tm_time.tm_mday,
tm_time.tm_hour,
tm_time.tm_min,
tm_time.tm_sec,
microseconds);
}
else
{
snprintf(buf,
sizeof(buf),
"%4d%02d%02d %02d:%02d:%02d",
tm_time.tm_year + 1900,
tm_time.tm_mon + 1,
tm_time.tm_mday,
tm_time.tm_hour,
tm_time.tm_min,
tm_time.tm_sec);
}
return buf;
}
std::string Date::toDbStringLocal() const
{
char buf[128] = {0};
time_t seconds =
static_cast<time_t>(microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC);
struct tm tm_time;
#ifndef _WIN32
localtime_r(&seconds, &tm_time);
#else
localtime_s(&tm_time, &seconds);
#endif
bool showMicroseconds =
(microSecondsSinceEpoch_ % MICRO_SECONDS_PRE_SEC != 0);
if (showMicroseconds)
{
int microseconds =
static_cast<int>(microSecondsSinceEpoch_ % MICRO_SECONDS_PRE_SEC);
snprintf(buf,
sizeof(buf),
"%4d-%02d-%02d %02d:%02d:%02d.%06d",
tm_time.tm_year + 1900,
tm_time.tm_mon + 1,
tm_time.tm_mday,
tm_time.tm_hour,
tm_time.tm_min,
tm_time.tm_sec,
microseconds);
}
else
{
if (*this == roundDay())
{
snprintf(buf,
sizeof(buf),
"%4d-%02d-%02d",
tm_time.tm_year + 1900,
tm_time.tm_mon + 1,
tm_time.tm_mday);
}
else
{
snprintf(buf,
sizeof(buf),
"%4d-%02d-%02d %02d:%02d:%02d",
tm_time.tm_year + 1900,
tm_time.tm_mon + 1,
tm_time.tm_mday,
tm_time.tm_hour,
tm_time.tm_min,
tm_time.tm_sec);
}
}
return buf;
}
Date Date::fromDbStringLocal(const std::string &datetime)
{
unsigned int year = {0}, month = {0}, day = {0}, hour = {0}, minute = {0},
second = {0}, microSecond = {0};
std::vector<std::string> &&v = splitString(datetime, " ");
if (2 == v.size())
{
// date
std::vector<std::string> date = splitString(v[0], "-");
if (3 == date.size())
{
year = std::stol(date[0]);
month = std::stol(date[1]);
day = std::stol(date[2]);
std::vector<std::string> time = splitString(v[1], ":");
if (2 < time.size())
{
hour = std::stol(time[0]);
minute = std::stol(time[1]);
auto seconds = splitString(time[2], ".");
second = std::stol(seconds[0]);
if (1 < seconds.size())
{
if (seconds[1].length() > 6)
{
seconds[1].resize(6);
}
else if (seconds[1].length() < 6)
{
seconds[1].append(6 - seconds[1].length(), '0');
}
microSecond = std::stol(seconds[1]);
}
}
}
}
return std::move(
trantor::Date(year, month, day, hour, minute, second, microSecond));
}
std::string Date::toCustomedFormattedStringLocal(const std::string &fmtStr,
bool showMicroseconds) const
{
char buf[256] = {0};
time_t seconds =
static_cast<time_t>(microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC);
struct tm tm_time;
#ifndef _WIN32
localtime_r(&seconds, &tm_time);
#else
localtime_s(&tm_time, &seconds);
#endif
strftime(buf, sizeof(buf), fmtStr.c_str(), &tm_time);
if (!showMicroseconds)
return std::string(buf);
char decimals[12] = {0};
int microseconds =
static_cast<int>(microSecondsSinceEpoch_ % MICRO_SECONDS_PRE_SEC);
snprintf(decimals, sizeof(decimals), ".%06d", microseconds);
return std::string(buf) + decimals;
}
Date::Date(unsigned int year,
unsigned int month,
unsigned int day,
unsigned int hour,
unsigned int minute,
unsigned int second,
unsigned int microSecond)
{
struct tm tm;
memset(&tm, 0, sizeof(tm));
tm.tm_isdst = -1;
time_t epoch;
tm.tm_year = year - 1900;
tm.tm_mon = month - 1;
tm.tm_mday = day;
tm.tm_hour = hour;
tm.tm_min = minute;
tm.tm_sec = second;
epoch = mktime(&tm);
microSecondsSinceEpoch_ = epoch * MICRO_SECONDS_PRE_SEC + microSecond;
}
} // namespace trantor

View File

@ -1,281 +0,0 @@
/**
*
* @file Date.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/exports.h>
#include <stdint.h>
#include <string>
#define MICRO_SECONDS_PRE_SEC 1000000
namespace trantor
{
/**
* @brief This class represents a time point.
*
*/
class TRANTOR_EXPORT Date
{
public:
Date() : microSecondsSinceEpoch_(0){};
/**
* @brief Construct a new Date instance.
*
* @param microSec The microseconds from 1970-01-01 00:00:00.
*/
explicit Date(int64_t microSec) : microSecondsSinceEpoch_(microSec){};
/**
* @brief Construct a new Date instance.
*
* @param year
* @param month
* @param day
* @param hour
* @param minute
* @param second
* @param microSecond
*/
Date(unsigned int year,
unsigned int month,
unsigned int day,
unsigned int hour = 0,
unsigned int minute = 0,
unsigned int second = 0,
unsigned int microSecond = 0);
/**
* @brief Create a Date object that represents the current time.
*
* @return const Date
*/
static const Date date();
/**
* @brief Same as the date() method.
*
* @return const Date
*/
static const Date now()
{
return Date::date();
}
/**
* @brief Return a new Date instance that represents the time after some
* seconds from *this.
*
* @param second
* @return const Date
*/
const Date after(double second) const;
/**
* @brief Return a new Date instance that equals to *this, but with zero
* microseconds.
*
* @return const Date
*/
const Date roundSecond() const;
/// Create a Date object equal to * this, but numbers of hours, minutes,
/// seconds and microseconds are zero.
/**
* @brief Return a new Date instance that equals to * this, but with zero
* hours, minutes, seconds and microseconds.
*
* @return const Date
*/
const Date roundDay() const;
~Date(){};
/**
* @brief Return true if the time point is equal to another.
*
*/
bool operator==(const Date &date) const
{
return microSecondsSinceEpoch_ == date.microSecondsSinceEpoch_;
}
/**
* @brief Return true if the time point is not equal to another.
*
*/
bool operator!=(const Date &date) const
{
return microSecondsSinceEpoch_ != date.microSecondsSinceEpoch_;
}
/**
* @brief Return true if the time point is earlier than another.
*
*/
bool operator<(const Date &date) const
{
return microSecondsSinceEpoch_ < date.microSecondsSinceEpoch_;
}
/**
* @brief Return true if the time point is later than another.
*
*/
bool operator>(const Date &date) const
{
return microSecondsSinceEpoch_ > date.microSecondsSinceEpoch_;
}
/**
* @brief Return true if the time point is not earlier than another.
*
*/
bool operator>=(const Date &date) const
{
return microSecondsSinceEpoch_ >= date.microSecondsSinceEpoch_;
}
/**
* @brief Return true if the time point is not later than another.
*
*/
bool operator<=(const Date &date) const
{
return microSecondsSinceEpoch_ <= date.microSecondsSinceEpoch_;
}
/**
* @brief Get the number of milliseconds since 1970-01-01 00:00.
*
* @return int64_t
*/
int64_t microSecondsSinceEpoch() const
{
return microSecondsSinceEpoch_;
}
/**
* @brief Get the number of seconds since 1970-01-01 00:00.
*
* @return int64_t
*/
int64_t secondsSinceEpoch() const
{
return microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC;
}
/**
* @brief Get the tm struct for the time point.
*
* @return struct tm
*/
struct tm tmStruct() const;
/**
* @brief Generate a UTC time string
* @example:
* 20180101 10:10:25 //If the @param showMicroseconds is false
* 20180101 10:10:25:102414 //If the @param showMicroseconds is true
*/
std::string toFormattedString(bool showMicroseconds) const;
/**
* @brief Generate a UTC time string formated by the @param fmtStr
* The @param fmtStr is the format string for the function strftime()
* @example:
* 2018-01-01 10:10:25 //If the @param fmtStr is "%Y-%m-%d
* %H:%M:%S" and the @param showMicroseconds is false 2018-01-01
* 10:10:25:102414 //If the @param fmtStr is "%Y-%m-%d %H:%M:%S" and the
* @param showMicroseconds is true
*/
std::string toCustomedFormattedString(const std::string &fmtStr,
bool showMicroseconds = false) const;
/**
* @brief Generate a local time zone string, the format of the string is
* same as the mothed toFormattedString
*
* @param showMicroseconds
* @return std::string
*/
std::string toFormattedStringLocal(bool showMicroseconds) const;
/**
* @brief Generate a local time zone string formated by the @param fmtStr
*
* @param fmtStr
* @param showMicroseconds
* @return std::string
*/
std::string toCustomedFormattedStringLocal(
const std::string &fmtStr,
bool showMicroseconds = false) const;
/**
* @brief Generate a local time zone string for database.
* @example:
* 2018-01-01 //If hours, minutes, seconds and
* microseconds are zero 2018-01-01 10:10:25 //If the microsecond
* is zero 2018-01-01 10:10:25:102414 //If the microsecond is not zero
*/
std::string toDbStringLocal() const;
/**
* @brief From DB string to trantor local time zone.
*
* Inverse of toDbStringLocal()
*/
static Date fromDbStringLocal(const std::string &datetime);
/**
* @brief Generate a UTC time string.
*
* @param fmtStr The format string.
* @param str The string buffer for the generated time string.
* @param len The length of the string buffer.
*/
void toCustomedFormattedString(const std::string &fmtStr,
char *str,
size_t len) const; // UTC
/**
* @brief Return true if the time point is in a same second as another.
*
* @param date
* @return true
* @return false
*/
bool isSameSecond(const Date &date) const
{
return microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC ==
date.microSecondsSinceEpoch_ / MICRO_SECONDS_PRE_SEC;
}
/**
* @brief Swap the time point with another.
*
* @param that
*/
void swap(Date &that)
{
std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_);
}
private:
int64_t microSecondsSinceEpoch_{0};
};
} // namespace trantor

View File

@ -1,53 +0,0 @@
/**
*
* Funcs.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <algorithm>
#include <vector>
namespace trantor
{
inline uint64_t hton64(uint64_t n)
{
static const int one = 1;
static const char sig = *(char *)&one;
if (sig == 0)
return n; // for big endian machine just return the input
char *ptr = reinterpret_cast<char *>(&n);
std::reverse(ptr, ptr + sizeof(uint64_t));
return n;
}
inline uint64_t ntoh64(uint64_t n)
{
return hton64(n);
}
inline std::vector<std::string> splitString(const std::string &s,
const std::string &delimiter,
bool acceptEmptyString = false)
{
if (delimiter.empty())
return std::vector<std::string>{};
std::vector<std::string> v;
size_t last = 0;
size_t next = 0;
while ((next = s.find(delimiter, last)) != std::string::npos)
{
if (next > last || acceptEmptyString)
v.push_back(s.substr(last, next - last));
last = next + delimiter.length();
}
if (s.length() > last || acceptEmptyString)
v.push_back(s.substr(last));
return v;
}
} // namespace trantor

View File

@ -1,114 +0,0 @@
/**
*
* @file LockFreeQueue.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <atomic>
#include <type_traits>
#include <memory>
#include <assert.h>
namespace trantor
{
/**
* @brief This class template represents a lock-free multiple producers single
* consumer queue
*
* @tparam T The type of the items in the queue.
*/
template <typename T>
class MpscQueue : public NonCopyable
{
public:
MpscQueue()
: head_(new BufferNode), tail_(head_.load(std::memory_order_relaxed))
{
}
~MpscQueue()
{
T output;
while (this->dequeue(output))
{
}
BufferNode *front = head_.load(std::memory_order_relaxed);
delete front;
}
/**
* @brief Put a item into the queue.
*
* @param input
* @note This method can be called in multiple threads.
*/
void enqueue(T &&input)
{
BufferNode *node{new BufferNode(std::move(input))};
BufferNode *prevhead{head_.exchange(node, std::memory_order_acq_rel)};
prevhead->next_.store(node, std::memory_order_release);
}
void enqueue(const T &input)
{
BufferNode *node{new BufferNode(input)};
BufferNode *prevhead{head_.exchange(node, std::memory_order_acq_rel)};
prevhead->next_.store(node, std::memory_order_release);
}
/**
* @brief Get a item from the queue.
*
* @param output
* @return false if the queue is empty.
* @note This method must be called in a single thread.
*/
bool dequeue(T &output)
{
BufferNode *tail = tail_.load(std::memory_order_relaxed);
BufferNode *next = tail->next_.load(std::memory_order_acquire);
if (next == nullptr)
{
return false;
}
output = std::move(*(next->dataPtr_));
delete next->dataPtr_;
tail_.store(next, std::memory_order_release);
delete tail;
return true;
}
bool empty()
{
BufferNode *tail = tail_.load(std::memory_order_relaxed);
BufferNode *next = tail->next_.load(std::memory_order_acquire);
return next == nullptr;
}
private:
struct BufferNode
{
BufferNode() = default;
BufferNode(const T &data) : dataPtr_(new T(data))
{
}
BufferNode(T &&data) : dataPtr_(new T(std::move(data)))
{
}
T *dataPtr_;
std::atomic<BufferNode *> next_{nullptr};
};
std::atomic<BufferNode *> head_;
std::atomic<BufferNode *> tail_;
};
} // namespace trantor

View File

@ -1,273 +0,0 @@
/**
*
* LogStream.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
// taken from muduo lib
#include <trantor/utils/LogStream.h>
#include <algorithm>
#include <limits>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <iostream>
using namespace trantor;
using namespace trantor::detail;
namespace trantor
{
namespace detail
{
const char digits[] = "9876543210123456789";
const char *zero = digits + 9;
const char digitsHex[] = "0123456789ABCDEF";
// Efficient Integer to String Conversions, by Matthew Wilson.
template <typename T>
size_t convert(char buf[], T value)
{
T i = value;
char *p = buf;
do
{
int lsd = static_cast<int>(i % 10);
i /= 10;
*p++ = zero[lsd];
} while (i != 0);
if (value < 0)
{
*p++ = '-';
}
*p = '\0';
std::reverse(buf, p);
return p - buf;
}
size_t convertHex(char buf[], uintptr_t value)
{
uintptr_t i = value;
char *p = buf;
do
{
int lsd = static_cast<int>(i % 16);
i /= 16;
*p++ = digitsHex[lsd];
} while (i != 0);
*p = '\0';
std::reverse(buf, p);
return p - buf;
}
template class FixedBuffer<kSmallBuffer>;
template class FixedBuffer<kLargeBuffer>;
} // namespace detail
} // namespace trantor
template <int SIZE>
const char *FixedBuffer<SIZE>::debugString()
{
*cur_ = '\0';
return data_;
}
template <int SIZE>
void FixedBuffer<SIZE>::cookieStart()
{
}
template <int SIZE>
void FixedBuffer<SIZE>::cookieEnd()
{
}
template <typename T>
void LogStream::formatInteger(T v)
{
constexpr static int kMaxNumericSize = std::numeric_limits<T>::digits10 + 4;
if (exBuffer_.empty())
{
if (buffer_.avail() >= kMaxNumericSize)
{
size_t len = convert(buffer_.current(), v);
buffer_.add(len);
return;
}
else
{
exBuffer_.append(buffer_.data(), buffer_.length());
}
}
auto oldLen = exBuffer_.length();
exBuffer_.resize(oldLen + kMaxNumericSize);
size_t len = convert(&exBuffer_[oldLen], v);
exBuffer_.resize(oldLen + len);
}
LogStream &LogStream::operator<<(short v)
{
*this << static_cast<int>(v);
return *this;
}
LogStream &LogStream::operator<<(unsigned short v)
{
*this << static_cast<unsigned int>(v);
return *this;
}
LogStream &LogStream::operator<<(int v)
{
formatInteger(v);
return *this;
}
LogStream &LogStream::operator<<(unsigned int v)
{
formatInteger(v);
return *this;
}
LogStream &LogStream::operator<<(long v)
{
formatInteger(v);
return *this;
}
LogStream &LogStream::operator<<(unsigned long v)
{
formatInteger(v);
return *this;
}
LogStream &LogStream::operator<<(const long long &v)
{
formatInteger(v);
return *this;
}
LogStream &LogStream::operator<<(const unsigned long long &v)
{
formatInteger(v);
return *this;
}
LogStream &LogStream::operator<<(const void *p)
{
uintptr_t v = reinterpret_cast<uintptr_t>(p);
constexpr static int kMaxNumericSize =
std::numeric_limits<uintptr_t>::digits / 4 + 4;
if (exBuffer_.empty())
{
if (buffer_.avail() >= kMaxNumericSize)
{
char *buf = buffer_.current();
buf[0] = '0';
buf[1] = 'x';
size_t len = convertHex(buf + 2, v);
buffer_.add(len + 2);
return *this;
}
else
{
exBuffer_.append(buffer_.data(), buffer_.length());
}
}
auto oldLen = exBuffer_.length();
exBuffer_.resize(oldLen + kMaxNumericSize);
char *buf = &exBuffer_[oldLen];
buf[0] = '0';
buf[1] = 'x';
size_t len = convertHex(buf + 2, v);
exBuffer_.resize(oldLen + len + 2);
return *this;
}
// TODO: replace this with Grisu3 by Florian Loitsch.
LogStream &LogStream::operator<<(const double &v)
{
constexpr static int kMaxNumericSize = 32;
if (exBuffer_.empty())
{
if (buffer_.avail() >= kMaxNumericSize)
{
int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v);
buffer_.add(len);
return *this;
}
else
{
exBuffer_.append(buffer_.data(), buffer_.length());
}
}
auto oldLen = exBuffer_.length();
exBuffer_.resize(oldLen + kMaxNumericSize);
int len = snprintf(&(exBuffer_[oldLen]), kMaxNumericSize, "%.12g", v);
exBuffer_.resize(oldLen + len);
return *this;
}
LogStream &LogStream::operator<<(const long double &v)
{
constexpr static int kMaxNumericSize = 48;
if (exBuffer_.empty())
{
if (buffer_.avail() >= kMaxNumericSize)
{
int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12Lg", v);
buffer_.add(len);
return *this;
}
else
{
exBuffer_.append(buffer_.data(), buffer_.length());
}
}
auto oldLen = exBuffer_.length();
exBuffer_.resize(oldLen + kMaxNumericSize);
int len = snprintf(&(exBuffer_[oldLen]), kMaxNumericSize, "%.12Lg", v);
exBuffer_.resize(oldLen + len);
return *this;
}
template <typename T>
Fmt::Fmt(const char *fmt, T val)
{
length_ = snprintf(buf_, sizeof buf_, fmt, val);
assert(static_cast<size_t>(length_) < sizeof buf_);
}
// Explicit instantiations
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, char);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, short);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, unsigned short);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, int);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, unsigned int);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, long);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, unsigned long);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, long long);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, unsigned long long);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, float);
template TRANTOR_EXPORT Fmt::Fmt(const char *fmt, double);

View File

@ -1,277 +0,0 @@
/**
*
* @file LogStream.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
// Taken from muduo lib and modified. Classes in this file are used internally.
#include <trantor/utils/NonCopyable.h>
#include <trantor/exports.h>
#include <assert.h>
#include <string.h> // memcpy
#include <string>
namespace trantor
{
namespace detail
{
static constexpr size_t kSmallBuffer{4000};
static constexpr size_t kLargeBuffer{4000 * 1000};
template <int SIZE>
class TRANTOR_EXPORT FixedBuffer : NonCopyable
{
public:
FixedBuffer() : cur_(data_)
{
setCookie(cookieStart);
}
~FixedBuffer()
{
setCookie(cookieEnd);
}
bool append(const char * /*restrict*/ buf, size_t len)
{
if ((size_t)(avail()) > len)
{
memcpy(cur_, buf, len);
cur_ += len;
return true;
}
return false;
}
const char *data() const
{
return data_;
}
int length() const
{
return static_cast<int>(cur_ - data_);
}
// write to data_ directly
char *current()
{
return cur_;
}
int avail() const
{
return static_cast<int>(end() - cur_);
}
void add(size_t len)
{
cur_ += len;
}
void reset()
{
cur_ = data_;
}
void zeroBuffer()
{
memset(data_, 0, sizeof(data_));
}
// for used by GDB
const char *debugString();
void setCookie(void (*cookie)())
{
cookie_ = cookie;
}
// for used by unit test
std::string toString() const
{
return std::string(data_, length());
}
// StringPiece toStringPiece() const { return StringPiece(data_, length());
// }
private:
const char *end() const
{
return data_ + sizeof data_;
}
// Must be outline function for cookies.
static void cookieStart();
static void cookieEnd();
void (*cookie_)();
char data_[SIZE];
char *cur_;
};
} // namespace detail
class TRANTOR_EXPORT LogStream : NonCopyable
{
using self = LogStream;
public:
using Buffer = detail::FixedBuffer<detail::kSmallBuffer>;
self &operator<<(bool v)
{
append(v ? "1" : "0", 1);
return *this;
}
self &operator<<(short);
self &operator<<(unsigned short);
self &operator<<(int);
self &operator<<(unsigned int);
self &operator<<(long);
self &operator<<(unsigned long);
self &operator<<(const long long &);
self &operator<<(const unsigned long long &);
self &operator<<(const void *);
self &operator<<(float &v)
{
*this << static_cast<double>(v);
return *this;
}
self &operator<<(const double &);
self &operator<<(const long double &v);
self &operator<<(char v)
{
append(&v, 1);
return *this;
}
// self& operator<<(signed char);
// self& operator<<(unsigned char);
template <int N>
self &operator<<(const char (&buf)[N])
{
assert(strnlen(buf, N) == N - 1);
append(buf, N - 1);
return *this;
}
self &operator<<(char *str)
{
if (str)
{
append(str, strlen(str));
}
else
{
append("(null)", 6);
}
return *this;
}
self &operator<<(const char *str)
{
if (str)
{
append(str, strlen(str));
}
else
{
append("(null)", 6);
}
return *this;
}
self &operator<<(const unsigned char *str)
{
return operator<<(reinterpret_cast<const char *>(str));
}
self &operator<<(const std::string &v)
{
append(v.c_str(), v.size());
return *this;
}
void append(const char *data, size_t len)
{
if (exBuffer_.empty())
{
if (!buffer_.append(data, len))
{
exBuffer_.append(buffer_.data(), buffer_.length());
exBuffer_.append(data, len);
}
}
else
{
exBuffer_.append(data, len);
}
}
// const Buffer& buffer() const { return buffer_; }
const char *bufferData() const
{
if (!exBuffer_.empty())
{
return exBuffer_.data();
}
return buffer_.data();
}
size_t bufferLength() const
{
if (!exBuffer_.empty())
{
return exBuffer_.length();
}
return buffer_.length();
}
void resetBuffer()
{
buffer_.reset();
exBuffer_.clear();
}
private:
template <typename T>
void formatInteger(T);
Buffer buffer_;
std::string exBuffer_;
};
class TRANTOR_EXPORT Fmt // : boost::noncopyable
{
public:
template <typename T>
Fmt(const char *fmt, T val);
const char *data() const
{
return buf_;
}
int length() const
{
return length_;
}
private:
char buf_[48];
int length_;
};
inline LogStream &operator<<(LogStream &s, const Fmt &fmt)
{
s.append(fmt.data(), fmt.length());
return s;
}
} // namespace trantor

View File

@ -1,212 +0,0 @@
/**
*
* Logger.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/utils/Logger.h>
#include <stdio.h>
#include <thread>
#ifndef _WIN32
#include <unistd.h>
#include <sys/syscall.h>
#else
#include <sstream>
#endif
#ifdef __FreeBSD__
#include <pthread_np.h>
#endif
namespace trantor
{
// helper class for known string length at compile time
class T
{
public:
T(const char *str, unsigned len) : str_(str), len_(len)
{
assert(strlen(str) == len_);
}
const char *str_;
const unsigned len_;
};
const char *strerror_tl(int savedErrno)
{
#ifndef _MSC_VER
return strerror(savedErrno);
#else
static thread_local char errMsg[64];
(void)strerror_s<sizeof errMsg>(errMsg, savedErrno);
return errMsg;
#endif
}
inline LogStream &operator<<(LogStream &s, T v)
{
s.append(v.str_, v.len_);
return s;
}
inline LogStream &operator<<(LogStream &s, const Logger::SourceFile &v)
{
s.append(v.data_, v.size_);
return s;
}
} // namespace trantor
using namespace trantor;
static thread_local uint64_t lastSecond_{0};
static thread_local char lastTimeString_[32] = {0};
#ifdef __linux__
static thread_local pid_t threadId_{0};
#else
static thread_local uint64_t threadId_{0};
#endif
// static thread_local LogStream logStream_;
void Logger::formatTime()
{
uint64_t now = static_cast<uint64_t>(date_.secondsSinceEpoch());
uint64_t microSec =
static_cast<uint64_t>(date_.microSecondsSinceEpoch() -
date_.roundSecond().microSecondsSinceEpoch());
if (now != lastSecond_)
{
lastSecond_ = now;
#ifndef _MSC_VER
strncpy(lastTimeString_,
date_.toFormattedString(false).c_str(),
sizeof(lastTimeString_) - 1);
#else
strncpy_s<sizeof lastTimeString_>(
lastTimeString_,
date_.toFormattedString(false).c_str(),
sizeof(lastTimeString_) - 1);
#endif
}
logStream_ << T(lastTimeString_, 17);
char tmp[32];
snprintf(tmp,
sizeof(tmp),
".%06llu UTC ",
static_cast<long long unsigned int>(microSec));
logStream_ << T(tmp, 12);
#ifdef __linux__
if (threadId_ == 0)
threadId_ = static_cast<pid_t>(::syscall(SYS_gettid));
#elif defined __FreeBSD__
if (threadId_ == 0)
{
threadId_ = pthread_getthreadid_np();
}
#elif defined __OpenBSD__
if (threadId_ == 0)
{
threadId_ = getthrid();
}
#elif defined _WIN32
if (threadId_ == 0)
{
std::stringstream ss;
ss << std::this_thread::get_id();
threadId_ = std::stoull(ss.str());
}
#else
if (threadId_ == 0)
{
pthread_threadid_np(NULL, &threadId_);
}
#endif
logStream_ << threadId_;
}
static const char *logLevelStr[Logger::LogLevel::kNumberOfLogLevels] = {
" TRACE ",
" DEBUG ",
" INFO ",
" WARN ",
" ERROR ",
" FATAL ",
};
Logger::Logger(SourceFile file, int line)
: sourceFile_(file), fileLine_(line), level_(kInfo)
{
formatTime();
logStream_ << T(logLevelStr[level_], 7);
}
Logger::Logger(SourceFile file, int line, LogLevel level)
: sourceFile_(file), fileLine_(line), level_(level)
{
formatTime();
logStream_ << T(logLevelStr[level_], 7);
}
Logger::Logger(SourceFile file, int line, LogLevel level, const char *func)
: sourceFile_(file), fileLine_(line), level_(level)
{
formatTime();
logStream_ << T(logLevelStr[level_], 7) << "[" << func << "] ";
}
Logger::Logger(SourceFile file, int line, bool)
: sourceFile_(file), fileLine_(line), level_(kFatal)
{
formatTime();
logStream_ << T(logLevelStr[level_], 7);
if (errno != 0)
{
logStream_ << strerror_tl(errno) << " (errno=" << errno << ") ";
}
}
RawLogger::~RawLogger()
{
if (index_ < 0)
{
auto &oFunc = Logger::outputFunc_();
if (!oFunc)
return;
oFunc(logStream_.bufferData(), logStream_.bufferLength());
}
else
{
auto &oFunc = Logger::outputFunc_(index_);
if (!oFunc)
return;
oFunc(logStream_.bufferData(), logStream_.bufferLength());
}
}
Logger::~Logger()
{
logStream_ << T(" - ", 3) << sourceFile_ << ':' << fileLine_ << '\n';
if (index_ < 0)
{
auto &oFunc = Logger::outputFunc_();
if (!oFunc)
return;
oFunc(logStream_.bufferData(), logStream_.bufferLength());
if (level_ >= kError)
Logger::flushFunc_()();
}
else
{
auto &oFunc = Logger::outputFunc_(index_);
if (!oFunc)
return;
oFunc(logStream_.bufferData(), logStream_.bufferLength());
if (level_ >= kError)
Logger::flushFunc_(index_)();
}
// logStream_.resetBuffer();
}
LogStream &Logger::stream()
{
return logStream_;
}

View File

@ -1,383 +0,0 @@
/**
*
* @file Logger.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/Date.h>
#include <trantor/utils/LogStream.h>
#include <trantor/exports.h>
#include <cstring>
#include <functional>
#include <iostream>
#include <vector>
namespace trantor
{
/**
* @brief This class implements log functions.
*
*/
class TRANTOR_EXPORT Logger : public NonCopyable
{
public:
enum LogLevel
{
kTrace = 0,
kDebug,
kInfo,
kWarn,
kError,
kFatal,
kNumberOfLogLevels
};
/**
* @brief Calculate of basename of source files in compile time.
*
*/
class SourceFile
{
public:
template <int N>
inline SourceFile(const char (&arr)[N]) : data_(arr), size_(N - 1)
{
// std::cout<<data_<<std::endl;
const char *slash = strrchr(data_, '/'); // builtin function
if (slash)
{
data_ = slash + 1;
size_ -= static_cast<int>(data_ - arr);
}
}
explicit SourceFile(const char *filename) : data_(filename)
{
const char *slash = strrchr(filename, '/');
if (slash)
{
data_ = slash + 1;
}
size_ = static_cast<int>(strlen(data_));
}
const char *data_;
int size_;
};
Logger(SourceFile file, int line);
Logger(SourceFile file, int line, LogLevel level);
Logger(SourceFile file, int line, bool isSysErr);
Logger(SourceFile file, int line, LogLevel level, const char *func);
~Logger();
Logger &setIndex(int index)
{
index_ = index;
return *this;
}
LogStream &stream();
/**
* @brief Set the output function.
*
* @param outputFunc The function to output a log message.
* @param flushFunc The function to flush.
* @note Logs are output to the standard output by default.
*/
static void setOutputFunction(
std::function<void(const char *msg, const uint64_t len)> outputFunc,
std::function<void()> flushFunc,
int index = -1)
{
if (index < 0)
{
outputFunc_() = outputFunc;
flushFunc_() = flushFunc;
}
else
{
outputFunc_(index) = outputFunc;
flushFunc_(index) = flushFunc;
}
}
/**
* @brief Set the log level. Logs below the level are not printed.
*
* @param level
*/
static void setLogLevel(LogLevel level)
{
logLevel_() = level;
}
/**
* @brief Get the current log level.
*
* @return LogLevel
*/
static LogLevel logLevel()
{
return logLevel_();
}
protected:
static void defaultOutputFunction(const char *msg, const uint64_t len)
{
fwrite(msg, 1, len, stdout);
}
static void defaultFlushFunction()
{
fflush(stdout);
}
void formatTime();
static LogLevel &logLevel_()
{
#ifdef RELEASE
static LogLevel logLevel = LogLevel::kInfo;
#else
static LogLevel logLevel = LogLevel::kDebug;
#endif
return logLevel;
}
static std::function<void(const char *msg, const uint64_t len)>
&outputFunc_()
{
static std::function<void(const char *msg, const uint64_t len)>
outputFunc = Logger::defaultOutputFunction;
return outputFunc;
}
static std::function<void()> &flushFunc_()
{
static std::function<void()> flushFunc = Logger::defaultFlushFunction;
return flushFunc;
}
static std::function<void(const char *msg, const uint64_t len)>
&outputFunc_(size_t index)
{
static std::vector<
std::function<void(const char *msg, const uint64_t len)>>
outputFuncs;
if (index < outputFuncs.size())
{
return outputFuncs[index];
}
while (index >= outputFuncs.size())
{
outputFuncs.emplace_back(outputFunc_());
}
return outputFuncs[index];
}
static std::function<void()> &flushFunc_(size_t index)
{
static std::vector<std::function<void()>> flushFuncs;
if (index < flushFuncs.size())
{
return flushFuncs[index];
}
while (index >= flushFuncs.size())
{
flushFuncs.emplace_back(flushFunc_());
}
return flushFuncs[index];
}
friend class RawLogger;
LogStream logStream_;
Date date_{Date::now()};
SourceFile sourceFile_;
int fileLine_;
LogLevel level_;
int index_{-1};
};
class TRANTOR_EXPORT RawLogger : public NonCopyable
{
public:
~RawLogger();
RawLogger &setIndex(int index)
{
index_ = index;
return *this;
}
LogStream &stream()
{
return logStream_;
}
private:
LogStream logStream_;
int index_{-1};
};
#ifdef NDEBUG
#define LOG_TRACE \
if (0) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#else
#define LOG_TRACE \
if (trantor::Logger::logLevel() <= trantor::Logger::kTrace) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define LOG_TRACE_TO(index) \
if (trantor::Logger::logLevel() <= trantor::Logger::kTrace) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.setIndex(index) \
.stream()
#endif
#define LOG_DEBUG \
if (trantor::Logger::logLevel() <= trantor::Logger::kDebug) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kDebug, __func__) \
.stream()
#define LOG_DEBUG_TO(index) \
if (trantor::Logger::logLevel() <= trantor::Logger::kDebug) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kDebug, __func__) \
.setIndex(index) \
.stream()
#define LOG_INFO \
if (trantor::Logger::logLevel() <= trantor::Logger::kInfo) \
trantor::Logger(__FILE__, __LINE__).stream()
#define LOG_INFO_TO(index) \
if (trantor::Logger::logLevel() <= trantor::Logger::kInfo) \
trantor::Logger(__FILE__, __LINE__).setIndex(index).stream()
#define LOG_WARN \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kWarn).stream()
#define LOG_WARN_TO(index) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kWarn) \
.setIndex(index) \
.stream()
#define LOG_ERROR \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kError).stream()
#define LOG_ERROR_TO(index) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kError) \
.setIndex(index) \
.stream()
#define LOG_FATAL \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kFatal).stream()
#define LOG_FATAL_TO(index) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kFatal) \
.setIndex(index) \
.stream()
#define LOG_SYSERR trantor::Logger(__FILE__, __LINE__, true).stream()
#define LOG_SYSERR_TO(index) \
trantor::Logger(__FILE__, __LINE__, true).setIndex(index).stream()
#define LOG_RAW trantor::RawLogger().stream()
#define LOG_RAW_TO(index) trantor::RawLogger().setIndex(index).stream()
#define LOG_TRACE_IF(cond) \
if ((trantor::Logger::logLevel() <= trantor::Logger::kTrace) && (cond)) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define LOG_DEBUG_IF(cond) \
if ((Tensor::Logger::logLevel() <= Tensor::Logger::kDebug) && (cond)) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define LOG_INFO_IF(cond) \
if ((Tensor::Logger::logLevel() <= Tensor::Logger::kInfo) && (cond)) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define LOG_WARN_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define LOG_ERROR_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define LOG_FATAL_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#ifdef NDEBUG
#define DLOG_TRACE \
if (0) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define DLOG_DEBUG \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define DLOG_INFO \
if (0) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define DLOG_WARN \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define DLOG_ERROR \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define DLOG_FATAL \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#define DLOG_TRACE_IF(cond) \
if (0) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define DLOG_DEBUG_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define DLOG_INFO_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define DLOG_WARN_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define DLOG_ERROR_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define DLOG_FATAL_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#else
#define DLOG_TRACE \
if (trantor::Logger::logLevel() <= trantor::Logger::kTrace) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define DLOG_DEBUG \
if (Tensor::Logger::logLevel() <= Tensor::Logger::kDebug) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define DLOG_INFO \
if (Tensor::Logger::logLevel() <= Tensor::Logger::kInfo) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define DLOG_WARN \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define DLOG_ERROR \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define DLOG_FATAL \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#define DLOG_TRACE_IF(cond) \
if ((trantor::Logger::logLevel() <= trantor::Logger::kTrace) && (cond)) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define DLOG_DEBUG_IF(cond) \
if ((Tensor::Logger::logLevel() <= Tensor::Logger::kDebug) && (cond)) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define DLOG_INFO_IF(cond) \
if ((Tensor::Logger::logLevel() <= Tensor::Logger::kInfo) && (cond)) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define DLOG_WARN_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define DLOG_ERROR_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define DLOG_FATAL_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#endif
const char *strerror_tl(int savedErrno);
} // namespace trantor

View File

@ -1,232 +0,0 @@
/**
*
* MsgBuffer.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/utils/MsgBuffer.h>
#include <trantor/utils/Funcs.h>
#include <string.h>
#ifndef _WIN32
#include <sys/uio.h>
#include <netinet/in.h>
#else
#include <WindowsSupport.h>
#include <winsock2.h>
#endif
#include <errno.h>
#include <assert.h>
using namespace trantor;
namespace trantor
{
static constexpr size_t kBufferOffset{8};
}
MsgBuffer::MsgBuffer(size_t len)
: head_(kBufferOffset), initCap_(len), buffer_(len + head_), tail_(head_)
{
}
void MsgBuffer::ensureWritableBytes(size_t len)
{
if (writableBytes() >= len)
return;
if (head_ + writableBytes() >=
(len + kBufferOffset)) // move readable bytes
{
std::copy(begin() + head_, begin() + tail_, begin() + kBufferOffset);
tail_ = kBufferOffset + (tail_ - head_);
head_ = kBufferOffset;
return;
}
// create new buffer
size_t newLen;
if ((buffer_.size() * 2) > (kBufferOffset + readableBytes() + len))
newLen = buffer_.size() * 2;
else
newLen = kBufferOffset + readableBytes() + len;
MsgBuffer newbuffer(newLen);
newbuffer.append(*this);
swap(newbuffer);
}
void MsgBuffer::swap(MsgBuffer &buf) noexcept
{
buffer_.swap(buf.buffer_);
std::swap(head_, buf.head_);
std::swap(tail_, buf.tail_);
std::swap(initCap_, buf.initCap_);
}
void MsgBuffer::append(const MsgBuffer &buf)
{
ensureWritableBytes(buf.readableBytes());
memcpy(&buffer_[tail_], buf.peek(), buf.readableBytes());
tail_ += buf.readableBytes();
}
void MsgBuffer::append(const char *buf, size_t len)
{
ensureWritableBytes(len);
memcpy(&buffer_[tail_], buf, len);
tail_ += len;
}
void MsgBuffer::appendInt16(const uint16_t s)
{
uint16_t ss = htons(s);
append(static_cast<const char *>((void *)&ss), 2);
}
void MsgBuffer::appendInt32(const uint32_t i)
{
uint32_t ii = htonl(i);
append(static_cast<const char *>((void *)&ii), 4);
}
void MsgBuffer::appendInt64(const uint64_t l)
{
uint64_t ll = hton64(l);
append(static_cast<const char *>((void *)&ll), 8);
}
void MsgBuffer::addInFrontInt16(const uint16_t s)
{
uint16_t ss = htons(s);
addInFront(static_cast<const char *>((void *)&ss), 2);
}
void MsgBuffer::addInFrontInt32(const uint32_t i)
{
uint32_t ii = htonl(i);
addInFront(static_cast<const char *>((void *)&ii), 4);
}
void MsgBuffer::addInFrontInt64(const uint64_t l)
{
uint64_t ll = hton64(l);
addInFront(static_cast<const char *>((void *)&ll), 8);
}
uint16_t MsgBuffer::peekInt16() const
{
assert(readableBytes() >= 2);
uint16_t rs = *(static_cast<const uint16_t *>((void *)peek()));
return ntohs(rs);
}
uint32_t MsgBuffer::peekInt32() const
{
assert(readableBytes() >= 4);
uint32_t rl = *(static_cast<const uint32_t *>((void *)peek()));
return ntohl(rl);
}
uint64_t MsgBuffer::peekInt64() const
{
assert(readableBytes() >= 8);
uint64_t rll = *(static_cast<const uint64_t *>((void *)peek()));
return ntoh64(rll);
}
void MsgBuffer::retrieve(size_t len)
{
if (len >= readableBytes())
{
retrieveAll();
return;
}
head_ += len;
}
void MsgBuffer::retrieveAll()
{
if (buffer_.size() > (initCap_ * 2))
{
buffer_.resize(initCap_);
}
tail_ = head_ = kBufferOffset;
}
ssize_t MsgBuffer::readFd(int fd, int *retErrno)
{
char extBuffer[8192];
struct iovec vec[2];
size_t writable = writableBytes();
vec[0].iov_base = begin() + tail_;
vec[0].iov_len = static_cast<int>(writable);
vec[1].iov_base = extBuffer;
vec[1].iov_len = sizeof(extBuffer);
const int iovcnt = (writable < sizeof extBuffer) ? 2 : 1;
ssize_t n = ::readv(fd, vec, iovcnt);
if (n < 0)
{
*retErrno = errno;
}
else if (static_cast<size_t>(n) <= writable)
{
tail_ += n;
}
else
{
tail_ = buffer_.size();
append(extBuffer, n - writable);
}
return n;
}
std::string MsgBuffer::read(size_t len)
{
if (len > readableBytes())
len = readableBytes();
std::string ret(peek(), len);
retrieve(len);
return ret;
}
uint8_t MsgBuffer::readInt8()
{
uint8_t ret = peekInt8();
retrieve(1);
return ret;
}
uint16_t MsgBuffer::readInt16()
{
uint16_t ret = peekInt16();
retrieve(2);
return ret;
}
uint32_t MsgBuffer::readInt32()
{
uint32_t ret = peekInt32();
retrieve(4);
return ret;
}
uint64_t MsgBuffer::readInt64()
{
uint64_t ret = peekInt64();
retrieve(8);
return ret;
}
void MsgBuffer::addInFront(const char *buf, size_t len)
{
if (head_ >= len)
{
memcpy(begin() + head_ - len, buf, len);
head_ -= len;
return;
}
if (len <= writableBytes())
{
std::copy(begin() + head_, begin() + tail_, begin() + head_ + len);
memcpy(begin() + head_, buf, len);
tail_ += len;
return;
}
size_t newLen;
if (len + readableBytes() < initCap_)
newLen = initCap_;
else
newLen = len + readableBytes();
MsgBuffer newBuf(newLen);
newBuf.append(buf, len);
newBuf.append(*this);
swap(newBuf);
}

View File

@ -1,376 +0,0 @@
/**
*
* @file MsgBuffer.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <trantor/exports.h>
#include <vector>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#ifdef _WIN32
using ssize_t = long long;
#endif
namespace trantor
{
static constexpr size_t kBufferDefaultLength{2048};
static constexpr char CRLF[]{"\r\n"};
/**
* @brief This class represents a memory buffer used for sending and receiving
* data.
*
*/
class TRANTOR_EXPORT MsgBuffer
{
public:
/**
* @brief Construct a new message buffer instance.
*
* @param len The initial size of the buffer.
*/
MsgBuffer(size_t len = kBufferDefaultLength);
/**
* @brief Get the beginning of the buffer.
*
* @return const char*
*/
const char *peek() const
{
return begin() + head_;
}
/**
* @brief Get the end of the buffer where new data can be written.
*
* @return const char*
*/
const char *beginWrite() const
{
return begin() + tail_;
}
char *beginWrite()
{
return begin() + tail_;
}
/**
* @brief Get a byte value from the buffer.
*
* @return uint8_t
*/
uint8_t peekInt8() const
{
assert(readableBytes() >= 1);
return *(static_cast<const uint8_t *>((void *)peek()));
}
/**
* @brief Get a unsigned short value from the buffer.
*
* @return uint16_t
*/
uint16_t peekInt16() const;
/**
* @brief Get a unsigned int value from the buffer.
*
* @return uint32_t
*/
uint32_t peekInt32() const;
/**
* @brief Get a unsigned int64 value from the buffer.
*
* @return uint64_t
*/
uint64_t peekInt64() const;
/**
* @brief Get and remove some bytes from the buffer.
*
* @param len
* @return std::string
*/
std::string read(size_t len);
/**
* @brief Get the remove a byte value from the buffer.
*
* @return uint8_t
*/
uint8_t readInt8();
/**
* @brief Get and remove a unsigned short value from the buffer.
*
* @return uint16_t
*/
uint16_t readInt16();
/**
* @brief Get and remove a unsigned int value from the buffer.
*
* @return uint32_t
*/
uint32_t readInt32();
/**
* @brief Get and remove a unsigned int64 value from the buffer.
*
* @return uint64_t
*/
uint64_t readInt64();
/**
* @brief swap the buffer with another.
*
* @param buf
*/
void swap(MsgBuffer &buf) noexcept;
/**
* @brief Return the size of the data in the buffer.
*
* @return size_t
*/
size_t readableBytes() const
{
return tail_ - head_;
}
/**
* @brief Return the size of the empty part in the buffer
*
* @return size_t
*/
size_t writableBytes() const
{
return buffer_.size() - tail_;
}
/**
* @brief Append new data to the buffer.
*
*/
void append(const MsgBuffer &buf);
template <int N>
void append(const char (&buf)[N])
{
assert(strnlen(buf, N) == N - 1);
append(buf, N - 1);
}
void append(const char *buf, size_t len);
void append(const std::string &buf)
{
append(buf.c_str(), buf.length());
}
/**
* @brief Append a byte value to the end of the buffer.
*
* @param b
*/
void appendInt8(const uint8_t b)
{
append(static_cast<const char *>((void *)&b), 1);
}
/**
* @brief Append a unsigned short value to the end of the buffer.
*
* @param s
*/
void appendInt16(const uint16_t s);
/**
* @brief Append a unsigned int value to the end of the buffer.
*
* @param i
*/
void appendInt32(const uint32_t i);
/**
* @brief Appaend a unsigned int64 value to the end of the buffer.
*
* @param l
*/
void appendInt64(const uint64_t l);
/**
* @brief Put new data to the beginning of the buffer.
*
* @param buf
* @param len
*/
void addInFront(const char *buf, size_t len);
/**
* @brief Put a byte value to the beginning of the buffer.
*
* @param b
*/
void addInFrontInt8(const uint8_t b)
{
addInFront(static_cast<const char *>((void *)&b), 1);
}
/**
* @brief Put a unsigned short value to the beginning of the buffer.
*
* @param s
*/
void addInFrontInt16(const uint16_t s);
/**
* @brief Put a unsigned int value to the beginning of the buffer.
*
* @param i
*/
void addInFrontInt32(const uint32_t i);
/**
* @brief Put a unsigned int64 value to the beginning of the buffer.
*
* @param l
*/
void addInFrontInt64(const uint64_t l);
/**
* @brief Remove all data in the buffer.
*
*/
void retrieveAll();
/**
* @brief Remove some bytes in the buffer.
*
* @param len
*/
void retrieve(size_t len);
/**
* @brief Read data from a file descriptor and put it into the buffer.˝
*
* @param fd The file descriptor. It is usually a socket.
* @param retErrno The error code when reading.
* @return ssize_t The number of bytes read from the file descriptor. -1 is
* returned when an error occurs.
*/
ssize_t readFd(int fd, int *retErrno);
/**
* @brief Remove the data before a certain position from the buffer.
*
* @param end The position.
*/
void retrieveUntil(const char *end)
{
assert(peek() <= end);
assert(end <= beginWrite());
retrieve(end - peek());
}
/**
* @brief Find the position of the buffer where the CRLF is found.
*
* @return const char*
*/
const char *findCRLF() const
{
const char *crlf = std::search(peek(), beginWrite(), CRLF, CRLF + 2);
return crlf == beginWrite() ? NULL : crlf;
}
/**
* @brief Make sure the buffer has enough spaces to write data.
*
* @param len
*/
void ensureWritableBytes(size_t len);
/**
* @brief Move the write pointer forward when the new data has been written
* to the buffer.
*
* @param len
*/
void hasWritten(size_t len)
{
assert(len <= writableBytes());
tail_ += len;
}
/**
* @brief Move the write pointer backward to remove data in the end of the
* buffer.
*
* @param offset
*/
void unwrite(size_t offset)
{
assert(readableBytes() >= offset);
tail_ -= offset;
}
/**
* @brief Access a byte in the buffer.
*
* @param offset
* @return const char&
*/
const char &operator[](size_t offset) const
{
assert(readableBytes() >= offset);
return peek()[offset];
}
char &operator[](size_t offset)
{
assert(readableBytes() >= offset);
return begin()[head_ + offset];
}
private:
size_t head_;
size_t initCap_;
std::vector<char> buffer_;
size_t tail_;
const char *begin() const
{
return &buffer_[0];
}
char *begin()
{
return &buffer_[0];
}
};
inline void swap(MsgBuffer &one, MsgBuffer &two) noexcept
{
one.swap(two);
}
} // namespace trantor
namespace std
{
template <>
inline void swap(trantor::MsgBuffer &one, trantor::MsgBuffer &two) noexcept
{
one.swap(two);
}
} // namespace std

View File

@ -1,41 +0,0 @@
/**
*
* @file NonCopyable.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/exports.h>
namespace trantor
{
/**
* @brief This class represents a non-copyable object.
*
*/
class TRANTOR_EXPORT NonCopyable
{
protected:
NonCopyable()
{
}
~NonCopyable()
{
}
NonCopyable(const NonCopyable &) = delete;
NonCopyable &operator=(const NonCopyable &) = delete;
// some uncopyable classes maybe support move constructor....
NonCopyable(NonCopyable &&) noexcept(true) = default;
NonCopyable &operator=(NonCopyable &&) noexcept(true) = default;
};
} // namespace trantor

View File

@ -1,76 +0,0 @@
/**
*
* @file ObjectPool.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <vector>
#include <memory>
#include <type_traits>
#include <mutex>
namespace trantor
{
/**
* @brief This class template represents a object pool.
*
* @tparam T
*/
template <typename T>
class ObjectPool : public NonCopyable,
public std::enable_shared_from_this<ObjectPool<T>>
{
public:
std::shared_ptr<T> getObject()
{
static_assert(!std::is_pointer<T>::value,
"The parameter type of the ObjectPool template can't be "
"pointer type");
T *p{nullptr};
{
std::lock_guard<std::mutex> lock(mtx_);
if (!objs_.empty())
{
p = objs_.back();
objs_.pop_back();
}
}
if (p == nullptr)
{
p = new T;
}
assert(p);
std::weak_ptr<ObjectPool<T>> weakPtr = this->shared_from_this();
auto obj = std::shared_ptr<T>(p, [weakPtr](T *ptr) {
auto self = weakPtr.lock();
if (self)
{
std::lock_guard<std::mutex> lock(self->mtx_);
self->objs_.push_back(ptr);
}
else
{
delete ptr;
}
});
return obj;
}
private:
std::vector<T *> objs_;
std::mutex mtx_;
};
} // namespace trantor

View File

@ -1,56 +0,0 @@
/**
*
* SerialTaskQueue.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/utils/SerialTaskQueue.h>
#include <trantor/utils/Logger.h>
#ifdef __linux__
#include <sys/prctl.h>
#endif
namespace trantor
{
SerialTaskQueue::SerialTaskQueue(const std::string &name)
: queueName_(name.empty() ? "SerailTaskQueue" : name),
loopThread_(queueName_)
{
loopThread_.run();
}
void SerialTaskQueue::stop()
{
stop_ = true;
loopThread_.getLoop()->quit();
loopThread_.wait();
}
SerialTaskQueue::~SerialTaskQueue()
{
if (!stop_)
stop();
LOG_TRACE << "destruct SerialTaskQueue('" << queueName_ << "')";
}
void SerialTaskQueue::runTaskInQueue(const std::function<void()> &task)
{
loopThread_.getLoop()->runInLoop(task);
}
void SerialTaskQueue::runTaskInQueue(std::function<void()> &&task)
{
loopThread_.getLoop()->runInLoop(std::move(task));
}
void SerialTaskQueue::waitAllTasksFinished()
{
syncTaskInQueue([]() {
});
}
} // namespace trantor

View File

@ -1,100 +0,0 @@
/**
*
* SerialTaskQueue.h
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include "TaskQueue.h"
#include <trantor/net/EventLoopThread.h>
#include <trantor/exports.h>
#include <string>
#include <queue>
#include <mutex>
#include <atomic>
namespace trantor
{
/**
* @brief This class represents a task queue in which all tasks are executed one
* by one.
*
*/
class TRANTOR_EXPORT SerialTaskQueue : public TaskQueue
{
public:
/**
* @brief Run a task in the queue.
*
* @param task
*/
virtual void runTaskInQueue(const std::function<void()> &task);
virtual void runTaskInQueue(std::function<void()> &&task);
/**
* @brief Get the name of the queue.
*
* @return std::string
*/
virtual std::string getName() const
{
return queueName_;
};
/**
* @brief Wait until all tasks in the queue are finished.
*
*/
void waitAllTasksFinished();
SerialTaskQueue() = delete;
/**
* @brief Construct a new serail task queue instance.
*
* @param name
*/
explicit SerialTaskQueue(const std::string &name);
virtual ~SerialTaskQueue();
/**
* @brief Check whether a task is running in the queue.
*
* @return true
* @return false
*/
bool isRuningTask()
{
return loopThread_.getLoop()
? loopThread_.getLoop()->isCallingFunctions()
: false;
}
/**
* @brief Get the number of tasks in the queue.
*
* @return size_t
*/
size_t getTaskCount();
/**
* @brief Stop the queue.
*
*/
void stop();
protected:
std::string queueName_;
EventLoopThread loopThread_;
bool stop_{false};
};
} // namespace trantor

View File

@ -1,58 +0,0 @@
/**
*
* @file TaskQueue.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include "NonCopyable.h"
#include <functional>
#include <future>
#include <string>
namespace trantor
{
/**
* @brief This class is a pure virtual class that can be implemented as a
* SerialTaskQueue or a ConcurrentTaskQueue.
*
*/
class TaskQueue : public NonCopyable
{
public:
virtual void runTaskInQueue(const std::function<void()> &task) = 0;
virtual void runTaskInQueue(std::function<void()> &&task) = 0;
virtual std::string getName() const
{
return "";
};
/**
* @brief Run a task in the queue sychronously. This means that the task is
* executed before the method returns.
*
* @param task
*/
void syncTaskInQueue(const std::function<void()> &task)
{
std::promise<int> prom;
std::future<int> fut = prom.get_future();
runTaskInQueue([&]() {
task();
prom.set_value(1);
});
fut.get();
};
virtual ~TaskQueue()
{
}
};
} // namespace trantor

View File

@ -1,126 +0,0 @@
/**
*
* TimingWheel.cc
* An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/utils/TimingWheel.h>
using namespace trantor;
TimingWheel::TimingWheel(trantor::EventLoop *loop,
size_t maxTimeout,
float ticksInterval,
size_t bucketsNumPerWheel)
: loop_(loop),
ticksInterval_(ticksInterval),
bucketsNumPerWheel_(bucketsNumPerWheel)
{
assert(maxTimeout > 1);
assert(ticksInterval > 0);
assert(bucketsNumPerWheel_ > 1);
size_t maxTickNum = static_cast<size_t>(maxTimeout / ticksInterval);
auto ticksNum = bucketsNumPerWheel;
wheelsNum_ = 1;
while (maxTickNum > ticksNum)
{
++wheelsNum_;
ticksNum *= bucketsNumPerWheel_;
}
wheels_.resize(wheelsNum_);
for (size_t i = 0; i < wheelsNum_; ++i)
{
wheels_[i].resize(bucketsNumPerWheel_);
}
timerId_ = loop_->runEvery(ticksInterval_, [this]() {
++ticksCounter_;
size_t t = ticksCounter_;
size_t pow = 1;
for (size_t i = 0; i < wheelsNum_; ++i)
{
if ((t % pow) == 0)
{
EntryBucket tmp;
{
// use tmp val to make this critical area as short as
// possible.
wheels_[i].front().swap(tmp);
wheels_[i].pop_front();
wheels_[i].push_back(EntryBucket());
}
}
pow = pow * bucketsNumPerWheel_;
}
});
}
TimingWheel::~TimingWheel()
{
loop_->assertInLoopThread();
loop_->invalidateTimer(timerId_);
for (auto iter = wheels_.rbegin(); iter != wheels_.rend(); ++iter)
{
iter->clear();
}
LOG_TRACE << "TimingWheel destruct!";
}
void TimingWheel::insertEntry(size_t delay, EntryPtr entryPtr)
{
if (delay <= 0)
return;
if (!entryPtr)
return;
if (loop_->isInLoopThread())
{
insertEntryInloop(delay, entryPtr);
}
else
{
loop_->runInLoop(
[this, delay, entryPtr]() { insertEntryInloop(delay, entryPtr); });
}
}
void TimingWheel::insertEntryInloop(size_t delay, EntryPtr entryPtr)
{
loop_->assertInLoopThread();
delay = static_cast<size_t>(delay / ticksInterval_ + 1);
size_t t = ticksCounter_;
for (size_t i = 0; i < wheelsNum_; ++i)
{
if (delay <= bucketsNumPerWheel_)
{
wheels_[i][delay - 1].insert(entryPtr);
break;
}
if (i < (wheelsNum_ - 1))
{
entryPtr = std::make_shared<CallbackEntry>(
[this, delay, i, t, entryPtr]() {
if (delay > 0)
{
wheels_[i][(delay + (t % bucketsNumPerWheel_) - 1) %
bucketsNumPerWheel_]
.insert(entryPtr);
}
});
}
else
{
// delay is too long to put entry at valid position in wheels;
wheels_[i][bucketsNumPerWheel_ - 1].insert(entryPtr);
}
delay = (delay + (t % bucketsNumPerWheel_) - 1) / bucketsNumPerWheel_;
t = t / bucketsNumPerWheel_;
}
}

View File

@ -1,104 +0,0 @@
/**
*
* @file TimingWheel.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/net/EventLoop.h>
#include <trantor/utils/Logger.h>
#include <trantor/exports.h>
#include <map>
#include <mutex>
#include <deque>
#include <vector>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <atomic>
#include <assert.h>
#define TIMING_BUCKET_NUM_PER_WHEEL 100
#define TIMING_TICK_INTERVAL 1.0
namespace trantor
{
using EntryPtr = std::shared_ptr<void>;
using EntryBucket = std::unordered_set<EntryPtr>;
using BucketQueue = std::deque<EntryBucket>;
/**
* @brief This class implements a timer strategy with high performance and low
* accuracy. This is usually used internally.
*
*/
class TRANTOR_EXPORT TimingWheel
{
public:
class CallbackEntry
{
public:
CallbackEntry(std::function<void()> cb) : cb_(std::move(cb))
{
}
~CallbackEntry()
{
cb_();
}
private:
std::function<void()> cb_;
};
/**
* @brief Construct a new timing wheel instance.
*
* @param loop The event loop in which the timing wheel runs.
* @param maxTimeout The maximum timeout of the timing wheel.
* @param ticksInterval The internal timer tick interval. It affects the
* accuracy of the timing wheel.
* @param bucketsNumPerWheel The number of buckets per wheel.
* @note The max delay of the timing wheel is about
* ticksInterval*(bucketsNumPerWheel^wheelsNum) seconds.
* @example Four wheels with 200 buckets per wheel means the timing wheel
* can work with a timeout up to 200^4 seconds, about 50 years;
*/
TimingWheel(trantor::EventLoop *loop,
size_t maxTimeout,
float ticksInterval = TIMING_TICK_INTERVAL,
size_t bucketsNumPerWheel = TIMING_BUCKET_NUM_PER_WHEEL);
void insertEntry(size_t delay, EntryPtr entryPtr);
void insertEntryInloop(size_t delay, EntryPtr entryPtr);
EventLoop *getLoop()
{
return loop_;
}
~TimingWheel();
private:
std::vector<BucketQueue> wheels_;
std::atomic<size_t> ticksCounter_{0};
trantor::TimerId timerId_;
trantor::EventLoop *loop_;
float ticksInterval_;
size_t wheelsNum_;
size_t bucketsNumPerWheel_;
};
} // namespace trantor

View File

@ -1,55 +0,0 @@
/**
*
* WindowsSupport.cc
* An Tao
*
* Implementation of Windows support functions.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#include <trantor/utils/WindowsSupport.h>
#include <winsock2.h>
// from polipo
int win32_read_socket(int fd, void *buf, int n)
{
int rc = recv(fd, reinterpret_cast<char *>(buf), n, 0);
if (rc == SOCKET_ERROR)
{
_set_errno(WSAGetLastError());
}
return rc;
}
int readv(int fd, const struct iovec *vector, int count)
{
int ret = 0; /* Return value */
int i;
for (i = 0; i < count; i++)
{
int n = vector[i].iov_len;
int rc = win32_read_socket(fd, vector[i].iov_base, n);
if (rc == n)
{
ret += rc;
}
else
{
if (rc < 0)
{
ret = (ret == 0 ? rc : ret);
}
else
{
ret += rc;
}
break;
}
}
return ret;
}

View File

@ -1,26 +0,0 @@
/**
*
* @file WindowsSupport.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/exports.h>
#include <stdint.h>
struct iovec
{
void *iov_base; /* Starting address */
int iov_len; /* Number of bytes */
};
TRANTOR_EXPORT int readv(int fd, const struct iovec *vector, int count);