Open a file fails when nonblocking UDP port is open - c

I have a problem with a program. The program should be triggered by UDP messages, that's why I open a nonblocking UDP socket, because I want to use it later again. After that the program should open a file, copy out a certain amount of bytes and send it to a browser.
The problem occurs when I want to open a file, then I get a "resource temporarily not availabe" fault.
Here is a simple program, which creates the same fault.
main part:
udp_openPort(9999);
for(;;){
if(udp_receiveData(temp, 32) > 0){
printf("Received Message: %d\n",atoi(temp));
break;
}
}
filefd = open("test.txt",O_RDONLY);
printf("File Open: %s\n",strerror(errno));
read(filefd,buff,sizeof(buff));
printf("Daten: %s",buff);
close(filefd);
udp_closePort();
udp_receiveData():
int udp_receiveData(void* data, int size){
socklen_t dummy = sizeof(NetworkAddr);
NetworkAddr sender;
return recvfrom(sockfd, data, size, MSG_DONTWAIT, (struct sockaddr*) (&sender), &dummy);
}
When I open the socket as a blocking socket, there is no problem with opening the file, but I need I nonblocking socket for my purpose.
Did I make a mistake in coding the program or did I made a mistake, when I planned the program?
Best regards,
PG
EDIT: Here is the udp_openPort() function:
int udp_openPort(int portNr){
//Create handle to socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1){
return 0;
}
// Make sure that we don't receive our own packets.
char loop = 0;
if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) == -1){
}
// Bind to the port where we receive UDP messages.
NetworkAddr addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(portNr);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr*) &addr, sizeof(addr)) == -1){
return 0;
}
return 1;
}
Maybe someone sees a problem in here.

Looking at the manpage of open, the errno is set if and only if the error occurred, i.e. when returned descriptor is -1. Hence, your error handling is incorrect. You should have checked the value of filefd in order to determine if the file has been opened or not.
Because the file in fact was opened correctly, errno hasn't been modified and your error message was set by udp_receiveData; in this case, as your socket is non-blocking, there was no data on UDP socket (resource temporarily unavailable). You don't experience this with a blocking socket, as your program is then sleeping waiting for a message to arrive.

Are you sure that you error after open is not interfere with udp_openPort? Probably udp_openPort does something wrong and set the errno variable which you lately misinterpret as file open error.

Related

How to handle TCP client disconnect in C

