c++ UDP relay application latency - c++

I want to receive UDP packets from a server application (on the same computer) and forward it to an UDP receive app on a different port.
The server app is not mine, nor do i have the source code.
The UDP receive app is a Java application.
If i bind the Java application directly to the server app port, there is very low latency, but if i connect it to the relay appĀ“port i get almost one second of delay.
The receiving port has to be non-blocking.
#define rcv_length 160
fd_set fds;
int n;
struct timeval tv;
void CMClient::startUDPListener(){
CMport_number = 32200;
remoteAddrLen = sizeof(struct sockaddr_in);
if (WSAStartup(0x0101, &CMw) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
CMsd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (CMsd == INVALID_SOCKET)
{
fprintf(stderr, "Could not create socket.\n");
WSACleanup();
exit(0);
}
CMserver.sin_family = AF_INET;
CMserver.sin_port = htons(CMport_number);
CMserver.sin_addr.s_addr = inet_addr("127.0.0.1");
long rc=bind(CMsd,(SOCKADDR*)&CMserver,sizeof(SOCKADDR_IN));
if(rc==SOCKET_ERROR)
{
printf("Error: bind code: %d\n",WSAGetLastError());
}
}
void CMClient::updateData(UDPServer* svr, int CMnr){
FD_ZERO(&fds);
FD_SET(CMsd, &fds);
tv.tv_sec = 0;
tv.tv_usec = 1;
n = select ( CMsd, &fds, NULL, NULL, &tv ) ;
if (FD_ISSET(CMsd, &fds))
{
FD_CLR(CMsd,&fds);
char* rcvBuffer = new char[rcv_length];
long rc=recv(CMsd,rcvBuffer,rcv_length,0); //receive
if(rc!=SOCKET_ERROR)
{
rcvBuffer[0] = CMnr;
sendto(svr->sd, (char*)rcvBuffer, rcv_length, 0, (struct sockaddr*)&svr->server, sizeof(svr->server)) != (int)sizeof(rcvBuffer); //send
}
if(rcvBuffer)
delete [] rcvBuffer;
}
}
The UDP server to send to the Java application is initialized as follows:
void UDPServer::startUDPServer(){
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == INVALID_SOCKET)
{
fprintf(stderr, "Could not create socket.\n");
WSACleanup();
exit(0);
}
server.sin_family = AF_INET;
server.sin_port = htons(port_number);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
if (connect(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "Could not connect name to socket.\n");
stopUDPServer();
}
}
The main calls
UDPServer* udpsvr;
udpsvr = new UDPServer;
udpsvr->startUDPServer();
while(1){
CM->updateData(udpsvr, CMid);
}
Any help would be appreciated why i get that much delay.
The data received from the Java app is correct but ~1 second delay.
Thank you,
Regards

