blocking pcap and multiple I/O `select ` - c

I want to use pcap to capture packets
and then send the captured packets to another host
my source code snippets are like:
for(;;){
pcap_packet = pcap_next(pcap_handler, &pcap_header);
if(pcap_packet !=NULL)
printf("capture a packet with length of %d\n", pcap_header.len);
// send the packet as payload to the sender, excluding the Ethernet Header
n = send(sd_proxy, pcap_packet+ETHERNET_HDR_LEN, pcap_header.len-ETHERNET_HDR_LEN, 0);
if(n<0){
shutdown(connfd, SHUT_RDWR);
close(connfd);
break;
} new
}
so basically, I want program to be blocked by the pcap_next, once a
the socket sd_proxy establishes a TCP connection with the other host,
if the other host initiate an active TCP close, I want to detect this
active close. Ideally, I should use a select and a n=recv(rd_fd, ...)
if the other host initiates a active close, select will notice there is something with rd_fd and then I see whether 'n=0' or not.
but with pcap, select can't cooperate with pcap
so how to finish my task?
thanks!

select can't cooperate with pcap
Why not? Have you tried using pcap_get_selectable_fd() on pcap_handler and adding the resulting file descriptor to the file descriptor set in your select() call?
You're working on Linux, so that should Just Work.
(If you were running on a system that uses BPF, such as *BSD or OS X, you might have problems with this, at least with older versions of those OSes; various *BSDs have had their select-with-BPF bugs fixed for a while; on OS X, I fixed it in Lion, so it could have problems on Snow Leopard and earlier.)

Related

Understanding USBIP bind function

