2 program get same udp packets from a port - c

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.

Related

What is a best way to send message from tcp server to raspberry pi?

I'm trying to use REST API server on my pi1 and TCP server on AWS EC2
I have two raspberry pis and as I wanted to use tcp server (in C) that I learned
(first one at home, second one at anywhere with wifi)
My goal is
if anyone (external) sends something on my pi's raspberry pi REST API server INSTANTLY
in an endpoint function, creates tcp client and also sending some JSON result to send somewhere
let mut stream =
TcpStream::connect("ec2-XXX-compute.amazonaws.com:8888")
.await
.expect("connect failed");
// Buffer the bytes
stream
.write_all(action.as_bytes())
.await
.expect("sending msg");
stream
.shutdown(Shutdown::Both)
.expect("shutdown call failed");
this client sends the message to EC2's TCP server and read with C language
if ((client_socket = accept(server_fd, (struct sockaddr *)&newAddr,
&addr_size)) < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
valread = read(client_socket, buffer, 10);
printf("From client: %s\n", buffer);
It works very well so far but what I want to do from here is to send the buffer data to
my another raspberry pi (pi2)
(pi 2's wifi keeps changing so it can only access internet, can't run server here)
What will be the best way to do this without delay or checking?
Sorry for the ugly picture but hope this helps your understanding
on PI 1, I'm running rest api/tcp server
and pi 2 can run tcp client server anywhere and connect to the pi 1
implemented with multiple clients without threading
Thanks all who watched this question!

3 sockets created for one libevent bind on Windows?

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.

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.

"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.

how to kill a tcp connection in a tcp server program if no FIN/ACK or RST received

I wrote a tcp server program(linux c) and run it on host B
if host A establishes a TCP connection with host B
then A shutdown without sending FIN/ACK
how do I write source codes inside tcp server to kill this tcp connection?
use raw socket to craft s fake RST?
or other ways?
thanks!
Just close() the server's end of the socket once it has determined that the connection is no longer available. Eventually, the socket will time out internally and start reporting errors to read/write operations, at which time you can then close it. If you do not want to wait that long then implement a timeout in your own code, either as a keepalive/ping command in your protocol, or just as a simple timer that keeps track of the last time the client exchanged any data with the server. If the timeout period expires, close the socket regardless of its actual state.
I'm not sure in this case, but if you create a binary file with all the open connections:
FILE *ptr_myfile;
ptr_myfile=fopen("test.bin","wb"); //opened sockets
//.. your code ..
sockfd[k] = socket(AF_INET, SOCK_STREAM, 0);
fwrite(&sockfd[k], sizeof(sockfd[k]), 1, ptr_myfile_soc);
//.. your code ..
close(ptr_myfile);
and if host A shuts down without sending FIN/ACK, in another executable you will read from that file and close the related sockets:
fread(&sockfd[k],sizeof(sockfd[k]),1,ptr_myfile_soc);
printf("closing %d \n",k );
close(sockfd[k]);

Resources