Walter Hall · Feb 6, 2020

ISO Compliant Cache': Check if a port is available on a server?

We have multiple databases running on a single server. I have duplicate interfaces on each database.

If we're doing testing in copy #1, the interfaces should be running in that copy. I want to block analysts who try to start the interfaces in copy #2.

So, I'm looking for something that would check the port and tell me the status: already in use or free. 

My challenge is that this system needs to stay ISO/ANSI compliant.... so I can't use any of the newer tricks.
Is there any plain-old Cache' I could use for this task?


2 0 13 190


Thanks, Timothy. We're on Redhat Linux and while I have developer rights in the Cache' world, I don't have access to the Redhat environment.

Looking at the Linux reference you linked and using this Cache' documentation, I tried the following at a Cache' prompt.

OPEN "|CPIPE|5":("sudo ss -tulwn"):10

It threw the following result:

POC>OPEN "|CPIPE|5":("sudo ss -tulwn"):10

OPEN "|CPIPE|5":("sudo ss -tulwn"):10
<PROTECT> *OPEN[Q](sudo ss -tulwn)

Looking that up, I found this post. It seems I would need the %System_Callout:USE privilege.
Since this would be for our testing environments, I might be able to convince the server guys to give me that permission.

Before I go to that trouble, is there any other option?


Actually - if this is all on the same server (not seeing which ports are listening on a remote server), you could try starting to listen on a port and see if it fails. Presumably, a failure would only indicate that the port is already in use. Here's the code for that:

Class DC.Demo.PortAvailability

ClassMethod IsLocalPortInUse(pPort As %Integer) As %Boolean
    Quit '##class(%IO.ServerSocket).%New().Open(pPort,0)


That would probably require less convincing of the server guys. :)

Thanks! I'll give this a try!

%OnClose for %IO.ServerSocket (inherited from %IO.DeviceStream) handles that, so no need - I did test that before posting. ;)

[context: the device doesn't need to be closed after a successful open because it's closed automatically.]

OK, but OP's intention was to

block analysts to start the interface in copy #2

while your method just checking whether it's free.

I guess that's an interesting point - if the interfaces are already running in copy #1, they should be blocked from starting in copy #2 (on the same port) automatically because the port will already be in use. Perhaps the use case is more a matter of failing gracefully in such cases.

Great points. Here's a bit more. I don't think I can say which medical system I'm working in, but my interfaces setup has a line where I can put in a single-line of ISO compliant Cache'. I have code elements that if a check fails, I can tell the interface to gracefully fail and log an error.

What I'm looking for is code I can embed into a true false setup to test if the port is in use.

That old-school single line thing is a big disadvantage, I know.

Thanks, that's helpful context.

If that doesn't work, I might be able to build a function in the test environments, then call that function from the single line in the interface setup.

Honestly, I might even be able to use your class from above. The system is built on InterSystems. They need it to stay official ISO compliant, but I'm not sure if they're actually disabling the advance object oriented abilities. Since this is only for the test environments, I could give it a try.

But, if you've got any ideas for single-line complaint code, that's ideal. If not, ideas for a multi-line function in ISO compliant would be next best.

The challenge is calling out to the second instance on the same sever. I have a way I can check the globals to see what ports are in use by the "parent" instance. It is reaching out to the sibling instance that is the challenge. As a result, I'd need to check at the OS level.

Edit: here's a use case, if that's helpful:

Use case:
-- An interface is running in TST
-- An analyst wants to test something in TST2, so they try to start the interface.
-- The interface cannot start because the port on TestServerDB is already in use.
-- Current state: On the interface monitor, the interface comm status would show as connecting and the interface would not throw any errors.
-- Desired state: Upon comm start, the interface checks if the port is free. If yes, comm start proceeds. If no, comm start fails and error is thrown.

Oof - by "newer tricks" you meant "objects." Yikes. Really, it'd be significantly lower risk to use the object-based approach than to roll your own without objects. (e.g., see my comment on automatic cleanup via %OnClose)

I don't have bandwidth to provide an object-free version, but you might look at the code for %IO.ServerSocket for inspiration.


Why not configure different ports for your both instances?