Linux C Socket: Blocked on recv call - linux

In my application i have created a thread for a simple http server, then from within my application i tried to connect to http server but control is blocked/hanged on recv call.
But if try to connect to my application's http server using linux GET command, I will be connected to http server successfully.
As per my understanding by searching the google i found that this is not the right approach.
But if i want to do this, in what should i create the sockets so that i can connect o my http server from within the application.
Below is how my http server socket created
pthread_create(&pt_server, NULL, http_srvr, NULL);
//http server handler
void *http_server()
{
int sockfd, new_fd;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
socklen_t sin_size;
struct sigaction sa;
int yes=1;
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(HTTP_PORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)
{
perror("bind");
exit(1);
}
printf("Listening to sockets\n");
if (listen(sockfd, BACKLOG) == -1)
{
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1)
{
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,&sin_size)) == -1)
{
perror("accept");
continue;
}
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
handle_connection(new_fd);
}
}
And following is how i am doing http POST to my http server
/* create socket */
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return ERRSOCK;
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
/* connect to server */
if (connect(s, &server, sizeof(server)) < 0)
ret=ERRCONN;
else {
if (pfd) *pfd=s;
/* create header */
if (proxy) {
sprintf(header,
"%s http://%.128s:%d/%.256s HTTP/1.0\015\012User-Agent: %s\015\012%s\015\012",
command,
http_server1,
http_port,
url,
http_user_agent,
additional_header
);
} else {
sprintf(header,
"%s /%.256s HTTP/1.0\015\012User-Agent: %s\015\012%s\015\012",
command,
url,
http_user_agent,
additional_header
);
}
hlg=strlen(header);
/* send header */
if (send(s,header,hlg,0)!=hlg)
ret= ERRWRHD;
/* send data */
else if (length && data && (send(s,data,length,0)!=length) )
ret= ERRWRDT;
else {
/* read result & check */
ret=http_read_line(s,header,MAXBUF-1);
and following are the contents of http_read_line, and in this function recv call blocked
static int http_read_line (fd,buffer,max)
int fd; /* file descriptor to read from */
char *buffer; /* placeholder for data */
int max; /* max number of bytes to read */
{ /* not efficient on long lines (multiple unbuffered 1 char reads) */
int n=0;
while (n<max) {
if (recv(fd,buffer,1,0)!=1) {
n= -n;
break;
}
n++;
if (*buffer=='\015') continue; /* ignore CR */
if (*buffer=='\012') break; /* LF is the separator */
buffer++;
}
*buffer=0;
return n;
}

You need to either send an HTTP 1.0 header, or else read about content-length in HTTP 1.1. You are reading the stream to EOS when the server is under no obligation to close the connection, so you block. The Content-Length header tells you how much data is in the body: you should only try to read that many bytes.
If you specify HTTP 1.0 (and no fancy headers) the server will close the connection after sending the response.

You have told "In my application i have created a thread for a simple http server, then from within my application
i tried to connect to http server but control is blocked/hanged on recv call."
That means the recv is never returning 0. Now when the recv function will
return a 0? ->When it gets a TCP FIN segment. It seems that your server is never
sending a TCP FIN segment to the client.
The reason that is most likely here is that, your client code needs modification.
You are sending data from from the client, but you are never sending the FIN,
so I assume that your server function is continuing forever and it had not
sent the FIN. This made the recv wait for ever.
In the current code perhaps the fix is to add a line
else {
/*Send the FIN segment, but we can still read the socket*/
shutdown(s, SHUT_WR);
/* read result & check */
ret=http_read_line(s,header,MAXBUF-1);
In this case the shutdown function sends the TCP FIN and the server function can return and possibly then it would do a proper close.
And on a proper close, the FIN from the server will be received by the client. This would make the recv return 0, instead of getting blocked for ever.
Now if you want to continue any further data transfer from the client, you need to again connect or may be you need to have some different algorithm.
I hope my explanation may help fix the current problem.

Related

Win32 multithreaded sockets

I have a server class that has a method called handle_client as follows:
void server::handle_client()
{
do {
// Accept a client socket
EnterCriticalSection(&listenSocketCriticalSection);
SOCKET clientSocket = accept(listenSocket, NULL, NULL);
LeaveCriticalSection(&listenSocketCriticalSection);
// ... rest of the client handling code that reads
// from the client socket and sends appropriate response
// ...
} while(true);
}
I have a run method as follows:
void server::run()
{
// create the threads
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
DWORD dwThreadId;
thread_pool_handle[i] = CreateThread(NULL, 0, thread_function, this, 0, &dwThreadId);
}
WaitForMultipleObjects(THREAD_POOL_SIZE, thread_pool_handle, true, INFINITE);
}
I have a thread_function as follows:
DWORD WINAPI thread_function(LPVOID lpParam)
{
server* pServer = (server*)lpParam;
pServer->handle_client();
}
I am creating a pool of threads that are all waiting for a client socket connection to be accepted. Since I have wrapped the accept within a critical section, only one thread will succeed at a time. Once a client socket is accepted by the server thread, that thread continues to go on to handle the request. The idea is that the thread will loop back indefinitely to the accept call after completing a request.
Questions:
Is the Critical Section necessary? (I think so, because otherwise the accept call from the multiple threads on the same listenSocket would clobber things. Is this correct?)
If handle_client loops indefinitely, what is the best way to cleanly terminate all the threads and exit the server? Should I use a special message from the client to trigger the thread terminations? Any other suggestions?
How should I handle the server process termination gracefully (as it pertains to the thread pool)?
It Is recommended to use Select model to store socket objects in multithreaded sockets. In Select model, you can use FD_CLR() to clear sockets when there are no network events.
I have the code for the server with the select socket, You can try to run and modify.
#include <iostream>
#include<WinSock2.h>
#include<windows.h>
#include<WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)//inet_addr
int main()
{
//1.Obtain version info
WSADATA wsaData = { 0 };
SOCKET hServer = { 0 };
WSAStartup(MAKEWORD(2, 2), &wsaData);
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("version failed %d\n", GetLastError());
return -1;
}
else
{
printf("version succeed \n");
}
//2.create socket
hServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hServer == SOCKET_ERROR)
{
printf("create socket tcp failed %d\n", GetLastError());
return -1;
}
else
{
printf("create socket tcp succeed \n");
}
//3. Create a protocol address family
sockaddr_in ServerAddr = { 0 };
ServerAddr.sin_family = AF_INET6;
ServerAddr.sin_zero[8];
ServerAddr.sin_port = htons(8888);
ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.2.50");;//modify your address
//4.bind
int nRet = bind(hServer, (sockaddr*)&ServerAddr, sizeof ServerAddr);
if (nRet == SOCKET_ERROR)
{
printf("bind failed %d\n", GetLastError());
closesocket(hServer);
WSACleanup();
return -1;
}
else
{
printf("bind succeed \n");
}
//5.listen
nRet = listen(hServer, 3);
if (nRet == SOCKET_ERROR)
{
printf("listen failed %d\n", GetLastError());
closesocket(hServer);
WSACleanup();
return -1;
}
else
{
printf("listen succeed \n");
}
sockaddr_in clientAddr = { 0 };// The protocol address family used to receive the client
int len = sizeof(clientAddr);// The size of the accepted client protocol address family information
// Create a select model to store socket objects
FD_SET fd_read;
FD_ZERO(&fd_read);
FD_SET(hServer, &fd_read);
//6. Accept client connections
while (1) {
FD_SET fd_tmp = fd_read;// Read backup can only be in
const timeval tv = { 1,0 };
int Ret = select(NULL, &fd_tmp, NULL, NULL, &tv);
if (Ret == 0) // No network events, TMP is automatically deleted
{
Sleep(1000);
continue;
}
for (int i = 0; i < fd_tmp.fd_count; i++)
{
// If there are network events for a listening socket, it proves that a client is connecting to the socket
if (fd_tmp.fd_array[i] == hServer)
{
SOCKET hclient;
hclient = accept(hServer, (sockaddr*)&clientAddr, &len);// If you do not want to store the protocol address family information of the client, you can pass a NULL address
if (hclient == SOCKET_ERROR)
{
printf("recieve information of client failed %d\n", GetLastError());
closesocket(hServer);
return -1;
}
printf("connecting: %s******** \n", inet_ntoa(clientAddr.sin_addr));
FD_SET(hclient, &fd_read);
}
else // The client socket has network events that prove that the client is sending data and the server is accepting the data
{
char buff[32] = { 0 };
int nRet = recv(fd_tmp.fd_array[i], (char*)buff, 32, NULL);
if (nRet > 0)
{
printf("message: %s\n", buff);
}
else// Removes the current socket fd_array from the fd_read
{
FD_CLR(fd_tmp.fd_array[i], &fd_read);
printf("Disconnect \n", GetLastError());
closesocket(hServer);
closesocket(fd_read.fd_array[i]);
break;
}
}
break;
}
}
//7.close socket
WSACleanup();
getchar();
return 0;
}

