why it can be "bad file number" when i write to socket - c

I have a problem with sending message to server socket from client.
write function returns error - bad file number. It means that I haven't permission to write to this socket.
But from another client I can write to this socket, and do it successfully.
Most interesting, that when another client connected to server my(problem) client can send message too.
the code of my client:
SOCKET OnceCommand;
struct sockaddr_in SAddress4;
struct autoC
{
char buf[4];
short fromx;
short fromy;
short tox;
short toy;
char step;
char cycle;
};
union autocomm{
char byte[14];
struct autoC command;
} Command1, Command2;
memset(&SAddress4,0,sizeof(SAddress4));
SAddress4.sin_family = AF_INET;
SAddress4.sin_port = htons(444);
SAddress4.sin_addr.s_addr = inet_addr(RobotsIP[Robot1]);
memset(&(SAddress4.sin_zero),0,8);
if((OnceCommand = socket(AF_INET,SOCK_STREAM,0))!=SOCKET_ERROR)
{
Err(OnceCommand);
if(conn = connect(OnceCommand,(struct sockaddr *)&SAddress4,sizeof(struct sockaddr))!=SOCKET_ERROR)
{
rc = write(OnceCommand,(char*)Command1.byte,sizeof(Command1.byte));
if(rc < 0)
{
perror("Client-write() error");
rc = getsockopt(OnceCommand, SOL_SOCKET, SO_ERROR, &temp, &length);
if(rc == 0)
{
Err(OnceCommand);
perror("SO_ERROR was");
}
closesocket(OnceCommand);
}
else
{
adv_printf("Client-write() is OK\n");
adv_printf("String successfully sent lol!\n");
}
shutdown(OnceCommand,2);
closesocket(OnceCommand);
}
}
in SO_ERROR was "bad file number"
I'm using sockets lib in ADAM-5510 microcontroller based with ROM-DOS.
I tried to solve this problem by using NONBLOCKing sockets, but select returns only read ready flag.

You are using 0 for the protocol. What is this supposed to be? If TCP, try using IPPROTO_TCP in the socket call, ie.
OnceCommand = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)

The problem was not in client part of program. May be by the reason of using advantech socket library or another server program accepted clients' connect, but has no data to read. When i modified server program to receive data only by select it starts work fine.

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.

Socket freezes when write is attempted