Don't use bind() on client. Use connect().
Summing up, for UDP:
Server:
socket()
bind()
Client:
socket()
connect()
Example of code for server:
// socket()
fd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (fd_ < 0) {
throw std::runtime_error ("Client socket error");
}
// connect()
struct sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
struct in_addr addr;
inet_aton(address.c_str(), &addr);
bcopy(&addr, &serv_addr.sin_addr.s_addr, sizeof(addr));
if (connect(fd_, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0) {
::close(fd_);
throw std::runtime_error ("Client socket error");
}
Example of code for client:
// socket()
fd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (fd_ < 0) {
throw std::runtime_error ("Client socket error");
}
// connect()
struct sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
struct in_addr addr;
inet_aton(address.c_str(), &addr);
bcopy(&addr, &serv_addr.sin_addr.s_addr, sizeof(addr));
if (connect(fd_, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0) {
::close(fd_);
throw std::runtime_error ("Client socket error");
}
Finally, you may want to have a look at flushing UDP buffers.

Related

c udp socket not receiving/sending correctly

I am currently experiencing some trouble while testing UDP sockets.
So I have 2 c programs, one sends and receives, the other receives and sends a message.
Here is send_recv.c:
#define PORT 1010
int main(int argc, const char *argv[]) {
int socketInfo, opt;
struct sockaddr_in server;
char msgOut[30], msgIn[30];
opt = 1;
printf("Input message: ");
fgets(msgOut, 30, stdin);
socketInfo = socket(AF_INET, SOCK_DGRAM, 0);
if(socketInfo < 0) {
perror("socket error");
return EXIT_FAILURE;
}
if(setsockopt(socketInfo, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt failed");
return EXIT_FAILURE;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
if(bind(socketInfo, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("bind error");
return EXIT_FAILURE;
}
if(connect(socketInfo, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("connection error");
return EXIT_FAILURE;
}
puts("connected");
send(socketInfo, msgOut, strlen(msgOut), 0);
puts("sleeping for 5");
sleep(5);
puts("message sent");
recv(socketInfo, msgIn, sizeof(msgIn), 0);
printf("received msg: %s\n", msgIn);
close(socketInfo);
return EXIT_SUCCESS;
}
And here is recv_send.c:
#define PORT 1010
int main(int argc, const char *argv[]) {
int socketInfo, opt;
struct sockaddr_in server;
char msgOut[30], msgIn[30];
opt = 1;
socketInfo = socket(AF_INET, SOCK_DGRAM, 0);
if(socketInfo < 0) {
perror("socket error");
return EXIT_FAILURE;
}
if(setsockopt(socketInfo, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt failed");
return EXIT_FAILURE;
}
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY;
if(bind(socketInfo, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("bind error");
return EXIT_FAILURE;
}
if(connect(socketInfo, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("connection error");
return EXIT_FAILURE;
}
puts("connected");
recv(socketInfo, msgIn, sizeof(msgIn), 0);
printf("received msg: %s\n", msgIn);
printf("Input message: ");
fgets(msgOut, 30, stdin);
send(socketInfo, msgOut, strlen(msgOut), 0);
puts("message sent");
close(socketInfo);
return EXIT_SUCCESS;
}
The problem is that the receive program never receives anything, and the send program sends and then just receives the message it already received.
The output of send_rcv is this:
Input message: hello there
connected
message sent
received msg: hello there
and the output of rcv_send is this:
connected
(ctrl+z) Job 6, 'sudo ./rcv_send' has stopped
Another problem is that when I don't run the program with sudo it just says this: bind error: Permission denied
The problem is that both endpoints are listening on the same port while running on the same machine, and you have both sides sending to INADDR_ANY.
Also, port numbers below 1024 are privileged ports and therefore require root access to bind to.
Use a different port (1024 or higher) for each side of the connection, and choose a specific IP address to connect to. For example:
#define LOCAL_PORT 1100
#define REMOTE_PORT 1101
...
struct sockaddr_in local, remote;
local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = htons(LOCAL_PORT);
remote.sin_family = AF_INET;
remote.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
remote.sin_port = htons(LOCAL_PORT);
if(bind(socketInfo, (struct sockaddr *)&local, sizeof(local)) < 0) {
perror("bind error");
return EXIT_FAILURE;
}
if(connect(socketInfo, (struct sockaddr *)&remote, sizeof(remote)) < 0) {
perror("connection error");
return EXIT_FAILURE;
}
The values of LOCAL_PORT and REMOTE_PORT would be swapped in the two programs.
Note also that you can get rid of the setsockopt call as you don't have two programs open on the same port.

recvfrom() doesn't get any UDP messages

I'm trying to get UDP messages that are being sent from different applications on my machine.
I created a socket and bind it to an address. When I send UDP messages using Packet Sender, nothing arrives. I tried disabling the firewall just to be sure, and still nothing happens.
I send messages to 127.0.0.1 port 8034.
I tried binding to both 127.0.0.1 and INADDR_ANY, neither work.
This is the code I'm using to listen :
SOCKET SendSocket = INVALID_SOCKET;
sockaddr_in RecvAddr, ClientAddr;
WSADATA wsaData;
struct sockaddr_in serv, client;
int l = sizeof(client);
char buffer[256];
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
wprintf(L"WSAStartup failed with error: %d\n", iResult);
}
SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (SendSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
}
ClientAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
ClientAddr.sin_family = AF_INET;
ClientAddr.sin_port = htons(8034);
bind(SendSocket, (struct sockaddr *) &ClientAddr, sizeof(ClientAddr));
bool valid = true;
while( valid )
{
//cout << "\ngoing to recv\n";
int rc = recvfrom(SendSocket, buffer, sizeof(buffer), 0, (struct sockaddr *)&client, &l);
if (rc < 0)
{
//cout << "ERROR READING FROM SOCKET";
}
else
{
cout << "\n the message received is : " << buffer << endl;
}
DoPostDrawTask( valid );
}

How to use 2 sockets PF_INET and PF_PACKET at the same time?

I have the following 2 functions
int listen_socket(unsigned int ip, int port, char *inf)
{
struct ifreq interface;
int fd;
struct sockaddr_in addr;
int n = 1;
DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s\n", ip, port, inf);
if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
return -1;
}
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = ip;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) {
close(fd);
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &n, sizeof(n)) == -1) {
close(fd);
return -1;
}
strncpy(interface.ifr_ifrn.ifrn_name, inf, IFNAMSIZ);
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,(char *)&interface, sizeof(interface)) < 0) {
close(fd);
return -1;
}
if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
close(fd);
return -1;
}
return fd;
}
int raw_socket(int ifindex)
{
int fd;
struct sockaddr_ll sock;
DEBUG(LOG_INFO, "Opening raw socket on ifindex %d\n", ifindex);
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
return -1;
}
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
sock.sll_family = AF_PACKET;
sock.sll_protocol = htons(ETH_P_IP);
sock.sll_ifindex = ifindex;
if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
close(fd);
return -1;
}
return fd;
}
Both are socket listener functions.
I used these functions in my application in this way
fd = listen_socket(INADDR_ANY, 67, client_config.interface);
fd2 = raw_socket(client_config.ifindex);
Now if I send packet to my application (with destination = ip of the interface and port=67). What socket should catch my packet? is it fd2 or fd or both?
And if I send a packet to my application (with destination = broacast:255.255.255.0 and port=67). What socket should catch my packet? is it fd2 or fd or both?
Both sockets will receive that packet. As each packet arrives from the network driver to the kernel, it is duplicated and sent to all PF_PACKET (layer 2) sockets. The packet is also sent to the layer 3 (IP/TCP) kernel code and from there, to the addressed socket.
If this didn't happen, running a separate program doing raw packet captures (e. g. wireshark) would prevent any other communications over the network.

