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.
Related
I am having trouble getting my TCP/IP connection between my client and server working.
Here is the server code -
int main() {
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
unsigned short echoServPort; /* Server port */
struct sockaddr_in echoServAddr; /* Local address */
struct sockaddr_in echoClntAddr; /* Local address */
pid_t processID; /* Process ID from fork()*/
unsigned int childProcCount = 0; /* Number of child processes */
unsigned int clntLen;
unsigned int recvMsgSize;
echoServPort = 22;
if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
printf("Socket failed");
}
echoServAddr.sin_family = AF_INET; //Internet address family
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); //Any incoming interface
echoServAddr.sin_port = htons(echoServPort); // Local port
if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0){
printf("bind failed");
}
if (listen(servSock, MAXPENDING) < 0){
printf("listen() failed");
}
clntLen = sizeof(echoClntAddr);
if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen))<0){
printf("accept() failed");
}
if ((recvMsgSize = recv(clntSock, buf, 1024, 0)) < 0){
printf("recv() failed");
}
/* Send received string and receive again until end of transmission */
while (recvMsgSize > 0) { /* zero indicates end of transmission */
printf("%d", recvMsgSize);
if (send(clntSock, buf, recvMsgSize, 0) != recvMsgSize){
//printf(“send() failed”);
}
if ((recvMsgSize = recv(clntSock, buf, 1024, 0)) < 0){
//printf(“recv() failed”);
}
}
sleep(60);
}
}
return EXIT_SUCCESS;
}
And the client code, which is a CGI application.
int main(void) {
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
unsigned short echoServPort; /* Server port */
struct sockaddr_in echoServAddr; /* Local address */
struct sockaddr_in echoClntAddr; /* Local address */
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
/*pid_t processID; Process ID from fork()
unsigned int childProcCount = 0; Number of child processes
unsigned int clntLen;*/
//char echoservIP = "10.0.0.2";
printf("Content-type: text/html\n\n");
puts("<HTML>");
puts("<BODY>");
echoServPort = 22;
servSock = 22;
clntSock = 22;
puts("<br>");
if ((clntSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
printf("socket() failed");
}
echoServAddr.sin_family = AF_INET; //Internet address family
echoServAddr.sin_addr.s_addr = inet_addr("10.0.0.2"); //Server IP address
echoServAddr.sin_port = htons(echoServPort); //Server port
echoClntAddr.sin_addr.s_addr = inet_addr("10.0.0.1");
if (connect(clntSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0){
printf("connect() failed\n");
}
int clntLen;
clntLen = sizeof(echoClntAddr);
if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen))<0){
printf("accept() failed\n");
}
char echoString[4] = "helo";
int echoStringLen;
echoStringLen = strlen(echoString); //Determine input length
//Send the string to the server
if (send(clntSock, echoString, echoStringLen, 0) != echoStringLen){
printf("send() sent a different number of bytes than expected");
}
puts("<p>Hello <b>CGI</b</p>");
puts("</BODY>");
puts("</HTML>");
return EXIT_SUCCESS;
}
When debugging, the problem occurs on the client side at the line
if ((clntSock=accept(servSock,(struct sockaddr
*)&echoClntAddr,&clntLen))<0){
printf("accept() failed\n");
}
And at
if(send(clntSock, echoString, echoStringLen, 0) != echoStringLen){
printf("send() sent a different number of bytes than expected");
}
I get the output
<HTML>
<BODY>
<br>
accept() failed
send() sent a different number of bytes than expected<p>Hello
<b>CGI</b</p>
Need help fixing this!, thanks.
You don't need to call accept() on the client - you just need to connect.
And
char echoString[4] = "helo";
is wrong. It's not NUL-terminated. Just do
char echoString[] = "helo";
If accept fails you shouldn't be proceeding with other operations on socket like recv. TCP connections is not in place for you to proceed in data exchange between server and client. You need to handle error conditions with out fail.
On the client side you have a custom error message on send. That does not help. Usually, partial sends are not common. Hence your print `sent a different number of bytes than expected' can be misleading. You need to find the real reason.
Calling accept in client code is not needed. Its the server which accepts and clients the ones which connect
Use errno and perror like - perror("Accept Failed") on ALL of your system calls for easier debugging and remove custom prints
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
I have a simple C program that's supposed to listen for connections and start a new thread for each client that connects. The thread simply prints what messages it receives (for now). I followed two tutorials while making this.
It works, but I tried connecting and disconnecting repeatedly with netcat without sending any messages. Each time I connect, the program takes 8KB of memory, but it only releases 4KB when I disconnect. But I can't find the cause of the leak. It ends the thread and closes the socket every time the user disconnects. Here is all of the code involved:
void* clientFunction(void* arg) {
char receiveBuffer[RECEIVE_BUFFER_SIZE];
long receiveSize;
int clntSocket = * ((int*) arg);
while (true) {
//receive messages
receiveSize = recv(clntSocket, receiveBuffer, RECEIVE_BUFFER_SIZE, 0);
if (receiveSize <= 0) {
close(clntSocket);
return NULL;
}
printf("Received message: %s", receiveBuffer);
memset(&receiveBuffer, 0, sizeof(receiveBuffer));
}
return 0;
}
int main(int argc, const char * argv[]) {
//FOR LISTENING SOCKET =====
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
struct sockaddr_in serverAddress; /* Local address */
struct sockaddr_in clientAddress; /* Client address */
unsigned int clntLen; /* Length of client address data structure */
// =======
/* Create socket for incoming connections */
if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
printf("Socket creation failed!\n");
return SOCKET_ERROR;
}
memset(&serverAddress, 0, sizeof(serverAddress)); /* Zero out structure */
serverAddress.sin_family = AF_INET; /* Internet address family */
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
serverAddress.sin_port = htons(PORT); /* Local port */
if (bind(servSock, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
printf("Socket binding failed!\n");
return SOCKET_ERROR;
}
if (listen(servSock, MAXPENDING) < 0) {
printf("Socket listening failed!\n");
return SOCKET_ERROR;
}
isListening = true;
int* arg = &clntSock;
while (isListening) { //should have a timer?
/* Set the size of the in-out parameter */
clntLen = sizeof(clientAddress);
/* Wait for a client to connect */
if ((clntSock = accept(servSock, (struct sockaddr *) &clientAddress, &clntLen)) >= 0) { //??????
/* clntSock is connected to a client! */
pthread_t clientThread;
pthread_create(&clientThread, NULL, &clientFunction, (void*) arg);
}
}
return 0;
}
I put in pthread_detach(pthread_self()) right after the socket closing line, and it doesn't have the problem anymore. – sudo
The following routine will timeout if a non-existant ip address is given, which is great. However, if the linux system (which it is running on) is not connected to any network on either eth0 or wlan0 then it hangs. Even if a network is connected to eth0 again, still no response. Is there a way to get the timeout to apply even if not connected to a network? Alternatively, is there a check that can be done before hand that will determine if a connection to a network exists? Thanks.
int connect_to_host()
{
u_short port; /* user specified port number */
char *addr; /* will be a pointer to the address */
struct sockaddr_in address; /* the libc network address data structure */
short int sock = -1; /* file descriptor for the network socket */
fd_set fdset;
struct timeval tv;
int connected = 0;
port = 22;
addr = "192.168.2.5";
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(addr); /* assign the address */
address.sin_port = htons(port); /* translate int2port num */
sock = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sock, F_SETFL, O_NONBLOCK);
connect(sock, (struct sockaddr *)&address, sizeof(address));
FD_ZERO(&fdset);
FD_SET(sock, &fdset);
tv.tv_sec = 3; /* 10 second timeout */
tv.tv_usec = 0;
if (select(sock + 1, NULL, &fdset, NULL, &tv) == 1)
{
int so_error;
socklen_t len = sizeof so_error;
getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0) {
printf("%s:%d is open\n", addr, port);
connected = 1;
}
}
close(sock);
return connected;
}
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.