3 sockets created for one libevent bind on Windows? - c

I'm writing a BitTorrent client to learn some more about networking, and I've got something that I'm struggling to Google for. As part of the BT spec, I need a server to listen for peer connections to my computer. In the win32 port, I have code like this to setup my server
struct sockaddr_in saServer;
struct hostent* localHost;
char* localIP;
// Get the local host information
localHost = gethostbyname("");
localIP = inet_ntoa(*(struct in_addr *)*localHost->h_addr_list);
saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = inet_addr(localIP);
saServer.sin_port = htons(6881);
struct evconnlistener *listener = evconnlistener_new_bind(base, accept_conn_cb, NULL,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (SOCKADDR*)&saServer, sizeof(saServer));
That seems to work, but if I look at netstat, I see the following,
BitTorrentClient.exe 6092 TCP hostname 50216 localhost 50217 ESTABLISHED
BitTorrentClient.exe 6092 TCP hostname 50217 localhost 50216 ESTABLISHED
BitTorrentClient.exe 6092 TCP hostname.home 6881 hostname 0 LISTENING
Why are there two other connections, one from port 50216->50217 and one looping back from 50217->50216? I was expected to have just one listening connection on port 6881. Is this a libevent quirk, or something more fundamental related to networking?
What can I search for to understand what the other two ports are used for?

This is most likely a result of libevent calling evutil_make_internal_pipe_ internally.
Libevent creates internal "pipes" for inter-thread communication and signal delivery using socketpair(2) on POSIX-compliant systems, whereas on Windows libevent has to resort to manually connecting two sockets together instead.

Related

C - getaddrinfo returns "Servname not supported for ai_socktype"

So, after I got this error, I've been looking for an answer in here, almost everyone had a difficult way to fix this error but no one explained why this error occurs at all, so I don't find this question to be exactly duplicate.
I wrote a TCP socket in C and I used "getaddrinfo" function to make the socket work with hostnames, well it worked perfectly! you can find my codes on github.
but when I tried to create a UDP socket by "getaddrinfo" I got this error:
Servname not supported for ai_socktype
client.c
const char *host = argv[1];
const char *service = argv[2];
const char *string = argv[3];
struct addrinfo addrCriteria;
memset(&addrCriteria, 0, sizeof(addrCriteria));
addrCriteria.ai_family = AF_UNSPEC;
addrCriteria.ai_socktype = SOCK_DGRAM;
addrCriteria.ai_protocol = IPPROTO_UDP;
struct addrinfo *servAddr;
int ret = getaddrinfo(host, service, &addrCriteria, &servAddr);
if(ret != 0)
sysError(gai_strerror(ret));
I realized that when I give "service" a numeric input like 8080, no errors would return but when I use a string as service name like "tproxy" which points to port/8081, 'gai_strerror' returns mentioned error.
Obviously, gai_strerror says: "service names not supported for 'SOCK_DGRAM' socket types", but why? I mean the exact reason for "getaddrinfo" not supporting name services over UDP sockets?
Is there any other way to use service names with UDP sockets instead of port numbers? how?
TL;DR: There is no tproxy UDP port.
If you look up the tproxy service for UDP sockets in your service database,
getent services tproxy/udp
You get no output, because tproxy is not an UDP service. If you look at all tproxy services regardless of the protocol, getent services | grep -e tproxy, you'll see
tproxy 8081/tcp
which means that tproxy service is only defined for TCP protocol.
This means that if you ask getaddrinfo() for an UDP socket for service 8081, you will not find anything, because tproxy is only defined for TCP and not UDP.
Compare to the case where you ask for and UDP socket for xmpp-client service. At least my service database (getent services xmpp-client/udp) responds with
xmpp-client 5222/udp jabber-client
and indeed, getaddrinfo() happily provides the socket description for such UDP sockets (using xmpp-client or jabber-client as the service).
So, there are services like xmpp-client that do have both TCP and UDP ports defined. On my system, getent services | grep -e xmpp-client shows
xmpp-client 5222/tcp jabber-client
xmpp-client 5222/udp jabber-client
Because TCP and UDP are different protocols over IP, it makes sense that a service could use a different port number for TCP and UDP communications. So, it is unreasonable to assume that the service database should just return the same port numbers for TCP and UDP sockets.
In other words, you encounter the error because you mistakenly assume that because some service uses a TCP port, with a name registered in the service database, you should be able to use that name to specify an UDP port number, too.
TCP and UDP are separate protocols, and their port number spaces are separate. For example, TCP port 512 is used by the Unix exec r-service, whereas UDP port 512 is used by the biff mail notification service.
When a non-numeric value is given for the service parameter, it is looked up (on Linux) in the /etc/services file. This file maps a service name to a port/protocol. Below are some sample entries:
ssh 22/tcp
telnet 23/tcp
domain 53/tcp # name-domain server
domain 53/udp
The reason you're getting an error is because there is no UDP entry in your /etc/services file for "tproxy". Take a look at this file and look for an entry that does specify a UDP port such as "domain". That should have entries for both 53/tcp and 53/udp. If you pass in "domain" as the service name you should get a result back.

