Unable to find the Internal port of the NAT mapping in the PJSIP/PJNATH library - p2p

I using the PJSIP/PJNATH port-punching library (for STUN/TURN/ICE) and want to create my own UDP-based transport over the punched-ports.
I’m unable to find the data-structure that holds the internal port of the NAT mapping. The reason I need the internal port (on both sides) is to bind the UDP socket to the internal port (instead of the OS picking a random port). Please see diagram.
I realize that the icedemo sample app is able to do send data back-and-forth on the internet (after punching the ports); so it must bind to the internal UDP port. I just need to know which data-structure holds the internal port.
The pj_ice_sess_send_data function in the in the ice_session.c file looked like a promising place to dump variables. But none contain the internal port of the NAT mapping.
//my attempt did *not* work
pj_ice_sess_cand *cand;
cand = comp->valid_check->lcand;
char addrinfo[80];
pj_sockaddr_print(&cand->base_addr, addrinfo, sizeof(addrinfo), 3);
printf("***Local address %s\n", addrinfo);
FYI, the public IP:Port is readily available.
Background
The PJNATH library implements a standards-based STUN/TURN/ICE protocol and punches UDP ports using ICE-UDP checks after it has exchanged the host/server-reflexive/relay IP:Port from both sides.

It looks like its the bound_addr pj_sockaddr in the pj_stun_sock_cfg struct.
According to the docs, "If the port is set to zero, the socket will bind at any port (chosen by the OS)."

I found that, on ICE "complete", the lcand part of the data-structure does hold the local bound IP and port. In most consumer NATs, this was the same port number (which it indeed is) which was puzzling. After experimenting with a few enterprice NATs, I found that the port numbers are different on either side of the mapping.
You can print it with something like this...
static void cb_on_ice_complete(pj_ice_strans *ice_st,
pj_ice_strans_op op,
pj_status_t status)
{
const char *opname =
(op==PJ_ICE_STRANS_OP_INIT? "initialization" :
(op==PJ_ICE_STRANS_OP_NEGOTIATION ? "negotiation" : "unknown_op"));
if (status == PJ_SUCCESS)
{
PJ_LOG(3,(THIS_FILE, "ICE %s successful", opname));
if ( op == PJ_ICE_STRANS_OP_NEGOTIATION )
{
const pj_ice_sess_check *check;
check = pj_ice_strans_get_valid_pair(icedemo.icest, 1);
if ((check != NULL) && (check->nominated == PJ_TRUE)) { //local (l) and remote(r) candidate
pj_sockaddr_print(&check->lcand->addr, icedemo.local_ip_port,
sizeof(icedemo.local_ip_port), 3);
pj_sockaddr_print(&check->rcand->addr, icedemo.remote_ip_port,
sizeof(icedemo.remote_ip_port), 3);
pj_sockaddr_print(&check->lcand->base_addr, icedemo.local_bound_ip_port, sizeof(icedemo.local_bound_ip_port), 3);
}
else
{
PJ_LOG(3,(THIS_FILE, "err: unable to get valid pair for ice1 "
"component %d", icedemo.icest, 1));
}
}
}
else
{
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(1,(THIS_FILE, "ICE %s failed: %s", opname, errmsg));
pj_ice_strans_destroy(ice_st);
icedemo.icest = NULL;
}
}

Related

Do I ever need to re-create listening socket?

