pcap_next return NULL - linux

I am working in openwrt with libpcap 1.5.3.
I have init pcap as following:
handle = pcap_create(capnic, errbuf);
if(!handle) {
sys_err("pcap_create failed:%s\n", errbuf);
exit(-1);
}
if(pcap_set_snaplen(handle, BUFSIZE)) {
sys_err("pcap_set_snaplen failed\n");
exit(-1);
}
if(pcap_activate(handle)) {
sys_err("pcap_activate failed: %s\n",
pcap_geterr(handle));
exit(-1);
}
and capture packet with pcap_next:
struct pcap_pkthdr hdr;
const u_char * sysbuf;
if(!(sysbuf = pcap_next(handle, &hdr))) {
sys_err("recv packet failed\n");
return 0;
}
The program could catch packets, but there's a lot of error info:
recv packet failed
I have checked block state with function pcap_getnonblock, the handle is block.

To quote the pcap_next()/pcap_next_ex() man page on my machine:
pcap_next_ex() returns 1 if the packet was read without problems, 0 if
packets are being read from a live capture, and the timeout expired, -1
if an error occurred while reading the packet, and -2 if packets are
being read from a ``savefile'', and there are no more packets to read
from the savefile. If -1 is returned, pcap_geterr() or pcap_perror()
may be called with p as an argument to fetch or display the error text.
pcap_next() returns a pointer to the packet data on success, and
returns NULL if an error occured, or if no packets were read from a
live capture (if, for example, they were discarded because they didn't
pass the packet filter, or if, on platforms that support a read timeout
that starts before any packets arrive, the timeout expires before any
packets arrive, or if the file descriptor for the capture device is in
non-blocking mode and no packets were available to be read), or if no
more packets are available in a ``savefile.'' Unfortunately, there is
no way to determine whether an error occured or not.
Note especially
pcap_next() ... returns NULL if an error occured, *or if no packets were read from a live capture (if, for example, they were discarded because they didn't pass the packet filter, or if, on platforms that support a read timeout that starts before any packets arrive, the timeout expires before any packets arrive...)
Note also
Unfortunately, there is no way to determine whether an error occured or not.
which is the man page's way of telling you that you should probably be using pcap_next_ex(), which does distinguish between those two cases.

Related

What is the best way to implement multi client server?

From TCP based environment, I implement my software like below,
Actually, it's my first time implementing a network, so I don't know if this is the right way.
When the client connects, the server creates two threads. (Such as send, recv)
Send thread sends data when data enters the queue, and waits if it is empty.
Recv thread continuously receives and processes messages (ex. settings) sent by the client.
Currently, the total number of clients I am targeting is 4~5.
This is my sample code,
////////////////////////
// Send Thread
while(m_thread_stop_send == false) { // thread stop flag (when it terminated)
if(m_sendQueue.empty()) // Queue is memeber variable
continue;
// Send data to client
// until the size of MSG is completely transmitted.
while(send size < message size) {
int ret = send(... );
send size += ret;
...
if(send size == message size) break;
}
// (depending on the MSG) if necessary,
// Heres recv routine only treat send's ack
while(recv size < message size) { // according to packet header
int ret = recv(... );
recv size += ret;
...
if(recv size == message size) break;
}
m_sendQueue.pop();
}
////////////////////////
// Recv Thread
while(m_thread_stop_recv == false) { // thread stop flag (when it terminated)
if(alive_flag > 5) // if no alive Msg while 25 sec,
close socket;
terminate recv thread
notify to termination to send thread
// recv client's message and parsing OP-Code
switch(OP-Code)
{
case A:
processing...
and send response to client
// response was sent directly, without send queue & thread
send(... response data ...);
case B:
processing...
and send response to client
case Alive: // 5 sec term
alive_flag = 0
}
}
So I try to these code, but I'm not sure this is correct way ...
Do you have any good examples or open sources of handling Send and Recv continuously, and for each client?

Get system error 115(operation in progress) on blocked socket connect()

In general, system error 115 occurs on a non blocking socket connect(), and the connection needs to be further checked through the select() interface.
But I didn't use fcntl() to set socket to O_NONBLOCK, just set a send timeout as shown below:
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len);
So, In my scenario, is the cause of the 115 error in connect() the same as that of a non block socket? And how do I know how long the connect interface is blocked when I get a 115 error?
Code example:
socklen_t len = sizeof(timeout);
ret = setsockopt(real_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len);
if (-1 == ret)
{
LOG(" error setsockopt");
return SOCKET_FAIL;
}
ret = connect(fd, (struct sockaddr *) &dest, sizeof(dest));
if (0 != ret)
{
LOG("error connect = %s", strerror(errno));
return ret;
}
Result:
Sometimes get system error "Operation now in progress".
The error number is 115, which is also defined as EINPROGRESS.
Thank you for your ideas. I found the answer in the man socket(7). EINPROGRESS errors can also occur in blocked sockets.
SO_RCVTIMEO and SO_SNDTIMEO
Specify the receiving or sending timeouts until reporting an
error. The argument is a struct timeval. If an input or output
function blocks for this period of time, and data has been sent
or received, the return value of that function will be the
amount of data transferred; if no data has been transferred and
the timeout has been reached, then -1 is returned with errno set
to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just
as if the socket was specified to be nonblocking. If the time‐
out is set to zero (the default), then the operation will never
timeout. Timeouts only have effect for system calls that per‐
form socket I/O (e.g., read(2), recvmsg(2), send(2),
sendmsg(2)); timeouts have no effect for select(2), poll(2),
epoll_wait(2), and so on.

