#if !defined(__linux__) && !defined(ANDROID)
#include <winsock2.h>
#include <synchapi.h>
typedef SOCKET socket_t; /* https://stackoverflow.com/questions/10817252/why-is-invalid-socket-defined-as-0-in-winsock2-h-c */
#ifndef SHUT_WR
#define SHUT_WR SD_SEND
#endif
#ifndef SHUT_RD
#define SHUT_RD SD_RECEIVE
#endif
#define close(s) closesocket(s)
#ifndef messagebox
#define messagebox(str) MessageBoxA(NULL,str,"win32_pipe",0);
#endif
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
typedef int socket_t;
#define INVALID_SOCKET -1
#endif

#ifndef FILLIPV4ADDR
#define FILLIPV4ADDR(a,family,addr,port) \
                memset(&(a),0,sizeof(struct sockaddr_in)),\
                s.sin_family=family,\
                s.sin_addr.s_addr=addr,\
                s.sin_port=htons(port)
#endif


#if 1
#include <stdio.h>
#endif

static int *
win32pipe_initvalue(void)
{
        static int init=0;
        return(&init);
}

int
win32pipe_init(void)
{
        int *init;
        init=win32pipe_initvalue();
        if(*init!=0)
                return(0);
        *init=1;
#if !defined(__linux__) && !defined(ANDROID)
        {
                WSADATA wsaData;
                return(WSAStartup(0x202,&wsaData));
        }
#else
        return(0);
#endif
}

void
win32pipe_fini(void)
{
        int *init;
        init=win32pipe_initvalue();
        if(*init==0)
                return;
#if !defined(__linux__) && !defined(ANDROID)
        WSACleanup();
#endif
        *init=0;
}

int
win32pipe_pipe(int fds[2])
{
        socket_t serverfd,workfd,clientfd;
        struct sockaddr_in s;
        int sizes;
        unsigned char *ip;
        char *errstr;
        win32pipe_init();
        FILLIPV4ADDR(s,AF_INET,htonl(INADDR_ANY),0);
        ip=(unsigned char *) &(s.sin_addr.s_addr);
        ip[0]=127,ip[1]=0,ip[2]=0,ip[3]=1;
        serverfd=workfd=clientfd=INVALID_SOCKET;
        if((errstr="Couldn't create server socket")==NULL
          || (serverfd=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET
          || (errstr="Couldn't bind server socket")==NULL
          || bind(serverfd,(struct sockaddr *)&s,sizeof(s))!=0
          || (errstr="Couldn't listen on server socket")==NULL
          || listen(serverfd,4)==-1
          || (sizes=sizeof(s))!=sizeof(s)
          || (errstr="Couldn't get server socket name")==NULL
          || getsockname(serverfd,(struct sockaddr *)&s,&sizes)==-1
          || (errstr="Couldn't create client socket")==NULL
          || (clientfd=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET
          || (errstr="Couldn't connect client socket to server socket")==NULL
          || connect(clientfd,(struct sockaddr *)&s,sizeof(s))==-1
          || (errstr="Couldn't accept client socket connection to server socket")==NULL
          || (workfd=accept(serverfd,(struct sockaddr *)&s,&sizes))==-1
        ) {
                {
                        char errbuf[4096];
                        unsigned char *ip;
                        int port;
                        if(strcmp(errstr,"Couldn't connect client socket to server socket")==0) {
                                ip=(unsigned char *) &(s.sin_addr.s_addr);
                                port=ntohs(s.sin_port);
                                snprintf(errbuf,sizeof(errbuf),"%s\nWinsock error: %ld\nRemote address:%i.%i.%i.%i\nRemote port:%i"
                                  ,errstr
                                  ,WSAGetLastError()
                                  ,(int)(ip[0]),(int)(ip[1]),(int)(ip[2]),(int)(ip[3])
                                  ,port
                                );
                        } else {
                                snprintf(errbuf,sizeof(errbuf),"%s\nWinsock error: %ld",errstr,WSAGetLastError());
                        }
                        errbuf[sizeof(errbuf)-1]='\0';
                        messagebox(errbuf);
                }

                if(serverfd!=-1)
                        close(serverfd),serverfd=-1;
                if(clientfd!=-1)
                        close(clientfd),clientfd=-1;
                if(workfd!=-1)
                        close(workfd),workfd=-1;
                return(-1);
        }
        close(serverfd),serverfd=-1;
        shutdown(workfd,SHUT_WR);
        shutdown(clientfd,SHUT_RD);
        fds[0]=workfd,workfd=-1;
        fds[1]=clientfd,clientfd=-1;
        return(0);
}

int
win32pipe_read(int fd, char *buf, int count)
{
        return(recv(fd,buf,count,0));
}

int
win32pipe_write(int fd, char *buf, int count)
{
        return(send(fd,buf,count,0));
}

int
win32pipe_sleep(int ms)
{
       Sleep(ms);
       return(0);
}