Suppose I've created a socket, started listen()ing on it and run accept() in a loop to process incoming connections. I.e. smth like this:
s = socket();
bind(s, ...);
listen(s, ...);
loop {
new_s = accept(s, ...);
... // do smth with new_s
}
For various reasons accept() can return an error and most of these errors say this particular connection attempt failed, please carry on. Is there any scenario when you have to close the socket and start from scratch (i.e. make new socket + bind + listen) in order to be (eventually) reachable by clients? What error (returned from accept()) tell me that? I.e. should I ever structure my logic like this:
loop {
loop {
s = socket();
bind(s, ...);
listen(s, ...);
if !error { break; }
sleep(1second); // avoid busy loop
}
loop {
new_s = accept(s, ...);
if error {
if error == ??? break; <--- which error code(s)?
continue;
}
... // do smth with new_s
}
}
Notes:
Specifically I am looking at ENETDOWN (Linux) and WSAENETDOWN (Winsock2) -- looks like these happen when someone restarts the network (interface). Will my previously created socket continue accepting connections once network is up? I doubt it, but even if it is the case -- how to properly avoid busy accept loop?
Other platforms may have other error codes -- how to write a code that will work on all of them?
You don't need to recreate the listening socket if accept() fails on that listener (at least on Windows).
If one called bind on 0.0.0.0:(some port) - then you almost never need to worry about recreating the listening socket.
If one called bind on a specific IP address, and that IP address goes away, then you definitely need to recreate the listening socket (you aren't listening to anything anymore).

Testing akka tells without using Thread.sleep

i'm trying to develop a simple unit test to bind a port on my machine, test that the port is bound, then release the port and test that it is release. Currently I'm using this naive approach
class ServerTest extends FlatSpec with MustMatchers {
"Server" must "bind a tcp server to an address on our machine" in {
//if this fails this means that the port is in use before our test case is run
val port = 18333
isBound(port) must be (false)
val actor = Server()
actor ! Tcp.Bind(actor, new InetSocketAddress(port))
Thread.sleep(1000)
isBound(port) must be (true)
Thread.sleep(1000)
actor ! Tcp.Unbind
Thread.sleep(1000)
isBound(port) must be (false)
}
/**
* Tests if a specific port number is bound on our machine
* #param port
* #return
*/
def isBound(port : Int) : Boolean = {
val tryBinding : Try[Unit] = Try {
val socket = new java.net.Socket()
socket.connect(new java.net.InetSocketAddress(port),1000)
socket.close()
}
tryBinding.isSuccess
}
}
I would like to test this without using the calls to Thread.sleep since this is a blocking call. Can anyone provide me with a more idiomatic solution?
When sending TCP.Bind , you should expect a reply stating either success or failure: http://doc.akka.io/japi/akka/2.3.2/akka/io/Tcp.Bind.html
The Bind message is send to the TCP manager actor, which is obtained
via TcpExt.manager() in order to bind to a listening socket. The
manager replies either with a Tcp.CommandFailed or the actor handling
the listen socket replies with a Tcp.Bound message. If the local port
is set to 0 in the Bind message, then the Tcp.Bound message should be
inspected to find the actual port which was bound to.
You should use AkkaTestKit (http://doc.akka.io/docs/akka/snapshot/scala/testing.html) and use either ImplicitSender or a TestProbe to send the TCP.Bind, and then wait for the answer.
For example:
val probe = TestProbe()
probe.send(actor, Tcp.Bind(actor, new InetSocketAddress(port)))
probe.expectMsg(Tcp.Bound)
Your test code will either continue when the reply is received, or fail if not received within the timeout (which is configurable in the expectMsg call).
You can use
within (1000 millisends) {
...
}
see https://github.com/RayRoestenburg/AkkaExamples/blob/master/src/test/scala/unit/akka/TestKitUsageSpec.scala for more examples

using TCP Keep-Alives in server to get rid of idle client

I have a server to collect Tcp data from different clients to a certain port. I have a scenario that whenever the client creates tcp connection and remain idle for more than let's say 30 min then I need to close the connection.
I have learned about TCP keep alive to track that the peer is dead or not and Mostly I found examples used in client side. Similarly can I used in the server side to poll the connection whether it is active or not?
Further In linux sysctl.conf , there is a configuration file to edit the values. This seems that the whole tcp connection is destroyed after certain inactivity. I am in need such that certain connection form the device are destroyed after certain time inactivity but not the whole tcp port connection closed.
I am using ubuntu to create the server to collect tcp connection. Can I use TCP Keep-Alives in server code to find the inactive client and close the particular client? or is there any other way in server side to implement such feature?
and while going through the web it is mentioned that
(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen)
this getsockopt is for the main tcp connection and setting here seems the setting is for whole connection to the server.
However what I need is for the specific client. I have the event server code as
here client_fd is accepted and now I need to close this client_fd if next data through this client is not received within certain time.
void event_server(EV_P_ struct ev_io *w, int revents) {
int flags;
struct sockaddr_in6 addr;
socklen_t len = sizeof(addr);
int client_fd;
// since ev_io is the first member,
// watcher `w` has the address of the
// start of the _sock_ev_serv struct
struct _sock_ev_serv* server = (struct _sock_ev_serv*) w;
server->socket_len = len;
for (;;) {
if ((client_fd = accept(server->fd, (struct sockaddr*) &addr, &len)) < 0) {
switch (errno) {
case EINTR:
case EAGAIN:
break;
default:
zlog_info(_c, "Error accepting connection from client \n");
//perror("accept");
}
break;
}
char ip[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &addr.sin6_addr, ip, INET6_ADDRSTRLEN);
char *dev_ip = get_ip(ip);
server->device_ip = dev_ip;
zlog_debug(_c,"The obtained ip is %s and dev_ip is %s", ip, dev_ip);
/** check for the cidr address for config_ip **/
char *config_ip;
config_ip = get_config_ip(dev_ip, _client_map);
zlog_debug(_c,"The _config ip for dev_ip:%s is :%s", dev_ip, config_ip);
if (config_ip == NULL) {
zlog_debug(_c,"Connection attempted from unreigistered IP: %s", dev_ip);
zlog_info(_c, "Connection attempted from unregistered IP : %s", dev_ip);
AFREE(server->device_ip);
continue;
}
json_t *dev_config;
dev_config = get_json_object_from_json(_client_map, config_ip);
if (dev_config==NULL) {
zlog_debug(_c,"Connection attempted from unreigistered IP: %s", dev_ip);
zlog_info(_c, "Connection attempted from unregistered IP : %s", dev_ip);
AFREE(server->device_ip);
continue;
}
if ((flags = fcntl(client_fd, F_GETFL, 0)) < 0 || fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
zlog_error(_c, "fcntl(2)");
}
struct _sock_ev_client* client = malloc(sizeof(struct _sock_ev_client));
client->device_ip = dev_ip;
client->server = server;
client->fd = client_fd;
// ev_io *watcher = (ev_io*)calloc(1, sizeof(ev_io));
ev_io_init(&client->io, event_client, client_fd, EV_READ);
ev_io_start(EV_DEFAULT, &client->io);
}
}
TCP keep alives are not to detect idle clients but to detect dead connections, i.e. if a client crashed without closing the connection or if the line is dead etc. But if the client is only idle but not dead the connection is still open. Any attempts to send an empty packet (which keep-alive packets are) to the client will result in an ACK from the client and thus keep alive will not report a dead connection.
To detect idle clients instead use either timeouts for read (SO_RCVTIMEO) or use a timeout with select, poll or similar functions.
I have implemented below mechanism to detect idle status on Socket IO activity.
My Socket is wrapped in some class like UserConnection. This class has one more attribute lastActivtyTime. Whenever I get a read on write on this Socket, I will update this attribute.
I have one more background Reaper thread, which will iterate through all UserConnection objects and check for lastActivtyTime. If current time - lastActivtyTime is greater than configured threshold parameter like 15 seconds, I will close the idle connection.
In your case, when you are iterating through all UserConnections, you can check client_id and your threshold of 30 minutes inactivity to close idle connection.

Is it possible that Accept return a same socket value for different tcp connections on the same machine

Is there possible that accept() (on redhat Enterprise 4/linux kernel 2.6) return a same socket value for different tcp connections from the same process of a same application and same machine?
I am so surprised that when I got such a result that many connections have the same socket value on server side when I checked the log file!! How is it possible?!!
By the way, I am using TCP blocking socket to listen.
main(){
int fd, clientfd, len, clientlen;
sockaddr_in address, clientaddress;
fd = socket(PF_INET, SOCK_STREAM, 0);
....
memset(&address, 0, sizeof address);
address.sin_address = AF_INET;
address.sin_port = htons(port);
....
bind(fd, &address, sizeof address);
listen(fd, 100);
do {
clientfd = accept(fd, &clientaddress, &clientlen);
if (clientfd < 0) {
....
}
printf("clientfd = %d", clientfd);
switch(fork()){
case 0:
//do something else
exit(0);
default:
...
}
} while(1);
}
my question is that why printf("clientfd = %d"); prints a same number for different connections!!!
If server runs in multiple processes (like Apache with mpm worker model), then every process has its own file descriptor numbering starting from 0.
In other words, it is quite possible that different processes will get exact same socket file descriptor number. However, fd number it does not really mean anything. They still refer to different underlying objects, and different local TCP ports.
The socket is just a number.It is a hook to a data structure for the kernel.
BTW TCP uses IP. Look up the RFC
That printf() doesn't print any FD at all. It's missing an FD parameter. What you are seeing could be a return address or any other arbitrary junk on the stack.

Strange client's address returned throug accept(..) function

I'm a socket programming newbie. Here's a snippet:
struct sockaddr_storage client_addr;
...
client_addr_size = sizeof(client_addr);
client_socket = accept( server_socket,
(struct sockaddr *)&client_addr, &client_addr_size );
...
result = inet_ntop( AF_INET,
&((struct sockaddr_in *)&client_addr)->sin_addr,
client_addr_str, sizeof(client_addr_str) );
I'm working as a server. Whenever the client connects the address I get is 0.0.0.0 regardless from the host. Can anybody explain, what I'm doing wrong?
Thanks.
Check client_addr.ss_family - it may be returning an AF_INET6 family address.
Can you show a bit more code...what IP address/service are you trying to connect to?
The clue is in the IP address itself, 0.0.0.0, commonly a situation where a network interface has no IP address assigned, possibly looking for a DHCP server to renew/accept a DHCP lease from somewhere..
I am shooting myself in the foot as you have not provided enough information and hence would be deemed unfair to do so and get downvoted as a result as this answer does not satisfy your question!!
Just a guess - what's the declaration of client_addr_str? If it's char* then sizeof(client_addr_str) would return size of pointer (4 or 8, depending on 32- or 64-bit platform.) Try the following:
char client_addr_str[INET_ADDRSTRLEN];
if ( inet_ntop( AF_INET,
&((struct sockaddr_in *)&client_addr)->sin_addr,
client_addr_str, INET_ADDRSTRLEN ) == NULL )
{
/* complain */
}

Resources