I am trying to write a basic TCP server that streams serial data to a client. The server would connect to a serial device, read data from said device, and then transmit it as a byte stream to the client. Writing the TCP server is no problem. The issue is that the server will crash when a client disconnects. In other languages, like Python, I can simply wrap the write() statement in a try-catch block. The program will try to write to the socket, but if the client has disconnected then an exception will be thrown. In another project, this code snippet worked for me:
try:
client_socket.send(bytes(buf, encoding='utf8'))
except Exception as e:
logger.info("Client disconnected: %s", client_id)
I can handle client disconnects in my C code, but only by first reading from the socket and checking if the read is equal to 0. If it is, then my client has disconnected and I can carry on as usual. The problem with this solution is that my client has to ping back to the server after every write, which is less than ideal.
Does anyone know how to gracefully handle TCP client disconnects in C? My example code is shown below. Thank you!
// Define a TCP socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
// Allow for the backlog of 100 connections to the socket
int backlog = 100;
// Supply a port to bind the TCP server to
short port = 9527;
// Set up server attributes
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
// Set the socket so that we can bind to the same port when we exit the program
int flag = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1) {
perror("setsockopt fail");
}
// Bind the socket to the specified port
int res = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (res < 0) {
perror("bind fail");
exit(1);
}
// Listen for incoming connections
if (listen(sockfd, backlog) == -1) {
perror("listen fail");
exit(1);
} else {
printf("Server listening on port\n", port);
}
for(;;) {
// Wait for incoming connection
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len);
if (-1 == connfd) {
perror("Could not accept incoming client");
continue;
}
//Resolving Client Address
char buff[INET_ADDRSTRLEN + 1] = {0};
inet_ntop(AF_INET, &cliaddr.sin_addr, buff, INET_ADDRSTRLEN);
uint16_t cli_port = ntohs(cliaddr.sin_port);
printf("connection from %s, port %d\n", buff, cli_port);
for(;;) {
// Read from serial device into variable here, then send
if(send(connfd, "Data...Data...Data\n", 19, 0) < 0) {
printf("Client disconnected...\n");
break;
}
}
}
Looks like a duplicate of this, this and this.
Long story short you can't detect the disconnection until you perform some write (or read) on that connection. More exactly, even if it seems there is no error returned by send, this is not a guarantee that this operation was really sent and received by the client. The reason is that the socket operations are buffered and the payload of send is just queued so that the kernel will dispatch it later on.
Depending on the context, the requirements and the assumptions you can do something more.
For example, if you are under the hypothesys that you will send periodic message at constant frequency, you can use select and a timeout approach to detect an anomaly.
In other words if you have not received anything in the last 3 minutes you assume that there is an issue.
As you can easily found, this and this are a good read on the topic.
Look at that for a far more detailed explanation and other ideas.
What you call the ping (intended as a message that is sent for every received packet) is more similar to what is usually known as an ACK.
You only need something like that (ACK/NACK) if you also want to be sure that the client received and processed that message.
Thanks to #emmanuaf, this is the solution that fits my project criteria. The thing that I was missing was the MSG_NOSIGNAL flag, referenced here.
I use Mashpoe's C Vector Library to create a new vector, which will hold all of my incoming client connections.
int* client_array = vector_create();
I then spawn a pthread that continually reads from a serial device, stores that data in a variable, and then sends it to each client in the client list
void* serve_clients(int *vargp) {
for(;;) {
// Perform a microsleep
sleep(0.1);
// Read from the Serial device
// Get the size of the client array vector
int client_vector_size = vector_size(vargp);
for(int i = 0 ; i < client_vector_size ; i++) {
// Make a reference to the socket
int* conn_fd = &vargp[i];
/*
In order to properly handle client disconnects, we supply a MSG_NOSIGNAL
flag to the send() call. That way, if the client disconnects, we will
be able to detect this, and properly remove them from the client list.
Referenced from: https://beej.us/guide/bgnet/html//index.html#sendman
*/
if (send(*conn_fd, "Reply from server\n", 18, MSG_NOSIGNAL) < 0) {
printf("Client disconnected...\n");
// Close the client connection
close(*conn_fd);
// Remove client socket from the vector
vector_remove(vargp, i);
// Decrement index and client_server_size by 1
i--;
client_vector_size--;
}
}
}
}
To spawn the pthread:
// Spawn the thread that serves clients
pthread_t serving_thread;
pthread_create(&serving_thread, NULL, serve_clients, client_array);
When a new connection comes in, I simply add the new connection to the client vector
while(1) {
// Wait for incoming connection
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len);
if (-1 == connfd) {
perror("Could not accept incoming client");
continue;
}
//Resolving Client Address
char buff[INET_ADDRSTRLEN + 1] = {0};
inet_ntop(AF_INET, &cliaddr.sin_addr, buff, INET_ADDRSTRLEN);
uint16_t cli_port = ntohs(cliaddr.sin_port);
printf("connection from %s:%d -- Connfd: %d\n", buff, cli_port, connfd);
// Add client to vector list
vector_add(&client_array, connfd);
}
In the end, we have a TCP server that can multiplex data to many clients, and handle when those clients disconnect.

udp sendto can not send the whole txt file in a real time

I have really strange problem. I made server and client communicating using unicast sockets.
Server is sending text file in blocks of 512 bytes and client is receiving and writing blocks to a txt file. But I noticed that without sleep(1) function on both sides server can not send the whole file. For example the file is made of 2939 blocks and in wireshark I can see just 1827, 2005, 1657 but never the whole file , all 2939 blocks ? Why ? Packets are not lost because server and client are connected via ethernet cable to the router and are on the same local network.
Can you give me directions and advices how to solve this problem? Here is the code :
#includes...
#define BUF_SIZE 512
#define PORT 1234
#define IP "192.168.0.103" // address of a client
static int val = 1;
int sent=0;
int main() {
struct sockaddr_in client,server;
char tmp[BUF_SIZE];
int n,s,fd;
ssize_t numRead;
int rv,optval=1;
if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))<0){
printf("Opening datagram socket error",strerror(errno));
return 1;
}else{
printf("Opening datagram socket....OK.\n");
}
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1){
printf("Setsockopt error: %s", strerror(errno));
return 1;
}
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
memset((char *) &client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_addr.s_addr = inet_addr(IP);
client.sin_port = htons(PORT);
if(bind(s, (struct sockaddr*)&server, sizeof(server))){
printf("Binding datagram socket error %s",strerror(errno));
close(s);
return 1;
}
if((fd = open("udp_text.txt", O_RDONLY , 0777))== -1){
printf("Error while opening txt file %s!\n",strerror(errno));
return 1;
}
while (1) {
if((numRead = read(fd,tmp,512)) == 512){
tmp[numRead]='\0';
rv = sendto(s,tmp,sizeof(tmp),0, (struct sockaddr *) &client, sizeof(struct sockaddr_in));
memset(tmp,0,BUF_SIZE);
}else{
rv = sendto(s,tmp,sizeof(tmp),0, (struct sockaddr *) &client, sizeof(struct sockaddr_in));
printf("EOF !\n");
return 1;
}
}
close(s);
return 0;
}
Thx
Since not all the packets show up in wireshark, I would guess that the sender is running out of network packet buffer space in the operating system. UDP can not only suffer packet loss from transmission failures but also if any routing component runs out of capacity and is forced to drop the packet because it is too busy. This includes the local internet protocol stack.
As a start, check the error code from sendto(). If the local operating system is to blame then it will likely have the courtesy of reporting an error.
Update: No error from sendto(), well then, no easy fix.
One final note of caution/advice. Even direct ethernet connections between hosts does not guarantee packets will always get through. If you depend on the file data getting transferred reliably then you'll need to add some kind of acknowledgement response from the receiver to confirm successful reception of the data. And associated logic in the sender to retransmit data as required.
That's a fair bit of work and why you might rather switch to TCP sockets which do all that for you.
If you are going to send files over UDP, at least use an existing protocol that is designed for that purpose, like Trivial FTP (see RFC 1350). It offers buffer size control and safety from dropped packets.

