Inspired by Benjamin Wharton's Winsock, Multisync, and Tempest Network Libraries, I set off on a adventure to learn more about Winsock in DBP and create my own TCP/UDP Network Lib with Winsock in DB. In this sub-project I'm getting exposed to DLLs, advance DBP features like Pointers, and the lower inner workings Networking in Windows.
My goal for Inter-Connector (iCon or DarkICon?) is to support both TCP/UDP. I expect to learn and share what I uncover in this project with all interested parties. If all else fails, I will resort Benjamin's excellent Network Libraries.
iCon Network Lib v011208
`iCon Winsock Library v011208 by Techlord
`Inspired by Benjamin Wharton's Winsock DBP library
`
`LINKS
`Functions - http://msdn2.microsoft.com/en-us/library/ms741394.aspx
`Error codes - http://msdn2.microsoft.com/en-us/library/ms740668.aspx
`Sockets for Dummies - http://www.amk.ca/python/howto/sockets/
#Constant ICON_NETWORK_DATA_SIZE 400
#Constant ICON_NETWORK_ERROR -1
#Constant ICON_SOCKET_MAX 64
#Constant ICON_SOCKET_AF_INET 2
#Constant ICON_SOCKET_STREAM 1
#Constant ICON_SOCKET_DGRAM 2
#Constant ICON_SOCKET_IPPROTO_TCP 6
#Constant ICON_SOCKET_IPPROTO_UDP 17
#Constant ICON_SOCKET_ADDRESS_SIZE 16
#Constant ICON_SOCKET_DATA_BUFFER_SIZE 256
#Constant ICON_SOCKET_ERROR_WSAEWOULDBLOCK 10035
#Constant ICON_SOCKET_ERROR -1
#Constant ICON_SOCKET_INVALID -1
#Constant ICON_SOCKET_FIONBIO 0x8004667e `Reference: http://www.xs4all.nl/~rjg70/vbapi/ref/i/ioctlsocket.html
Type iCon_Socket
`Purpose: iCon_Socket Object
`Properties:
ID as Integer
TCPSocket as Dword
UDPSocket as Dword
IP as String
Port as Word
Type as byte
Protocol as byte
AddressPtr as Dword
RecvAddressPtr as Dword
AddressFamilyAndPort
AddressSize as Byte
TCPDataBufferPtr as Dword
UDPDataBufferPtr as Dword
TCPDataBufferLength as Dword
UDPDataBufferLength as Dword
TCPDataBufferBytesRecvPtr as Dword
TCPDataBufferBytesSendPtr as Dword
EndType
Type iCon_Server
ListenSocket as iCon_Socket
FdSetReadPtr as Dword
FdSetWritePtr as Dword
FdSetExceptPtr as Dword
TimeValPtr as Dword
ClientTCPSockets as Word
ClientUDPSockets as Word
EndType
Function iCon_Declarations()
`Purpose: Initializes Arrays and Globals for use a 3rd party Dba Lib.
`Parameters: None
`Return: None
`Globals
Global iCon_DLLID
Global iCon_ErrorMessage$
Global iCon_SocketIndex
Global iCon_Server As iCon_Server
Global iCon_SocketNoBlockPtr as Dword
Global iCon_NetworkSockets as Dword
`Arrays
Dim iCon_Socket() As iCon_Socket
EndFunction 0
Function iCon_NetworkStart()
`Purpose: Loads and initializes Winsock
`Parameters: None
`Return: 1 for success, -1 for failure
iCon_Declarations()
Repeat `find available DBP dll ID
Inc iCon_DLLID
If iCon_DLLID > 256
iCon_ErrorMessage$ = "DLL ID Not Avaliable!"
ExitFunction ICON_NETWORK_ERROR
EndIf
Until Not DLL Exist(iCon_DLLID)
Load DLL "ws2_32.dll",iCon_DLLID
iCon_WSAdata = Make Memory(ICON_NETWORK_DATA_SIZE)
iCon_WSAStartup = Call DLL(iCon_DLLID, "WSAStartup", 0x0202, iCon_WSAdata)
Delete Memory iCon_WSAdata
If iCon_WSAStartup > 0
iCon_ErrorMessage$ = "Failed to Start! ErrorCode[" + Str$(iCon_WSAStartup) + "]"
ExitFunction ICON_NETWORK_ERROR
EndIf
iCon_SocketNoBlockPtr = Make Memory(1)
*iCon_SocketNoBlockPtr = 1
EndFunction 1
Function iCon_NetworkStop()
`Purpose: Frees any allocated resources and DLL
`Parameters: None
`Return: 1
If iCon_SocketNoBlockPtr Then Delete Memory iCon_SocketNoBlockPtr
Call DLL iCon_DLLID, "WSACleanup"
Delete DLL iCon_DLLID
EndFunction 1
Function iCon_SocketNew(iCon_IP As String, iCon_Port As word)
`Purpose: Creates a TCP and UDP socket, allocates and sets address structure
`Parameters:
` iCon_IP "xxx.xxx.xxx.xxx"
` iCon_Port
`Return: socket ID or -1 if any failure occurs. Use iCon_Error and iCon_ErrorMessage to view error.
`TCP Socket
iCon_TCPSocket = Call DLL(iCon_DLLID, "socket", ICON_SOCKET_AF_INET, ICON_SOCKET_STREAM, ICON_SOCKET_IPPROTO_TCP)
If iCon_TCPSocket = ICON_SOCKET_INVALID
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed to Open TCP Socket! ErrorCode[" + Str$(iCon_Error) + "]"
ExitFunction ICON_SOCKET_INVALID
EndIf
`UDP Socket
iCon_UDPSocket = Call DLL(iCon_DLLID, "socket", ICON_SOCKET_AF_INET, ICON_SOCKET_DGRAM, ICON_SOCKET_IPPROTO_UDP)
If iCon_UDPSocket = ICON_SOCKET_INVALID
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed to Open UDP Socket! ErrorCode[" + Str$(iCon_Error) + "]"
ExitFunction ICON_SOCKET_INVALID
EndIf
Add To Queue iCon_Socket()
this = iCon_SocketIndex
iCon_Socket(this).ID = this
iCon_Socket(this).IP = iCon_IP
iCon_Socket(this).Port = iCon_Port
iCon_Socket(this).TCPSocket = iCon_TCPSocket
iCon_Socket(this).UDPSocket = iCon_UDPSocket
iCon_Socket(this).TCPDataBufferPtr = Make Memory(ICON_SOCKET_DATA_BUFFER_SIZE + 4) `WSABUF Structure (u_long len) + (CHAR buf)
iCon_Socket(this).UDPDataBufferPtr = Make Memory(ICON_SOCKET_DATA_BUFFER_SIZE + 4)
iCon_SocketTCPDataBufferPtr = iCon_Socket(this).TCPDataBufferPtr
iCon_SocketUDPDataBufferPtr = iCon_Socket(this).UDPDataBufferPtr
*iCon_SocketTCPDataBufferPtr = ICON_SOCKET_DATA_BUFFER_SIZE
*iCon_SocketUDPDataBufferPtr = ICON_SOCKET_DATA_BUFFER_SIZE
Inc iCon_SocketIndex
`Address Structure: IP address & port of the Server to be connected to.
iCon_Socket(this).AddressPtr = Make Memory(ICON_SOCKET_ADDRESS_SIZE)
iCon_Socket(this).AddressFamilyAndPort = ICON_SOCKET_AF_INET || (Call DLL(iCon_DLLID, "htons", iCon_Socket(this).Port) << 16)
iCon_SocketAddressPtr = iCon_Socket(this).AddressPtr
iCon_SocketIPPtr = iCon_Socket(this).AddressPtr + 4
*iCon_SocketAddressPtr = iCon_Socket(this).AddressFamilyAndPort
*iCon_SocketIPPtr = Call DLL(iCon_DLLID, "inet_addr", iCon_Socket(this).IP)
Print "iCon_Socket(" + Str$(iCon_Socket(this).ID) + ") = " + Str$(iCon_Socket(this).TCPSocket)
EndFunction this
Function iCon_SocketOpen(iCon_IP As String, iCon_Port As word)
`Purpose: Creates a new socket and Connects to a server
`Parameters:
` iCon_IP "xxx.xxx.xxx.xxx"
` iCon_Port
`Return: socket ID or -1 if any failure occurs. Use iCon_Error and iCon_ErrorMessage to view error.
If iCon_NetworkStart() = ICON_NETWORK_ERROR Then ExitFunction ICON_NETWORK_ERROR
this = iCon_SocketNew(iCon_IP, iCon_Port)
If this = ICON_SOCKET_INVALID Then ExitFunction ICON_SOCKET_INVALID
`Connect to server
iCon_SocketConnect = Call DLL(iCon_DLLID, "connect", iCon_Socket(this).TCPSocket, iCon_Socket(this).AddressPtr, ICON_SOCKET_ADDRESS_SIZE)
If iCon_SocketConnect = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed to Connect! ErrorCode[" + Str$(iCon_Error) + "]"
iCon_SocketClose(this)
ExitFunction ICON_SOCKET_ERROR
EndIf
Print "iCon_SocketConnect = " + Str$(iCon_SocketConnect)
EndFunction this
Function iCon_SocketClose(this) `- disconnects If connected, and free Socket
`Purpose: Close socket and Free memory
`Parameters: None
`Return: 0
If iCon_Socket(this).AddressPtr Then Delete Memory iCon_Socket(this).AddressPtr
If iCon_Socket(this).RecvAddressPtr Then Delete Memory iCon_Socket(this).RecvAddressPtr
If iCon_Socket(this).TCPDataBufferPtr Then Delete Memory iCon_Socket(this).TCPDataBufferPtr
If iCon_Socket(this).UDPDataBufferPtr Then Delete Memory iCon_Socket(this).UDPDataBufferPtr
If iCon_Socket(this).TCPSocket Then Call DLL iCon_DLLID, "closesocket", iCon_Socket(this).TCPSocket
If iCon_Socket(this).UDPSocket Then Call DLL iCon_DLLID, "closesocket", iCon_Socket(this).UDPSocket
iCon_NetworkStop()
EndFunction 0
Function iCon_ServerStart(iCon_IP As String, iCon_Port As Word)
`Purpose: Creates a new socket, Binds socket to address to accept clients, Listens for client connections
`Parameters:
` iCon_SocketType: iCon_TYPE_TCP or iCon_TYPE_UDP
` iCon_IP "xxx.xxx.xxx.xxx"
` iCon_Port
`Return: Server Socket ID or -1 if any failure occurs. Use iCon_Error and iCon_ErrorMessage to view error.
If iCon_NetworkStart() = ICON_NETWORK_ERROR Then ExitFunction ICON_NETWORK_ERROR
this = iCon_SocketNew(iCon_IP, iCon_Port)
If this = ICON_SOCKET_INVALID Then ExitFunction ICON_SOCKET_INVALID
`Recv Address for UDP
iCon_Socket(this).RecvAddressPtr = Make Memory(ICON_SOCKET_ADDRESS_SIZE)
iCon_SocketRecvAddressPtr = iCon_Socket(this).RecvAddressPtr
iCon_SocketRecvIPPtr = iCon_Socket(this).RecvAddressPtr + 4
*iCon_SocketRecvAddressPtr = iCon_Socket(this).AddressFamilyAndPort
*iCon_SocketRecvIPPtr = Call DLL(iCon_DLLID, "htonl", 0x0000) `INADDR_ANY
`Bind Socket with address & port to accept TCPsockets
If Call DLL(iCon_DLLID, "bind", iCon_Socket(this).TCPSocket, iCon_Socket(this).AddressPtr, ICON_SOCKET_ADDRESS_SIZE) = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed to Bind TCP Socket! ErrorCode[" + Str$(iCon_Error) + "]"
iCon_ServerStop()
ExitFunction ICON_SOCKET_ERROR
EndIf
`Bind to UDPSocket to receive sockets
If Call DLL(iCon_DLLID, "bind", iCon_Socket(this).UDPSocket, iCon_Socket(this).RecvAddressPtr, ICON_SOCKET_ADDRESS_SIZE) = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed to Bind UDP Socket! ErrorCode[" + Str$(iCon_Error) + "]"
iCon_ServerStop()
ExitFunction ICON_SOCKET_ERROR
EndIf
`Allow connections to our bound Socket
If Call DLL(iCon_DLLID, "listen", iCon_Socket(this).TCPSocket, 10) = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed to Listen on Server Socket! ErrorCode[" + Str$(iCon_Error) + "]"
iCon_ServerStop()
ExitFunction ICON_SOCKET_ERROR
EndIf
`Change the socket mode on the listeni wsocket from blocking to non-block
iCon_SocketIOCtl = Call DLL(iCon_DLLID, "ioctlsocket",iCon_Socket(this).TCPSocket,ICON_SOCKET_FIONBIO,iCon_SocketNoBlockPtr)
if iCon_SocketIOCtl = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed Call to IOctlsocket! ErrorCode[" + Str$(iCon_Error) + "]"
iCon_ServerStop()
ExitFunction ICON_SOCKET_ERROR
EndIf
`Create FdSet Structures
iCon_Server.FdSetReadPtr = iCon_FdSetNew()
iCon_Server.FdSetWritePtr = iCon_FdSetNew()
iCon_Server.FdSetExceptPtr = iCon_FdSetNew()
iCon_Server.TimeValPtr = iCon_TimeValMake(0,0) `select will return immediately; this is used to poll the state of the selected sockets.
Print "FdSets = " + Str$(iCon_Server.FdSetReadPtr) + ", " + Str$(iCon_Server.FdSetWritePtr) + ", " + Str$(iCon_Server.FdSetExceptPtr)
`iCon_FdSetAdd(iCon_Server.FdSetReadPtr,iCon_Socket(0).TCPSocket)
`iCon_FdSetAdd(iCon_Server.FdSetExceptPtr,iCon_Socket(0).TCPSocket)
EndFunction this
Function iCon_ServerStop()
`Purpose: Close socket and Free memory and other associated memory for server
`Parameters: None
`Return: 0
If iCon_Server.FdSetReadPtr
Delete Memory iCon_Server.FdSetReadPtr
Delete Memory iCon_Server.FdSetWritePtr
Delete Memory iCon_Server.FdSetExceptPtr
Delete Memory iCon_Server.TimeValPtr
EndIf
iCon_SocketClose(0)
EndFunction 0
Function iCon_ServerAccept() `accept() - blocks until a connection is received
`Purpose: Accepts Client Connections, Creates a new socket object for managment, blocks until connection is present
`Parameters: None
`Return: Socket ID
iCon_TCPSocket = Call DLL(iCon_DLLID, "accept", iCon_Socket(0).TCPSocket, 0, 0)
If iCon_TCPSocket > ICON_SOCKET_INVALID
Add To Queue iCon_Socket()
this = iCon_SocketIndex
iCon_Socket(this).ID = this
iCon_Socket(this).Type = ICON_SOCKET_STREAM
iCon_Socket(this).Protocol = ICON_SOCKET_IPPROTO_TCP
iCon_Socket(this).TCPSocket = iCon_TCPSocket
iCon_Socket(this).AddressPtr = Make Memory(ICON_SOCKET_ADDRESS_SIZE)
iCon_Socket(this).TCPDataBufferPtr = Make Memory(ICON_SOCKET_DATA_BUFFER_SIZE + 4) `WSABUF Structure (u_long len) + (CHAR buf)
iCon_Socket(this).UDPDataBufferPtr = Make Memory(ICON_SOCKET_DATA_BUFFER_SIZE + 4)
iCon_SocketTCPDataBufferPtr = iCon_Socket(this).TCPDataBufferPtr
iCon_SocketUDPDataBufferPtr = iCon_Socket(this).UDPDataBufferPtr
*iCon_SocketTCPDataBufferPtr = ICON_SOCKET_DATA_BUFFER_SIZE
*iCon_SocketUDPDataBufferPtr = ICON_SOCKET_DATA_BUFFER_SIZE
Inc iCon_SocketIndex
Print "iCon_Socket(" + Str$(iCon_Socket(this).ID) + ") = " + Str$(iCon_Socket(this).TCPSocket) `TESTING
Else
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
If iCon_Error <> ICON_SOCKET_ERROR_WSAEWOULDBLOCK
iCon_ErrorMessage$ = "Failed to Open Socket! ErrorCode[" + Str$(iCon_Error) + "]"
iCon_ServerStop()
ExitFunction ICON_SOCKET_ERROR
EndIf
EndIf
EndFunction this
Function iCon_ServerAccept2()
`Purpose:
`Parameters:
`Return:
`reference http://www.codersource.net/winsock_tutorial_server_select_model.html
`intialize read and write socket set
iCon_FdSetZero(iCon_Server.FdSetReadPtr)
iCon_FdSetZero(iCon_Server.FdSetWritePtr)
`check for connections attempts
iCon_FdSetAdd(iCon_Server.FdSetReadPtr,iCon_Socket(0).TCPSocket)
`set read and write notification for each socket based on the current state of the buffer
For iCon_ClientTCPSocketLoop = 1 to iCon_NetworkSockets
iCon_SocketTCPDataBufferBytesRecvPtr = iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferBytesRecvPtr
iCon_SocketTCPDataBufferBytesSendPtr = iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferBytesSendPtr
iCon_SocketTCPDataBufferBytesRecvValue = *iCon_SocketTCPDataBufferBytesRecvPtr
iCon_SocketTCPDataBufferBytesSendValue = *iCon_SocketTCPDataBufferBytesSendPtr
If iCon_SocketTCPDataBufferBytesRecvValue > iCon_SocketTCPDataBufferBytesSendValue
iCon_FdSetAdd(iCon_Server.FdSetWritePtr,iCon_Socket(iCon_ClientTCPSocketLoop).TCPSocket)
Else
iCon_FdSetAdd(iCon_Server.FdSetReadPtr,iCon_Socket(iCon_ClientTCPSocketLoop).TCPSocket)
EndIf
Next 0
iCon_Server.ClientTCPSockets = Call DLL(iCon_DLLID, "select", 0, iCon_Server.FdSetReadPtr, iCon_Server.FdSetWritePtr, iCon_Server.FdSetExceptPtr, iCon_Server.TimeValPtr)
If iCon_Server.ClientTCPSockets = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Select Function Returned with Error! ErrorCode[" + Str$(iCon_Error) + "]"
iCon_ServerStop()
ExitFunction ICON_SOCKET_ERROR
EndIf
`checking for arriving connections on the listnening socket
If iCon_FdSetIs(iCon_Server.FdSetWritePtr,iCon_Socket(0).TCPSocket)
Dec iCon_Server.ClientTCPSockets
iCon_TCPSocket = Call DLL(iCon_DLLID, "accept", iCon_Socket(0).TCPSocket, 0, 0)
If iCon_TCPSocket > ICON_SOCKET_INVALID
Add To Queue iCon_Socket()
this = iCon_SocketIndex
iCon_Socket(this).ID = this
iCon_Socket(this).Type = ICON_SOCKET_STREAM
iCon_Socket(this).Protocol = ICON_SOCKET_IPPROTO_TCP
iCon_Socket(this).TCPSocket = iCon_TCPSocket
iCon_Socket(this).AddressPtr = Make Memory(ICON_SOCKET_ADDRESS_SIZE)
iCon_Socket(this).TCPDataBufferPtr = Make Memory(ICON_SOCKET_DATA_BUFFER_SIZE + 4) `WSABUF Structure (u_long len) + (CHAR buf)
iCon_Socket(this).UDPDataBufferPtr = Make Memory(ICON_SOCKET_DATA_BUFFER_SIZE + 4)
iCon_SocketTCPDataBufferPtr = iCon_Socket(this).TCPDataBufferPtr
iCon_SocketUDPDataBufferPtr = iCon_Socket(this).UDPDataBufferPtr
*iCon_SocketTCPDataBufferPtr = ICON_SOCKET_DATA_BUFFER_SIZE
*iCon_SocketUDPDataBufferPtr = ICON_SOCKET_DATA_BUFFER_SIZE
Inc iCon_SocketIndex
Print "iCon_Socket(" + Str$(iCon_Socket(this).ID) + ") = " + Str$(iCon_Socket(this).TCPSocket)
`Set the accept socket to non-blocking mode so the server will not get caught in a blocked condition on WSSASends
iCon_SocketIOCtl = Call DLL(iCon_DLLID, "ioctlsocket", iCon_Socket(this).TCPSocket, ICON_SOCKET_FIONBIO, iCon_SocketNoBlockPtr)
if iCon_SocketIOCtl = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed Call to IOctlsocket! ErrorCode[" + Str$(iCon_Error) + "]"
iCon_ServerStop()
ExitFunction ICON_SOCKET_ERROR
EndIf
Inc iCon_NetworkSockets
Else
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
If iCon_Error <> ICON_SOCKET_ERROR_WSAEWOULDBLOCK
iCon_ErrorMessage$ = "Failed to Accept! ErrorCode[" + Str$(iCon_Error) + "]"
ExitFunction ICON_SOCKET_ERROR
EndIf
EndIf
EndIf
`checking each socket for read and write notification for total number of sockets
iCon_ClientTCPSocketLoop = 1
while iCon_Server.ClientTCPSockets > 0 and iCon_ClientTCPSocketLoop < iCon_NetworkSockets
`if the reader is marked for this socket then this means data is available to be read on the socket.
If iCon_FdSetIs(iCon_Server.FdSetWritePtr,iCon_Socket(iCon_ClientTCPSocketLoop).TCPSocket)
Dec iCon_Server.ClientTCPSockets
`SocketInfo->DataBuf.buf = SocketInfo->Buffer;
`SocketInfo->DataBuf.len = BUFFERSIZE;
iCon_SocketTCPDataBufferPtr = iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferPtr
*iCon_SocketTCPDataBufferPtr = ICON_SOCKET_DATA_BUFFER_SIZE
iCon_WSARecv = Call DLL(iCon_DLLID, "WSARecv", iCon_Socket(iCon_ClientTCPSocketLoop).TCPSocket, iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferPtr + 4, 1, iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferBytesRecvPtr, FlagsPtr, NULL, NULL)
If iCon_WSARecv = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
If iCon_Error <> ICON_SOCKET_ERROR_WSAEWOULDBLOCK
iCon_ErrorMessage$ = "Failed to Recieve! ErrorCode[" + Str$(iCon_Error) + "]"
`Free Socket
Dec iCon_NetworkSockets
`ExitFunction ICON_SOCKET_ERROR
`continue
EndIf
Else
iCon_SocketTCPDataBufferBytesRecvPtr = iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferBytesRecvPtr
`if zero bytes are rx, this indicates connection is closed.
If (*iCon_SocketTCPDataBufferBytesRecvPtr) = 0
`Free Socket
Dec iCon_NetworkSockets
`ExitFunction ICON_SOCKET_ERROR
`continue
EndIf
EndIf
EndIf
`If the Writer is marked on this socket then this means the internal data buffers are available for more data.
If iCon_FdSetIs(iCon_Server.FdSetWritePtr,iCon_Socket(iCon_ClientTCPSocketLoop).TCPSocket)
Dec iCon_Server.ClientTCPSockets
iCon_SocketTCPDataBufferPtr = iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferPtr
iCon_SocketTCPDataBufferBytesSendPtr = iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferBytesSendPtr
iCon_SocketTCPDataBufferBytesRecvPtr = iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferBytesRecvPtr
iCon_SocketTCPDataBufferValue = *iCon_SocketTCPDataBufferPtr
iCon_SocketTCPDataBufferBytesSendValue = *iCon_SocketTCPDataBufferBytesSendPtr
iCon_SocketTCPDataBufferBytesRecvValue = *iCon_SocketTCPDataBufferBytesRecvPtr
`SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->SendBytes;
`SocketInfo->DataBuf.len = SocketInfo->RecvBytes - SocketInfo->SendBytes;
*iCon_SocketTCPDataBufferPtr = iCon_SocketTCPDataBufferValue + iCon_SocketTCPDataBufferBytesSendValue
iCon_SocketTCPDataBufferLength = iCon_SocketTCPDataBufferBytesRecvValue - iCon_SocketTCPDataBufferBytesSendValue
iCon_WSASend = Call DLL(iCon_DLLID, "WSASend", iCon_Socket(iCon_ClientTCPSocketLoop).TCPSocket, iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferPtr + 4, 1, iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferBytesSendPtr, 0, NULL, NULL)
If iCon_WSASend = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
If iCon_Error <> ICON_SOCKET_ERROR_WSAEWOULDBLOCK
iCon_ErrorMessage$ = "Failed to Send! ErrorCode[" + Str$(iCon_Error) + "]"
`Free Socket
Dec iCon_NetworkSockets
`ExitFunction ICON_SOCKET_ERROR
`continue
EndIf
Else
`iCon_SocketTCPDataBufferBytesSendPtr = iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferBytesSendPtr
`iCon_SocketTCPDataBufferBytesRecvPtr = iCon_Socket(iCon_ClientTCPSocketLoop).TCPDataBufferBytesRecvPtr
`iCon_SocketTCPDataBufferBytesSendValue = *iCon_SocketTCPDataBufferBytesSendPtr
`iCon_SocketTCPDataBufferBytesRecvValue = *iCon_SocketTCPDataBufferBytesRecvPtr
Inc *iCon_SocketTCPDataBufferBytesSendPtr,*iCon_SocketTCPDataBufferBytesSend
If iCon_SocketTCPDataBufferBytesSendValue = iCon_SocketTCPDataBufferBytesRecvValue
*iCon_SocketTCPDataBufferBytesSendPtr = 0
*iCon_SocketTCPDataBufferBytesRecvPtr = 0
ExitFunction ICON_SOCKET_ERROR
EndIf
EndIf
EndIf
Inc iCon_ClientTCPSocketLoop
EndWhile
EndFunction this
Function iCon_SocketSend(this, iCon_SocketData As String, iCon_SocketProtocol As Byte)
`Purpose: Send data over socket
`Parameters: None
`Return: Number of bytes sent
Print "Sending to Socket " + Str$(iCon_Socket(this).TCPSocket) + " Protocol = " + Str$(iCon_SocketProtocol)
Select iCon_SocketProtocol
Case ICON_SOCKET_STREAM
iCon_SocketDataSent = Call DLL(iCon_DLLID, "send", iCon_Socket(this).TCPSocket, iCon_SocketData, Len(iCon_SocketData) + 1, 0)
EndCase
Case ICON_SOCKET_DGRAM
iCon_SocketDataSent = Call DLL(iCon_DLLID, "sendto", iCon_Socket(this).UDPSocket, iCon_SocketData, Len(iCon_SocketData) + 1, 0, iCon_Socket(this).AddressPtr, ICON_SOCKET_ADDRESS_SIZE)
EndCase
Case Default
ExitFunction 0
EndCase
EndSelect
If iCon_SocketDataSent = ICON_SOCKET_ERROR
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed to Send Data! ErrorCode[" + Str$(iCon_Error) + "]"
ExitFunction ICON_SOCKET_ERROR
EndIf
EndFunction iCon_SocketDataSent
Function iCon_SocketRecv(this, iCon_SocketProtocol As Byte)
`Purpose: Receives data
`Parameters: None
`Return: String$ Received.
If iCon_SocketProtocol = ICON_SOCKET_DGRAM
iCon_SocketDataRecv = Call DLL(iCon_DLLID, "recvfrom", iCon_Socket(this).UDPSocket, iCon_Socket(this).UDPDataBufferPtr + 4, ICON_SOCKET_DATA_BUFFER_SIZE, 0, iCon_Socket(this).AddressPtr, ICON_SOCKET_ADDRESS_SIZE)
Print "Recv UDP on Socket " + Str$(iCon_Socket(this).UDPSocket)
Else
iCon_SocketDataRecv = Call DLL(iCon_DLLID, "recv", iCon_Socket(this).TCPSocket, iCon_Socket(this).TCPDataBufferPtr + 4, ICON_SOCKET_DATA_BUFFER_SIZE, 0)
Print "Recv TCP on Socket " + Str$(iCon_Socket(this).TCPSocket)
EndIf
`0 means connection closed, -1 means error, anything else is amount recv'd
If iCon_SocketDataRecv < 1
iCon_Error = Call DLL(iCon_DLLID, "WSAGetLastError")
iCon_ErrorMessage$ = "Failed to Recv Data! ErrorCode[" + Str$(iCon_Error) + "]"
ExitFunction ""
EndIf
For iCon_SocketDataLoop = 0 to iCon_SocketDataRecv -1
If iCon_SocketProtocol = ICON_SOCKET_DGRAM
iCon_SocketDataPtr = iCon_Socket(this).UDPDataBufferPtr + 4 + iCon_SocketDataLoop
Else
iCon_SocketDataPtr = iCon_Socket(this).TCPDataBufferPtr + 4 + iCon_SocketDataLoop
EndIf
iCon_SocketData$ = iCon_SocketData$ + Chr$((*iCon_SocketDataPtr) && 0xFF)
Next 0
EndFunction iCon_SocketData$
Function iCon_SocketWrite(this, iCon_SocketWriteString$, iCon_SocketProtocol As Byte)
`Purpose: Write to socket data buffer
`Parameters:
` Socket ID
` iCon_SocketWriteString$ string value to be written to databuffer
` iCon_SocketProtocol selects the TCP|UDP data buffers to write string to
`Return: None
EndFunction 0
Function iCon_SocketRead(this, iCon_SocketProtocol As Byte)
`Purpose: Reads from socket data buffer
`Parameters:
` Socket ID
` iCon_SocketProtocol selects the TCP|UDP data buffers to write string to
`Return:
EndFunction iCon_SocketData$
Function iCon_Timeouts()
`Purpose:
`Parameters: Socket ID
`Return:
EndFunction 0
Function iCon_SocketIP(this)
`Purpose: Return Socket Remote IP Address
`Parameters: Socket ID
`Return: IP Address Dotted notation
EndFunction
Function iCon_SocketPort(this)
`Purpose: Returns Socket Remote Port number
`Parameters: Socket ID
`Return:
EndFunction 0
`fdset Structure
Function iCon_FdSetNew()
`Purpose: Creates a new FdSet Structure in memory
`Parameters: None
`Return: Fd Set pointer
iCon_FdSetptr = make memory(ICON_SOCKET_MAX * 4 + 4)
*iCon_FdSetptr = 0
endFunction iCon_FdSetPtr
Function iCon_FdSetDelete(iCon_FdSetPtr as Dword)
`Purpose: Deletes socket from set
`Parameters: Fd Set pointer
`Return: None
delete memory iCon_FdSetPtr
endFunction 0
Function iCon_FdSetAdd(iCon_FdSetPtr as Dword, iCon_TCPSocket as Dword)
`Purpose: Adds socket to Set.
`Parameters:
` Fd Set pointer
` iCon_TCPSocket Socket
`Return: None
if (*iCon_FdSetPtr) = ICON_SOCKET_MAX then exitFunction
` Find address of entry to set, and set it
ptr = iCon_FdSetPtr + ((*iCon_FdSetPtr) * 4) + 4
*ptr = iCon_TCPSocket
inc *iCon_FdSetPtr
endFunction 0
Function iCon_FdSetZero(iCon_FdSetPtr as Dword)
`Purpose: Sets set to Zero.
`Parameters:
` Fd Set pointer
`Return:
*iCon_FdSetPtr = 0
endFunction 0
Function iCon_FdSetIs(iCon_FdSetPtr as Dword, iCon_TCPSocket as Dword)
`Purpose: Checks if socket is in set
`Parameters:
` Fd Set pointer
`Return:
For iCon_FdSetLoop = 1 To (*iCon_FdSetPtr)
ptr = iCon_FdSetPtr + (iCon_FdSetLoop * 4)
If (*ptr) = iCon_TCPSocket Then ExitFunction 1
Next 0
endFunction 0
`timeout structure
Function iCon_timevalMake(iCon_timeval_sec,iCon_timeval_usec)
`Purpose: Creates TimVal Pointer and sets timing values
`Parameters:
` iCon_timeval_sec time interval in seconds
` iCon_timeval_usec time interval in microseconds
`Return: timeval ptr
iCon_timevalptr = Make Memory(8)
iCon_tv_sec = iCon_timevalptr `32 bits
iCon_tv_usec = iCon_timevalptr + 4 `32 bits
*iCon_tv_sec = iCon_timeval_sec
*iCon_tv_usec = iCon_timeval_usec
EndFunction iCon_timevalptr
`IP$ = Call DLL(iCon_DLLID, "inet_ntoa",address)
`The inet_ntoa Function converts an (Ipv4) Internet network address into a string in Internet standard dotted-decimal format.
` accept Available
` bind Available
` closesocket Available
` connect Available
` freeaddrinfo Available
` FreeAddrInfoW Available
` getaddrinfo Available
` GetAddrInfoW Available
` gethostbyaddr Available
` gethostbyname Available
` gethostname Available
` getnameinfo Available
` GetNameInfoW Available
` getpeername Available
` getprotobyname Available
` getprotobynumber Available
` getservbyname Available
` getservbyport Available
` getsockname Available
` getsockopt Available
` htonl Available
` htons Available
` inet_addr Available
` inet_ntoa Available
` ioctlsocket Available
` listen Available
` ntohl Available
` ntohs Available
` recv Available
` recvfrom Available
` select Available
` send Available
` sendto Available
` setsockopt Available
` shutdown Available
` socket Available
` WSAAccept Available
` WSAAsyncGetHostByAddr Available
` WSAAsyncGetHostByName Available
` WSAAsyncGetProtoByName Available
` WSAAsyncGetProtoByNumber Available
` WSAAsyncGetServByName Available
` WSAAsyncGetServByPort Available
` WSAAsyncSelect Available
` WSACancelAsyncRequest Available
` WSACancelBlockingCall Available
` WSACleanup Available
` WSACloseEvent Available
` WSAConnect Available
` WSACreateEvent Available
` WSAEnumNetworkEvents Available
` WSAEventSelect Available
` __WSAFDIsSet Available
` WSAGetLastError Available
` WSAGetOverlappedResult Available
` WSAGetQOSByName Available
` WSAHtonl Available
` WSAHtons Available
` WSAIoctl Available
` WSAIsBlocking Available
` WSAJoinLeaf Available
` WSALookupServiceEnd Available
` WSANSPIoctl Available
` WSANtohl Available
` WSANtohs Available
` WSAProviderConfigChange Available
` WSARecv Available
` WSARecvDisconnect Available
` WSARecvFrom Available
` WSARemoveServiceClass Available
` WSAResetEvent Available
` WSASend Available
` WSASendDisconnect Available
` WSASendTo Available
` WSASetBlockingHook Available
` WSASetEvent Available
` WSASetLastError Available
` WSAStartup Available
` WSAUnhookBlockingHook Available
` WSAWaitForMultipleEvents Available
` ===========================================
` AcceptEx Not Available
` ConnectEx Not Available
` DisconnectEx Not Available
` EnumProtocols Not Available
` FreeAddrInfoEx Not Available
` gai_strerror Not Available
` GetAcceptExSockaddrs Not Available
` GetAddressByName Not Available
` GetAddrInfoEx Not Available
` GetNameByType Not Available
` GetService Not Available
` GetTypeByName Not Available
` SetAddrInfoEx Not Available
` SetService Not Available
` TransmitFile Not Available
` TransmitPackets Not Available
` WSAAddressToString Not Available
` WSAConnectByList Not Available
` WSAConnectByName Not Available
` WSADeleteSocketPeerTargetName Not Available
` WSADuplicateSocket Not Available
` WSAEnumNameSpaceProviders Not Available
` WSAEnumNameSpaceProvidersEx Not Available
` WSAEnumProtocols Not Available
` WSAGetServiceClassInfo Not Available
` WSAGetServiceClassNameByClassId Not Available
` WSAImpersonateSocketPeer Not Available
` WSAInstallServiceClass Not Available
` WSALookupServiceBegin Not Available
` WSALookupServiceNext Not Available
` WSAPoll Not Available
` WSAQuerySocketSecurity Not Available
` WSARecvEx Not Available
` WSARecvMsg Not Available
` WSARevertImpersonation Not Available
` WSASendMsg Not Available
` WSASetService Not Available
` WSASetSocketPeerTargetName Not Available
` WSASetSocketSecurity Not Available
` WSASocket Not Available
` WSAStringToAddress Not Available
iCon Server
`iCon Server
#Include "iCon.Lib.dba"
#constant TCP 1
#constant UDP 2
set display mode 640,480,32
set window on
iCon_ServerStartup = iCon_ServerStart("127.0.0.1",1337)
If iCon_ServerStartup = ICON_SOCKET_ERROR Then Exit Prompt iCon_ErrorMessage$,"Runtime Error!"
Print "Waiting for client..."
Sync
`Wait for client - non blocking.
repeat
iCon_ClientSocketID = iCon_ServerAccept()
If iCon_ClientSocketID = ICON_SOCKET_ERROR Then Exit Prompt iCon_ErrorMessage$,"Runtime Error!"
If EscapeKey() Then iCon_ServerStop()
Until iCon_ClientSocketID
Print iCon_ClientSocketID
` Wait for string
iCon_SocketDataRecv$ = iCon_SocketRecv(iCon_ClientSocketID,TCP)
If iCon_SocketDataRecv$ = "" Then iCon_SocketDataRecv$ = "No Data Received."
Print "Message: " + iCon_SocketDataRecv$
` Send reply
message$ = "Pong!"
iCon_SocketDataSent = iCon_SocketSend(iCon_ClientSocketID, message$,TCP)
If iCon_SocketDataSent = ICON_SOCKET_ERROR Then Print "No Data Sent."
Print "Sent response: " + message$ + Str$(iCon_SocketDataSent)
Wait Key
iCon_ServerStop()
End
iCon Client
`iCon Client
#Include "iCon.Lib.dba"
#constant TCP 1
#constant UDP 2
set display mode 640,480,32
set window on
iCon_SocketID = iCon_SocketOpen("127.0.0.1",1337)
If iCon_SocketID = ICON_SOCKET_ERROR Then Exit Prompt iCon_ErrorMessage$,"Runtime Error!"
print "Connected to server. " + Str$(iCon_SocketID)
` Send string
message$ = "Ping!"
iCon_SocketDataSent = iCon_SocketSend(iCon_SocketID, message$,TCP)
If iCon_SocketDataSent = -1 Then Print "No Data Sent."
Print "Sent response: " + message$ + Str$(iCon_SocketDataSent)
` Wait for reply
iCon_SocketDataRecv$ = iCon_SocketRecv(iCon_SocketID,TCP)
If iCon_SocketDataRecv$ = "" Then iCon_SocketDataRecv$ = "No Data Received."
Print "Message: " + iCon_SocketDataRecv$
wait key
iCon_SocketClose(iCon_SocketID)
end