2 program get same udp packets from a port

there is a server will send some UDP packets to my localhost, for example: if it send some UDP packets to my localhost and destination port is 5000. and there will have a client program to receive it on port 5000. but, what I want is to create another program, it will try to receive the same packets on port 5000.
if the server send packets p1, p2, p3....pn to my localhost port 5000, I want to both client programs will receive same packets. (client program 1: p1, p2, p3....pn, client program 2: p1, p2, p3...pn)
I tried to use pcap to do this, but seems lost some packets in sometimes.(the server will send some video stream to client)
You need to use multicast if you want to do this with a single send / sendto on the server process. Here are quick examples done in Python 2.7.x for the sake of brevity / reuse of code I had laying around.
It's import for the transmit side to set IP_MULTICAST_LOOP if you are going to use this method with transmitter & receivers running on the same host.
sender.py:
#!/usr/bin/env python
import socket
import sys
MCAST_GROUP=sys.argv[1]
MCAST_PORT=int(sys.argv[2])
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt( socket.SOL_SOCKET, socket.IP_MULTICAST_LOOP, 1 )
for ii in xrange(10):
msg = 'message %d' %ii
print 'sending: "%s"' %msg
s.sendto( msg, (MCAST_GROUP, MCAST_PORT)
receiver.py:
#!/usr/bin/env python
import socket
import sys
import struct
MCAST_GROUP=sys.argv[1]
MCAST_PORT=int(sys.argv[2])
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
s.bind( (MCAST_GROUP, MCAST_PORT) )
# In C, you'll want to use struct ip_mreq here. See 'man 7 ip' for details.
# Python's socket module doesn't define a convenient way to do this, hence the
# 'manual' struct.pack
mreq = struct.pack( '4sI', socket.inet_aton(MCAST_GROUP), socket.INADDR_ANY )
s.setsockopt( socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq )
while True:
rx_data = s.recv(1000)
print 'received: "%s"' %rx_data
Both programs expect two command line arguments, an IPv4 multicast IP (224.0.0.0 - 239.255.255.255), and a port. For example (./sender.py 239.10.10.10 5000).
You should be able to run as many instances of receiver.py as you like in different terminals, and see that a single instance of sender.py will transmit to all receivers.
To translate this to C, it's basically:
Convert s = socket.socket(...) -> s = socket(...)
Convert s.X(...) to X(s, ...) for X={setsockopt, bind, send, recv}
See notes about ip_mreq.
Once you read/recv on the socket the messages will be gone from the socket, so even if you use SO_REUSEADDR/ SO_REUSEPORT, I don't think you will be able to read the packets with both clients.
I think the easiest option is to have a local service running on port 5000 which then forwards all packets to the other services. Whether you write that as a server pub/sub style or hard-code it is probably something to decide based on how much effort you want to put into this.

Choose a local source port that is already in use

I want to connect to a remote server using a specific local port, not one assigned randomly by the kernel. I can do this by calling bind() to bind to the local port before calling connect() to the remote server.
My question is what happens if the local port I want to use is already in use by another application? I should be able to use it anyway, provided the destination or remote port are different (the same way a server can accept() multiple connections on port 80). But shouldn't my bind call fail in this case, and if so how can I set up the socket to use the local port that's already in use by another application?
The reason I want to do this is I am trying to write a local proxy that connects to a server application who checks the source port. If the source port is wrong the server won't allow the connection. The client side application connects to my proxy, and I want my proxy to use the same port to connect to the server - but if the proxy is on the same machine it won't work because the port is already in use by the application connecting to my proxy.
You can make an argument that you should be able to use it anyway, but TCP implementations don't let you unless the two binds are different. For example, you are probably able to bind to the same port with different IP addresses.
There are two problems with permitting overlapping binds:
What happens if both applications call accept? Do they fight over incoming connections?
What happens if both applications try to make an outbound connection to the same IP and port? How can those two connections be distinguished?
Now these problems could be solved. But I don't know of any implementations that bother. The argument is that the applications would have to cooperate or they would get surprising results. And if they're cooperating, they can share the bound socket.
So the answer is: If you aren't cooperating with the other application that has the port, then you have no right to share it. If you are cooperating with the other application, ask it to give you a copy of its socket using the method your platform supports.
> But shouldn't my bind call fail in this case,
Yes if the socket does not have SO_REUSEADDR option set.
> and if so how can I set up the socket to use the local port that's already in use by another application?
Both your application and another application must set SO_REUSEADDR option on the socket, which wants to bind to the local port.
The code below connects to the HTTP server, given as command-line argument, from port 1111:
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>
#define CLIENT_PORT 1111
#define SERVER_PORT 80
int main(int argc, char *argv[]) {
struct sockaddr_in client_name, server_name;
struct hostent *server_info;
if (argc != 2)
return printf("Exactly one argument is required: host to connect\n"), 1;
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
return perror("socket"), 1;
/* Without the next 4 lines, bind refuses to use the same port */
int reuseaddr = 1;
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
sizeof(reuseaddr)) < 0)
return perror("setsockopt"), 1;
client_name.sin_family = AF_INET;
client_name.sin_port = htons(CLIENT_PORT);
client_name.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock_fd, (struct sockaddr *) &client_name,
sizeof(struct sockaddr_in)) < 0)
return perror("bind"), 1;
server_name.sin_family = AF_INET;
server_name.sin_port = htons(SERVER_PORT);
if ((server_info = gethostbyname(argv[1])) == NULL)
return printf("Unknown host: %s\n", argv[1]), 1;
server_name.sin_addr = *(struct in_addr *) server_info->h_addr;
if (connect(sock_fd, (struct sockaddr *) &server_name,
sizeof(server_name)) < 0)
return perror("connect"), 1;
return 0;
}
> what happens if the local port I want to use is already in use by another application?
Without SO_REUSEADDR (try to comment out the 4 lines around setsockopt), bind fails:
$ ./client google.com
$ ./client stackoverflow.com
bind: Address already in use
With SO_REUSEADDR, you can connect to different remote servers:
$ ./client google.com
$ ./client stackoverflow.com
But then connect will not allow you to open two sockets with same source and destinations:
$ ./client google.com
$ ./client google.com
connect: Cannot assign requested address
bind knows just one endpoint.
Suppose that two sockets are bound to the same port. Which one the incoming packet shall be routed to?
accept on the other hand knows both peers.

