How can I listen and serve information over a TCP port? [Windows]

For issues with communication ports, protocols, etc.
Post Reply
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

How can I listen and serve information over a TCP port? [Windows]

Post by counting_pine »

How hard would it be to have an FB program that listens on a TCP port, and returns some status information to the client computer?

Basically, doing something like the Check_MK Agent that listens on port 6556, and non-interactively dumps a text-based stream of information out to it when something connects.

The Linux version of the agent is just a bash script that is generally served using xinetd, but the Windows version is a binary and runs as a service, with code that listens on the port itself.
However, I've found whatever it does can be unreliable on some machines, and fail to return anything. So I'm thinking of writing a small, stand-alone program that intercepts the requests, calls the agent itself, and sends back the output. Would this be easy to do?
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: How can I listen and serve information over a TCP port? [Windows]

Post by MrSwiss »

counting_pine wrote:However, I've found whatever it does can be unreliable on some machines, and fail to return anything.
Well, the first thing I'd investigate, whould be: "are my assuptions" regarding
the way, the agent is "expected" to react, correct? (may not be the case)
Before that, I'd not even start to look at a possible way, to solve the issue.

In general, security-people tend to have very specific ways of thinking:
- typically, expecting some sort of authentication, from connecting device
(let's call it a security-token or similar, may need to be encrypted, too)

Just my two cents, at the moment.
St_W
Posts: 1619
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: How can I listen and serve information over a TCP port? [Windows]

Post by St_W »

If you want to really implement something yourself, have a look at the Winsock documentation (which works quite similar to Unix sockets). You'll also find an example there:
https://docs.microsoft.com/en-us/window ... erver-code

If you want to have a little bit less work take an existing network library for FB that wraps winsock (and unix sockets) like TSNE or SimpleNetwork. There are also others, but I can't remember their names right now.
marcov
Posts: 3454
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: How can I listen and serve information over a TCP port? [Windows]

Post by marcov »

Afaik winsock is not that hard. Simply searching for some C winsock sample and converting it should suffice if you have a winsock2 header. Installing as service is afaik not necessary for ports over 1024.

However the reliability of the existing binary might not be the binary itself, just security software related (firewall/antivirus).
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: How can I listen and serve information over a TCP port? [Windows]

Post by counting_pine »

Thanks for the suggestions!
I've ported the example Microsoft code:

Code: Select all

' https://docs.microsoft.com/en-us/windows/desktop/winsock/complete-server-code
#define WIN32_LEAN_AND_MEAN

#include "win/winsock2.bi"
#include "win/ws2tcpip.bi"

const DEFAULT_BUFLEN = 512
const DEFAULT_PORT = "27015"

dim as WSADATA wsaData
dim as long iResult
dim as SOCKET ListenSocket = INVALID_SOCKET
dim as SOCKET ClientSocket = INVALID_SOCKET

dim as addrinfo ptr result = NULL

dim as addrinfo hints

dim as long iSendResult
dim as ubyte recvbuf(0 to DEFAULT_BUFLEN - 1)
dim as long recvbuflen = DEFAULT_BUFLEN

'' Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), @wsaData)

if iResult <> 0 then
    print "WSAStartup failed with error: " & iResult
    end 1
end if

ZeroMemory(@hints, sizeof(hints))
with hints
    .ai_family = AF_INET
    .ai_socktype = SOCK_STREAM
    .ai_protocol = IPPROTO_TCP
    .ai_flags = AI_PASSIVE
end with

'' Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, @hints, @result)
if iResult <> 0 then
    print "getaddrinfo failed with error: " & iResult
    WSACleanup()
    end 1
end if

'' Create a SOCKET for connecting to server
ListenSocket = socket_(result->ai_family, result->ai_socktype, result->ai_protocol)
if ListenSocket = INVALID_SOCKET then
    print "socket failed with error: " & WSAGetLastError()
    freeaddrinfo(result)
    WSACleanup()
    end 1
end if

'' Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, result->ai_addrlen)
if iResult = SOCKET_ERROR then
    print "bind failed with error: " & WSAGetLastError()
    freeaddrinfo(result)
    WSACleanup()
    end 1
end if

freeaddrinfo(result)

iResult = listen(ListenSocket, SOMAXCONN)
if iResult = SOCKET_ERROR then
    print "listen failed with error: " & WSAGetLastError()
    closesocket(ListenSocket)
    WSACleanup()
    end 1
end if

'' Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL)
if ClientSocket = INVALID_SOCKET then
    print "accept failed with error: " & WSAGetLastError()
    closesocket(ListenSocket)
    WSACleanup()
    end 1
end if

'' No longer need server socket
closesocket(ListenSocket)

'' Receive until the peer shuts down the connection
do
    iResult = recv(ClientSocket, @recvbuf(0), recvbuflen, 0)
    if iResult then
        print "Bytes received: " & iResult
    
        '' Echo the buffer back to the sender
        iSendResult = send(ClientSocket, @recvbuf(0), iResult, 0)
        if iSendResult = SOCKET_ERROR then
            print "send failed with error: " & WSAGetLastError()
            closesocket(ClientSocket)
            WSACleanup()
            end 1
        end if
        print "Bytes sent: " & iSendResult
    elseif iResult = 0 then
        print "Connection closing..."
    else
        print "recv failed with error: " & WSAGetLastError()
        closesocket(ClientSocket)
        WSACleanup()
        end 1
    end if
loop while iResult > 0

'' shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND)
if iResult = SOCKET_ERROR then
    print "shutdown failed with error: " & WSAGetLastError()
    closesocket(ClientSocket)
    WSACleanup()
    end 1
end if

'' cleanup
closesocket(ClientSocket)
WSACleanup()

end 0
I've tested it with 'telnet localhost 27015', and it works. (It echoes every character as I type).
Now I just have to see if I can adapt this to run the program and return the output to the client. It hopefully shouldn't be too hard.
Post Reply