\ Windows Sockets

WINAPI: socket          WSOCK32.DLL
WINAPI: listen          WSOCK32.DLL
WINAPI: accept          WSOCK32.DLL
WINAPI: connect         WSOCK32.DLL
WINAPI: send            WSOCK32.DLL
WINAPI: recv            WSOCK32.DLL
WINAPI: closesocket     WSOCK32.DLL
WINAPI: bind            WSOCK32.DLL
WINAPI: ioctlsocket     WSOCK32.DLL
WINAPI: WSAGetLastError WSOCK32.DLL
WINAPI: gethostbyaddr   WSOCK32.DLL
WINAPI: gethostbyname   WSOCK32.DLL
WINAPI: getpeername     WSOCK32.DLL
WINAPI: WSAStartup      WSOCK32.DLL
WINAPI: WSACleanup      WSOCK32.DLL
WINAPI: inet_addr       WSOCK32.DLL
\ WINAPI: inet_ntoa       WSOCK32.DLL

1  CONSTANT SOCK_STREAM
-1 CONSTANT INVALID_SOCKET
-1 CONSTANT SOCKET_ERROR
2  CONSTANT PF_INET
2  CONSTANT AF_INET
6  CONSTANT IPPROTO_TCP

0
2 -- sin_family
2 -- sin_port
4 -- sin_addr
8 -- sin_zero
CONSTANT /sockaddr_in

CREATE sock_addr HERE /sockaddr_in DUP ALLOT ERASE
AF_INET sock_addr sin_family W!


: CreateSocket ( -- socket ior )
  IPPROTO_TCP SOCK_STREAM PF_INET
  socket DUP INVALID_SOCKET =
  IF WSAGetLastError
  ELSE 0 THEN
;
: ToRead ( socket -- n ior )
  \       
  \    ReadSocket   
  \    n=0
  PAD [ HEX ] 4004667F [ DECIMAL ] ROT ioctlsocket SOCKET_ERROR =
  IF 0 WSAGetLastError ELSE PAD @ 0 THEN
;
: ConnectSocket ( IP port socket -- ior )
  >R
  256 /MOD SWAP 256 * +
  sock_addr sin_port W!
  sock_addr sin_addr !
  /sockaddr_in sock_addr R> connect SOCKET_ERROR =
  IF WSAGetLastError ELSE 0 THEN
;
: CloseSocket ( s -- ior )
  closesocket SOCKET_ERROR =
  IF WSAGetLastError ELSE 0 THEN
;
: WriteSocket ( addr u s -- ior )
  >R SWAP 2>R 0 2R> R> send SOCKET_ERROR =
  IF WSAGetLastError ELSE 0 THEN
;
: WriteSocketLine ( addr u s -- ior )
  DUP >R WriteSocket ?DUP IF R> DROP EXIT THEN
  LT LTL @ R> WriteSocket
;
: WriteSocketCRLF ( s -- ior )
  HERE 0 ROT WriteSocketLine
;
: ReadSocket ( addr u s -- rlen ior )
  >R SWAP 2>R 0 2R> R> recv DUP SOCKET_ERROR =
  IF WSAGetLastError ELSE 0 THEN
  OVER 0= IF DROP -1002 THEN
  (   0,    )
;
: GetHostName ( IP -- addr u ior )
  PAD ! PF_INET 4 PAD gethostbyaddr
  ?DUP IF @ ASCIIZ> 0 ELSE HERE 0 WSAGetLastError THEN
;
: Get.Host.Name ( addr u -- addr u ior )
  DROP inet_addr GetHostName
;
: GetHostIP ( addr u -- IP ior )
  DROP gethostbyname DUP IF 3 CELLS + @ @ @ 0
                         ELSE WSAGetLastError THEN
;
CREATE sock_addr2 HERE /sockaddr_in DUP ALLOT ERASE
AF_INET sock_addr2 sin_family W!

: GetPeerName ( s -- addr u ior )
  /sockaddr_in HERE !
  HERE sock_addr2 ROT getpeername SOCKET_ERROR =
  IF HERE 0 WSAGetLastError
  ELSE sock_addr2 sin_addr @ GetHostName THEN
;
: SocketsStartup ( -- ior )
  HERE 257 WSAStartup
;
: SocketsCleanup ( -- ior )
  WSACleanup
;
: BindSocket ( port s -- ior )
  >R /sockaddr_in ALLOCATE ?DUP IF NIP R> DROP EXIT THEN
  >R
  256 /MOD SWAP 256 * +
  R@ sin_port W!
  AF_INET R@ sin_family W!
  R@
  0 R@ sin_addr !
  /sockaddr_in R> R> bind SWAP FREE DROP SOCKET_ERROR =
  IF WSAGetLastError ELSE 0 THEN
;
: ListenSocket ( s -- ior )
  2 SWAP listen SOCKET_ERROR =
  IF WSAGetLastError ELSE 0 THEN
;
CREATE SINLEN /sockaddr_in ,

: AcceptSocket ( s -- s2 ior )
  SINLEN HERE ROT accept DUP INVALID_SOCKET =
  IF WSAGetLastError ELSE 0 THEN
;
: NtoA ( IP -- addr u )
  [ BASE @ HEX ]
  >R 0 0 <# 2DROP R@  1000000 U/ FF AND 0 #S [CHAR] . HOLD
            2DROP R@    10000 U/ FF AND 0 #S [CHAR] . HOLD
            2DROP R@      100 U/ FF AND 0 #S [CHAR] . HOLD
            2DROP R>             FF AND 0 #S
         #>
  [ BASE ! ]
;