Second time TFTP PUT opearation doesnt work after GET/PUT opearation is successfully finished first time on TFTP client side

Implementing the TFTP client over UDP socket.
First I create the UDP non blocking socket and perform the PUT/GET operation it works fine.
But when again I try to perform the GET/PUT it does not work. The RRQ/WRQ request itself is not reaching to the server but from the client side it has been sent successfully.
Below is my tftp client code.
=========================================================
int sockfd;
struct sockaddr_in serv_addr;
//called when we retrieve a file from the server
void getFile(int port, char *filename)
{
printf("enter to get file\n");
FILE * file;
if (strchr(filename,'/') != NULL )
{
printf("We do not support file transfer out of the current working directory\n");
return;
}
file = fopen(filename, "wb");
if(file == NULL)
{
perror(filename);
return;
}
if(sockfd < 0)
{
printf("Couldn't open socket\n");
return;
}
if(!send_RRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE))
{
printf("Error: couldn't send RRQ\n");
return;
}
if(!recvFile(sockfd, (struct sockaddr *) &serv_addr, file,filename))
{
printf("Error: didn't receive file\n");
return;
}
fclose(file);
return;
}
//used to upload files to the server
void putFile(int port, char *filename)
{
printf("filenemae is: %s \t",filename);
PACKET packet;
int result;
FILE * fileh;
int timeout_counter = 0;
if (strchr(filename,'/') != NULL )
{
printf("We do not support file transfer out of the current working directory\n");
return;
}
fileh = fopen(filename, "rb");
if(fileh == NULL)
{
perror(filename);
return;
}
if(!send_WRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE))
{
printf("Error: couldn't send WRQ to server\n");
return;
}
while (timeout_counter < MAX_TFTP_TIMEOUTS)
{
result = waitForPacket(sockfd, (struct sockaddr *) &serv_addr, TFTP_OPTCODE_ACK, &packet);
if (result < 0)
{
printf("Error: Timeout sending packet to server\n");
if(!send_WRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE))
{
printf("Error: couldn't send WRQ to server\n");
return;
}
timeout_counter++;
}else
{
break;
}
}
if (result < 0)
{
//we still timed out
printf("Timed out after %d tries, is the server running\n",MAX_TFTP_TIMEOUTS);
fclose(fileh);
return;
}
if (packet.optcode == TFTP_OPTCODE_ERR)
{
//we recieved an error, print it
printError(&packet);
}else
{
if (!sendFile(sockfd, (struct sockaddr *) &serv_addr, fileh))
{
printf("Unable to send file to server\n");
}
}
fclose(fileh);
return;
}
int createUDPSocketAndBind(int port)
{
//create a socket
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
//return -1 on error
if (sockfd == -1)
{
return -1;
}
//zero out the struct
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(port);
return 0;
}
//main client, checks for args and starts an operation if no errors detected
int main(int argc, char *argv[])
{
int port = 59;
int argOffset = 1;
char* filename;
char fme[] = "test.txt";
createUDPSocketAndBind(port);
printf("for put file\n");
putFile(port,fme); //=====> this operation is successful.
//createUDPSocketAndBind(port); //=====> If I uncomment this function, next operation works.
printf("for getfile\n");
getFile(port,fme); //=======> It is failing.
printf("Usage: %s [-p port] (-w putfile || -r getFile)\n",argv[0]);
}
=========================================================================
I have investigated more and found the problem with my code and solution as well.
When you send the first RD/WR request to the Server it will create a separate process or thread to handle your request and at the same time it will create the new socket and will use the different port number as well to handle the RD/WR request.
Client side when you will receive the response from the Server using below UDP socket API.
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
In the "struct sockaddr *src_addr" instance port number will be updated as server is responding using different port number which server
has created to handle your request and your RD/WR operation will complete successfully using this port number.
Once RD/WR is done successfully server will close the socket which has been created to handle you request and start listening to your new request
on the Original port. But client side "struct sockaddr *src_addr" instance will still have the modified port number and when you try to send the new RD/WR request it will not reach to the server. And that is the reason second RD/WR request will not reach to the server and it will fail.
To fix this on the client side in the "struct sockaddr *src_addr" instance you have to reset the port to the initial value which you have used initially to configure the server instance of the "struct sockaddr *src_addr". So after each RD/WR operation you have to reset the port number
to the original value.
I am quite new to the UDP socket and it was good learning for me.
I think this will be helpful for the beginners like me.
Thanks