Generation of unique IP-port using bind(0)

I need to generate port numbers for some programm. Google tells, that bind with zero-port generates binds unused port. I want to bind zero-port, remember it's number, close port. Trying to do this? but netstat doesn't see my programm's port. Linux 2.6.27
int sfd;
struct sockaddr_in my_addr;
sfd = socket(PF_INET , SOCK_STREAM, 0);
if (sfd == -1)
{
printf("socket error\n");
return -1;
}
memset(&my_addr, 0, sizeof(struct sockaddr_in ));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = 0;
if (bind(sfd, (struct sockaddr_in *) &my_addr,
sizeof(struct sockaddr_in)) == -1)
printf("bind error\n");
if (listen(sfd, LISTEN_BACKLOG) == -1)
printf("listen error\n");
bind() expects a sockaddr* not a sockaddr_in*:
bind(sfd, (struct sockaddr *) &my_addr, sizeof(my_addr))
Other than that, I don't see any other errors. Binding to port 0 is the correct way to bind to a random available port. If bind() and listen() do not report a failure then netstat should see an open port. Use getsockname() to find out which port bind() actually chose, eg:
int sfd = socket(PF_INET , SOCK_STREAM, 0);
if (sfd == -1)
{
printf("socket error: %d\n", errno);
return -1;
}
struct sockaddr_in my_addr;
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = 0;
if (bind(sfd, (struct sockaddr *) &my_addr, sizeof(my_addr)) == -1)
{
printf("bind error: %d\n", errno);
close(sfd);
return -1;
}
if (listen(sfd, LISTEN_BACKLOG) == -1)
{
printf("listen error: %d\n", errno);
close(sfd);
return -1;
}
memset(&my_addr, 0, sizeof(my_addr));
socklen_t my_addrlen = sizeof(my_addr);
if (getsockname(sfd, (struct sockaddr *) &my_addr, &my_addrlen ) == -1)
{
printf("getsockname error: %d\n", errno);
close(sfd);
return -1;
}
printf("listening on port: %hu\n", ntohs(my_addr.sin_port));

Socket does not accept connections

I have a server socket accepting client socket connections. Accept is in a thread
socket creation
int ServerSocket::CreateSocket(int port)
{
listenfd = 0;
struct sockaddr_in serv_addr;
unsigned long iMode = 1;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
ioctlsocket(listenfd, FIONBIO, &iMode);
if (bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
{
return 0;
}
if (listen(listenfd, 20) < 0)
{
return 0;
}
return listenfd;
}
Socket Accept
void ServerSocket::AcceptClients_1(void * p)
{
struct sockaddr_in cli_addr;
// get a pointer to the ServerSocket object
ServerSocket * pThis = (ServerSocket *)p;
int iResult, cli_len;
cli_len = sizeof(cli_addr);
struct timeval tv = { 0, 1000 };
SOCKET s = pThis->GetSocket();
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(s, &rfds);
while (!pThis->ShutDownRequested)
{
iResult = select(s+1, &rfds, (fd_set *) 0, (fd_set *) 0, &tv);
if(iResult > 0)
{
// never comes here
SOCKET sclient = accept(s, (struct sockaddr *)&cli_addr,
&cli_len);
}
else if (iResult == 0) /// timeout
{
continue;
}
// error comes here are going to accept 2nd time
DWORD dwError = GetLastError();
return;
}
}
The code comes on select(). Returns 0 the first time but second time always returns -1 with error 10022. I don't understand why. Please help.
Make sure your pThis->GetSocket() is correctly returning the listenfd. Also, you should reinitialize cli_len = sizeof(cli_addr); before each call to accept (it's a value-result argument).
iResult=0 does not always mean timeout, for non-blocking sockets, you need to check WSAGetLastError and deal with some error codes, for example WSAEWOULDBLOCK means you need to wait next event on this socket.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx