segmentation fault with accept() on linux - c

I have a problem with a client/server programm on linux.
I wrote a server programm wich is sending data cyclic to one conneted client.
Now I want to detect, if the client close the connection to the server. When the connection is closed from the client, i want to wait with accept(...) for an new connection.
Here the critical parts of my code:
error = send(client_sock, Zeichen, 1, MSG_NOSIGNAL);
if(error < 0)
{
connected = 0;
printf("Error, write on TCP Socket failed!!! Reconnecting... \r\n");
close(serverSocket);
initServer();
}
int initServer(void)
{
int *new_sock;
socklen_t size;
struct sockaddr_in server, client;
serverSocket = socket(AF_INET , SOCK_STREAM , 0); //Create socket
if (serverSocket == -1)
{
printf("Could not create socket \r\n");
return 0;
}else
{
printf("Socket created \r\n");
}
server.sin_addr.s_addr = inet_addr(IPAdresse);
server.sin_family = AF_INET;
server.sin_port = htons(TCPPort);
if(bind(serverSocket,(struct sockaddr *)&server , sizeof(server)) < 0)
{
printf("bind failed. Error \r\n");
return 0;
}else
{
printf("bind done \r\n");
}
listen(serverSocket, 1);
printf("Waiting for incoming connections... \r\n");
size = sizeof(sockaddr_in);
printf("size of sockaddr_in: %i \r\n", size);
client_sock = accept(serverSocket, (struct sockaddr *)&client, &size);
if (client_sock < 0)
{
printf("accept failed \r\n");
return 0;
}else
{
connected = 1;
return 1;
}
}
The first time it works fine, I can connect and can send data over the socket. When the client close the connection the error is detected, I close the socket an start the server again to wait for a new connection. But than I get a segmentation fault when I do the accept(..) for the second time!!!
Can someone help me please!!! Thanks a lot!

It's not clear what you're doing when the client connection closes. I see no loop in your code, and yet you're suggesting that accept() is called more than once.
Without seeing the rest or the code, I can only speculate that:
you're repeatedly calling initServer(), hence attempting to recreate the same server socket over and over (which, of course, would be bad),
or
you're calling accept() again somewhere else in your code, most likely with corrupt arguments.
At the very least, what your server-side code should do is initialize the server socket once, then loop around accept(), like so:
call socket() once
call bind() once
call listen() once
then in a loop:
call accept(), this call will block until a client connects, and then return a connected socket,
do whatever you need to do with that (connected client) socket
resume with the loop

Related

Trying to get started with winsock in C, how to keep connected?

I'm a beginner and trying to set up a TCP-client for the first time, using winsock. I put together a minimal client using some bits of code I found in examples (see below). It's basically working, i.e. I can receive the server's messages, and sending messages gives the expected results.
However, unless I add a loop which constantly does a receive/send routine (or even just the receive part) the connection is closed immediately after it has been established. Can I do something to keep the connection open and only receive or send something when there is demand for it?
The server is a closed source piece of software, so I have no idea about how it is set up.
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
int startWinsock(void) {
WSADATA wsa;
return WSAStartup(MAKEWORD(2, 2), &wsa);
}
int main(void) {
long rc;
SOCKET s;
SOCKADDR_IN addr;
printf("Starting Winsock... ");
rc = startWinsock();
if (rc != 0) {
printf("Error: unable to start Winsock, error code: %d\n", rc);
}
else {
printf("done.\n");
}
printf("Creating socket... ");
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
printf("Error: Unable to create socket, error code: %d\n", WSAGetLastError());
}
else {
printf("done.\n");
}
memset(&addr, 0, sizeof(SOCKADDR_IN));
addr.sin_family = AF_INET;
addr.sin_port = htons(10134);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
rc = connect(s, (SOCKADDR*)&addr, sizeof(SOCKADDR));
if (rc == SOCKET_ERROR) {
printf("Connection failed, error code: %d\n", WSAGetLastError());
}
else {
printf("Connected to 127.0.0.1.\n");
}
//if I add a loop here, which receives and/or sends stuff constantly, the connection stays established
return 0;
}
Very simple:
Your client tries to connect to the server.
If it succeeds, send a command, and read the response.
Keep receiving and sending until you're "done", then close the socket.
In other words:
You have control over when to close the connection - the socket will stay open until you close it.
Essentially, you're inventing your own custom network protocol
STRONG SUGGESTION:
Review Beej's Guide to Network Programming

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.

How to push (i.e. flush) data sent to a TCP stream

