im playing around with STP packets and writing a program raw sockets to modify them.
Reading fropm eth0 sending to eth1. System is ubuntu 14.10/ Kernel 3.somewhat.
Packets are generated with additional computers with Karat and Wireshark is running this interfaces too.
Inject a packet and after first run recvfrom didn't stop. Read the same packet from eth0
and send it to eth1. Debugging session ???????
The final edition should read all frame from eth0 , forward all and put all STP in a "unicast tunnel" - Read alle eth1 frame an forward eth0 and "unpack" special "Tunnel"
frames.
i put some code here:
typedef struct {
unsigned char mac[6];
unsigned char ifName[IFNAMSIZ];
int sockfd;
struct sockaddr_ll socketaddress;
struct ifreq ifopts; /* set promiscuous mode */
} interfaces;
extern int errno;
nt i;
int sockopt;
ssize_t numbytes;
unsigned char InBuf[BUF_SIZ]; // this is the frame buffer
interfaces in,out; // interface struct var's
unsigned char PeerMac[6]; // Peer mac for simple Tunnel
unsigned char myMac[6]; // my Peer address
int c;
unsigned char IEEE802_1q_STP[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0d};
/* Header structures */
struct ether_header *InTunnelPtr = (struct ether_header*) InBuf;
struct ether_header *InPtr = (struct ether_header*) (InBuf+14);
/ First Do it for IN_IF
memset(&in.socketaddress, 0, sizeof(struct sockaddr_ll)); // clear Var
in.socketaddress.sll_family = PF_PACKET;
in.socketaddress.sll_protocol = htons(ETH_P_ALL); // just dummy, don't needed
in.socketaddress.sll_halen = ETH_ALEN;
/* Open PF_PACKET socket, listening for EtherType ETHER_TYPE */
if ((in.sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("listener: socket");
return -1;
}
memset (&in.ifopts, 0, sizeof (struct ifreq));
// Set interface to promiscuous mode - do we need to do this every time?
strncpy(in.ifopts.ifr_name, in.ifName, IFNAMSIZ-1); // set if name
ioctl(in.sockfd, SIOCGIFFLAGS, &in.ifopts); // get current flags
in.ifopts.ifr_flags |= IFF_PROMISC; // set promiscuous mode
ioctl(in.sockfd, SIOCSIFFLAGS, &in.ifopts); // write flags
// get my mac addr
//ioctl(in.sockfd,SIOCGIFHWADDR,&in.ifopts);
//memcpy(in.mac,in.ifopts.ifr_hwaddr.sa_data,ETH_ALEN);
// find Interface index
strncpy(in.ifopts.ifr_name, in.ifName, IFNAMSIZ-1); //
ioctl(in.sockfd, SIOCGIFINDEX, &in.ifopts); // get if index
in.socketaddress.sll_ifindex=in.ifopts.ifr_ifindex; // set index to sockaddr_ll
// Allow the socket to be reused - incase connection is closed prematurely
if (setsockopt(in.sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
close(in.sockfd);
exit(EXIT_FAILURE);
}
// Bind to device
if (setsockopt(in.sockfd, SOL_SOCKET, SO_BINDTODEVICE, in.ifName, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(in.sockfd);
exit(EXIT_FAILURE);
}
// -----------------------------------
// Now, do the OUT Interface
// -----------------------------------
memset(&out.socketaddress, 0, sizeof(struct sockaddr_ll)); // clear Var
out.socketaddress.sll_family = PF_PACKET;
out.socketaddress.sll_protocol = htons(ETH_P_ALL); // just dummy, don't needed
out.socketaddress.sll_halen = ETH_ALEN;
// Open PF_PACKET socket, listening for EtherType ETHER_TYPE */
if ((out.sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("listener: socket");
exit(EXIT_FAILURE);
}
memset (&out.ifopts, 0, sizeof (struct ifreq));
// Set interface to promiscuous mode - do we need to do this every time? */
strncpy(out.ifopts.ifr_name, out.ifName, IFNAMSIZ-1);
ioctl(out.sockfd, SIOCGIFFLAGS, &out.ifopts);
out.ifopts.ifr_flags |= IFF_PROMISC;
ioctl(out.sockfd, SIOCSIFFLAGS, &out.ifopts);
// get my mac addr
// ioctl(out.sockfd,SIOCGIFHWADDR,&out.ifopts);
// memcpy(out.mac, out.ifopts.ifr_hwaddr.sa_data, ETH_ALEN);
// find Interface index */
strncpy(out.ifopts.ifr_name, out.ifName, IFNAMSIZ-1);
ioctl(out.sockfd, SIOCGIFINDEX, &out.ifopts);
out.socketaddress.sll_ifindex=out.ifopts.ifr_ifindex;
// Allow the socket to be reused - incase connection is closed prematurely */
if (setsockopt(out.sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
close(out.sockfd);
exit(EXIT_FAILURE);
}
// Bind to device */
if (setsockopt(out.sockfd, SOL_SOCKET, SO_BINDTODEVICE, out.ifName, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(out.sockfd);
exit(EXIT_FAILURE);
}
// Working LOOP
// interface in
// buffer structur
// ------------------------------------------------------------
// | dest | source | len | recv packet |
// ------------------------------------------------------------
// ^InTunnelPtr ^ InPtr
repeat:
numbytes=0;
numbytes = recvfrom(in.sockfd, &InBuf[14], BUF_SIZ, 0, NULL, NULL) ;
/* let the game begin */
// test multicast addresses here
// and do something:-)
if (numbytes > 0) {
/* if (memcmp(InPtr->ether_dhost,CISCOSHARED_STP, ETH_ALEN) == 0) {
if (debug == 1) printf("Cisco Shard stp found");
}
else if (memcmp(InPtr->ether_dhost,IEEE802_1AD_STP, ETH_ALEN)==0) {
if ( debug == 1) printf("IEEE802.1AD stp found");
}
else */
if (memcmp(InPtr->ether_dhost,IEEE802_1D_STP, ETH_ALEN)==0) // this tunnel
{
if (debug == 1) printf("IEEE802.1D stp for tunnel eth1\n");
memcpy(InTunnelPtr->ether_dhost,PeerMac , ETH_ALEN); // Copy PeerMac to destination address
memcpy(InTunnelPtr->ether_shost,myMac , ETH_ALEN); // Copy my peer mac to source address
InTunnelPtr->ether_type=numbytes+14; // set tunnel header len
// if (numbytes = sendto(out.sockfd, &InBuf[0] , (numbytes+14), 0,(struct sockaddr_ll *)&out.socketaddress,sizeof(out.socketaddress)) < 0)
i = numbytes+14;
if (numbytes = sendall_eth1(out.sockfd, &InBuf[0] , &i, &out.socketaddress, sizeof(out.socketaddress)) < 0)
{
printf("send error %s \n",strerror(errno));
}
} else { // send untunneled packet out
if (debug == 1) printf ("send untunneled packet eth1\n");
// if (numbytes = sendto(out.sockfd, &InBuf[14], numbytes, 0,(struct sockaddr_ll *)&out.socketaddress,sizeof(out.socketaddress)) < 0)
i = numbytes;
if (numbytes =
sendall_eth1(out.sockfd, &InBuf[14], &i, &out.socketaddress, sizeof(out.socketaddress)) < 0)
{
printf("send error %s \n",strerror(errno));
}
}
}
goto repeat
Related
The following code is part of a C-RAN program where the server code is part of a larger module code that serves as an interface to communicate with the Remote Radio Head.
To simplify it, let us treat it as a simple client-server service. The server will send an audio file through a specific UDP socket (port1) to the client and this one will play it back. Then, the client sends an ACK to the server through another socket (port2). Afterwards, the client starts recording audio and sends the datagrams via socket (port3). FInally, the client sends again a last ack through socket (port4).
Why so many different sockets? It is mandatory, full-duplex is a must, let's leave it here.
If I "comment" the code where the client records audio, communications between client-server are fine, audio is played back properly, no choppy playback. As soon as I activate the client code for recording, the playback starts to be choppy and the recording is a mess.
I've tried all sort of tests, like reducing the number of sockets, increasing the buffer sizes, removing one or all the acks, etc..
My network programming skills are so so, thus I don't know what else I can do. One thing is for sure, either there's a datagram flow issue or the ALSA lib drives can not cope, the latter I doubt it.
The way the code is in here, audio playback will be fine, all code parts for recording are commented in the client code.
Client:
//COMPILE: gcc -o client client.c -lasound
//EXECUTE (only playback): ./client
//EXECUTE (playback&recording): ./client > recordedFilename.raw
/*
-------- Remote Radio Head - client side
Remote Radio Head recieves audio from a dedicated socket from BBU, may process it or not
and sends audio through a different socket to the BBU.
*/
/* DEPENDENCIES */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <alsa/asoundlib.h>
#include <dirent.h>
/* CONSTANTS */
#define PORT1 8070
#define PORT2 8080
#define PORT3 8090
#define PORT4 8100
#define MAXLINE 1024
#define FRAME_SIZE 512
#define PAYLOAD_SIZE (FRAME_SIZE * 4)
/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API
// START
int main(int argc, char *argv[])
{
// Sockets variables
int sockfd1, sockfd2, sockfd3, sockfd4;
int len, n;
int i = 1;
const char* ACK_play = "playback_ack";
const char* ACK_rec = "recording_ack";
const char* START_BROADCAST = "CLIENT: Connected !!!";
const char* MSG = "\nCLIENT: sending recording datagrams\n";
char buffer[MAXLINE];
struct sockaddr_in servaddr1, servaddr2, servaddr3, servaddr4;
// ALSA playback variables
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
// ALSA recording variables
long loops;
int rc2;
int size2;
snd_pcm_t *handle2;
snd_pcm_hw_params_t *params2;
unsigned int val2;
int dir2;
snd_pcm_uframes_t frames2;
char *buffer2;
/*********************************************
* ALSA PLAYBACK DRIVERS SETUP *
*********************************************/
// Open PCM device for playback.
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
exit(1);
}
// Allocate a hardware parameters object.
snd_pcm_hw_params_alloca(¶ms);
// Fill it in with default values.
snd_pcm_hw_params_any(handle, params);
// Set the desired hardware parameters.
// Interleaved mode
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
// Signed 16-bit little-endian format
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
// Two channels (stereo)
snd_pcm_hw_params_set_channels(handle, params, 2);
// playback sampling rate
val = 48000;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
// Set period size to 32 frames.
frames = FRAME_SIZE;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
// Write the parameters to the driver
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
exit(1);
}
/*********************************************
* ALSA RECORDING DRIVERS SETUP *
*********************************************/
// Open PCM device for recording (capture).
rc2 = snd_pcm_open(&handle2, "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc2 < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc2));
exit(1);
}
// Allocate a hardware parameters object.
snd_pcm_hw_params_alloca(¶ms2);
// Fill it in with default values.
snd_pcm_hw_params_any(handle2, params2);
// Set the desired hardware parameters.
// Interleaved mode
snd_pcm_hw_params_set_access(handle2, params2, SND_PCM_ACCESS_RW_INTERLEAVED);
// Signed 16-bit little-endian format
snd_pcm_hw_params_set_format(handle2, params2, SND_PCM_FORMAT_S16_LE);
// Two channels (stereo)
snd_pcm_hw_params_set_channels(handle2, params2, 2);
// recording sampling rate
val2 = 48000;
snd_pcm_hw_params_set_rate_near(handle2, params2, &val, &dir2);
// Set period size to 32 frames.
frames2 = FRAME_SIZE;
snd_pcm_hw_params_set_period_size_near(handle2, params2, &frames, &dir2);
// Write the parameters to the driver
rc2 = snd_pcm_hw_params(handle2, params2);
if (rc2 < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc2));
exit(1);
}
/*********************************************
* CREATING SOCKET FILE DESCRIPTOR *
*********************************************/
// --------------- SOCKET 1
if ((sockfd1 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket 1 creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr1, 0, sizeof(servaddr1));
// Filling server 1 information
servaddr1.sin_family = AF_INET; // ipv4
servaddr1.sin_addr.s_addr = INADDR_ANY; // Any server
servaddr1.sin_port = htons(PORT1);
// --------------- SOCKET 2
if ((sockfd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket 2 creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr2, 0, sizeof(servaddr2));
// Filling server 2 information
servaddr2.sin_family = AF_INET; // ipv4
servaddr2.sin_addr.s_addr = INADDR_ANY; // Any server
servaddr2.sin_port = htons(PORT2);
// --------------- SOCKET 3
if ((sockfd3 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket 3 creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr3, 0, sizeof(servaddr3));
// Filling server 2 information
servaddr3.sin_family = AF_INET; // ipv4
servaddr3.sin_addr.s_addr = INADDR_ANY; // Any server
servaddr3.sin_port = htons(PORT3);
// --------------- SOCKET 4
if ((sockfd4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket 4 creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr4, 0, sizeof(servaddr4));
// Filling server 2 information
servaddr4.sin_family = AF_INET; // ipv4
servaddr4.sin_addr.s_addr = INADDR_ANY; // Any server
servaddr4.sin_port = htons(PORT4);
/********************************************
* SEND MSG TO SERVER *
********************************************/
//sockfd: File descriptor of socket
//buffer: Application buffer cointaining the data to be sent
//len: Size of buffer
//flags: Bitwise OR flags to modify socket behaviour
//dest_addr: Structure containing address of destination
//addrlen: Size of dest_addr structure
sendto(sockfd1, START_BROADCAST, strlen(START_BROADCAST), 0, (const struct sockaddr *)&servaddr1, sizeof(servaddr1));
printf("CLIENT: Waiting for audio!!!\n");
/********************************************
* RECIEVE MSG FROM SERVER *
********************************************/
//sockfd: file descriptor of socket
//buffer: Apllication buffer in which to recieve data
//len: Size of buffer
//flags: Bitwise OR flags to modify socket behaviour
//src_addr: Structure containing source address is returned
//addrlen: Variable in which size of src_addr structure is returned
/* We allocate memory to store the payload of the incoming datagram. */
char *play_load = (char *)malloc(PAYLOAD_SIZE * sizeof(char));
char *rec_load = (char *)malloc(PAYLOAD_SIZE * sizeof(char));
///////////////////////////////////////////////////////////////////////////////////////
/* HERE CLIENT (RRH) RECIEVES AND SENDS DATA TO SERVER (BBU) NEEDS TO BE FULL DUPLEX */
///////////////////////////////////////////////////////////////////////////////////////
while (1)
{
//----------------------------------------- RECIEVE AUDIO DATAGRAMS
len = PAYLOAD_SIZE;
int playback_bytes = recvfrom(sockfd1, (void *)play_load, PAYLOAD_SIZE, MSG_WAITALL, (struct sockaddr *)&servaddr1, &len);
//----------------------------------------- ALSA PLAYBACK DATAGRAMS
rc = snd_pcm_writei(handle, play_load, frames);
// if true, audio is playing
if (rc>0 && i>0){
printf("CLIENT: Playing audio!!!\n");
i--;
}
if (rc == -EPIPE) {
// EPIPE means underrun
fprintf(stderr, "playback underrun occurred\n");
snd_pcm_prepare(handle);
} else if (rc < 0) {
fprintf(stderr, "playback error from writei: %s\n", snd_strerror(rc));
} else if (rc != (int)frames) {
fprintf(stderr, "playback short write, write %d frames\n", rc);
}
//------------------------------------------- SEND PLAYBACK ACK
sendto(sockfd2, ACK_play, strlen(ACK_play), 0, (const struct sockaddr *)&servaddr2, len);
printf("1 -sending audio playback ACK\n");
//------------------------------------------- ALSA RECORDING DATAGRAMS
/*//¡¡¡uncomment to record audio and send it to server!!!
rc2 = snd_pcm_readi(handle2, rec_load, frames2);
if (rc2 == -EPIPE) {
// EPIPE means overrun
fprintf(stderr, "recording overrun occurred\n");
snd_pcm_prepare(handle2);
} else if (rc2 < 0) {
fprintf(stderr, "recording error from read: %s\n", snd_strerror(rc2));
} else if (rc2 != (int)frames2) {
fprintf(stderr, "recording short read, read %d frames\n", rc2);
}
//rc2 = write(1, buffer2, size2); //Only to see recorded data// Only uncomment to save recorded audio into a raw file
if (rc2 != size2)
fprintf(stderr, "recording short write: wrote %d bytes\n", rc2);
*/
//------------------------------------------- SEND RECORDING DATAGRAMS
sendto(sockfd3, MSG, strlen(MSG), 0, (const struct sockaddr *)&servaddr3, len);
//sendto(sockfd3, rec_load, PAYLOAD_SIZE, 0, (const struct sockaddr *)&servaddr3, len);//uncomment to send audio recorded datagrams
printf("2 -sending audio recording datagrams\n");
//------------------------------------------- SEND RECORDING ACK
sendto(sockfd4, ACK_rec, strlen(ACK_rec), 0, (const struct sockaddr *)&servaddr4, len);
printf("3 -sending audio recording ACK\n\n");
//------------------------------------------- PLAYBACK FINISH
if(playback_bytes<2048){
printf("END PLAYBACK DATAGRAMS %d\n",playback_bytes);
break;
}
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
close(sockfd1); //close file descriptor
close(sockfd2);
close(sockfd3);
close(sockfd4);
return 0;
}
//END
server:
//COMPILE: gcc -o server server.c
//EXECUTE: ./server < filename.wav
/*
-----Implementation Base Band Unit server side
BBU sends audio through a dedicated sockets to RRH
and recieves it throught a different socket from it
through a dedicated socket to process it afterwards
in other modules.
*/
/* DEPENDENCIES */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/* CONSTANTS */
#define PORT1 8070
#define PORT2 8080
#define PORT3 8090
#define PORT4 8100
#define MAXLINE 1024
#define PAYLOAD_SIZE 2048
// START
int main(int argc, char *argv[])
{
int sockfd1, sockfd2, sockfd3, sockfd4;
int len, len2, len3, n, ad;
char buffer1[MAXLINE];
char buffer2[MAXLINE];
const char* msg = "\nSERVER: Sending audio complete";
const char* ACK = "ack";
struct sockaddr_in servaddr1, cliaddr1;
struct sockaddr_in servaddr2, cliaddr2;
struct sockaddr_in servaddr3, cliaddr3;
struct sockaddr_in servaddr4, cliaddr4;
/*********************************************
* CREATING SOCKET FILE DESCRIPTOR *
*********************************************/
// SOCKET 1
if ((sockfd1 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
/*AL_INET: ipv4; SOCK_DGRAM: UPD; 0: default protocol*/
perror("socket 1 creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr1, 0, sizeof(servaddr1)); // Allocate memory for structure
memset(&cliaddr1, 0, sizeof(cliaddr1));
// Filling server information
servaddr1.sin_family = AF_INET; // IPv4
servaddr1.sin_addr.s_addr = INADDR_ANY; // Any client
servaddr1.sin_port = htons(PORT1);
// SOCKET 2
if ((sockfd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
/*AL_INET: ipv4; SOCK_DGRAM: UPD; 0: default protocol*/
perror("socket 2 creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr2, 0, sizeof(servaddr2)); // Allocate memory for structure
memset(&cliaddr2, 0, sizeof(cliaddr2));
// Filling server information
servaddr2.sin_family = AF_INET; // IPv4
servaddr2.sin_addr.s_addr = INADDR_ANY; // Any client
servaddr2.sin_port = htons(PORT2);
// SOCKET 3
if ((sockfd3 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
/*AL_INET: ipv4; SOCK_DGRAM: UPD; 0: default protocol*/
perror("socket 3 creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr3, 0, sizeof(servaddr3)); // Allocate memory for structure
memset(&cliaddr3, 0, sizeof(cliaddr3));
// Filling server information
servaddr3.sin_family = AF_INET; // IPv4
servaddr3.sin_addr.s_addr = INADDR_ANY; // Any client
servaddr3.sin_port = htons(PORT3);
// SOCKET 4
if ((sockfd4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
/*AL_INET: ipv4; SOCK_DGRAM: UPD; 0: default protocol*/
perror("socket 4 creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr4, 0, sizeof(servaddr4)); // Allocate memory for structure
memset(&cliaddr4, 0, sizeof(cliaddr4));
// Filling server information
servaddr4.sin_family = AF_INET; // IPv4
servaddr4.sin_addr.s_addr = INADDR_ANY; // Any client
servaddr4.sin_port = htons(PORT4);
/********************************************
* BIND THE SOCKET WITH THE SERVER ADDRESS *
********************************************/
//sockfd: File descriptor of socket to be binded
//addr: Structure in which address to be binded to is specified
//addrlen: Size of addr structure
// BIND SOCKET 1
if (bind(sockfd1, (const struct sockaddr *)&servaddr1, sizeof(servaddr1)) < 0) {
perror("bind socket 1 failed");
exit(EXIT_FAILURE);
}
// BIND SOCKET 2
if (bind(sockfd2, (const struct sockaddr *)&servaddr2, sizeof(servaddr2)) < 0) {
perror("bind socket 2 failed");
exit(EXIT_FAILURE);
}
// BIND SOCKET 3
if (bind(sockfd3, (const struct sockaddr *)&servaddr3, sizeof(servaddr3)) < 0) {
perror("bind socket 3 failed");
exit(EXIT_FAILURE);
}
// BIND SOCKET 4
if (bind(sockfd4, (const struct sockaddr *)&servaddr4, sizeof(servaddr4)) < 0) {
perror("bind socket 4 failed");
exit(EXIT_FAILURE);
}
/********************************************
* RECEIVE MSG FROM CLIENT *
/*******************************************/
//sockfd: file descriptor of socket
//buffer: Apllication buffer in which to recieve data
//len: Size of buffer
//flags: Bitwise OR flags to modify socket behaviour
//src_addr: Structure containing source address is returned
//addrlen: Variable in which size of src_addr structure is returned
len = PAYLOAD_SIZE; // len is value/result
printf("\nSERVER: Waiting for client connection...\n");
n = recvfrom(sockfd1, (char *)buffer1, MAXLINE, MSG_WAITALL, (struct sockaddr *)&cliaddr1, &len);
buffer1[n] = '\0';
printf("%s\n", buffer1);
/********************************************
* SEND MSG TO CLIENT *
********************************************/
//sockfd: File descriptor of socket
//buffer: Application buffer cointaining the data to be sent
//len: Size of buffer
//flags: Bitwise OR flags to modify socket behaviour
//dest_addr: Structure containing address of destination
//addrlen: Size of dest_addr structure
// We allocate memory for the datagrams payload
char* payload = (char*)malloc(PAYLOAD_SIZE * sizeof(char));
printf("SERVER: Sending audio...\n");
//////////////////////////////////////////////////////////////////////////
/* HERE SERVER (BBU) SENDS DATA TO CLIENT (RRH) NEEDS TO BE FULL DUPLEX */
//////////////////////////////////////////////////////////////////////////
while (1)
{
//---------------------------------------- READING AUDIO FILE
int playback = read(0, (void*)payload, PAYLOAD_SIZE);
if (playback <= 0){// If true, audio send end
printf("%s\n\n", msg);
break;
}
//--------------------------------------- SEND AUDIO PLAYBACK DATAGRAMS
sendto(sockfd1, (void*)payload, playback, 0, (struct sockaddr *)&cliaddr1, len);
printf(" 1- Sending audio playback datagrams\n");
//--------------------------------------- RECIEVE AUDIO PLAYBACK ACK
len2 = sizeof(cliaddr2);
n = recvfrom(sockfd2, (char *)buffer1, MAXLINE, MSG_WAITALL, (struct sockaddr *)&cliaddr2, &len);
buffer1[n] = '\0';
//printf("CLIENT: %s\n", buffer1);// to check incoming ack
printf(" 2- Receiving audio playback ACK\n");
//--------------------------------------- RECIEVE AUDIO RECORDING DATAGRAMS
ad = recvfrom(sockfd3, (char *)buffer2, PAYLOAD_SIZE, MSG_WAITALL, (struct sockaddr *)&cliaddr3, &len);
printf(" 3- Receiving audio recording datagrams\n");
buffer2[ad] = '\0';
printf("%s\n", buffer2);
//--------------------------------------- RECEIVE RECORDING ACK
n = recvfrom(sockfd4, (char *)buffer1, MAXLINE, MSG_WAITALL, (struct sockaddr *)&cliaddr4, &len);
buffer1[n] = '\0';
//printf("CLIENT: %s\n", buffer1);//to check incoming ack
printf(" 4- Receiving audio recording ACK\n");
}
return 0;
}
//END
I am trying to create multiple TUN devices to tunnel the multi-device traffic through a common physical interface.
This is the schema I have:
Socket 1 is sending traffic through tun1 with destiny IP 1.1.1.2 and Socket 2 is doing the same on the other interface.
I have a program running between both TUN devices and the physical interface (eth0) that encapsulates IP packets from the TUN devices into UDP packets and then it sends them to the server. The server unpacks the received packets and answers both clients with echo packets (also encapsulated).
When those packets arrive in eth0, another program reads the packets and forwards them to its TUN device. After that, both programs that are running behind the sockets are blocked on recv() function waiting for the server answer on tunX devices. However, it seems like the kernel is discarding those packets on the TUN devices even when they are well-formed.
I tried by change the netmask of both interfaces to 255.255.255.0 and then only one of the sockets receives correctly the answer.
All this software has been written in C.
This is the function to create a new TUN device:
#define MTU_SIZE 1500
#define SUBNET_MASK 0xFFFFFFFF
int open_tun_iface(char * name, uint8_t * ip)
{
int sock;
struct ifreq ifr_tun;
struct sockaddr_in * sa;
int tunfd = tun_init(name, &ifr_tun, IFF_TUN | IFF_NO_PI);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("Open socket");
tun_close(tunfd);
return -1;
}
/* Set tun IP */
if (set_ip(&ifr_tun, sock, ip) < 0) {
tun_close(tunfd);
return -1;
}
sa = (struct sockaddr_in *)&ifr_tun.ifr_netmask;
memset(sa,0,sizeof(*sa));
sa->sin_family = AF_INET;
sa->sin_addr.s_addr = htonl(SUBNET_MASK);
/* Set the mask */
if (ioctl(sock, SIOCSIFNETMASK, &ifr_tun) < 0)
{
perror("SIOCSIFNETMASK");
tun_close(tunfd);
close(sock);
return -1;
}
/* Read flags */
if (ioctl(sock, SIOCGIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set Iface up and flags */
ifr_tun.ifr_flags |= IFF_UP;
ifr_tun.ifr_flags |= IFF_RUNNING;
if (ioctl(sock, SIOCSIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set MTU size */
ifr_tun.ifr_mtu = MTU_SIZE;
if (ioctl(sock, SIOCSIFMTU, &ifr_tun) < 0) {
perror("SIOCSIFMTU");
tun_close(tunfd);
close(sock);
return -1;
}
close(sock);
return tunfd;
}
The function that reads packets from eth0 and forward them to the correct TUN interface is the following one:
void * downlink_distributor(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in spgw_addr;
int sockfd;
int sockaddr_len = sizeof(spgw_addr);
int len, packet_len, teid;
eNB * enb = (eNB *) args;
sockfd = get_spgw_socket(enb);
while(1)
{
/* Read packets from the server */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &spgw_addr, (socklen_t *)&sockaddr_len);
if(len < 0)
{
perror("recv downlink_distributor");
return NULL;
}
/* Get the TEID that identifies the TUN device */
teid = analyze_gtp_header(buffer, &packet_len);
if(teid > -1)
{
/* Write the packet in the TUN device associated with the packet TEID */
tun_write(get_tun_device(tun_descriptors[teid % MAX_TUN_DESCRIPTORS]), buffer + 8, packet_len);
}
}
return NULL;
}
Finally, this is the function that is running on both sockets and generate some traffic:
void * _generate_udp_traffic(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in dest_addr, spgw_addr;
fd_set fds;
struct timeval timeout;
int retval;
timeout.tv_sec = 0;
timeout.tv_usec = 1;
int tunfd;
char msg[] = "Uplink traffic";
int sockfd;
int len;
int sockaddr_len = sizeof(dest_addr);
udp_generator gen;
/* Copy args */
memcpy(&gen, args, sizeof(udp_generator));
free(args);
/* Get TUN device */
tunfd = get_tun_device(gen.ue);
/* Get UE data socket (TUN socket) */
sockfd = get_data_plane_socket(gen.ue);
/* Configure destiny address */
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(gen.port_dest);
memcpy((void*) &dest_addr.sin_addr.s_addr, gen.dest_ip, sizeof(struct in_addr));
/* Configure SPGW address */
memset(&spgw_addr, 0, sizeof(spgw_addr));
spgw_addr.sin_family = AF_INET;
spgw_addr.sin_port = htons(S1_U_PORT);
memcpy((void*) &spgw_addr.sin_addr.s_addr, get_spgw_ip(gen.ue), sizeof(struct in_addr));
while(1)
{
sendto(sockfd, msg, strlen(msg), 0, (const struct sockaddr *) &dest_addr, sizeof(dest_addr));
while(1)
{
FD_ZERO(&fds);
FD_SET(tunfd, &fds);
retval = select(tunfd+1, &fds, 0, 0, &timeout);
if (retval == -1){
perror("select()");
}
else if (retval){
/* Reuse of the buffer with enough space for the GTP header */
len = tun_read(tunfd, buffer+8, BUFFER_DATA_LEN); /* We call read to clean the buffer from external traffic */
/* Detect IPv4 packets*/
if((buffer[8] & 0xF0) == 0x40)
{
generate_gtp_header(buffer, gen.ue, len);
break;
}
}
}
/* Protect the access to the eNB socket with a lock*/
pthread_mutex_lock(&lock);
/* Send tho the SPGW */
sendto(get_spgw_socket(gen.enb), buffer, len+8, 0, (const struct sockaddr *) &spgw_addr, sizeof(spgw_addr));
/* Unlock the mutex */
pthread_mutex_unlock(&lock);
/* Receive server answer listening on the TUN device */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &dest_addr, (socklen_t *)&sockaddr_len);
printf("UE %d has received: %s\n", get_ue_id(gen.ue), buffer);
/* Sleep 5 seconds */
sleep(5);
}
return NULL;
}
If the netmask is 32 both programs that are generating client traffic get blocked on recvfrom() inside _generate_udp_traffic function. If I set both netmask to 24 only one of them receive the answer from the server and the other gets stuck at recvfrom.
How can I configure both TUN devices to make both attached sockets work correctly?
UPDATE: I think that my problem is a kernel route table problem. If I use just one socket, I only receive traffic with netmask <= 30. With a netmask of 32, I can see that the server answer is introduced correctly on the TUN interface but somehow, the socket that is blocked in recv() does not receive anything.
I have a program where i want to forward packet coming from one interface ( VxBridge) & sending it on another interface (ens3:- listing raw sockets ) and vice versa also.
Although my program listens to 3 interfaces
1. VxBridge --> Listing on port 1702
2. ens3 --> listen raw interface
3. tap interface --> tun tap interface
Packet coming from ens3 <--> VxBridge
Problem :-
So program works fine if i have running Wireshark listing on ens3.
If wireshark is stop then Program doesn't listen to packets on ens3. Below is code snippet of program.
Also i believe it is related to somewhat in select() function where waiting of I/O event to occur.
I know i am doing something really wrong here. Any help in redirection would be appreciated.
Below is program :-
main(int argc, char **argv)
{
struct sockaddr_in addr;
struct sockaddr_ll daddr;
fd_set rfds;
fd_set hfds;
int cc,ccd;
struct sockaddr_in from;
size_t fromlen;
int fdmax;
int i;
char* newframe=NULL;
int fdcounter =0;
char *vb = NULL;
int vxSocketfdSet,hwSocketfdSet,tapSocketfdSet;
vxSocketfdSet= hwSocketfdSet=tapSocketfdSet=0;
// Open sockets for L2 device
if (send_to_hw){
if ( ( destsock_fd = socket( PF_PACKET , SOCK_RAW , IPPROTO_RAW) ) < 0){
perror("destsocket creation failed exit");
exit(1);
}
global_fd[fdcounter]=destsock_fd;
fdcounter++;
}
memset(&daddr, 0, sizeof(struct sockaddr_ll));
daddr.sll_family = AF_PACKET;
daddr.sll_protocol = htons(ETH_P_ALL);
daddr.sll_ifindex = if_nametoindex("ens3");
if (bind(destsock_fd, (struct sockaddr*) &daddr, sizeof(daddr)) < 0) {
printf(" ens3 bind failed\n");
close(destsock_fd);
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "ens3");
if (setsockopt(destsock_fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
printf("setsockopt to ens3 failed");
}
/* Open a socket for receiving frames from the Bridge, and forwarding to other l2fwd instances of remote host. */
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
global_fd[fdcounter]=sock_fd;
if (vb != NULL)
{
/* create a TAP interface and attach to virtual bridge */
if ((tap_fd = tap_alloc_via_tun_helper(argv[tap_ip_arg], vb)) < 0) {
exit(1);
}
global_fd[fdcounter]=tap_fd;
fdcounter++;
}
memset(&addr, '\0', sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(DE);
if (bind(sock_fd, (void *) &addr, sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
write(1, "> ", 2);
if (pcap)
tv_wait = &pcap_flush_delay;
for (;;) {
FD_ZERO(&rfds);
fdmax = 0;
for ( i =0;i<=fdcounter;i++){
FD_SET(global_fd[i], &rfds);
if (global_fd[i] > fdmax)
fdmax = global_fd[i];
}
if (select(fdmax + 1, &rfds, 0, 0, tv_wait) < 0) {
perror("select");
continue;
}
for (i = 0;i <= fdcounter; i++)
{
if (FD_ISSET(global_fd[i], &rfds)) {
printf ("\nfdset value is %d &&& %d\n",i,global_fd[i]);
if (i==0)
{
printf("hw set ");
hwSocketfdSet = 1;
destsock_fd=global_fd[i];
}
else if (i==1){
printf ("vx Set x");
vxSocketfdSet = 1;
sock_fd=global_fd[i];
}
else if (i ==2){
tapSocketfdSet = 1;
tap_fd=global_fd[i];
}
break;
}
}
if (vxSocketfdSet){
fromlen = sizeof(from);
cc = recvfrom(sock_fd, buf, sizeof(buf), 0, (void *) &from, &fromlen);
if (cc < 0) {
perror("recvfrom");
continue;
}
printf("\nvx frame buf\n");
tempFrom = &from;
forward(buf, cc, &from,0);
}
if (tapSocketfdSet){
printf("tap frame received");
/* Ethernet frame received from local XC. */
if ((cc = read(tap_fd, buf, sizeof(buf))) < 0) {
perror("read");
continue;
}
forward(buf, cc, NULL,0);
}
if (hwSocketfdSet){
printf ("Packet received on ens3 header buffer\n");
if ((ccd = read(destsock_fd, hbuf, sizeof(hbuf))) < 0) {
printf ("error reading");
perror("read");
continue;
}
if (headerbuff != NULL && tempFrom != NULL)
{
printf("headerbuff =%u\n",headerbuff);
printf("headerbuff+ACTUAL_PAYLOAD_OFFSET %u\n",headerbuff+ACTUAL_PAYLOAD_OFFSET);
memcpy(headerbuff+ACTUAL_PAYLOAD_OFFSET,hbuf,ccd+ACTUAL_PAYLOAD_OFFSET);
newframe=headerbuff;
// printing packet with raw buffer
// weird logic is used don't try to understand this one.
// forward(headerbuff, ccd+ACTUAL_PAYLOAD_OFFSET,tempFrom,1);
}
}
vxSocketfdSet=hwSocketfdSet=tapSocketfdSet=0;
}
}
Enabling promiscuous mode on the interface allows it to receive packets for any address. Otherwise the interface ignores packets for foreign addresses. To do this, set the IFF_PROMISC bit in the flags argument to the SIOCSIFFLAGS ioctl call.
Don't forget to turn it off when the program ends.
The program got misc ethernet traffic from some source, change ip and should redirect it to localhost(for example, it should be used for ssh connection) and send answers from localhost back. I used following code:
int bind_if(int raw , char *device , int protocol) {
struct sockaddr_ll sll;
struct ifreq ifr; bzero(&sll , sizeof(sll));
bzero(&ifr , sizeof(ifr));
strncpy((char *)ifr.ifr_name ,device , IFNAMSIZ);
//copy device name to ifr
if((ioctl(raw , SIOCGIFINDEX , &ifr)) == -1)
{
perror("Unable to find interface index");
return -1;
}
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(protocol);
if((bind(raw , (struct sockaddr *)&sll , sizeof(sll))) ==-1)
{
perror("bind: ");
return -1;
}
return 0;
}
int _create_input_socket(int *s, char* interface)
{
struct packet_mreq mreq;
struct ifreq if_idx;
int sockopt;
int ifnumber = 0;
if ((*s = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
perror("cannot create socket");
return -1;
}
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, interface, IFNAMSIZ-1);
if (ioctl(*s, SIOCGIFINDEX, &if_idx) < 0)
{
perror("SIOCGIFINDEX for interface failed");
close(*s);
return -1;
}
ifnumber = if_idx.ifr_ifindex;
/* Get the current flags that the device might have */
if (ioctl(*s, SIOCGIFFLAGS, &if_idx) <0)
{
perror("SIOCGIFFLAGS failed");
close(*s);
return -1;
}
/* Set the old flags plus the IFF_PROMISC flag */
if_idx.ifr_flags |= IFF_PROMISC;
if (ioctl(*s, SIOCSIFFLAGS, &if_idx) == -1)
{
perror("SIOCSIFFLAGS while adding IFF_PROMISC failed");
close(*s);
}
int flags = fcntl(*s, F_GETFL, 0);
int ret = fcntl(*s, F_SETFL, flags | O_NONBLOCK);
printf("ret = %d\n", ret);
if(ret < 0)
{
perror("fcntl for O_NONBLOCK failed");
close(*s);
return -1;
}
if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) == -1) {
perror("setsockopt SO_REUSEADDR failed");
close(*s);
return -1;
}
if( bind_if(*s, interface, ETH_P_ALL) == -1 )
{
close(*s);
return -1;
}
if (setsockopt(*s, SOL_SOCKET, SO_BINDTODEVICE, interface, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(*s);
return -1;
}
memset(&mreq,0,sizeof(mreq));
mreq.mr_ifindex = ifnumber;
mreq.mr_type = PACKET_MR_PROMISC;
mreq.mr_alen = 6;
if (setsockopt(*s,SOL_PACKET,PACKET_ADD_MEMBERSHIP,
(void*)&mreq,(socklen_t)sizeof(mreq)) < 0)
perror("setsockopt(PACKET_ADD_MEMBERSHIP)");
printf("create socket %d for iface %s(%d)\n", *s, interface, ifnumber);
return ifnumber;
}
void SendTo(int sock, int ifindex, const unsigned char*buffer, int buffer_size)
{
struct sockaddr_ll socket_address;
memset(&socket_address, 0, sizeof(socket_address));
socket_address.sll_ifindex = ifindex;
socket_address.sll_halen = ETH_ALEN;
socket_address.sll_family = htons(PF_PACKET);
socket_address.sll_protocol = htons(ETH_P_ALL);
socket_address.sll_hatype = ARPHRD_ETHER;
memcpy(socket_address.sll_addr, buffer, 6);
if (sendto(sock, buffer, buffer_size, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)) < 0)
printf("Send failed due error %d\n", errno);
}
Somewhere in main():
ifindex_lo = _create_input_socket(&socket_loopback, "lo");
...
SendTo(socket_loopback, ifindex_lo, buffer, size);
I used tcpdump on loopback interface to check how it works, when I send ping through program:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
00:10:24.269431 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 29046, seq 1, length 64
00:10:25.269125 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 29046, seq 2, length 64
And when I perform real ping from linux command:
00:43:49.228192 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 535, seq 1, length 64
00:43:49.228219 IP localhost.localdomain > localhost.localdomain: ICMP echo reply, id 535, seq 1, length 64
00:43:50.227183 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 535, seq 2, length 64
00:43:50.227203 IP localhost.localdomain > localhost.localdomain: ICMP echo reply, id 535, seq 2, length 64
I checked packets - its looks the same except icmp sequence numbers. The same situation is with all other traffic: system does not reply to traffic generated by my program, but make reply by traffic generated by other sources. I am confused for such behavior of sendto on loopback interface. Anyone have idea how avoid that?
Try examining the complete packets, including ethernet header ( -e to tcpdump) and make sure those are correct.
I think struct sockaddr_ll.sll_protocol set to ETH_P_ALL in SendTo()might be messing up your packets. Having the wrong protocol would explain why they are not delivered to the appropriate protocol handler.
Try removing everything except the struct sockaddr_ll.sll_family and struct sockaddr_ll.sll_ifindex from the SendTo(). In case that does not work, manually set .sll_protocol as the type you are sending out. The man-page could be interpreted as saying that sll_protocol has no influence when the socket is SOCK_RAW but I think it might.
man 7 packet:
When you send packets it is enough to specify sll_family,
sll_addr, sll_halen, sll_ifindex. The other fields should be 0.
sll_hatype and sll_pkttype are set on received packets for your
information. For bind only sll_protocol and sll_ifindex are
used.
You could post all of the code you are using, but it is already rather long. It would be best, if you put together a very short program, that exhibits the same symptoms and post that.
I have writter code snippet for UDP Client and server. I am using same port for sending and receiving. My problem is that there are many messages drops at client side, so can someone help me to optimize my code, here is my code for UDP client:
#define SERVERIP "192.168.170.155"
#define SERVERPORT 5000
#define DEVICE_SEND_PORT 5000
#define DEVICE_RECEIVE_PORT 5000
#define BUFFERSIZE 2048
/**For socket file descriptor identification*/
#define S1READY 0x01
int m_SendSocketId;
int m_ReceiveSocketId;
int msgcount;
int socketbuffsize = 1*1024*1024;
/**
* FUNCTION NAME : waitToRead
* Implementation of select and non-blocking socket mechanism
* #param socket Socket that needs to be in select and non blocking mode
* #return Returnd the file descriptors which, returned by select function
*/
int waitToRead(int socket)
{
fd_set fds;
struct timeval timeout;
int rc; // number of file descriptor returned
int result; // result
int fd; // file descriptor
fd=fcntl(socket,F_GETFL,0);
fcntl(socket,F_SETFL,fd | O_NONBLOCK);
// Set time limit.
timeout.tv_sec = 1;
timeout.tv_usec = 0;
// Create a descriptor containing our sockets.
FD_ZERO(&fds);
FD_SET(socket, &fds);
rc = select(sizeof(fds)*8, &fds, NULL, NULL, &timeout);
if (rc==-1)
{
printf("[%s:%d#%s] Select Failed\n",__FILE__, __LINE__,__func__);
return -1;
}
result = 0;
if (rc > 0)
{
if (FD_ISSET(socket, &fds))
result |= S1READY;
}
return result;
}
/**
* FUNCTION NAME : receiveMessage
* This function opens particular port that is defined in the
* Configuration file, and listens on that port.
* #return if there'll be any issue in listening, then it will return
* false otherwise it will return true.
*/
bool receiveMessage()
{
struct sockaddr_in serverAddr; //Information about the Device UDP Server
struct sockaddr_in client_addr; // Information about Qgate Server
char buffer[BUFFERSIZE]; // Buffer to store incoming message
int addr_len; // to store client address length
int serverlen; // to store server address length
int sockResult; // to store result given by waitToRead
int optval = 1;
int receivedByte = 0;
//Open a datagram Socket
if((m_ReceiveSocketId = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("[%s:%d#%s] UDP Client - socket() error\n",__FILE__, __LINE__,__func__);
return false;
}
//Configure Server Address.
//set family and port
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(DEVICE_RECEIVE_PORT);
setsockopt(m_ReceiveSocketId, SOL_SOCKET,SO_REUSEADDR, &optval, sizeof(optval));
/*if (setsockopt(m_ReceiveSocketId, SOL_SOCKET, SO_RCVBUF, &socketbuffsize, sizeof(socketbuffsize)) == -1)
{
printf("Recieve Socket memory Allocation fail\n");
}*/
if((serverAddr.sin_addr.s_addr = INADDR_ANY) == (unsigned long)INADDR_NONE)
{
printf("[%s:%d#%s] Host Not found(%d)\n",__FILE__, __LINE__,__func__,h_errno);
close(m_ReceiveSocketId); // close the socket
return false;
}
if (bind(m_ReceiveSocketId, (struct sockaddr *) &serverAddr,sizeof(struct sockaddr_in)) < 0 )
{
printf("[%s:%d#%s] UDP Client- Socket Bind error=%s\n",__FILE__, __LINE__,__func__,strerror(errno));
close(m_ReceiveSocketId); // close the socket
return false;
}
serverlen = (int )sizeof(serverAddr);
addr_len = sizeof(struct sockaddr);
// Loop and listen for incoming message
while(1)
{
//wait at select to, read
sockResult = waitToRead(m_ReceiveSocketId);
if(sockResult == S1READY)
{
receivedByte = read(m_ReceiveSocketId,buffer,BUFFERSIZE);
buffer[receivedByte] = '\0';
if(receivedByte == -1)
{
printf("[%s:%d#%s] UDP Client - receive error", __FILE__,__LINE__,__func__);
close(m_ReceiveSocketId);
return false;
}
else if(receivedByte > 0)
{
//printf("[%s:%d#%s] received message = %d bytes\n",__FILE__,__LINE__,__func__,(int)strlen(buffer));
printf("count: %d, buffer %s \n", msgcount++, buffer);
}
}
memset(buffer, 0, BUFFERSIZE);
fflush(stdout);
}
close(m_ReceiveSocketId); // close the socket
printf("[%s:%d#%s] Recieve socket closed:%s\n",
__FILE__, __LINE__,__func__, strerror(errno));
return true;
}
bool sendMessage(char *message)
{
struct sockaddr_in serverAddr; //Information about the server
struct sockaddr_in deviceAddr; //Device UDP Client Address for sending message
int optval = 1;
//Open a datagram Socket
if((m_SendSocketId = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("[%s:%d#%s] UDP Client - socket() error\n",__FILE__, __LINE__,__func__);
return false;
}
// Clear out the device struct
memset(&deviceAddr, 0x00, sizeof(struct sockaddr_in));
deviceAddr.sin_family = AF_INET;
deviceAddr.sin_port = htons(DEVICE_SEND_PORT);
setsockopt(m_SendSocketId, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
/*if (setsockopt(m_SendSocketId, SOL_SOCKET, SO_SNDBUF, &socketbuffsize, sizeof(socketbuffsize)) == -1)
{
printf("send Socket memory Allocation fail\n");
}*/
if((deviceAddr.sin_addr.s_addr = INADDR_ANY) == (unsigned long)INADDR_NONE)
{
// in netdb.h
printf("[%s:%d#%s] Host Not found(%d)\n",__FILE__, __LINE__,__func__, h_errno);
close(m_SendSocketId); // close the socket
return false;
}
if (bind(m_SendSocketId, (struct sockaddr *) &deviceAddr,sizeof(struct sockaddr_in)) < 0 )
{
printf("[%s:%d#%s] UDP Client- Socket Bind error=%s\n",__FILE__, __LINE__,__func__,strerror(errno));
close(m_SendSocketId); // close the socket
return false;
}
// Clear out the server struct
memset(&serverAddr, 0x00, sizeof(struct sockaddr_in));
//Configure Server Address.
//set family and port
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVERPORT);
//serverAddr.sin_addr.s_addr = htonl(39898);
if((serverAddr.sin_addr.s_addr = inet_addr(SERVERIP)) == (unsigned long)INADDR_NONE)
{
printf("[%s:%d#%s] Host Not found %d\n",__FILE__, __LINE__,__func__,h_errno);
close(m_SendSocketId);
return false;
}
// Send data to the server.
if( sendto(m_SendSocketId, message,strlen(message) ,0, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0 )
{
printf("[%s:%d#%s] UDP Client - sendto() error=%s \n",__FILE__, __LINE__,__func__,strerror(errno));
close(m_SendSocketId);
return false;
}
close(m_SendSocketId);
return true;
}
int main ()
{
int loop;
char str[10];
msgcount = 1;
pthread_t receiveThread;
if(pthread_create(&receiveThread, NULL,(void *)&receiveMessage, NULL) != 0)
{
printf("[%s:%d#%s] thread create Failed(%s)\n",
__FILE__, __LINE__,__func__, strerror(errno));
return false;
}
for(loop =0; loop < 1000; loop++)
{
sprintf(str,"%4d",loop);
sendMessage(str);
}
pthread_join(receiveThread, NULL);
return 0;
}
Here is the temporary UDP server code, it receives almost above 90% messages and also sends the same, but udpclient is not able to receive the messages.
int main()
{
int sock;
int addr_len, bytes_read, bytes_send;
char recv_data[1024];
int i;
int count=0;
struct sockaddr_in server_addr , client_addr;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5000);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
//client_addr.sin_family = AF_INET;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if (bind(sock,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1)
{
perror("Bind");
exit(1);
}
addr_len = sizeof(struct sockaddr);
printf("\nUDPServer Waiting for client on port 5000");
fflush(stdout);
while (1)
{
bytes_read = recvfrom(sock,recv_data,1024,0,(struct sockaddr *)&client_addr, (socklen_t *)&addr_len);
recv_data[bytes_read] = '\0';
if(recv_data[0]!=0x07)
{
recv_data[0] = 0x09;
//client_addr.sin_port = htons(51254);
bytes_send = sendto(sock, recv_data, bytes_read, 0, (struct sockaddr *)&client_addr, (socklen_t)sizeof(client_addr));
if(bytes_send < 0 )
{
perror("send to ");
}
printf("\nNumber %d", ++count);
memset(&recv_data, 0x00, 1024);
}
else
{
printf("Received Keep ALive\n");
}
memset(&client_addr, 0x00, sizeof(struct sockaddr_in));
fflush(stdout);
}
return 0;
}
Any help would be highly appreciated.
Thanks Yuvi
Your code has nothing to do with UDP dropping packets, except possibly that you are sending packets too fast for the network or the receiver. UDP isn't reliable. It drops packets. If your application protocol requires no dropped packets, you have to build in reliability at that level, via an ACK-based or NACK-based protocol with retries.
Or use TCP like everybody else does in this situation.
The problem was in sendMessage Function, here I was recreating socket every time when I need to send message, and I think that takes time. I don't know yet which is calls are blocking but making sending socket resolves my problem. Now the dropping of message is upto 20 to 30 % only.