Fixes
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
set(SRC_FILES
|
set(SRC_FILES
|
||||||
|
"imp/cpp/IPC.cpp"
|
||||||
"imp/cpp/JSON.cpp"
|
"imp/cpp/JSON.cpp"
|
||||||
"imp/cpp/IACore.cpp"
|
"imp/cpp/IACore.cpp"
|
||||||
"imp/cpp/Logger.cpp"
|
"imp/cpp/Logger.cpp"
|
||||||
|
|||||||
@ -28,15 +28,93 @@ namespace IACore
|
|||||||
#if IA_PLATFORM_WINDOWS
|
#if IA_PLATFORM_WINDOWS
|
||||||
::UnmapViewOfFile(std::get<1>(handles));
|
::UnmapViewOfFile(std::get<1>(handles));
|
||||||
::CloseHandle(std::get<2>(handles));
|
::CloseHandle(std::get<2>(handles));
|
||||||
::CloseHandle(std::get<0>(handles));
|
|
||||||
|
if (std::get<0>(handles) != INVALID_HANDLE_VALUE)
|
||||||
|
::CloseHandle(std::get<0>(handles));
|
||||||
#elif IA_PLATFORM_UNIX
|
#elif IA_PLATFORM_UNIX
|
||||||
::munmap(std::get<1>(handles), (SIZE_T) std::get<2>(handles));
|
::munmap(std::get<1>(handles), (SIZE_T) std::get<2>(handles));
|
||||||
::close((INT32) ((UINT64) std::get<0>(handles)));
|
const auto fd = (INT32) ((UINT64) std::get<0>(handles));
|
||||||
|
if (fd != -1)
|
||||||
|
::close(fd);
|
||||||
#else
|
#else
|
||||||
# error "IACore FileOps does not support this platform"
|
# error "IACore FileOps does not support this platform"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expected<PCUINT8, String> FileOps::MapSharedMemory(IN CONST String &name, IN SIZE_T size, IN BOOL isOwner)
|
||||||
|
{
|
||||||
|
#if IA_PLATFORM_WINDOWS
|
||||||
|
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, NULL, 0);
|
||||||
|
std::wstring wName(wchars_num, 0);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, &wName[0], wchars_num);
|
||||||
|
|
||||||
|
HANDLE hMap = NULL;
|
||||||
|
if (isOwner)
|
||||||
|
hMap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, (DWORD) (size >> 32),
|
||||||
|
(DWORD) (size & 0xFFFFFFFF), wName.c_str());
|
||||||
|
else
|
||||||
|
hMap = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, wName.c_str());
|
||||||
|
|
||||||
|
if (hMap == NULL)
|
||||||
|
return MakeUnexpected(
|
||||||
|
std::format("Failed to {} shared memory '{}'", isOwner ? "owner" : "consumer", name.c_str()));
|
||||||
|
|
||||||
|
const auto result = static_cast<PCUINT8>(MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, size));
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
CloseHandle(hMap);
|
||||||
|
return MakeUnexpected(std::format("Failed to map view of shared memory '{}'", name.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
s_mappedFiles[result] = std::make_tuple((PVOID) INVALID_HANDLE_VALUE, (PVOID) result, (PVOID) hMap);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
#elif IA_PLATFORM_UNIX
|
||||||
|
int fd = -1;
|
||||||
|
if (isOwner)
|
||||||
|
{
|
||||||
|
fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||||
|
if (fd != -1)
|
||||||
|
{
|
||||||
|
if (ftruncate(fd, size) == -1)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
shm_unlink(name.c_str());
|
||||||
|
return MakeUnexpected(std::format("Failed to truncate shared memory '{}'", name.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fd = shm_open(name.c_str(), O_RDWR, 0666);
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
return MakeUnexpected(
|
||||||
|
std::format("Failed to {} shared memory '{}'", isOwner ? "owner" : "consumer", name.c_str()));
|
||||||
|
|
||||||
|
void *addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (addr == MAP_FAILED)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return MakeUnexpected(std::format("Failed to mmap shared memory '{}'", name.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto result = static_cast<PCUINT8>(addr);
|
||||||
|
|
||||||
|
s_mappedFiles[result] = std::make_tuple((PVOID) ((UINT64) fd), (PVOID) addr, (PVOID) size);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error "IACore FileOps does not support this platform"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID FileOps::UnlinkSharedMemory(IN CONST String &name)
|
||||||
|
{
|
||||||
|
#if IA_PLATFORM_UNIX
|
||||||
|
shm_unlink(name.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Expected<PCUINT8, String> FileOps::MapFile(IN CONST FilePath &path, OUT SIZE_T &size)
|
Expected<PCUINT8, String> FileOps::MapFile(IN CONST FilePath &path, OUT SIZE_T &size)
|
||||||
{
|
{
|
||||||
#if IA_PLATFORM_WINDOWS
|
#if IA_PLATFORM_WINDOWS
|
||||||
@ -192,7 +270,7 @@ namespace IACore
|
|||||||
result = "./" + result;
|
result = "./" + result;
|
||||||
return FilePath(result);
|
return FilePath(result);
|
||||||
#else
|
#else
|
||||||
# error "unreachable. previous checks must have stopped compilation beforehand .unsupported platform."
|
# error "IACore FileOps does not support this platform"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace IACore
|
} // namespace IACore
|
||||||
22
Src/IACore/imp/cpp/IPC.cpp
Normal file
22
Src/IACore/imp/cpp/IPC.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||||
|
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <IACore/IPC.hpp>
|
||||||
|
|
||||||
|
namespace IACore
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@ -18,6 +18,54 @@
|
|||||||
|
|
||||||
namespace IACore
|
namespace IACore
|
||||||
{
|
{
|
||||||
|
BOOL SocketOps::Listen(IN SocketHandle sock, IN INT32 queueSize)
|
||||||
|
{
|
||||||
|
return listen(sock, queueSize) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketHandle SocketOps::CreateUnixSocket()
|
||||||
|
{
|
||||||
|
return socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL SocketOps::BindUnixSocket(IN SocketHandle sock, IN PCCHAR path)
|
||||||
|
{
|
||||||
|
if (!IS_VALID_SOCKET(sock))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
UNLINK_FILE(path);
|
||||||
|
|
||||||
|
sockaddr_un addr{};
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
size_t maxLen = sizeof(addr.sun_path) - 1;
|
||||||
|
|
||||||
|
strncpy(addr.sun_path, path, maxLen);
|
||||||
|
|
||||||
|
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL SocketOps::ConnectUnixSocket(IN SocketHandle sock, IN PCCHAR path)
|
||||||
|
{
|
||||||
|
if (!IS_VALID_SOCKET(sock))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
sockaddr_un addr{};
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
size_t maxLen = sizeof(addr.sun_path) - 1;
|
||||||
|
|
||||||
|
strncpy(addr.sun_path, path, maxLen);
|
||||||
|
|
||||||
|
if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL SocketOps::IsPortAvailable(IN UINT16 port, IN INT32 type)
|
BOOL SocketOps::IsPortAvailable(IN UINT16 port, IN INT32 type)
|
||||||
{
|
{
|
||||||
SocketHandle sock = socket(AF_INET, type, IPPROTO_UDP);
|
SocketHandle sock = socket(AF_INET, type, IPPROTO_UDP);
|
||||||
|
|||||||
143
Src/IACore/inc/IACore/ADT/RingBuffer.hpp
Normal file
143
Src/IACore/inc/IACore/ADT/RingBuffer.hpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||||
|
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <IACore/PCH.hpp>
|
||||||
|
|
||||||
|
namespace IACore
|
||||||
|
{
|
||||||
|
class RingBufferView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
STATIC CONSTEXPR UINT16 PACKET_ID_SKIP = 0;
|
||||||
|
|
||||||
|
struct ControlBlock
|
||||||
|
{
|
||||||
|
alignas(64) Atomic<UINT32> WriteOffset{0};
|
||||||
|
alignas(64) Atomic<UINT32> ReadOffset{0};
|
||||||
|
UINT32 Capacity;
|
||||||
|
|
||||||
|
// Padding to ensure data starts on a cache line
|
||||||
|
UINT8 _padding[64 - sizeof(UINT32) * 3];
|
||||||
|
};
|
||||||
|
|
||||||
|
// All of the data in ring buffer will be stored as packets
|
||||||
|
struct PacketHeader
|
||||||
|
{
|
||||||
|
UINT16 ID{};
|
||||||
|
UINT16 PayloadSize{};
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
INLINE RingBufferView(IN Span<UINT8> buffer);
|
||||||
|
|
||||||
|
INLINE BOOL Pop(OUT PacketHeader &outHeader, OUT Span<UINT8> outBuffer);
|
||||||
|
INLINE BOOL Push(IN UINT16 packetID, IN Span<CONST UINT8> data);
|
||||||
|
|
||||||
|
INLINE ControlBlock *GetControlBlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PUINT8 m_dataPtr{};
|
||||||
|
UINT32 m_capacity{};
|
||||||
|
ControlBlock *m_controlBlock{};
|
||||||
|
|
||||||
|
private:
|
||||||
|
INLINE VOID WritePacket(IN UINT32 offset, IN UINT16 id, IN PCVOID data, IN UINT16 dataSize);
|
||||||
|
};
|
||||||
|
} // namespace IACore
|
||||||
|
|
||||||
|
namespace IACore
|
||||||
|
{
|
||||||
|
RingBufferView::RingBufferView(IN Span<UINT8> buffer)
|
||||||
|
{
|
||||||
|
IA_ASSERT(buffer.size() > sizeof(ControlBlock));
|
||||||
|
|
||||||
|
m_controlBlock = reinterpret_cast<ControlBlock *>(buffer.data());
|
||||||
|
m_dataPtr = buffer.data() + sizeof(ControlBlock);
|
||||||
|
m_controlBlock->Capacity = m_capacity = buffer.size() - sizeof(ControlBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RingBufferView::Pop(OUT PacketHeader &outHeader, OUT Span<UINT8> outBuffer)
|
||||||
|
{
|
||||||
|
UINT32 currentWriteOffset = m_controlBlock->WriteOffset.load(std::memory_order_acquire);
|
||||||
|
UINT32 currentReadOffset = m_controlBlock->ReadOffset.load(std::memory_order_acquire);
|
||||||
|
|
||||||
|
if (currentReadOffset == currentWriteOffset)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto header = reinterpret_cast<PacketHeader *>(m_dataPtr + currentReadOffset);
|
||||||
|
|
||||||
|
if (header->ID == PACKET_ID_SKIP)
|
||||||
|
{
|
||||||
|
m_controlBlock->ReadOffset.store(0, std::memory_order_release);
|
||||||
|
return Pop(outHeader, outBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
outHeader = *header;
|
||||||
|
if (outHeader.PayloadSize > outBuffer.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(outBuffer.data(), m_dataPtr + currentReadOffset + sizeof(PacketHeader), outHeader.PayloadSize);
|
||||||
|
m_controlBlock->ReadOffset.store(currentReadOffset + sizeof(PacketHeader) + outHeader.PayloadSize, std::memory_order_release);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RingBufferView::Push(IN UINT16 packetID, IN Span<CONST UINT8> data)
|
||||||
|
{
|
||||||
|
IA_ASSERT(data.size() <= UINT16_MAX);
|
||||||
|
|
||||||
|
UINT32 currentWriteOffset = m_controlBlock->WriteOffset.load(std::memory_order_acquire);
|
||||||
|
UINT32 currentReadOffset = m_controlBlock->ReadOffset.load(std::memory_order_acquire);
|
||||||
|
|
||||||
|
UINT32 requiredSpace = sizeof(PacketHeader) + data.size();
|
||||||
|
if (currentWriteOffset + requiredSpace <= m_capacity)
|
||||||
|
{
|
||||||
|
WritePacket(currentWriteOffset, packetID, data.data(), static_cast<UINT16>(data.size()));
|
||||||
|
m_controlBlock->WriteOffset.store(currentWriteOffset + requiredSpace, std::memory_order_release);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 remainingAtEnd = m_capacity - currentWriteOffset;
|
||||||
|
if (requiredSpace < currentReadOffset)
|
||||||
|
{
|
||||||
|
if (remainingAtEnd >= sizeof(PacketHeader))
|
||||||
|
{
|
||||||
|
const auto p = PacketHeader{PACKET_ID_SKIP, 0};
|
||||||
|
memcpy(m_dataPtr + currentWriteOffset, &p, sizeof(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
WritePacket(0, packetID, data.data(), static_cast<UINT16>(data.size()));
|
||||||
|
m_controlBlock->WriteOffset.store(requiredSpace, std::memory_order_release);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RingBufferView::ControlBlock *RingBufferView::GetControlBlock()
|
||||||
|
{
|
||||||
|
return m_controlBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID RingBufferView::WritePacket(IN UINT32 offset, IN UINT16 id, IN PCVOID data, IN UINT16 dataSize)
|
||||||
|
{
|
||||||
|
PacketHeader h = {id, dataSize};
|
||||||
|
memcpy(m_dataPtr + offset, &h, sizeof(PacketHeader));
|
||||||
|
memcpy(m_dataPtr + offset + sizeof(PacketHeader), data, dataSize);
|
||||||
|
}
|
||||||
|
} // namespace IACore
|
||||||
@ -30,6 +30,10 @@ namespace IACore
|
|||||||
STATIC VOID UnmapFile(IN PCUINT8 mappedPtr);
|
STATIC VOID UnmapFile(IN PCUINT8 mappedPtr);
|
||||||
STATIC Expected<PCUINT8, String> MapFile(IN CONST FilePath &path, OUT SIZE_T &size);
|
STATIC Expected<PCUINT8, String> MapFile(IN CONST FilePath &path, OUT SIZE_T &size);
|
||||||
|
|
||||||
|
// @param `isOwner` TRUE to allocate/truncate. FALSE to just open.
|
||||||
|
STATIC Expected<PCUINT8, String> MapSharedMemory(IN CONST String &name, IN SIZE_T size, IN BOOL isOwner);
|
||||||
|
STATIC VOID UnlinkSharedMemory(IN CONST String &name);
|
||||||
|
|
||||||
STATIC Expected<StreamReader, String> StreamFromFile(IN CONST FilePath &path);
|
STATIC Expected<StreamReader, String> StreamFromFile(IN CONST FilePath &path);
|
||||||
STATIC Expected<StreamWriter, String> StreamToFile(IN CONST FilePath &path, IN BOOL overwrite = false);
|
STATIC Expected<StreamWriter, String> StreamToFile(IN CONST FilePath &path, IN BOOL overwrite = false);
|
||||||
|
|
||||||
|
|||||||
34
Src/IACore/inc/IACore/IPC.hpp
Normal file
34
Src/IACore/inc/IACore/IPC.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||||
|
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <IACore/PCH.hpp>
|
||||||
|
|
||||||
|
namespace IACore
|
||||||
|
{
|
||||||
|
class IPC_Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class IPC_Server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -21,19 +21,24 @@
|
|||||||
#if IA_PLATFORM_WINDOWS
|
#if IA_PLATFORM_WINDOWS
|
||||||
|
|
||||||
# include <winsock2.h>
|
# include <winsock2.h>
|
||||||
|
# include <ws2tcpip.h>
|
||||||
|
# include <afunix.h>
|
||||||
# pragma comment(lib, "ws2_32.lib")
|
# pragma comment(lib, "ws2_32.lib")
|
||||||
# define CLOSE_SOCKET(s) closesocket(s)
|
# define CLOSE_SOCKET(s) closesocket(s)
|
||||||
# define IS_VALID_SOCKET(s) (s != INVALID_SOCKET)
|
# define IS_VALID_SOCKET(s) (s != INVALID_SOCKET)
|
||||||
|
# define UNLINK_FILE(p) DeleteFileA(p)
|
||||||
using SocketHandle = SOCKET;
|
using SocketHandle = SOCKET;
|
||||||
|
|
||||||
#elif IA_PLATFORM_UNIX
|
#elif IA_PLATFORM_UNIX
|
||||||
|
|
||||||
|
# include <sys/un.h>
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <sys/socket.h>
|
# include <sys/socket.h>
|
||||||
# include <netinet/in.h>
|
# include <netinet/in.h>
|
||||||
# define CLOSE_SOCKET(s) close(s)
|
# define CLOSE_SOCKET(s) close(s)
|
||||||
# define IS_VALID_SOCKET(s) (s >= 0)
|
# define IS_VALID_SOCKET(s) (s >= 0)
|
||||||
# define INVALID_SOCKET -1
|
# define INVALID_SOCKET -1
|
||||||
|
# define UNLINK_FILE(p) unlink(p)
|
||||||
using SocketHandle = int;
|
using SocketHandle = int;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -72,6 +77,13 @@ namespace IACore
|
|||||||
return IsPortAvailable(port, SOCK_DGRAM);
|
return IsPortAvailable(port, SOCK_DGRAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC BOOL Listen(IN SocketHandle sock, IN INT32 queueSize = 5);
|
||||||
|
|
||||||
|
STATIC SocketHandle CreateUnixSocket();
|
||||||
|
|
||||||
|
STATIC BOOL BindUnixSocket(IN SocketHandle sock, IN PCCHAR path);
|
||||||
|
STATIC BOOL ConnectUnixSocket(IN SocketHandle sock, IN PCCHAR path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
STATIC BOOL IsPortAvailable(IN UINT16 port, IN INT32 type);
|
STATIC BOOL IsPortAvailable(IN UINT16 port, IN INT32 type);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user