Linux application for reading packets from raw socket stops receiving packets after sometime

I have written a Linux application program that receives UDP packets transmitted from a Desktop with fixed & known IP-address on the network. I am using a raw socket to receive packets on my system and filter the received packets based on the source address.
The problem I am facing is, the program runs fine for some time and I get all the required packets, but after a couple of hours, the application stops getting any packets. If I run the command,
tcpdump -i eth0 src 192.168.20.48 on my system, then I see that the system continues to receive the expected packets. But I am not sure what is causing my program to stop receiving packets.
Below is the code snippet used to open a raw socket, receive packets, and filter out the UDP packets transmitted from the known IP address.
int main()
{
int sockfd;
int one = 1;
struct timeval tv;
socklen_t len;
int bytes;
unsigned char tsptr[2048];
struct sockaddr_in cliaddr;
struct iphdr *iph;
int result=0;
char source_add[50];
char expected_source_add[50];
len = sizeof(struct sockaddr_in);
// Creating socket file descriptor
if ((sockfd = socket(AF_INET , SOCK_RAW , IPPROTO_UDP)) < 0 ) {
BRH_PERROR("socket creation failed");
return 1;
}
tv.tv_sec = 30;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &one, sizeof(one));
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,(char*)&tv,sizeof(tv));
strcpy(expected_source_add, "192.168.20.48");
while (1) {
/*Read fixed data count from socket*/
bytes =recvfrom(sockfd, tsptr, 1500, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);
iph=(struct iphdr*)tsptr;
//get only UDP packet
if (iph->protocol != 17) continue;
strcpy(source_add,inet_ntoa(cliaddr.sin_addr));
result = strcmp(expected_source_add,source_add);
/*receive data from expected IP address only*/
if( result == 0) {
//Consume the packet
}
}
return 0;
}
Any clue on why the packet receive stops on my application, even though tcpdump shows that packets are being received on the interface, will be helpful.
The code you write here can not see any problem that you describe, I think you should do something like below.
1. using wireshark or tcpdump to see if the nic receive packets successfully
2. beyond the program, do you use any buffer or message queue and are they working good?
3. using tools to see if there exists any memeory leak
4. writing log in every step, especially around recvefrom and strcmp