Ethernet frame transmission via raw socket

My intent is to write a function which takes as parameter a buffer holding an entire ethernet frame and sends it to a raw socket (so needed only for transmission).
Here the obvious steps:
sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
// ...
write(sockfd, buffer, buffer_len);
// ...
close(sockfd);
But the write function fails with an EXNIO error code: "No such device or address". I grab the packet content from a wireshark session, so it should be well formatted.
There are several examples on internet about sending a raw eth packet, but I haven't found anything using write() instead of sendto(), which requires the sockaddr_ll struct to be filled.
Has anyone experienced the same issue? Is using sendto() the only way to accomplish the task?
Thanks.
Note: the program runs as root.
Here is a part of code which worked for me. In my understanding of things, write will not work as it is supposed to send a stream of chars. It can write to a file or to a TCP connection or similar. I think that raw packets are very different.
int sock;
sock = socket(PF_INET, SOCK_RAW, 0);
if (sock < 0) {
printf("Can't get socket\n");
exit(1);
}
/* Insist that we have header included */
int one = 1;
if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof (one)) < 0) {
printf ("Cannot set IP_HDRINCL!\n");
exit(1);
}
...
struct sockaddr_in sockin;
sockin.sin_family = AF_INET;
sockin.sin_port = dest_port;
sockin.sin_addr.s_addr = dest_ip;
...
sendto (sock, buffer, bufferlen, 0, (struct sockaddr *) &sockin, sizeof (sockin));
...
close(sock);

Linux server socket - Bad file descriptor