I am writing a FTP server in C. Currently I am struggling with passive connection. I maintain a connection via sockets, and I have two of those. The first one is const int a_socket, it is created when a client connects and it accepts all client commands and sends response codes from the server. The second one is int p_socket, which is only connected when passive mode is requested by the client It is supposed to send large data. I get an error when I try to send anything through p_socket - the server gets stuck in the write function and the client (I am currently testing against Filezilla) recieves ECONNRESET. It also appears that the server is sending RST instead of the message.
I create the sockets with create_socket
int create_socket(int *ap_socket, const int a_port) {
// variables
struct sockaddr_in serverAddr;
int yes = 1;
// create address
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(a_port);
// create socket
if ((*ap_socket = socket(serverAddr.sin_family, SOCK_STREAM, 0)) < 0) {
perror("service_create(): create socket");
return 0;
}
// set options
if (setsockopt(*ap_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) {
perror("service_create(): socket opts");
return 0;
}
// bind socket
if (bind(*ap_socket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0) {
perror("service_create(): bind socket");
close(*ap_socket);
return 0;
}
// listen to socket
if (listen(*ap_socket, SERVER_SOCKET_BACKLOG) < 0) {
perror("service_create(): listen socket");
close(*ap_socket);
return 0;
}
return 1;
}
The client connects without issues on both sockets, but only a_socket is able to send any data. I am using the following function to check the sockets.
int check_socket(const int sd) {
int result = write(sd, "\0", 2);
if (result >= 0) {
return 1;
}
else {
return 0;
}
}
I am using wireshark to view the packets and I do all of the testing on localhost. Socket a_socket connects client
port 43684 to FTP port 21 on server (not seen in the log). Server provides port 20 for passive connection and client connects via port 50601.
Last three lines of the log show results of check_socket. Test message sent from a_socket (\000\000) arrives fine and is ACKned by the client, but the same message sent from p_socket results in RST right on the next line.
I am not fluent in C and I am a beginner in sockets and networking, so any help will be appreciated.

TCP server seems not working in LWIP+FreeRTOS

I have developed a tcp server in my one embedded device using lwip+freeRTOS.
Now this is the flow how I communicate with other device ( Other device has Linux system and let's name it LinuxDevice) using my device ( let's name it lwipDevice)
Send UDP packet from lwipDevice to LinuxDevice to initiate that I am ready to share my information.
Now LinuxDevice recognises this message successfully and sends one TCP packet (which contain command) to lwipDevice for telling to send its information.
But at lwipDevice side this message is not received. So it will not send any response to LinuxDevice. And steps 1-3 repeat again and again.
Now this is code of lwipDevice for TCP server:
long server_sock=-1;
#define FAIL 1
#define PASS 0
int CreateTcpServerSocket(long *pSock, int port)
{
struct sockaddr_in sin;
int addrlen = sizeof(sin);
int e;
struct linger linger;
linger.l_linger=0;
int i = 1;
*pSock = socket(AF_INET, SOCK_STREAM, 0);
if (*pSock == -1)
{
printf("*** createTcpSercerSocket:open sock error,port %d\n",port);
return FAIL;
}
memset((char *)&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(sin);
sin.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard IP address */
sin.sin_port = htons(port);
e = bind(*pSock, (struct sockaddr*)&sin, addrlen);
if (e != 0)
{
printf("error %d binding tcp listen on port\n");
closesocket(*pSock);
*pSock = -1;
return FAIL;
}
lwip_ioctl(*pSock, FIONBIO, &i); //Set Non blocking mode
e = listen(*pSock, 2);
if (e != 0)
{
pprintf("error :listen on TCP server\n");
closesocket(*pSock);
*pSock = -1;
return FAIL;
}
return PASS;
}
void vTCPTask(void *parm)
{
struct sockaddr client; /* for BSDish accept() call */
int clientsize;
long sock;
if(CreateTcpServerSocket(&server_sock, 8000) == FAIL) //Here server created successfully
{
printf("Fail to create server!!!!!\n");
server_sock=-1;
}
while(1)
{
// some code for other stuff
sock= accept(server_sock, &client, &clientsize); //This line always fails and reurn -1
if(sock != -1)
{
printf("accepted socket:\n\n");
//...now receive data from client....
// send some data to client
}
// some code for other stuff
//sleep for 15 seconds
}
}
int main()
{
//...initilization of lwip stack
//....some more code
//...................
xTaskCreate(vTCPTask, (signed char const *) "tcptask",
356, NULL, 3, (xTaskHandle *)&xNotifierServiceTaskHandle);
/* Start the scheduler */
vTaskStartScheduler();
return 1
}
I have checked lwip_accept function and it will return from this condition:
if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0))
{
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK);
return -1;
}
EDIT:
I know that netconn_is_nonblocking(sock->conn) condition will always true because have set socket in non blocking mode. But why sock->rcvevent always zero even LinuxDevice already send packet to it?
EDIT:
For testing purpose have commented all other stuff code in task ( see //some code for other stuff ) then socket is successfully accepted and i try to receive the packet but now problem is it's now stuck in lwip_recvfrom function (Note: LinuxDevice continue send packets). So have further debug more and found that it stuck in function sys_arch_mbox_fetch ( function call flow:: lwip_recvfrom\netconn_recv\netconn_recv_data\sys_arch_mbox_fetch).
Does anyone have an idea what is wrong with it?
You have configured the socket as non-blocking, so the accept() call will never block. If there is no incoming connection pending it will return the EWOULDBLOCK error code, which is what you see.
Finally I figured out what is cause of issue.
In lwipopt.h file there is macro like
/* Non-static memory, used with DMA pool */
#ifdef __CODE_RED
#define MEM_SIZE (6 * 1024)
#else
#define MEM_SIZE (24 * 1024)
#endif
I have defined _CODE_RED. So MEM_SIZE will (6 * 1024). Now when i change that memory size to (16 * 1024) then everything working fine.
Now all the time connection accepted and after that i am able to send/recv tcp packets successfully.
Where do you set rcvevent? Your code doesn't reveal it. I suppose it's the result of recv (or read). Reading from a non-blocking that has no available data (haven't yet received data) returns EAGAIN, which evaluates true in your rcvevent <= 0 condition. You have to manually check these specific error codes.
But why sock->rcvevent always zero even LinuxDevice already send packet to it?
Have you tried sending data with telnet or netcat to be sure the error is in your server and not in your client? Maybe your client is not sending to the correct destination, or something else.

send() and sendto() blocking in a file transfer program

it seems that when i use send() function (in a TCP file transfer program) like this
while((count = recv(socketConnection, buff, 100000, 0))>0)
myfile.write(buff,count);
the function recv() just waits untill the whole data comes and exits the loop when it is no more receiving any data but in a similar program for a UDP program
while((n = recvfrom(sockfd,mesg,1024,0,(struct sockaddr *)&cliaddr,&len))>0)
myfile.write(mesg,n);
the recvfrom() function just blocks and does not exit the loop for some reason, as far as i know both recv() and recvfrom() are blocking right?? Then why the difference. Does it have something to do with the functions or just the nature of TCP,UDP(which i guess is not a reason)??
P.S. Please help me understand this guys, I'm a newbie to socket programming and networking.
EDIT: full server program for both TCP and UDP
UDP server (with recvfrom() )
int i=0;
int sockfd,n;
struct sockaddr_in servaddr,cliaddr;
socklen_t len;
char mesg[1024];
sockfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
ofstream myfile;
// fcntl(sockfd,F_SETFL,O_NONBLOCK);
myfile.open("2gb",ios::out);
while((n = recvfrom(sockfd,mesg,1024,0,(struct sockaddr *)&cliaddr,&len))>0)
myfile.write(mesg,n);
TCP (recv() ) server program
struct sockaddr_in socketInfo;
char sysHost[MAXHOSTNAME+1]; // Hostname of this computer we are running on
struct hostent *hPtr;
int socketHandle;
int portNumber = 8070;
//queue<char*> my_queue;
bzero(&socketInfo, sizeof(sockaddr_in)); // Clear structure memory
gethostname(sysHost, MAXHOSTNAME); // Get the name of this computer we are running on
if((hPtr = gethostbyname(sysHost)) == NULL)
{
cerr << "System hostname misconfigured." << endl;
exit(EXIT_FAILURE);
}
if((socketHandle = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
close(socketHandle);
exit(EXIT_FAILURE);
}
// std::cout<<"hi starting server";
socklen_t optlen;
int rcvbuff=262144;
optlen = sizeof(rcvbuff);
socketInfo.sin_family = AF_INET;
socketInfo.sin_addr.s_addr = htonl(INADDR_ANY);
socketInfo.sin_port = htons(portNumber); // Set port number
if( bind(socketHandle, (struct sockaddr *) &socketInfo, sizeof(socketInfo)) < 0)
{
close(socketHandle);
perror("bind");
exit(EXIT_FAILURE);
}
listen(socketHandle, 1);
int socketConnection;
if( (socketConnection = accept(socketHandle, NULL, NULL)) < 0)
{
exit(EXIT_FAILURE);
}
close(socketHandle);
time_start(boost::posix_time::microsec_clock::local_time());
int rc = 0; // Actual number of bytes read
int count=0;
char *buff;
int a=100000;
buff=new char[a];
ofstream myfile;
myfile.open("345kb.doc",ios::out|ios::app);
if(myfile.is_open())
{
long i=0;
while((count = recv(socketConnection, buff, 100000, 0))>0)
{
myfile.write(buff,count);
}}
the function recv() just waits untill the whole data comes and exits the loop when it is no more receiving any data
recv() on a TCP connection returns 0 when the sending side has closed the connection and this is the condition for your loop to terminate.
for a UDP program the recvfrom() function just blocks and does not exit the loop for some reason,
Because UDP is a connection-less protocol hence there is no special return code from recv() for a closed UDP connection. Unless someone sends you a 0-length datagram.
recv() will end the loop because at the other side the socket is closed, so recv() will return 0 (socket gracefully closed) whereas, recvfrom that does not have that signal, it does not know about closing, because it's an unconnected socket. It's stay there until it receives a packet or timeout, with UDP you need a way to tell that the communication is over (finish).

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.

Resources