Understandng the reason for recv blocking forever

I run a Linux program written in C that would periodically receive data by parsing an HTTP response, crunch some numbers and then report the result by HTTP GET of another web page.
My problem is that sometimes, one of the instances would "freeze".
Looking at top I can see that it is in sk_wait_data state and attaching a debugger reveals that it is blocked by a recv call.
Here is a minimal version of the code that does the TCP connection (it was adapted from http://www.linuxhowtos.org/C_C++/socket.htm):
int connectTCP(const char* host, const char* page, int portno) {
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
// Create socket //
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0)
error("ERROR opening socket");
// Get ip from hostname //
server = gethostbyname(host);
if (server == NULL)
error("ERROR, can not find host\n");
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
memcpy((char *)&serv_addr.sin_addr.s_addr, // Destination
(char *)server->h_addr, // Source
server->h_length); // Size
serv_addr.sin_port = htons(portno);
// Conect to socket //
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
return sockfd;
}
char* httpGet(const char* host, const char* page, int portno) {
int sockfd, n;
sockfd = connectTCP(host, page, portno);
memset(buffer, 0, sizeof(buffer));
sprintf(buffer, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", page, host);
n = send(sockfd,buffer,strlen(buffer), 0);
if (n < 0)
error("ERROR writing to socket");
int count = 0;
do {
n = recv(sockfd, buffer + count, BUFFER_MAX_SIZE - count, 0);
if (n < 0) {
error("ERROR reading from socket");
}
count += n;
} while(n != 0);
close(sockfd);
return buffer;
}
Bugs in your code:
If recv() returns zero you whould close the socket and stop reading.
If recv() returns -1 you should report the error, close the socket, and stop reading, unless you had set a read timeout and errno was EAGAIN/EWOULDBLOCK, in which case you should handle the timeout however is appropriate for your application.

why my TCP server code send a SYN/ACK on only first packet or only on the first connection?

SOCKET sock;
SOCKET fd;
uint16 port = 18001;
void CreateSocket()
{
struct sockaddr_in server, client; // creating a socket address structure: structure contains ip address and port number
WORD wVersionRequested;
WSADATA wsaData;
int len;
printf("Initializing Winsock\n");
wVersionRequested = MAKEWORD (2, 2);
iResult = WSAStartup (wVersionRequested, &wsaData);
if (iResult != NO_ERROR)
printf("Error at WSAStartup()\n");
// create socket
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
printf("Could not Create Socket\n");
//return 0;
}
printf("Socket Created\n");
// create socket address of the server
memset( &server, 0, sizeof(server));
// IPv4 - connection
server.sin_family = AF_INET;
// accept connections from any ip adress
server.sin_addr.s_addr = htonl(INADDR_ANY);
// set port
server.sin_port = htons(18001);
//Binding between the socket and ip address
if(bind (sock, (struct sockaddr *) &server, sizeof(server)) < 0)
{
printf("Bind failed with error code: %d", WSAGetLastError());
}
//Listen to incoming connections
if(listen(sock,3) == -1){
printf("Listen failed with error code: %d", WSAGetLastError());
}
printf("Server has been successfully set up - Waiting for incoming connections");
for(;;){
len = sizeof(client);
fd = accept(sock, (struct sockaddr*) &client, &len);
if (fd < 0){
printf("Accept failed");
close(sock);
}
//echo(fd);
printf("\n Process incoming connection from (%s , %d)", inet_ntoa(client.sin_addr),ntohs(client.sin_port));
//closesocket(fd);
}
}
The server code is accepting a connection from the client via the ip address and the port number. It is sending SYN/ACK to the client only during the first connection and It is sending like below for the second time: RST / ACK (it is resetting during the second time).
Could anyone tell me what is the error in the above code ??
Look at Accept multiple subsequent connections to socket
Here is a quote: "To service multiple clients, you need to avoid blocking I/O -- i.e., you can't just read from the socket and block until data comes in."

