2022-04-16 15:42:48 +00:00
/***
Copyright ( C ) 2022 J Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
2022-12-14 05:03:37 +00:00
File : AuIPCPipe . NT . cpp
2022-04-16 15:42:48 +00:00
Date : 2022 - 4 - 15
Author : Reece
* * */
# include <Source/RuntimeInternal.hpp>
# include "IPC.hpp"
2022-12-14 05:03:37 +00:00
# include "AuIPCHandle.hpp"
2022-04-16 15:42:48 +00:00
2022-06-11 23:52:46 +00:00
# include <Source/IO/Loop/ILoopSourceEx.hpp>
# include <Source/IO/Loop/LSHandle.hpp>
# include <Source/IO/Loop/LSEvent.hpp>
2022-04-17 12:40:08 +00:00
# include <Source/IO/FS/Async.NT.hpp>
2023-07-30 13:27:04 +00:00
# include <Source/IO/AuIOHandle.hpp>
2022-12-14 05:03:37 +00:00
# include "AuIPCPipe.NT.hpp"
2022-06-22 20:24:04 +00:00
2022-06-11 23:52:46 +00:00
namespace Aurora : : IO : : IPC
2022-04-16 15:42:48 +00:00
{
2022-04-17 12:40:08 +00:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pipes
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct IPCPipeImpl ;
2022-06-22 13:42:17 +00:00
struct IPCHasConnectionEvent : Loop : : LSHandle
2022-04-17 12:40:08 +00:00
{
IPCHasConnectionEvent ( AuSPtr < IPCPipeImpl > parent ) ;
bool IsSignaled ( ) override ;
Loop : : ELoopSource GetType ( ) override ;
bool OnTrigger ( AuUInt handle ) override ;
private :
AuWPtr < IPCPipeImpl > parent_ ;
} ;
2022-06-22 13:42:17 +00:00
IPCHasConnectionEvent : : IPCHasConnectionEvent ( AuSPtr < IPCPipeImpl > parent ) : parent_ ( parent ) , LSHandle ( ( AuUInt ) parent - > GetConnectHandle ( ) )
2022-04-17 12:40:08 +00:00
{
}
bool IPCHasConnectionEvent : : IsSignaled ( )
{
return OnTrigger ( 0 ) ;
}
Loop : : ELoopSource IPCHasConnectionEvent : : GetType ( )
{
return Loop : : ELoopSource : : eSourceIPCHasClient ;
}
bool IPCHasConnectionEvent : : OnTrigger ( AuUInt handle )
{
auto parent = this - > parent_ . lock ( ) ;
if ( ! parent )
{
SysPushErrorMem ( " IPC pipe is dead " ) ;
return false ;
}
parent - > TryConnect ( ) ;
2022-07-21 06:18:53 +00:00
if ( WaitForSingleObject ( parent - > overlapped . hEvent , 0 ) ! = WAIT_OBJECT_0 )
{
return false ;
}
if ( parent - > clientHandle_ ! = INVALID_HANDLE_VALUE )
{
return true ;
}
DWORD avail { } ;
auto h = parent - > GetPipeHandle ( ) ;
if ( ! PeekNamedPipe ( h , NULL , NULL , NULL , & avail , NULL ) )
{
return false ;
}
return true ;
2022-04-17 12:40:08 +00:00
}
IPCPipeImpl : : IPCPipeImpl ( HANDLE clientHandle , HANDLE serverHandle , const IPCHandle & handle ) :
2023-10-21 09:39:47 +00:00
serverHandle_ ( serverHandle ) ,
clientHandle_ ( clientHandle ) ,
ipcHandle_ ( handle ) ,
pipeReader_ ( this ) ,
pipeWriter_ ( this )
2022-04-17 12:40:08 +00:00
{
if ( serverHandle ! = INVALID_HANDLE_VALUE )
{
2024-07-30 16:30:19 +00:00
this - > hasClient_ = Loop : : NewLSEventSlow ( false , false , true ) ;
2023-12-16 21:08:46 +00:00
if ( ! this - > hasClient_ )
{
this - > bDead = true ;
return ;
}
2022-04-17 12:40:08 +00:00
}
2023-07-29 07:02:47 +00:00
this - > fsHandle_ = AuIO : : IOHandleShared ( ) ;
2023-12-16 21:08:46 +00:00
if ( ! this - > fsHandle_ )
{
this - > bDead = true ;
return ;
}
2022-04-17 12:40:08 +00:00
2023-12-16 21:08:46 +00:00
this - > fsStream_ = AuMakeShared < IO : : FS : : NtAsyncFileStream > ( ) ;
if ( ! this - > fsStream_ )
{
this - > bDead = true ;
return ;
}
2023-07-29 07:02:47 +00:00
2023-12-16 21:08:46 +00:00
( void ) this - > fsHandle_ - > InitFromMove ( ( AuUInt ) this - > GetPipeHandle ( ) ) ;
2023-07-30 13:27:04 +00:00
AuStaticCast < AFileHandle > ( this - > fsHandle_ ) - > bIsAsync = true ;
2023-09-16 21:47:45 +00:00
AuStaticCast < AFileHandle > ( this - > fsHandle_ ) - > pIPCPipe = this ;
2023-07-30 13:27:04 +00:00
2024-03-16 09:51:41 +00:00
this - > fsBlockingStream_ = AuFS : : OpenBlockingFileStreamFromHandleShared ( this - > fsHandle_ ) ;
2023-12-16 21:08:46 +00:00
if ( ! this - > fsBlockingStream_ )
{
this - > bDead = true ;
return ;
}
2023-10-20 15:33:18 +00:00
2022-04-17 12:40:08 +00:00
this - > fsStream_ - > Init ( this - > fsHandle_ ) ;
TryConnect ( ) ;
}
void IPCPipeImpl : : TryConnect ( )
{
if ( this - > serverHandle_ = = INVALID_HANDLE_VALUE )
{
return ;
}
2022-06-22 13:42:17 +00:00
this - > overlapped . hEvent = GetConnectHandle ( ) ;
2022-04-17 12:40:08 +00:00
2022-08-09 06:16:09 +00:00
if ( AuExchange ( bFirstTime , false ) | |
( WaitForSingleObject ( this - > overlapped . hEvent , 0 ) = = WAIT_OBJECT_0 ) )
2022-04-17 12:40:08 +00:00
{
ResetEvent ( this - > overlapped . hEvent ) ;
if ( ConnectNamedPipe ( this - > serverHandle_ , & this - > overlapped ) )
{
2022-08-09 06:16:09 +00:00
this - > bFirstTime = true ;
2022-04-17 12:40:08 +00:00
TryConnect ( ) ;
}
2022-08-09 06:16:09 +00:00
else
2022-04-17 12:40:08 +00:00
{
2022-08-09 06:16:09 +00:00
auto lastError = GetLastError ( ) ;
if ( lastError = = ERROR_IO_PENDING )
{
// No-op
}
else if ( lastError = = ERROR_PIPE_CONNECTED )
{
SetEvent ( this - > overlapped . hEvent ) ;
}
else if ( lastError = = ERROR_NO_DATA )
{
DisconnectNamedPipe ( this - > serverHandle_ ) ;
this - > bFirstTime = true ;
TryConnect ( ) ;
}
else
{
SysPushErrorIO ( " {} " , lastError ) ;
}
2022-04-17 12:40:08 +00:00
}
}
}
IPCPipeImpl : : ~ IPCPipeImpl ( )
{
2023-12-24 06:54:19 +00:00
if ( this - > fsHandle_ )
{
AuStaticCast < AFileHandle > ( this - > fsHandle_ ) - > pIPCPipe = nullptr ;
}
2022-04-17 12:40:08 +00:00
}
AuSPtr < Loop : : ILoopSource > IPCPipeImpl : : AsReadChannelIsOpen ( )
{
if ( this - > serverHandle_ = = INVALID_HANDLE_VALUE )
{
return { } ;
}
if ( ! this - > lshasConnection_ )
{
this - > lshasConnection_ = AuMakeShared < IPCHasConnectionEvent > ( AuSharedFromThis ( ) ) ;
}
2022-06-22 13:42:17 +00:00
return this - > lshasConnection_ ;
2022-04-17 12:40:08 +00:00
}
AuSPtr < Loop : : ILoopSource > IPCPipeImpl : : AsReadChannelHasData ( )
{
2023-09-16 21:47:45 +00:00
return this - > SharedFromThis ( ) ;
2022-04-17 12:40:08 +00:00
}
2022-05-12 08:04:32 +00:00
AuSPtr < IO : : IAsyncTransaction > IPCPipeImpl : : NewAsyncTransaction ( )
2022-04-17 12:40:08 +00:00
{
2022-06-22 20:24:04 +00:00
auto transaction = AuStaticCast < AuFS : : NtAsyncFileTransaction > ( this - > fsStream_ - > NewTransaction ( ) ) ;
if ( transaction )
{
2022-08-18 16:19:32 +00:00
transaction - > pNtIpcPipeImpl = AuSharedFromThis ( ) ;
2022-06-22 20:24:04 +00:00
}
return transaction ;
2022-04-17 12:40:08 +00:00
}
2023-07-29 07:52:33 +00:00
AuSPtr < IO : : IIOHandle > IPCPipeImpl : : GetCurrentSharedDuplexHandles ( )
{
return this - > fsHandle_ ;
}
2022-04-17 12:40:08 +00:00
bool IPCPipeImpl : : Read ( const Memory : : MemoryViewStreamWrite & write , bool nonblocking )
{
DWORD size = write . length ;
2023-12-28 16:49:11 +00:00
write . outVariable = 0 ;
2022-04-17 12:40:08 +00:00
TryConnect ( ) ;
auto h = this - > GetPipeHandle ( ) ;
if ( h = = INVALID_HANDLE_VALUE )
{
SysPushErrorUninitialized ( ) ;
return false ;
}
2022-05-01 19:16:36 +00:00
if ( nonblocking | | ! write . ptr )
{
DWORD avail { } ;
if ( ! PeekNamedPipe ( h , NULL , NULL , NULL , & avail , NULL ) )
{
return false ;
}
if ( ! avail )
{
return true ;
}
size = AuMin ( size , avail ) ;
}
2022-04-17 12:40:08 +00:00
if ( ! write . ptr )
{
write . outVariable = size ;
return true ;
}
2022-07-05 19:35:40 +00:00
OVERLAPPED a { } ;
a . hEvent = CreateEventA ( NULL , true , 0 , NULL ) ;
if ( ! : : ReadFile ( h , write . ptr , size , NULL , & a ) & &
: : GetLastError ( ) ! = ERROR_IO_PENDING )
{
: : CloseHandle ( a . hEvent ) ;
return false ;
}
: : WaitForSingleObject ( a . hEvent , 0 ) ;
if ( ! : : GetOverlappedResult ( h , & a , & size , true ) )
{
: : CloseHandle ( a . hEvent ) ;
return false ;
}
: : CloseHandle ( a . hEvent ) ;
2022-04-17 12:40:08 +00:00
write . outVariable = size ;
2022-07-05 19:35:40 +00:00
return true ;
2022-04-17 12:40:08 +00:00
}
bool IPCPipeImpl : : Write ( const Memory : : MemoryViewStreamRead & read )
{
2023-12-28 16:49:11 +00:00
read . outVariable = 0 ;
2022-04-17 12:40:08 +00:00
auto h = this - > GetPipeHandle ( ) ;
if ( h = = INVALID_HANDLE_VALUE )
{
SysPushErrorUninitialized ( ) ;
return false ;
}
TryConnect ( ) ;
DWORD temp ;
2022-07-05 19:35:40 +00:00
OVERLAPPED a { } ;
a . hEvent = CreateEventA ( NULL , true , 0 , NULL ) ;
if ( ! : : WriteFile ( h , read . ptr , read . length , NULL , & a ) & &
: : GetLastError ( ) ! = ERROR_IO_PENDING )
{
SysPushErrorIO ( " {} " , GetLastError ( ) ) ;
: : CloseHandle ( a . hEvent ) ;
return false ;
}
: : WaitForSingleObject ( a . hEvent , 0 ) ;
if ( ! : : GetOverlappedResult ( h , & a , & temp , true ) )
2022-04-17 12:40:08 +00:00
{
2022-07-05 19:35:40 +00:00
: : CloseHandle ( a . hEvent ) ;
2022-04-17 12:40:08 +00:00
return false ;
}
2022-07-05 19:35:40 +00:00
: : CloseHandle ( a . hEvent ) ;
2022-04-17 12:40:08 +00:00
read . outVariable = temp ;
return true ;
}
HANDLE IPCPipeImpl : : GetPipeHandle ( )
{
return this - > clientHandle_ = = INVALID_HANDLE_VALUE ? this - > serverHandle_ : this - > clientHandle_ ;
}
2022-06-22 20:24:04 +00:00
HANDLE IPCPipeImpl : : GetConnectHandle ( )
{
return ( HANDLE ) AuStaticCast < Loop : : LSEvent > ( this - > hasClient_ ) - > GetHandle ( ) ;
}
void IPCPipeImpl : : OnEndOfReadStream ( )
{
// TODO: fire inverse LS
DisconnectNamedPipe ( this - > serverHandle_ ) ;
this - > bFirstTime = true ;
this - > TryConnect ( ) ;
}
2022-04-17 12:40:08 +00:00
bool IPCPipeImpl : : IsSignaled ( )
{
DWORD avail { } ;
TryConnect ( ) ;
if ( ! PeekNamedPipe ( this - > GetPipeHandle ( ) , NULL , NULL , NULL , & avail , NULL ) )
{
return false ;
}
return avail ;
}
bool IPCPipeImpl : : WaitOn ( AuUInt32 timeout )
{
return LSHandle : : WaitOn ( timeout ) ;
}
Loop : : ELoopSource IPCPipeImpl : : GetType ( )
{
return Loop : : ELoopSource : : eSourceIPCReadPipe ;
}
AuString IPCPipeImpl : : ExportToString ( )
{
TryConnect ( ) ;
return this - > clientHandle_ = = INVALID_HANDLE_VALUE ?
this - > ipcHandle_ . ToString ( ) :
AuString { } ;
}
2023-10-20 15:33:18 +00:00
AuSPtr < IO : : FS : : IFileStream > IPCPipeImpl : : ToFileStream ( )
{
return this - > fsBlockingStream_ ;
}
AuSPtr < IStreamReader > IPCPipeImpl : : ToStreamReader ( )
{
2023-10-21 09:39:47 +00:00
return AuSPtr < IStreamReader > ( this - > SharedFromThis ( ) , & this - > pipeReader_ ) ;
2023-10-20 15:33:18 +00:00
}
AuSPtr < IStreamWriter > IPCPipeImpl : : ToStreamWriter ( )
{
2023-10-21 09:39:47 +00:00
return AuSPtr < IStreamWriter > ( this - > SharedFromThis ( ) , & this - > pipeWriter_ ) ;
2023-10-20 15:33:18 +00:00
}
2023-10-20 09:45:59 +00:00
AUKN_SYM AuSPtr < IPCPipe > NewPipeEx ( AuUInt32 uBytesLength )
2022-04-16 17:40:36 +00:00
{
2022-07-21 06:18:53 +00:00
IPC : : IPCHandle handle ;
IPC : : IPCToken token ;
token . NewId ( ) ;
2022-04-17 12:40:08 +00:00
2022-07-21 06:18:53 +00:00
handle . PushId ( EIPCHandleType : : eIPCPipe , token ) ;
auto path = token . ToNTPath ( ) ;
2024-01-03 02:39:54 +00:00
# if defined(AURORA_PLATFORM_WIN32)
2022-07-21 06:18:53 +00:00
auto name = " \\ \\ . \\ pipe \\ " + token . ToNTPath ( ) ;
2024-01-03 02:39:54 +00:00
# else
auto name = " \\ \\ . \\ pipe \\ LOCAL \\ " + token . ToNTPath ( ) ;
# endif
2023-10-20 09:45:59 +00:00
auto pageSize = AuHwInfo : : GetPageSize ( ) ;
auto maxLength = uBytesLength ? AuPageRound ( uBytesLength , pageSize ) : pageSize ? 16 * pageSize : 4096 ;
2022-04-17 12:40:08 +00:00
auto pipeServer = CreateNamedPipeA ( name . c_str ( ) ,
2023-10-20 09:45:59 +00:00
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED ,
PIPE_WAIT ,
1 ,
maxLength ,
maxLength ,
NMPWAIT_WAIT_FOREVER ,
nullptr ) ;
2022-07-21 06:18:53 +00:00
if ( ( ! pipeServer ) | |
( pipeServer = = INVALID_HANDLE_VALUE ) )
2022-04-17 12:40:08 +00:00
{
SysPushErrorIO ( " {} " , GetLastError ( ) ) ;
return { } ;
}
auto object = AuMakeShared < IPCPipeImpl > ( INVALID_HANDLE_VALUE , pipeServer , handle ) ;
if ( ! object )
{
SysPushErrorMem ( ) ;
AuWin32CloseHandle ( pipeServer ) ;
return { } ;
}
2023-12-16 21:08:46 +00:00
if ( object - > bDead )
{
SysPushErrorMemory ( ) ;
SysPushErrorNested ( ) ;
return { } ;
}
2022-04-17 12:40:08 +00:00
return object ;
2022-04-16 17:40:36 +00:00
}
2022-04-16 15:42:48 +00:00
2023-10-20 09:45:59 +00:00
AUKN_SYM AuSPtr < IPCPipe > NewPipe ( )
{
return NewPipeEx ( 0 ) ;
}
2022-04-17 12:40:08 +00:00
AUKN_SYM AuSPtr < IPCPipe > ImportPipe ( const AuString & handleString )
2022-04-16 17:40:36 +00:00
{
2022-04-17 12:40:08 +00:00
IPCHandle handle ;
HANDLE pipe ;
if ( ! handle . FromString ( handleString ) )
{
SysPushErrorParseError ( ) ;
return { } ;
}
2022-07-21 06:18:53 +00:00
auto token = handle . GetToken ( EIPCHandleType : : eIPCPipe , 0 ) ;
if ( ! token )
{
SysPushErrorParseError ( ) ;
return { } ;
}
2024-01-03 02:39:54 +00:00
# if defined(AURORA_PLATFORM_WIN32)
2022-07-21 06:18:53 +00:00
auto name = " \\ \\ . \\ pipe \\ " + token - > token . ToNTPath ( ) ;
2024-01-03 02:39:54 +00:00
# else
auto name = " \\ \\ . \\ pipe \\ LOCAL \\ " + token - > token . ToNTPath ( ) ;
# endif
2024-04-09 22:39:00 +00:00
pipe = Win32Open ( AuLocale : : ConvertFromUTF8 ( name ) . c_str ( ) ,
GENERIC_WRITE | GENERIC_READ ,
0 ,
false ,
OPEN_ALWAYS ,
2024-04-10 07:20:47 +00:00
FILE_FLAG_OVERLAPPED ,
FILE_ATTRIBUTE_NORMAL ) ;
2022-04-17 12:40:08 +00:00
2022-07-21 06:18:53 +00:00
if ( ( ! pipe ) | |
( pipe = = INVALID_HANDLE_VALUE ) )
2022-04-17 12:40:08 +00:00
{
if ( GetLastError ( ) = = ERROR_PIPE_BUSY )
{
SysPushErrorIO ( " Pipe is used -> a client has already connected or the nt server is not ready " ) ;
return { } ;
}
SysPushErrorIO ( " {} " , GetLastError ( ) ) ;
return { } ;
}
auto object = AuMakeShared < IPCPipeImpl > ( pipe , INVALID_HANDLE_VALUE , handle ) ;
if ( ! object )
{
2023-12-16 21:08:46 +00:00
SysPushErrorMemory ( ) ;
2022-04-17 12:40:08 +00:00
AuWin32CloseHandle ( pipe ) ;
return { } ;
}
2023-12-16 21:08:46 +00:00
if ( object - > bDead )
{
SysPushErrorMemory ( ) ;
SysPushErrorNested ( ) ;
return { } ;
}
2022-04-17 12:40:08 +00:00
return object ;
2022-04-16 17:40:36 +00:00
}
2022-04-17 12:40:08 +00:00
}
// > The pipe created by UWP process with name \\.\pipe\Local\PipeName is converted to \\.\pipe\Sessions\<SessionId>\AppContainerNamedObjects\<AppContainerSid>\PipeName.
// > I can use this to communicate between UWP as server and Win32 as client.
// https://jike.in/qa/?qa=103904/
// ...good to know