I am trying to understand the USBIP tool code from Linux (https://github.com/torvalds/linux/tree/master/tools/usb/usbip).
USBIP has a command that attaches a remote USB from an IP to a client system. If you look at the code (https://github.com/torvalds/linux/blob/master/tools/usb/usbip/src/usbip_bind.c#L130) below, which binds the USB, if the function calls close(sockfd); and close the socket, then how the communication is done between client and server for USB data.
From Docs (https://docs.kernel.org/usb/usbip_protocol.html):
Once the client knows the list of exported USB devices it may decide
to use one of them. First the client opens a TCP/IP connection to the
server and sends an OP_REQ_IMPORT packet. The server replies with
OP_REP_IMPORT. If the import was successful the TCP/IP connection
remains open and will be used to transfer the URB traffic between the
client and the server.
It says connection remains open if import is successful, then what is the purpose of close(sockfd);. I can also see sockfd is sent inside query_import_device(sockfd, busid); but if it is closed how this is used?
static int attach_device(char *host, char *busid)
{
int sockfd;
int rc;
int rhport;
// creates a TCP connection to the specified host on the specified port.
sockfd = usbip_net_tcp_connect(host, usbip_port_string);
if (sockfd < 0) {
err("tcp connect");
return -1;
}
// sends a query to the connected host to import the device specified by "busid".
rhport = query_import_device(sockfd, busid);
if (rhport < 0)
return -1;
// closes the previously established TCP connection.
close(sockfd);
// records details of the connection, such as the host and port, the busid of the device, and the assigned rhport.
rc = record_connection(host, usbip_port_string, busid, rhport);
if (rc < 0) {
err("record connection");
return -1;
}
return 0;
}
If you look at the source code of usbip helper program, query_import_device(), it establishes the connection and then calls import_device() to finish it.
In turn, import_device() calls usbip_vhci_attach_device(), that calls usbip_vhci_attach_device2()... that eventually writes the sockfd and some extra data to the /sys/*/attach pseudo file for the given device.
To see what happens next we need to go to kernel mode. So, looking at the source code of the usbip, at function attach_store(). This function parses the sockfd back into an integer file descriptor and, most notably, does this:
struct socket *socket;
socket = sockfd_lookup(sockfd, &err);
This converts a file descriptor into a real kernel socket object. And it increases the reference count. Note how if any of the further checks fail, it calls sockfd_put(socket); to decrease that reference count.
But if the function succeeds, the socket is stored into the device. It is just as if an userland program had done a call to dup(): it doesn't matter if the original sockfd is closed, the kernel keeps the actual socket opened as long as it is needed.
You can see that the value of sockfd is also stored in the device, but it isn't actually used for anything other than reading back from /sys, so it doesn't matter if it is no longer a valid file descriptor.
So the close is actually necessary because the kernel dups the socket internally, that keeps the connection opened. And you do not want to keep an extra FD referencing the same socket, if you try to use that socket for anything that could mess up the device connection. The responsible thing to do is just to close it.

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

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

Server program is stuck at send

I am building a server client model in C. The clients connects to the server and they start exchanging data. However, the user can end the client at any time in the program, but the server is not notified about it. The server keeps sending that data even after the client is closed.
I was in the impression that send function will return -1 if the server is unable to send the data, but my server program just stuck at send
if((byteSent = send(new_fd, fileContents, strlen(fileContents), 0)) == -1){ //
the program just halts at the above line.
How do I overcome this problem?
//Code
exitT = 0;
//execution_count = 1;
for(i=0;i<execution_count;i++)
{
sleep(time_delay);
//getting the current time on the server machine
time_t t;
time(&t);
char *time=ctime(&t);
printf("The Execution time at server = %s\n",time);
system(exec_command);
/*Open the file, get file size, read the contents and close the file*/
// Open the file
fp = fopen(fileName,"r");
// Get File Size
fseek(fp,0,SEEK_END);
dataLength = ftell(fp);
rewind(fp);
fileContents = (char*)malloc(dataLength+1);
// Read File
fread(fileContents,1,dataLength,fp);
fileContents[dataLength] = '\0';
// Close file
fclose(fp);
printf("sockfd = %d \n",new_fd);
// send file length to client
rc=send(new_fd, &dataLength, sizeof(dataLength), 0) ;
printf("length of client data = %d \n",rc);
printf("sockfd = %d \n",new_fd);
// send time to client
rc=send(new_fd, time, strlen(time), 0) ;
printf("length of client time = %d \n",rc);
usleep(20000);
// Send file contents to Client
while(dataLength>0){
printf("sockfd = %d \n",new_fd);
if((byteSent = send(new_fd, fileContents, strlen(fileContents), 0)) == -1){
printf("bytes sent = %d \n",byteSent);
exitT = 1;
break;
}
dataLength-=byteSent;
}
//Delete the log file
sprintf(deleteCommand,"rm %s",fileName);
system(deleteCommand);
if(exitT == 1)
break;
}
bzero(fileName,sizeof(fileName));
bzero(exec_command,sizeof(exec_command));
bzero(deleteCommand,sizeof(deleteCommand));
//decClientNum();
kill(parent_id,SIGALRM);
close(new_fd); // parent doesn't need this
printf("STATUS = CLOSED\n");
exit(0);
}
Thanks
I assume you are coding for a Linux or Posix system.
When a syscall like send fails it returns -1 and sets the errno; you very probably should use errno to find out why it failed.
You could use strace to find out which syscalls are done by your sever, or some other one. Of course, use also the gdb debugger.
You very probably need to multiplex inputs or outputs. The system calls doing that are poll, select (and related ppoll and pselect). Read e.g. the select_tut(2) man page.
You may want to use (or at least to study the source code of) existing event oriented libraries like libevent, libev etc.. (Both Gtk and Qt frameworks provide also their own, which might be used even outside of GUI applications).
I strongly suggest reading about advanced unix programming and unix network programing (and perhaps also about advanced linux programming).
maybe you're using a tcp protocol and the server is waiting for an ACK. Try using udp if you want your connection to be asynchronous.
From the man page: No indication of failure to deliver is implicit in a send(). Locally detected errors are indicated by a return value of -1.
Proably something like this might help: http://stefan.buettcher.org/cs/conn_closed.html
I think I am pretty late in the party, but I think this answer might help someone.
If space is not available at the sending socket to hold the message to be transmitted, and the socket file descriptor does not have O_NONBLOCK set, send() shall block until space is available.
When send() function gets stuck, there might be a situation like, TCP window size has become 0. It happens when the other end of the connection is not consuming received data.
There might be a scenario like this, the receiving end process is running by GDB and segfault occurred.
The TCP connection remains established.
Data is being send continuously.
The receiver end is not consuming it.
Consequently the receiver TCP window size will keep decreasing and you can send data till it is greater than zero. Once it becomes 0, send() function will get stuck forever.
As the situation mentioned in the question is not a scenario of closed connection. When a process writes something on a closed TCP connection, it receives a signal SIGPIPE. Default handler of SIGPIPE terminates the process. So, in a closed connection scenario if you are not using your own SIGPIPE handler then process should be terminated by default handler whenever something is written on the socket.

C pcap detecting inbound datagrams

In C I bind a datagram socket (AF_INET, SOCK_DGRAM) to INADDR_ANY. I then periodically use this socket to send and receive datagrams, and monitor the flow of packets with pcap. The problem is, I can't tell whether a packet is incoming or outgoing using pcap.
The transmission/receiving and the pcap monitoring are running in separate threads, and for synchronisation reasons they can't communicate. I only want to track the incoming packets, not the ones being sent, so does anyone have an idea as to how I can do that?
I thought already of testing the destination ip address, but I can't figure out any way to get my local ip. the machine this is running on doesn't have a static ip, much less an assigned domain name, and it seems that getsockname doesn't work on sockets bound to INADDR_ANY. Also tried using ioctl(sockfd, SIOCGIFCONF, &buffer), which didn't work either - sets buffer.ifc_len=0.
Found a solution. I can get my own ip using this:
char *command = malloc(100);
sprintf(command,"ifconfig %s|grep -o \"inet addr:[^ ]\"|grep -o -e \"[0-9]\.[0-9]\.[0-9]\.[0-9]*\"",device);
char path[1035];
FILE *fp;
fp = popen(command,"r");
fgets(path, 1034, fp);
pclose(fp);
my_ip = malloc(sizeof(char)*(1+strlen(path)));
memcpy(my_ip, path, strlen(path)-1);
my_ip[strlen(path)-1] = 0;

C file transfer question

I implemented a client-server program that allows to transfer files b/w them. The server is using select() to check changes of sockets.
Every test is good except this one:
- When server is sending a huge file to client (not yet finished), client hit "Ctrl-C" to kill the client program, then the server is killed too :(
The snippet:
fprintf(stderr,"Reading done, sending ...\n");
if(send(sockClient, sendBuf, chunk_length, 0) < 0)
{
printf("Failed to send through socket %d \n", sockClient);
return -1;
}
fprintf(stderr,"Sending done\n");
When the client is killed, the server terminal displays:
user$./server
Reading done, sending ...
Sending done
Reading done, sending ...
Sending done
Reading done, sending ...
Sending done
Reading done, sending ...
user$
What's wrong with it?
Thanks for your answers!
You probably want to ignore SIGPIPE. Try adding something like this in your server startup:
#include <signal.h>
signal(SIGPIPE, SIG_IGN);
The send() call may be used only when the socket is in a connected state (so that the intended recipient is known). the return is the bytescount sent...
if(send(sockClient, sendBuf, chunk_length, 0) < 0)
so when disconnected, it skipped out...
MSG_NOSIGNAL is not portable and will not be available on Windows.

Resources