Writing to closed TCP/IP connection hangs

My TCP/IP client hangs while writing to socket. This happens even if server properly closes an accepted connection with close() (or with shutdown()) call. I've always thought that write should return with ECONNRESET error for this case.
How do i prevent hang ups in synchronous output? Or rather what am I doing wrong so that an error is not reported by write()?
Should I use send() instead of write() or they are interchangeable?
I'm testing networking in a separate application with two threads.
Main thread starts server thread, that accepts connection and immediately closes it. Main thread then imitates client behavior by connecting to listening port.
Main thread code:
sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port);
int s = socket(AF_INET, SOCK_STREAM, 0);
if (bind(s, (sockaddr*)(&serv_addr), sizeof(serv_addr)) < 0) {
close(s);
throw runtime_error(strerror(errno));
}
listen(s,1);
start_thread(s); // posix thread accepting a connection on s is started here
//Code below imitates TCP/IP client
struct hostent *hp;
struct sockaddr_in addr;
if((hp = gethostbyname(host.c_str())) == NULL){
throw HErrno();
}
bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
int _socket = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (_socket < 0) {
throw Errno();
}
assert(ENOTCONN==107);
assert(_socket>=0);
if(::connect(_socket, (const struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1){
throw Errno();
}
while(true) {
const char a[] = "pattern";
if (write( _socket, a, 7)<0) // Writes 30000 times, then hangs
break;
}
Server thread code:
int connection = accept(s);
close(connection);
EDIT:
The problem reduced to my programming error. It seems I've failed to start accepting thread properly.
Each TCP connection has a receive buffer for storing data that are received but not delivered to application. If in your server you don't do read(), than the data is accumulated in receive buffer, and at one point this receive buffer becomes full, causing TCP sends Window=0 message.
Your server thread code should look like this:
char a[10];
int connection = accept(s);
while(true)
if (read( connection , a, 7)<=0)
break;
close(connection);
Did you perhaps set up a handler for SIGPIPE instead of setting it to SIG_IGN?

Resources