Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly maintain a listening port for a long time?

Tags:

c

sockets

daemon

I wrote this small server application in pure C that listens to incoming connections in a given port, very simple stuff.

It goes with the usual socket initialization procedure, create the socket() then bind() to the port, says its a listen(), and ifinitely loops through a select() waiting for incoming connections to accept().

All goes just fine and works like a charm, except that if I leave the thing running for a couple months, the listening port closes while the application server keeps running unaware of it, since I wrote it to trust the listening socket will not close if not told to.

So the question is: Why the hell is the port being closed without my application's concern and what can I do to prevent it from happening?

Is that expected behaviour? Should I check for some kind of exceptions or make "health check" on the listening socket to reopen it if necessary?

Code: https://gist.github.com/Havenard/e930be035a3bee75c018 (yes I realize I'm using 0 as cue for errors and it's bad pratice and stuff, but it is not relevant to the question as I explained in the comments, when I set the socket file descriptor to 0 it is to stop the loop and shut down the application).

like image 981
Havenard Avatar asked Mar 02 '13 19:03

Havenard


People also ask

How long can a network port be?

A port number is a 16-bit unsigned integer, thus ranging from 0 to 65535.

How do I resolve port issues?

The best way to resolve the port issue is to find an alternative unused port and map it to the application. This is more to do with the design of the application. As an example if port 80 is already in use by a web application then one can choose 8080 for another web application.

Does a listening port mean that its open?

Listening port is a network port on which an application or process listens on, acting as a communication endpoint. Each listening port can be open or closed (filtered) using a firewall. In general terms, an open port is a network port that accepts incoming packets from remote locations.


2 Answers

I would start by cleaning it up:

  • cut it up into smaller, readable, verifyable , testable functions
  • the linked lists usage look messy; it could be simplified a lot, maybe by introducing some generic functions.
  • replace all the silly '\x20' character constants by the more readable ' ' equivalents
  • avoid manifest magic constants like here if (n_case > 0) memcpy(nick, node->nick, (n_case > 32 ? 32 : n_case)); ; sizeof is your friend.
  • don't use zero as a sentinel value for an unused file descriptor; use -1 instead.
  • use unsigned types for sizes and indexes; negative indexes will corrupt memory, fold-over unsigned types will fail fast. (failfast is your friend)

That's only a few hours of editing.

My guess is that, after cleanup/refactoring your "bug" will come to the surface magically.

Footnote: No,I won't do your work for you. Not for 100 points, not for 1000. Please clean up your own mess.

like image 78
wildplasser Avatar answered Oct 01 '22 07:10

wildplasser


This answer is mostly a code review of places where you call close().

Line 330: You close the socket but don't continue right away like in other places in your code. This could lead to weird behavior.

Line 928: In most places, you set the client or server socket to 0 after a call to close(). You don't after this call.

Line 1193: Same comment as line 928.

Line 1195: Same comment as line 928.

Line 1218: Same comment as line 928.

Line 1234: Same comment as line 928.

Line 1236: Same comment as line 928.

When I compiled the code with full warnings, I saw a number of places where the compiler noted functions declared to return a value, but no value is being returned.

x.c:582: warning: no return statement in function returning non-void
x.c:591: warning: no return statement in function returning non-void
x.c:598: warning: no return statement in function returning non-void
x.c:609: warning: no return statement in function returning non-void
x.c:620: warning: no return statement in function returning non-void
x.c:728: warning: no return statement in function returning non-void
x.c:779: warning: no return statement in function returning non-void

There are many other problems, as noted in other posts.

As far as debugging this issue, If I suspected the binding socket was being closed early, I would intercept the close() call with my own version that asserts that the descriptor being closed should not match the binding socket.

However, as wildplasser noted, select() would return an error about the invalid descriptor if it was closed.

like image 28
jxh Avatar answered Oct 01 '22 09:10

jxh