I have a problem with a server socket under Linux. For some reason unknown to me the server socket vanishes and I get a Bad file descriptor error in the select call that waits for an incomming connection. This problem always occurs when I close an unrelated socket connection in a different thread. This happens on an embedded Linux with 2.6.36 Kernel.
Does anyone know why this would happen? Is it normal that a server socket can simply vanish resulting in Bad file descriptor?
edit:
The other socket code implements a VNC Server and runs in a completely different thread. The only thing special in that other code is the use of setjmp/longjmp but that should not be a problem.
The code that create the server socket is the following:
int server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(1234);
const int optionval = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &optionval, sizeof(optionval));
if (bind(server_socket, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
perror("bind");
return 0;
}
if (listen(server_socket, 1) < 0) {
perror("listen");
return 0;
}
I wait for an incomming connection using the code below:
static int WaitForConnection(int server_socket, struct timeval *timeout)
{
fd_set read_fds;
FD_ZERO(&read_fds);
int max_sd = server_socket;
FD_SET(server_socket, &read_fds);
// This select will result in 'EBADFD' in the error case.
// Even though the server socket was not closed with 'close'.
int res = select(max_sd + 1, &read_fds, NULL, NULL, timeout);
if (res > 0) {
struct sockaddr_in caddr;
socklen_t clen = sizeof(caddr);
return accept(server_socket, (struct sockaddr *) &caddr, &clen);
}
return -1;
}
edit:
When the problem case happens i currently simply restart the server but I don't understand why the server socket id should suddenly become an invalid file descriptor:
int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (server_socket, SOL_SOCKET, SO_ERROR, &error, &len );
if (retval < 0) {
close(server_socket);
goto server_start;
}
Sockets (file descriptors) usually suffer from the same management issues as raw pointers in C. Whenever you close a socket, do not forget to assign -1 to the variable that keeps the descriptor value:
close(socket);
socket = -1;
As you would do to C pointer
free(buffer);
buffer = NULL;
If you forget to do this yo can later close socket twice, as you would free() memory twice if it was a pointer.
The other issue might be related to the fact that people usually forget: file descriptors in UNIX environment start from 0. If somewhere in the code you have
struct FooData {
int foo;
int socket;
...
}
// Either
FooData my_data_1 = {0};
// Or
FooData my_data_2;
memset(&my_data_2, 0, sizeof(my_data_2));
In both cases my_data_1 and my_data_2 have a valid descriptor (socket) value. And later, some piece of code, responsible for freeing FooData structure may blindly close() this descriptor, that happens to be you server's listening socket (0).
1- close your socket:
close(sockfd);
2- clear your socket file descriptor from select set:
FD_CLR(sockfd,&master); //opposite of FD_SET
You don't distinguish the two error cases in your code, both can fail select or accept. My guess is that you just have a time out and that select returns 0.
print retval and errno in an else branch
investigate the return value of accept seperately
ensure that errno is reset to 0 before each of the system calls
In Linux once you create a connection and it get closed then you have to wait for some time before making new connection.
As in Linux, socket doesn't release the port no. as soon as you close the socket.
OR
You reuse the socket, then bad file descriptor want come.

C socket programming: connect() hangs

Hey all, I'm about to rip my hair out. I have this client that tries to connect to a server, everything seems to be fine, using gethostbyname(), socket(), bind(), but when trying to connect() it just hangs there and the server doesn't see anything from the client. I know that the server works because another client (also in C) can connect just fine. What causes the server to not see this incoming connection? I'm at the end of my wits here. The two different clients are pretty similar too so I'm even more lost.
if (argc == 2) {
host = argv[1]; // server address
}
else {
printf("plz read the manual\n");
exit(1);
}
hserver = gethostbyname(host);
if (hserver) {
printf("host found: %p\n", hserver);
printf("host found: %s\n", hserver->h_name );
}
else {
printf("host not found\n");
exit(1);
}
bzero((char * ) &server_address, sizeof(server_address)); // copy zeroes into string
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(hserver->h_addr);
server_address.sin_port = htons(SERVER_PORT);
bzero((char * ) &client_address, sizeof(client_address)); // copy zeroes into string
client_address.sin_family = AF_INET;
client_address.sin_addr.s_addr = htonl(INADDR_ANY);
client_address.sin_port = htons(SERVER_PORT);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
exit(1);
else {
printf("socket is opened: %i \n", sockfd);
info.sock_fd = sockfd;
rv = fcntl(sockfd, F_SETFL, O_NONBLOCK); // socket set to NONBLOCK
if(rv < 0)
printf("nonblock failed: %i %s\n", errno, strerror(errno));
else
printf("socket is set nonblock\n");
}
timeout.tv_sec = 0; // seconds
timeout.tv_usec = 500000; // micro seconds ( 0.5 seconds)
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
rv = bind(sockfd, (struct sockaddr *) &client_address, sizeof(client_address));
if (rv < 0) {
printf("MAIN: ERROR bind() %i: %s\n", errno, strerror(errno));
exit(1);
}
else
printf("socket is bound\n");
rv = connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
printf("rv = %i\n", rv);
if (rv < 0) {
printf("MAIN: ERROR connect() %i: %s\n", errno, strerror(errno));
exit(1);
}
else
printf("connected\n");
Any thoughts or insights are deeply greatly humongously appreciated.
-Fourier
EDIT:
If the socket is NOT set on non-block, then it hangs.
If the socket is set on non-block, then I get ERROR connect() 115: Operation now in progress
[EINPROGRESS]
O_NONBLOCK is set for the file descriptor for the socket and the connection cannot be immediately established; the connection shall be established asynchronously.
I would also like to mention that the server and the client are running on computers next to each other, connected by like one router.
The gethostbyname() function produces addresses in network byte order, so you do not need to pass them through htonl(). Also, the hostent->h_addr entry is a pointer to the address. Replace this line:
server_address.sin_addr.s_addr = htonl(hserver->h_addr);
with:
memcpy(&server_address.sin_addr, hserver->h_addr, hserver->h_length);
I see you set your socket in O_NONBLOCK mode.
Thus connect must return -1 and set errno to EAGAIN according to the man page of connect.
You can then know when the connection succeeded using select() on the socket.
This is a very common pattern to control the connection timeout (because select() must be feed with a timeout).
Check whether you can connect with the program telnet (it accepts a server name and port number). If that works, the bug must be in your code. If telnet also hangs, then check your firewall settings.
If you want to connect twice from the same machine I can see the reason for your problem.
You are binding the clientsocket. Your code binds the client socket very specifically to a fixed port (the server port). This leaves the O/S NOT free in choosing an available port for making the connection FROM. If one process has the port allocated (it has succesfully bound() and connected() to the server) then the other process cannot use that same port.
If there is no compelling reason for sending traffic FROM a specific port, let the O/S find an available port by changing this line
client_address.sin_port = htons(SERVER_PORT);
to
client_address.sin_port = 0;

Resources