evio/tincan/trunk/include/windows/tapdev_win.h

212 lines
5.3 KiB
C++

/*
* EdgeVPNio
* Copyright 2020, University of Florida
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef TINCAN_TAPDEV_WIN_H_
#define TINCAN_TAPDEV_WIN_H_
#if defined(_TNC_WIN)
#include "tincan_base.h"
#include "rtc_base/logging.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include <Winsock2.h>
#include "async_io.h"
#include "tapdev_inf.h"
namespace tincan
{
namespace windows
{
/*
NOTE: A TapDev object cannot be reused, ie.,
TapDev::Open(); TapDev::Close(); TapDev::Open();
It must be deleted after it is closed and a new instance create.
*/
class TapDevWin :
public TapDevInf,
public MessageHandler
{
public:
struct IoThreadDescriptor
{
HANDLE handle_; //thread join needs this to be first member
HANDLE exit_ev_;
HANDLE cmpl_prt_hdl_;
DWORD id_;
uint16_t num_;
IoThreadDescriptor() :
handle_(INVALID_HANDLE_VALUE),
cmpl_prt_hdl_(0),
id_(0), num_(0)
{
exit_ev_ = CreateEvent(NULL, FALSE, FALSE, NULL);
}
~IoThreadDescriptor()
{
CloseHandle(exit_ev_);
CloseHandle(handle_);
}
static DWORD __stdcall IoCompletionThread(void * param);
};
struct IoThreadPool
{
IoThreadPool(uint8_t max_threads = 1) :
ref_(0),
num_threads_(0),
max_threads_(max_threads), is_alloc(false)
{}
~IoThreadPool()
{
if(is_alloc)
Free();
}
bool Alloc()
{
io_threads_ = new IoThreadDescriptor[max_threads_];
for(uint16_t i = 0; i < max_threads_; i++)
{
io_threads_[i].num_ = i;
io_threads_[i].handle_ = CreateThread(0, 0,
IoThreadDescriptor::IoCompletionThread, (void *)&io_threads_[i],
CREATE_SUSPENDED, &io_threads_[i].id_);
++num_threads_;
}
is_alloc = true;
return is_alloc;
}
void Free()
{
for(uint16_t i = 0; i < max_threads_; i++)
{
SetEvent(io_threads_[i].exit_ev_);
PostQueuedCompletionStatus(io_threads_[i].cmpl_prt_hdl_, 0,
(DWORD)NULL, NULL);
ResumeThread(io_threads_[i].handle_);
}
//wait for io threads to terminate, 10 seconds or bust
WaitForMultipleObjects(num_threads_, (const HANDLE*)io_threads_,
TRUE, 10000);
delete[]io_threads_;
is_alloc = false;
}
void Attach(HANDLE completion_port_handle)
{
lock_guard<mutex> lg(iot_mutex_);
if(0 == ref_++)
{
for(uint16_t i = 0; i < max_threads_; i++)
{
io_threads_[i].cmpl_prt_hdl_ = completion_port_handle;
ResumeThread(io_threads_[i].handle_);
}
}
}
void Release()
{
lock_guard<mutex> lg(iot_mutex_);
if(0 == --ref_)
{
for(uint16_t i = 0; i < max_threads_; i++)
{
SuspendThread(io_threads_[i].handle_);
io_threads_[i].cmpl_prt_hdl_ = 0;
}
}
}
IoThreadDescriptor* io_threads_;
uint16_t ref_;
uint16_t num_threads_;
uint16_t max_threads_;
mutex iot_mutex_;
bool is_alloc;
};
TapDevWin();
virtual ~TapDevWin();
void Open(
const TapDescriptor & tap_desc) override;
void Close() override;
void Up() override;
void Down() override;
uint32_t Read(
AsyncIo & aio_rd) override;
uint32_t Write(
AsyncIo & aio_wr) override;
MacAddressType MacAddress() override;
IP4AddressType Ip4() override;
uint16_t Mtu() override;
//
//IO Completion Port
void CompletionPortHandle(HANDLE handle)
{
cmpl_prt_handle_ = handle;
}
HANDLE CompletionPortHandle()
{
return cmpl_prt_handle_;
}
HANDLE DeviceHandle()
{
return dev_handle_;
}
uint32_t MediaStatus();
sigslot::signal1<AsyncIo *> read_completion_;
sigslot::signal1<AsyncIo *> write_completion_;
protected:
void NetDeviceNameToGuid(
const string & name,
string & guid);
void GetMacAddress();
void OnMessage(
Message * msg) override;
static const char * const NETWORK_PATH_;
static const char * const USER_MODE_DEVICE_DIR_;
static const char * const TAP_SUFFIX_;
MacAddressType mac_address_;
DWORD mac_len_;
string tap_name_;
HANDLE cmpl_prt_handle_;
HANDLE dev_handle_;
mutex rw_mutex_;
IoThreadPool io_thread_pool_;
DWORD media_status_;
IP4AddressType ip4_;
rtc::Thread writer_;
};
} // namespace win
} // namespace tincan
#endif // _TNC_WIN
#endif // TINCAN_TAPDEV_WIN_H_