"tcp session control protocol" in linux kernel?

I'm programming in Linux environment.
I want to establish a TCP socket between two PCs, and multiplexing it.
To be specific, here is the pseudo-code:
void func_in_process0()
{
socket s = socket(AF_INET, SOCK_STREAM, 0);
connect(s, "1.1.1.1", 8080);
socket s1 = ADD_CHANNEL(s, 1); // key part
SEND_FILE_DESCRIPTOR_TO_PROCESS(s1, process1);
socket s2 = ADD_CHANNEL(s, 2); // key part
SEND_FILE_DESCRIPTOR_TO_PROCESS(s2, process2);
WAIT_FOR_PROCESS_TO_FINISH(process1);
WAIT_FOR_PROCESS_TO_FINISH(process2);
close(s);
}
void func_in_process1()
{
socket s1 = GET_SOCKET_FROM_PROCESS0();
send(s1, "abcdefg");
close(s1);
}
void func_in_process2()
{
socket s2 = GET_SOCKET_FROM_PROCESS0();
send(s2, "abcdefg");
close(s2);
}
The key part is how to implement function ADD_CHANNEL.
I found a document TCP Session Control Protocol which provides exactly the function I want.
But I don't think it is implemented in Linux kernel.
I can implement this protocol in userspace, but variable "s1" and "s2" will not be file descriptor and can't be sent to other processses.
Edit:
process0, process1 and process2 are all on localhost.
socket "s" is a client socket.
1.1.1.1 is a remote PC, who is the server. so proc1 and proc2 both sends packet to 1.1.1.1 through the CHANNEL.
the server is CHANNEL aware too.
Edit2:
I read the SCP Protocol, but it still has no in-kernel implementation.
I learned the SCTP multi-streaming, which is implemented in kernel, but there's no API that creates sub-socket so the problem remains.
Sure, they can be file descriptors. Create two pipes and give one end to each of the other two processes. Your 'multiplexor' will read from, and write two, the other ends of the two bidirectional pipes.

error in binding port "Address already in use" TCP socket programming in unix

I've gone through many posts and forums and I'm new to socket programming. Major parts of my code are similar to
BIND ERROR : Address already in use
but then i changed my code so that i include "setsockopt" function like so:
const char* port="5555";
int opt=1;
portno=atoi(port);
//parameters for server address
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(portno);
serv_addr.sin_addr.s_addr=INADDR_ANY;
//bind the socket to the address
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const char *)&opt,sizeof(int));
if(bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
{close(sockfd);
error("error in binding port!");
}
But still i get the error. I have to close the terminal and restart it in order to use the port again. I want to use a hardcoded port (like i mentioned in the code above)
Thanks a lot in advance
Check to see if the port is in use. Either telnet to that port or use netstat -a. It should be in use (as the error indicates) and kill the appropriate process. Perhaps using ps to find the process.
A port number can only be used by one application at a time. That means you can not start the same program twice expecting both to bind to the same port.
The SO_REUSEADDR is for when the socket bound to an address has already been closed, the same address (ip-address/port pair) can be used again directly.

Resources