local process=nil

if getOperatingSystem()~=2 then return 'invalid operating system' end

--todo: javapipe, etc...
function WinePipe2Socket(monoport)
  if process==getOpenedProcessID() then
    return true,'already hooked'
  end
  
  local loaded,err=autoAssemble([[
[ENABLE]
{$lua}
setModulePreference('ucrtbase') --so that 'malloc' will refer to the ucrtbase version
setModulePreference('ws2_32') --so that 'socket' will refer to the ws2_32 version (alternatively, loadlibrary)

{$asm}


{$c windows}
#include <stddef.h>
#include <stdint.h>
#include <windowslite.h>

#include <celog.h>
#include <cesocket.h>

typedef uint16_t WORD;
typedef uint8_t BYTE;
typedef uint32_t DWORD;
typedef size_t DWORD_PTR;
typedef int BOOL;

#define MAKEWORD(a,b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8))

extern int socket(int, int,int);
//extern int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

extern void *oldCreateNamedPipeW(wchar_t* pipename, int dwOpenMode, int dwPipeMode, int nMaxInstances, int nOutBufferSize, int nInBufferSize, int nDefaultTimeOut, void* lpSecurityAttributes);

extern int WSAStartup(uint16_t wVersionRequired, void* wsaData);
//pipehandle = CreateNamedPipeW(datapipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 100, 256 * 1024, 16, INFINITE, NULL);



void MessageBoxA(int,char *, char*, int);


uint64_t *clients;
int clientspos;
int clientsmax;
uint64_t monoserversocket=0;
uint64_t lastConnection;

void* newCreateNamedPipeW(wchar_t* pipename, int dwOpenMode, int dwPipeMode, int nMaxInstances, int nOutBufferSize, int nInBufferSize, int nDefaultTimeOut, void* lpSecurityAttributes)
{

  //MessageBoxA(0,"CreateNamedPipeW called", "newCreateNamedPipeW" ,0);
  if ((pipename[0]=='\\') && (pipename[1]=='\\')  && (pipename[2]=='.')  && (pipename[3]=='\\') &&
     (pipename[4]=='p')  && (pipename[5]=='i')   && (pipename[6]=='p')  && (pipename[7]=='e')  && (pipename[8]=='\\') &&
     (pipename[9]=='c')  && (pipename[10]=='e')  && (pipename[11]=='m') && (pipename[12]=='o') &&
     (pipename[13]=='n') && (pipename[14]=='o'))
  {
    char wsaData[512];
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    //MessageBoxA(0,"it is a cemono pipe", "newCreateNamedPipeW",0);

    if (monoserversocket==0)
    {
      monoserversocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

      if (monoserversocket)
      {

        //MessageBoxA(0,"created the socket", "newCreateNamedPipeW", 0);

        sockaddr_in serverAddr;
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_addr = inet_addr("127.0.0.1");
        serverAddr.sin_port = htons(]]..monoport..[[);

        bind(monoserversocket, (const struct sockaddr *)&serverAddr, sizeof(serverAddr));
        if (nMaxInstances==0)
          nMaxInstances=16;

        int lr=listen(monoserversocket, nMaxInstances);
        if (lr)
          MessageBoxA(0,"failed to listen","newCreateNamedPipeW", 0);
      }
      else
        MessageBoxA(0,"failed creating a socket","newCreateNamedPipeW", 0);
    }

    if (monoserversocket)
    {
      struct sockaddr_un addr_client;
      socklen_t clisize;
      int a=-1;

      //connect now as well and store the new socket in the list of clients
      //MessageBoxA(0,"waiting for connection","newCreateNamedPipeW", 0);

      a=accept(monoserversocket, NULL,NULL);
      if (a==-1)
        MessageBoxA(0,"after connected. Failure","newCreateNamedPipeW", 0);
      else
      {
        lastConnection=a;
        //MessageBoxA(0,"after connected. Success","newCreateNamedPipeW", 0);
      }


      return a;
    }
  }
  //else
  //  MessageBoxA(0,"not a cemono pipe","newCreateNamedPipeW",0);

  return oldCreateNamedPipeW(pipename, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, lpSecurityAttributes);
}


BOOL oldConnectNamedPipe(uint64_t hNamedPipe, void* lpOverlapped);

BOOL newConnectNamedPipe(uint64_t hNamedPipe, void* lpOverlapped)
{
  //MessageBoxA(0,"NewConnectNamedPipe entry","newConnectNamedPipe",0);

  //if it is a known client socket, exit true
  if ((lastConnection) && (lastConnection==hNamedPipe))
    return 1;


  return oldConnectNamedPipe(hNamedPipe, lpOverlapped);
}


{$asm}


hook(CreateNamedPipeW,newCreateNamedPipeW,oldCreateNamedPipeW)
hook(ConnectNamedPipe,newConnectNamedPipe,oldConnectNamedPipe)



[DISABLE]

unhook(CreateNamedPipeW)
unhook(ConnectNamedPipe)
]])

  process=getOpenedProcessID()

  return loaded,'new hook'
end

return 'loaded2'