How to handle all possible errors on async socket?

I have decided to use async io for my project and simply do a single threaded loop where I try to read some data each frame from each open socket. This worked quite well and overall I'm happy with it for now. The problem is weird problems I'm having with the async sockets.
I have code like this:
accept a connection...
fcntl(O_NONBLOCK) on the client socket...
int rc;
if((rc = recv(socket))>0)
process data
if rc == 0
close socket and cleanup
The problem is that I get rc == 0 sometimes even though I know that the connection is not closed. If I don't clean up then my app works as normal. But if I do cleanup then the client receives a disconnect before the connection is even established.
So my question is: Do I have to check somehow whether the socket is ready before doing a recv in order to get the correct return value from it?
Most of the information I have been able to find was inconclusive. I found a references to select() but it seems to block until there is a status change on the socket - but I need the socket to be nonblocking.
What I'm looking for is just the intuitive behavior that if there is data, it is read to the buffer and recv returns number of bytes read, if there is no data it returns -1 and if the socket is disconnected then it should return 0.
Do I have to do anything else to the socket before calling recv to make it work as expected?
First, taking on the heavy lifting of going "all asynchronous" with a socket server is a good start for a design and will enable scalability very easily.
As for your question.
recv() will return the following values:
A postive value returned by recv() indicates the number of bytes
copied to your buffer.(i.e you actually received these bytes)
recv() will return 0 when the socket was closed by the remote side.
For async sockets, recv() will return -1 and set errno to either
EAGAIN or EWOULDBLOCK if the connection is still valid, but there's
no new data to be consumed. Call select() or poll() on the socket to
wait for data.
Otherwise, any general connection failure will result in -1 being returned by recv(). (And the only thing you can do is close the socket).
So when you say, "rc == 0 sometimes even though I know that the connection is not closed", I suspect your pseudocode is not checking the return value, but instead checking the result of (rc > 0).
This is closer to the logic you want:
int rc;
rc = recv(s, buf, buffersize, 0);
if (rc == 0)
{
/* socket closed by remote end */
close(s); s=-1;
}
else if ((rc == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)) )
{
// need to wait. Call select() or poll()
}
else if (rc == -1)
{
close(s); s=-1;
}
else
{
ProcessNewData(s, buffer, rc);
}

React on client disconnect in linux

I am writing a simple socket daemon witch listens to a port and reads the incoming data. It works fine until i choose to disconnect a client from the server...then it enters in a infinte loop recv() returns the last packet never gets to -1. My question is how can i detect that the client had been disconnected and close the thread/ socket el
My thread is as follows :
void * SocketHandler(void* lp){
int * csock = (int*)lp;
int test = 0;
char buffer[1024];
int buffer_len = 1024;
int bytecount,ierr;
memset(buffer,0,buffer_len);
while (test == 0)
{
if ((bytecount = recv(*csock, buffer, buffer_len, 0))== -1){
close(csock);
free(csock);
test++;
return 0;
}
else
{
syslog(LOG_NOTICE,"%s",buffer);
}
}
return 0;
};
A cleanly closed socket will end up in a ZERO read, while a broken connection is an error state returning -1. You need to catch the 0 return of your recv.
What happens here is that your end may not detect the fact the socket is dead (especially, if you are just reading from it).
What you can do is set keepalive on the socket. This will turn on periodic checks of the socket liveness. But don't expect fast reactions, the default timeout is something like 20 minutes.
i = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i));
Another option is to do your own keep-alive communication.
recv() will indicate a proper shutdown of the socket by returning 0 (see the manpage for details). It will return -1 if and only if an error occurred. You should check errno for the exact error, since it may or may not indicate that the connection failed (EINTR, EAGAIN or EWOULDBLOCK [non-blocking sockets assumed] would both be recoverable errors).
Side note: there's no need to pass the fd of the socket as pointer and since you're returning a void * you may want to change return 0 to return NULL (just for readability).

Resources