RFC 793 says that TCP defines a "push" function that ensures that the receiver got the data:
Sometimes users need to be sure that all the data they have
submitted to the TCP has been transmitted. For this purpose a push
function is defined. To assure that data submitted to a TCP is
actually transmitted the sending user indicates that it should be
pushed through to the receiving user. A push causes the TCPs to
promptly forward and deliver data up to that point to the receiver.
However, I can't find a push system call. Using fsync on the file descriptor produces an invalid argument error.
I conducted an experiment with a simple server that accepts a connection from a client, waits, then sends 26 bytes to the client:
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 1234
int main(void)
{
int server_fd;
int client_fd;
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
}
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
perror("bind");
return 1;
}
}
if (listen(server_fd, 20) != 0) {
perror("listen");
return 1;
}
{
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
printf("Waiting for connection on port %d\n", PORT);
if ((client_fd = accept(server_fd, (struct sockaddr*)&addr, &addrlen)) < 0) {
perror("accept");
return 1;
}
printf("%s:%d connected\n",
inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
}
printf("Giving client time to close connection.\n");
sleep(10);
{
ssize_t sent_length;
if ((sent_length =
send(client_fd, "abcdefghijklmnopqrstuvwxyz", 26, 0)) < 0)
{
perror("send");
return 1;
}
printf("Sent %Zd bytes.\n", sent_length);
}
printf("Closing connection to client\n");
if (close(client_fd) != 0) {
perror("close(client_fd)");
return 1;
}
printf("Shutting down\n");
if (close(server_fd) != 0) {
perror("server: close(server_fd)");
return 1;
}
printf("Done!\n");
return 0;
}
I found that the send call immediately returns 26, even after I close the connection client-side or unplug the network cable. In the latter case, the data appears on the client when I plug the cable back in and wait a few seconds (long after the server has shut down).
How do I ensure that data sent with send is received and acknowledged?
There is no push, says the late W. Richard Stevens; the standard sockets API doesn't provide it, and is not required to do so by RFC 1122. You can set the TCP_NODELAY option, but that's only a partial solution.
If you want to be sure the other end got your data, then let it send an acknowledgment over the TCP channel.
try to add a shutdown call before the close of the socket;
shutdown(client_fd,SHUT_RDWR);
However the real solution is to get an acknowledgement back from the client that it has received the data -- I.e. you need to define a protocol -- the simplest of simple protocols is that the client is responsible for closing the socket when the data is received.
Well as per my limited knowledge, TCP will insure that the data is transferred to the other machine / socket.
But has the program at the other end read / accessed the data cannot be confirmed using standard socket API's. Your other end (client in this case) might be busy doing something else instead of waiting for data to show up.
I think that your requirement will be full filled if you implement some sort of handshaking between server / client to track what all has been received using some kind of acknowledgements.
The acknowledgement mechanism is important if your application depends on it.
You can force immediately sending of small packets by disabling Nagle's algorithm, but this does not guarantee that the client will receive it.
If you have to wait for the acknowledge you have to build this into the protocol and wait for the client to write something into the socket that signals the reception of message.
The only way to make sure your data is send over is to Receive an answer. After testing for many days this is the only way to make sure it is 'flushed' to the other side.
// Receive until the peer closes the connection to make sure all data has been send
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0){
printf("Bytes received: %d\n", iResult);
}
else if (iResult == 0){
printf("Connection closed\n");
}
else{
printf("recv failed with error: %d\n", WSAGetLastError());
}
} while (iResult > 0);

recvfrom infinite receiving problem

I m writing a server using udp socket. After a client send first message to connect, i open new socket to communicate with this client on this socket (first sockets for listening) and create a thread for each client. But in thread, the while loop goes infinitely because recvfrom receive data everytime altough any client send data. What is the problem in my code?
The code sample below:
int main()
{
.....
// creating socket
if( (sock = socket(AF_INET, SOCK_DGRAM, 0) ) == -1 )
{
perror("Socket cannot be created\n");
return FAILURE;
}
.....
for(; ;)
{
// TAKE CLIENTS INFORMATION
/**************************************/
recvfrom(sock, &client, sizeof(Client), MSG_WAITALL, (struct sockaddr *)&clientAddr, &size); //1
.......
if( (sock2 = socket(AF_INET, SOCK_DGRAM, 0) ) == -1 )
{
perror("Socket cannot be created\n");
return FAILURE;
}
client.sock = sock2;
...
pthread_create(thid+num_client-1, NULL, messanger, (void*)(clients + num_client-1));
} // end of for loop
}// end of main
// thread function
void *messanger(void *argClient)
{
Client client = *(Client*)argClient;
...
while(strcmp(message.buffer, "exit") != 0)
{
recvfrom(client.sock, &message, sizeof(Message), MSG_WAITALL, (struct sockaddr *)&clientAddr, &size);
printf("%s\n", message.buffer);
}// this file loops infinetely altough client does not send data. Printf prints onln new line
}
Where do you bind() the second socket (or the first, for that matter)? Why aren't you checking recvfrom() for failure?
This isn't the way to write a UDP server, anyway. You use a single socket to recieve all packets. You then inspect the sender address, match it up with the right client and handle it as appropriate (for example, you could put it onto a work queue for a per-client thread, then wake that thread up using pthread_cond_signal()).
You're busy-waiting. Try using poll or select instead.

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