transfer files in a tcp threaded server C++ - c++

Hi everyone i have a little problem, i supposed to transfer a file from a server( a tcp server with threads to a client). The problems appers at the end of transmision the file is recived by client but it stucks and I can't longer communicate with it.
This is the server
int main(int argc, char *argv[])
{
int socket_desc, client_sock, c;
struct sockaddr_in server, client;
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(2025);
//Bind
if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc, 5);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
int enable = 1;
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
pthread_t thread_id;
while ((client_sock = accept(socket_desc,
(struct sockaddr *) &client,
(socklen_t*) &c)))
{
puts("Connection accepted");
if (setsockopt(client_sock,
SOL_SOCKET,
SO_REUSEADDR,
&enable,
sizeof(int)) < 0)
error("setsockopt(SO_REUSEADDR) failed");
if (pthread_create(&thread_id,
NULL,
connection_handler,
(void*) &client_sock) < 0)
{
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
pthread_join(thread_id, NULL);
puts("Handler assigned");
}
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
return 0;
}
void *connection_handler(void *socket_desc)
{
printf("Enter in handler");
//Get the socket descriptor
int sock = *(int*) socket_desc;
send_problemo(sock);
return 0;
}
This is the sending function where I think is the real problem
int send_problemo(int *sock)
{
ssize_t read_return;
char *file_path = "Problems/1.txt";
char buffer[BUFSIZ];
int filefd;
filefd = open(file_path, O_RDONLY);
char end[2] = "1";
if (filefd == -1)
{
perror("open");
exit (EXIT_FAILURE);
}
while (1)
{
read_return = read(filefd, buffer, BUFSIZ);
if (read_return == 0)
{
printf("este 0 \n");
break;
}
if (read_return == -1)
{
perror("read");
exit (EXIT_FAILURE);
}
if (write(sock, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
}
// close(sock);
close(filefd);
}
The client is connecting normally and receives the file in this function
int recive_problemo(int *sockfd)
{
char *file_path = "path.c";
char buffer[BUFSIZ];
ssize_t read_return;
int filefd;
filefd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (filefd == -1)
{
perror("open");
exit (EXIT_FAILURE);
}
do
{
read_return = read(sockfd, buffer, BUFSIZ);
if (read_return == -1)
{
perror("read");
exit (EXIT_FAILURE);
}
if (write(filefd, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
} while (read_return > 0);
close(filefd);
}
I kind of managed how to solve this. If i shutdown(SHUT_WR) from server the client isnt stuck anymore, but i want to communicate with it further.
Also with the same function if i transfer from client to server, it works perfectly, so can anyone help me please?

do
{
read_return = read(sockfd, buffer, BUFSIZ);
// error handling
// file write
} while (read_return > 0);
Will keep looping until the socket closes or there's an error. It has no way to tell if a file has finished.
Common solutions are to close the socket (but you don't want that) and establish a communication protocol so that you know when the file is done and can exit the loop.
To keep things very simple, I recommend sending the length of the file before sending the file. The loop now looks something like:
uint64_t file_len;
read_return = recv(sockfd, &file_len, sizeof(file_len), MSG_WAITALL);
if (read_return == sizeof(file_len))
{
// Strongly consider handling the endian of file_len here
while (file_len)
{
size_t readmax = std::min(file_len, BUFSIZ);
read_return = read(sockfd, buffer, readmax);
if (read_return > 0)
{
if (write(filefd, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
file_len -= read_return;
}
else
{
// handle error
// exit loop if not recoverable
}
}
}
The server end picks up the responsibility of getting and sending the length of the file. I won't get into that because there are too many different ways to get the length of a file. Pick your favourite.
Documentation on recv and MSG_WAITALL.

Related

c++ socket accept() get Resource deadlock avoided errno with epoll [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm a C++ beginner learning I/O multiplexing.
Here is my code:
test.cpp (doesn't use epoll() and works well):
#include <iostream>
#include <cstdio>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
int main() {
std::cout << "Hello" << std::endl;
char buffer[1024];
buffer[0] = 'f';
fprintf(stdout, "%s", buffer);
std::cout << "Hello" << std::endl;
int serverFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
// bind & listen
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(80);
int bindResult = bind(serverFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
if (bindResult < 0) {
fprintf(stderr, "Fail to bind\n");
return 1;
}
int listenResult = listen(serverFd, 1024);
if (listenResult < 0) {
fprintf(stderr, "Fail to listen\n");
return 1;
}
struct sockaddr clientAddr;
unsigned int clientlen = sizeof(clientAddr);
int acceptFd = accept(serverFd, &clientAddr, &clientlen);
if (acceptFd < 0) {
fprintf(stderr, "Fail to create client connection file descriptor\n");
return 1;
}
int fd = acceptFd;
ssize_t received = recv(fd, &buffer, 1024, 0);
if (received < 0) {
fprintf(stderr, "Fail to received bytess from client\n");
if (errno == EINTR) {
fprintf(stderr, "Reason: EINTR\n");
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
fprintf(stderr, "Reason: EAGAIN or EWOULDBLOCK\n");
} else {
fprintf(stderr, "Reason: %d\n", errno);
close(fd);
return 1;
}
} else if (received == 0) {
close(fd);
} else {
buffer[received] = '\0';
fprintf(stdout, "%s", buffer);
}
}
test_2.cpp (does use epoll() and doesn't work well):
#include <iostream>
#include <sys/epoll.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
int main() {
// TODO: too much error message to handle, so it's necessary to deal with it (maybe macros can)
std::cout << "Hello" << std::endl;
// process ignore SIGPIPE which is caused by send(), or process will exit, which is hard to find out
signal(SIGPIPE, SIG_IGN);
// here needs a socket fd or other fd
// well, AF_INET is okay;socket(PF_INET, SOCK_SEQPACKET, 0) is sctp, tcp cannot use SOCK_SEQPACKET :(
// when using tcp, watch out **record boundaries**
int serverFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverFd < 0) {
fprintf(stderr, "Fail to create socket file descriptor\n");
return 1;
}
// nonblock
// nonblock
int flags = fcntl(serverFd, F_GETFL, 0);
if (flags < 0) {
fprintf(stderr, "Fail to get flags\n");
return 1;
}
int setFlagResult = fcntl(serverFd, F_SETFL, flags | O_NONBLOCK);
if (setFlagResult < 0) {
fprintf(stderr, "Fail to set flags\n");
return 1;
}
// bind & listen
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(80);
int bindResult = bind(serverFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
if (bindResult < 0) {
fprintf(stderr, "Fail to bind\n");
return 1;
}
int listenResult = listen(serverFd, 1024);
if (listenResult < 0) {
fprintf(stderr, "Fail to listen\n");
return 1;
}
// epoll fd
int epollFd = epoll_create(1);
if (epollFd < 0) {
fprintf(stderr, "Fail to create epoll file descriptor\n");
return 1;
}
// event
struct epoll_event event, events[1024];
event.events = EPOLLIN;
event.data.fd = serverFd;
// ctl
int ctlResult = epoll_ctl(epollFd, EPOLL_CTL_ADD, serverFd, &event);
if (ctlResult < 0) {
fprintf(stderr, "Fail to run epoll_ctl\n");
return 1;
}
// wait
while (1) {
int event_count = epoll_wait(epollFd, events, 1024, -1);
for (int i = 0; i < event_count; i++) {
struct epoll_event event = events[i];
// accept
if (event.data.fd == serverFd) {
unsigned int clientlen = sizeof(clientAddr);
int acceptFd = accept(serverFd, (struct sockaddr *) &clientAddr, &clientlen);
if (acceptFd < 0) {
fprintf(stderr, "Fail to create client connection file descriptor\n");
fprintf(stderr, "Fail Reason: %d\n", errno);
return 1;
}
// nonblock
int flags = fcntl(acceptFd, F_GETFL, 0);
if (flags < 0) {
fprintf(stderr, "Fail to get flags\n");
return 1;
}
int setFlagResult = fcntl(acceptFd, F_SETFL, flags | O_NONBLOCK);
if (setFlagResult < 0) {
fprintf(stderr, "Fail to set flags\n");
return 1;
}
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = serverFd;
int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_ADD, acceptFd, &event);
if (ctlClientResult < 0) {
fprintf(stderr, "Fail to run epoll_ctl\n");
return 1;
}
// client recv
} else if (event.events & EPOLLIN) {
int fd = event.data.fd;
char buffer[1024+1];
ssize_t received = recv(fd, &buffer, 1024, 0);
if (received < 0) {
fprintf(stderr, "Fail to received bytess from client\n");
if (errno == EINTR) {
fprintf(stderr, "Reason: EINTR\n");
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
fprintf(stderr, "Reason: EAGAIN or EWOULDBLOCK\n");
} else {
fprintf(stderr, "Reason: %d\n", errno);
close(fd);
int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, &event);
if (ctlClientResult < 0) {
fprintf(stderr, "Fail to run epoll_ctl\n");
return 1;
}
return 1;
}
} else if (received == 0) {
int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, &event);
if (ctlClientResult < 0) {
fprintf(stderr, "Fail to run epoll_ctl\n");
return 1;
}
close(fd);
} else {
buffer[received] = '\0';
fprintf(stdout, "%s", buffer);
// if you want to send something...
event.events |= EPOLLOUT;
// here is some data that event can hold
event.data.u32 = (uint32_t) 1;
// you can now send data or just put event in epoll, which is maybe easier
int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_MOD, fd, &event);
if (ctlClientResult < 0) {
fprintf(stderr, "Fail to run epoll_ctl\n");
return 1;
}
}
// client send
} else if (event.events & EPOLLOUT) {
int fd = event.data.fd;
char buffer[] = "I see you";
ssize_t sendResult = send(fd, &buffer, 1024, 0);
if (sendResult < 0) {
fprintf(stderr, "Fail to received bytess from client\n");
if (errno == EINTR) {
fprintf(stderr, "Reason: EINTR\n");
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
fprintf(stderr, "Reason: EAGAIN or EWOULDBLOCK\n");
} else {
if (errno == EPIPE) {
fprintf(stderr, "Reason: EPIPE\n");
} else {
fprintf(stderr, "Reason: %d\n", errno);
}
close(fd);
int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, &event);
if (ctlClientResult < 0) {
fprintf(stderr, "Fail to run epoll_ctl\n");
return 1;
}
return 1;
}
} else if (sendResult == 0) {
event.events = EPOLLIN;
int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_MOD, fd, &event);
if (ctlClientResult < 0) {
fprintf(stderr, "Fail to run epoll_ctl\n");
return 1;
}
} else {
// if you want to recv something...
// event.events |= EPOLLIN;
// // you can now send data or just put event in epoll, which is maybe easier
// int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_MOD, fd, &event);
// if (ctlClientResult < 0) {
// fprintf(stderr, "Fail to run epoll_ctl\n");
// return 1;
// }
}
}
}
}
return 0;
}
When I try to make a TCP socket connection (such as curl -v "http://host:80/", which can make test2.cpp run in line 81), acceptFd is < 0 and errno is 11 according to line 84, which means "Resource deadlock avoided".
Why? There isn't any thread-related code, is it?
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = serverFd;
int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_ADD, acceptFd, &event);
When you add the newly-accepted connection to the epoll set, you tell it to report it as a hit on serverFd. So when the client sends you data, you try to accept a new connection instead.
Change event.data.fd = serverFd to event.data.fd = acceptFd.
Then you can move on to your next bug:
char buffer[] = "I see you";
ssize_t sendResult = send(fd, &buffer, 1024, 0);
1024?!
Also, any time you use non-blocking sockets, you should add code to handle EAGAIN or EWOULDBLOCK errors as non-fatal.
Error code 11 is EAGAIN, which is a very common error code to encounter when dealing with non-blocking socket I/O. It means the requested operation has nothing to do, try it again later.
In the case of accept(), it means:
EAGAIN or EWOULDBLOCK
The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 and POSIX.1-2008 allow either error to be returned for this case, and do not require these constants to have the same value, so a portable application should check for both possibilities.
This means you are calling accept() at the wrong time, when the listening socket does not have any clients to accept. Double check your epoll() usage, it likely has a logic bug in it that is causing you to call accept() prematurely.
For instance, after accept() has successfully accepted a client, you are assigning the listening socket instead of the client socket to event.data.fd when calling epoll_ctl(EPOLL_CTL_ADD):
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = serverFd; // <-- HERE, SHOULD BE acceptFd INSTEAD!
int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_ADD, acceptFd, &event);
As such, when the client has data waiting to be read, your loop will end up calling accept() on the listening socket instead of calling recv() on the client socket.
Also, you are not checking the reported event.events field for socket errors. If an error occurs on a client socket, the reported events may include the EPOLLERR and/or EPOLLHUP flags. You should check for those flags and if present then close the client socket, before checking for the EPOLLIN flag to call recv().
Also, note that in your example, it is not necessary to call epoll_ctl(EPOLL_CTL_DEL) before calling close() on a socket. Closing a socket file descriptor will automatically remove it from the epoll instance that is monitoring it.

HTTPS proxy never manages to connect successfully

What I'm trying to do is a forking proxy that deals HTTP(S) connections: while GET (without SSL) requests are successfully executed and the contents are delivered to the client, when it comes to CONNECT method things are not going well, since connect()ing to the remote server may not immediately succeeds: in fact, it nevers succeeds.
I tried for a non blocking socket connected to the remote server, so I can see if connect() goes immediately or takes some time: in the second case, I'd call select() to see when the remote server is ready to send data to me: yet, connect() never connects.
Here's my proxy main() code:
int main(int argc, char *argv[]) {
// ClientManager.cpp is described below
ClientManager cm;
//listening on port given by argv
if (cm.startListeningForClient(listening_port)) {
while(true) {
int new_client_socket = cm.acceptConnectionFromClient();
if (new_client_socket >= 0) {
cm.forkAndManageClient();
}
else {
perror("accept error");
}
}
} else {
perror("Error on start listening");
}
return EXIT_SUCCESS;
}
Now follows, with some omissis not involved with my issue, ClientManager.cpp, whose functions are called in main() above:
ClientManager::ClientManager() {
sockfd_client = -1; // socket connected to client
new_sockfd_client = -1; // socket accepting connection from client
sockfd_server = -1; // socket connected to remote server
}
// error controls omitted
bool ClientManager::startListeningForClient(int port) {
struct sockaddr_in serv_addr;
bzero((char*)&serv_addr,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(port);
serv_addr.sin_addr.s_addr=INADDR_ANY;
sockfd_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(sockfd_client,(struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(sockfd_client, 50);
return true;
}
// error controls omitted
int ClientManager::acceptConnectionFromClient(void) {
struct sockaddr_in cli_addr;
unsigned int clilen;
bzero((char*)&cli_addr, sizeof(cli_addr));
clilen = sizeof(cli_addr);
new_sockfd_client = accept(sockfd_client, (struct sockaddr*)&cli_addr, &clilen);
return new_sockfd_client;
}
int ClientManager::forkAndManageClient() {
// getRequestFromClient: the method below receives requests from
// clients and parses the infos I need (i.e. what method,
// hostname of remote server to be resolved, its port, ...)
getRequestFromClient();
// managing the HTTP(S) request by the child process
int pid = fork();
if (pid < 0) {
perror("ERROR on fork");
}
else if (pid > 0) {
// parent process
// do nothing
}
else {
// close immediately the client socket used for accepting new connections from the parent process
close (sockfd_client);
if (!manageRequest()) {
perror("Error managing request from client");
}
// close the connection from the client
close (new_sockfd_client);
new_sockfd_client = -1;
// the child process will terminate now
_exit(EXIT_SUCCESS);
}
return pid;
}
// now the problematic method...
bool ClientManager::manageRequest(void) {
// if this is a CONNECT request
if (rm.isCONNECT()) {
struct sockaddr_in remote_server;
int conn_res;
remote_server.sin_family = AF_INET;
remote_server.sin_addr.s_addr = rm.getServerAddr();
remote_server.sin_port = rm.getServerPort();
fd_set fdset;
struct timeval tv;
sockfd_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// make socket not blocking
int flags = fcntl(sockfd_server, F_GETFL, 0);
flags = flags | O_NONBLOCK;
if (fcntl(sockfd_server, F_SETFL, flags) == -1) {
perror("FCNTL:");
}
printf("CONNECT set socket to non-blocking mode\n");
conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in));
printf("AFTER CONNECT()\n");
if (conn_res < 0) {
if (errno != EINPROGRESS) {
printf("CONNECT: connect() failed, quitting\n");
return false;
}
}
printf("CONNECT connection is taking place...\n");
// connected immediately
if (conn_res == 0) {
printf("CONNECT connected OK!\n");
goto CONNECTED;
}
FD_ZERO(&fdset);
FD_SET(sockfd_server, &fdset);
tv.tv_sec = 5; // tried 5, 20, 60 seconds, but it always times out
tv.tv_usec = 0;
printf("CONNECT attempting select()\n");
if (select(sockfd_server+1, NULL, &fdset, NULL, &tv) == 0) {
errno = ETIMEDOUT;
close(sockfd_server);
sockfd_server = -1;
return false;
}
if (FD_ISSET(sockfd_server, &fdset)) {
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(sockfd_server, SOL_SOCKET, SO_ERROR, &so_error, &len) < 0) {
return false;
}
} else {
printf("sockfd_server not set\n");
}
CONNECTED:
fcntl(sockfd_server, F_SETFL, flags &~ O_NONBLOCK);
// yeah, now I will start to deal the HTTPS flow in both directions
return true;
}
}
It does manage setting socket to non blocking mode, and to print CONNECT connection is taking place..., but it always returns Error managing request from client: Connection timed out.
I apologize for posting miles of LOC, but this is what drives me crazy since days, and after reading posts, tutorial and guides, I really don't know what to do.
It connects now to every site which requires an HTTPS connection!
Proper error checking and following closing of socket descriptors were missing. Here's my code:
bool ClientManager::manageRequest(void) {
if (rm.isCONNECT()) {
struct sockaddr_in remote_server, local_bind;
int conn_res, select_res;
memset(&remote_server, 0, sizeof(remote_server));
remote_server.sin_family = AF_INET;
remote_server.sin_addr.s_addr = rm.getServerAddr();
remote_server.sin_port = rm.getServerPort();
memset(&local_bind, 0, sizeof(local_bind));
local_bind.sin_family = AF_INET;
local_bind.sin_addr.s_addr = htonl(INADDR_ANY);
local_bind.sin_port = htons(0);
fd_set rdset, wrset;
struct timeval tv;
sockfd_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd_server < 0) {
perror("socket: ");
}
if(!setNonBlocking(sockfd_server))
perror("fcntl");
debug_green("CONNECT set socket to non-blocking mode\n");
bind(sockfd_server, (struct sockaddr*) &local_bind, sizeof(local_bind));
conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in));
// The socket is nonblocking and the connection cannot be completed immediately
// check for EINPROGRESS
if ((conn_res == -1) && (errno != EINPROGRESS)) {
FD_ZERO(&rdset);
FD_SET(sockfd_server, &rdset);
wrset = rdset;
tv.tv_sec = 0;
tv.tv_usec = 0;
debug_yellow("CONNECT attempting select()\n");
do {
select_res = select(sockfd_server+1, &rdset, &wrset, NULL, &tv);
} while ((select_res == -1) && (errno == EINTR));
if ((!FD_ISSET(sockfd_server, &rdset)) && ((!FD_ISSET(sockfd_server, &wrset)))) {
debug_red("SELECT sockfds not responding\n");
close(sockfd_server);
sockfd_server = -1;
return false;
}
conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in));
if (conn_res == -1) {
if(errno == EISCONN)
printf ("connect(): connections already existing, OK\n");
else {
printf("connect() for safety check: connection NOT successfull\n");
close(sockfd_server);
sockfd_server = -1;
return false;
}
}
printf("connection OK\n");
fflush(stdout);
} else {
debug_green("Connection immediately OK\n");
fflush(stdout);
}
if (!setBlocking(sockfd_server)) {
perror("FCNTL:");
}
debug_green("CONNECT set socket back to blocking mode\n");fflush(stdout);
}
return true;
}
Functions setting blocking or non blocking socket:
bool ClientManager::setNonBlocking(int sockfd) {
printf("setting non block socket\n"); fflush(stdout);
int flags;
if ((flags = fcntl(sockfd, F_GETFL, 0)) < 0)
return false;
flags |= O_NONBLOCK;
if (fcntl(sockfd, F_SETFL, flags) < 0)
return false;
return true;
}
bool ClientManager::setBlocking(int sockfd) {
printf("setting block socket\n"); fflush(stdout);
int flags;
if ((flags = fcntl(sockfd, F_GETFL, 0)) < 0)
return false;
flags &= (~O_NONBLOCK);
if (fcntl(sockfd, F_SETFL, flags) < 0)
return false;
return true;
}
Debug functions:
#define DEFAULTCOLOR "\033[0m"
#define RED "\033[22;31m"
#define YELLOW "\033[1;33m"
#define GREEN "\033[0;0;32m"
#define debug_red(...) std::cout << RED << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout);
#define debug_yellow(...) std::cout << YELLOW << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout);
#define debug_green(...) std::cout << GREEN << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout);

Client socket connect() succeeds after server accept() times out

I'm working on a c++ class that acts as a high-level wrapper around sockets in linux. While testing it, I purposely made the server's accept() call time out by having the client application sleep for a few seconds before calling connect().
However, after the server times out, the client application is still able to call connect() and send data without detecting an error. This is obviously a problem, because the server is not receiving the data, so the client should know the connection failed.
Here is my code. The server app calls Socket::accept_connection() and the client app sleeps and then calls Socket::connect_to().
// Accept a connection on the server side with a timeout
Socket *Socket::accept_connection(double timeout) {
Socket *new_connection = NULL;
socklen_t sin_size;
struct sockaddr_storage client_address; // Client's address
struct sockaddr_in client_port_address; // Client's port
char s[INET6_ADDRSTRLEN];
sin_size = sizeof client_address;
fd_set rfds;
struct timeval timeout_structure;
timeout_structure.tv_sec = (long)(timeout);
timeout_structure.tv_usec = int((timeout - timeout_structure.tv_sec) * 1e6);
struct timeval *timeout_ptr = NULL;
if(timeout > 0)
timeout_ptr = &timeout_structure;
// Loop until the timeout has been reached
while(true) {
FD_ZERO(&rfds);
FD_SET(socket_desc, &rfds);
if(select(socket_desc + 1, &rfds, NULL, NULL, timeout_ptr) > 0) {
int client_sock = accept(socket_desc, (struct sockaddr *)&client_address, &sin_size);
if(client_sock == -1) {
// Failed to connect
connected = false;
continue;
} else {
// Connected
inet_ntop(client_address.ss_family, get_in_addr((struct sockaddr *)&client_address), s, sizeof s);
getpeername(client_sock, (struct sockaddr*)&client_port_address, &sin_size);
int client_port = ntohs(client_port_address.sin_port);
// ...
}
} else {
// Timed out
connected = false;
std::cout << "accept() timed out\n";
break;
}
}
return new_connection;
}
// Connect to the given ip address and port
bool Socket::connect_to(std::string server_ip, int server_port, double timeout) {
connected = false;
// Create the socket and allocate memory for reading in data
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
struct timeval timeout_structure;
timeout_structure.tv_sec = (long)(timeout);
timeout_structure.tv_usec = int((timeout - timeout_structure.tv_sec) * 1e6);
struct timeval *timeout_ptr = NULL;
if(timeout > 0)
timeout_ptr = &timeout_structure;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(server_ip.c_str(), std::to_string(server_port).c_str(), &hints, &servinfo)) != 0) {
fprintf(stderr, "Socket error: connect_to, getaddrinfo: %s\n", gai_strerror(rv));
throw;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((socket_desc = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("Socket error: connect_to, socket");
continue;
}
int flags = 0, error = 0, ret = 0;
fd_set rset, wset;
socklen_t len = sizeof(error);
//clear out descriptor sets for select
//add socket to the descriptor sets
FD_ZERO(&rset);
FD_SET(socket_desc, &rset);
wset = rset; //structure assignment ok
//set socket nonblocking flag
if((flags = fcntl(socket_desc, F_GETFL, 0)) < 0)
continue;
if(fcntl(socket_desc, F_SETFL, flags | O_NONBLOCK) < 0)
continue;
//initiate non-blocking connect
if(ret = connect(socket_desc, p->ai_addr, p->ai_addrlen) == -1) {
if (errno != EINPROGRESS) {
close(socket_desc);
perror("Socket error: connect_to, could not connect");
continue;
}
}
if(ret != 0) { // If connect did not succeed right away
// We are waiting for connect to complete now
if((ret = select(socket_desc + 1, NULL, &wset, NULL, timeout_ptr)) < 0)
return false;
if(ret == 0){ //we had a timeout
errno = ETIMEDOUT;
return false;
}
//we had a positive return so a descriptor is ready
if(FD_ISSET(socket_desc, &rset) || FD_ISSET(socket_desc, &wset)){
if(getsockopt(socket_desc, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error != 0)
return false;
} else
return false;
if(error){ //check if we had a socket error
errno = error;
return false;
}
}
//put socket back in blocking mode
if(fcntl(socket_desc, F_SETFL, flags) < 0)
return false;
break;
}
if(p == NULL) {
fprintf(stderr, "Socket error: connect_to, failed to connect\n");
socket_desc = 0;
return false;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s);
freeaddrinfo(servinfo); // all done with this structure
connected = true;
return connected;
}
This is normal, not a problem.
TCP maintains a listen backlog queue into which connections are placed that have been completed by the TCP stack but not yet accepted by the application.
TCP maintains a socket receive buffer per socket into which data is placed that has arrived from the peer and not yet been read by the application.
the client should know the connection failed.
It didn't fail. The server can accept it and read the data.

error in send data to server

Why when run the program and send data to server return this errorrecv failed: Transport endpoint is not connected or don't show server accepted just show the message of send data function in client
server.cpp:
int main() {
char packet[30];
char buffer[20] = "I got your message";
int conn_sock, comm_sock, n, m;
struct sockaddr_in server_addr, client_addr;
if ((conn_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Couldn't create socket");
exit(1);
}
cout << "Already create socket!!!\n" << endl;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(0);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(&server_addr, 0, sizeof(server_addr));
if (bind(conn_sock, (struct sockaddr *) &server_addr, sizeof(server_addr))
== -1) {
perror("couldn't bind");
exit(1);
}
if (listen(conn_sock, 10) == -1) {
perror("couldn't listen");
exit(1);
}
cout << "Listening For Connection...\r" << endl;
socklen_t len = sizeof(server_addr);
if (getsockname(conn_sock, (struct sockaddr *) &server_addr, &len) == -1)
perror("getsockname");
else
printf("port number %d\n", ntohs(server_addr.sin_port));
while (1) {
memset(&client_addr, 0, sizeof(client_addr));
if ((comm_sock = accept(conn_sock, (struct sockaddr *) &client_addr,
(socklen_t *) &client_addr)) == -1) {
perror("couldn't accept\n");
continue;
}
cout << "accepted" << endl;
bzero(packet, 10);
m = recv(conn_sock, packet, 10, 0);
if (m < 0) {
perror("recv failed");
exit(1);
}
cout<<"recieved"<<endl;
/* Write a response to the client */
n = send(conn_sock, buffer, sizeof(buffer), 0);
if (n < 0) {
perror("ERROR send to client");
exit(1);
}
close(n);
close(m);
close(comm_sock);
}
close(conn_sock);
return 0;
}
cilent.cpp:
#define MYPORT 51833
namespace personalization {
bool client::conn() {
//create socket if it is not already created
if (sock == -1) {
//Create socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("Could not create socket");
}
cout << "Socket created" << endl;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(MYPORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (connect(sock , (struct sockaddr *)&server_addr , sizeof(server_addr)) < 0)
{
perror("connect failed. Error");
return false;
}
cout<<"Connected\n";
return true;
close(sock);
}
bool client::send_data() {
//Send some data
if( send(sock , packet , sizeof( packet ) , 0) < 0)
{
perror("Send failed");
return false;
}
cout<<"Data send\n";
return true;
close(sock);
}
bool client::rec_data() {
char buffer[20];
string reply;
//Receive a echo from the server
if (recv(sock, buffer, sizeof(buffer), 0) < 0) {
perror("receive failed");
return false;
}
reply = buffer;
return true;
close(sock);
}
client::client() {
// TODO Auto-generated constructor stub
sock=-1;
}
output is:
server:Already create socket!!!
Listening For Connection...
port number 51833
client: Socket created
Connected
Data send
receive failed: Connection reset by peer
or:
server:Already create socket!!!
Listening For Connection...
port number 51833
client:Socket created
Connected
Data send
srver:accepted
recv failed: Transport endpoint is not connected
In the server's recv and send calls, you need to pass the socket returned from accept.
So instead of
m = recv(conn_sock, packet, 10, 0);
do
m = recv(comm_sock, packet, 10, 0);
Same goes for the send call.
Also, don't call close on n and m, that is to say remove these two lines of code:
close(n);
close(m);
EDIT: Sorry, while I'm at it, this is probably not what you intended in the client's send_data and rec_data:
return true;
close(sock);

C++ send file and text via socket

Im trying to send a image using socket but I have to send the file name as well. Im using a code that i send the file but when I send the file name i receive some strange characters in client.
Client:
#define PORT 20000
#define LENGTH 512
int main(int argc, char *argv[]){
int sockfd;
int nsockfd;
char revbuf[LENGTH];
struct sockaddr_in remote_addr;
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno);
exit(1);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
exit(1);
}
else
printf("[Client] Connected to server at port %d...ok!\n", PORT);
/* Send File to Server */
//if(!fork())
//{
char* fs_name = "house.jpg";
char sdbuf[LENGTH];
char buffer[256];
int n;
fgets(buffer,255,stdin);
bzero(buffer,256);
n = write(sockfd,buffer, strlen(buffer));
if(n<0) printf("Error: sending filename");
printf("[Client] Sending %s to the Server... ", fs_name);
FILE *fs = fopen(fs_name, "r");
if(fs == NULL)
{
printf("ERROR: File %s not found.\n", fs_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
break;
}
bzero(sdbuf, LENGTH);
}
printf("Ok File %s from Client was Sent!\n", fs_name);
//}
close (sockfd);
printf("[Client] Connection lost.\n");
return (0);
}
Part of client that sends the text:
char buffer[256];
int n;
fgets(buffer,255,stdin);
bzero(buffer,256);
n = write(sockfd,buffer, strlen(buffer));
if(n<0) printf("Error: sending filename");
Server:
#define PORT 20000
#define BACKLOG 5
#define LENGTH 512
int main ()
{
int sockfd;
int nsockfd;
int num;
int sin_size;
struct sockaddr_in addr_local; /* client addr */
struct sockaddr_in addr_remote; /* server addr */
char revbuf[LENGTH];
/* Get the Socket file descriptor */
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor. (errno = %d)\n", errno);
exit(1);
}
else
printf("[Server] Obtaining socket descriptor successfully.\n");
/* Fill the client socket address struct */
addr_local.sin_family = AF_INET; // Protocol Family
addr_local.sin_port = htons(PORT); // Port number
addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct
/* Bind a special Port */
if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
{
fprintf(stderr, "ERROR: Failed to bind Port. (errno = %d)\n", errno);
exit(1);
}
else
printf("[Server] Binded tcp port %d in addr 127.0.0.1 sucessfully.\n",PORT);
/* Listen remote connect/calling */
if(listen(sockfd,BACKLOG) == -1)
{
fprintf(stderr, "ERROR: Failed to listen Port. (errno = %d)\n", errno);
exit(1);
}
else
printf ("[Server] Listening the port %d successfully.\n", PORT);
int success = 0;
while(success == 0)
{
sin_size = sizeof(struct sockaddr_in);
/* Wait a connection, and obtain a new socket file despriptor for single connection */
if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1)
{
fprintf(stderr, "ERROR: Obtaining new Socket Despcritor. (errno = %d)\n", errno);
exit(1);
}
else
printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));
char buffer[256];
bzero(buffer,256);
int n = 0;
n = read(nsockfd, buffer, 255);
if (n < 0) error("ERROR reading from socket");
printf("msg: %s\n",buffer);
/*Receive File from Client */
char* fr_name = "/house.jpg";
FILE *fr = fopen(fr_name, "a");
if(fr == NULL)
printf("File %s Cannot be opened file on server.\n", fr_name);
else
{
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0)
{
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz)
{
error("File write failed on server.\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512)
{
break;
}
}
if(fr_block_sz < 0)
{
if (errno == EAGAIN)
{
printf("recv() timed out.\n");
}
else
{
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
exit(1);
}
}
printf("Ok received from client!\n");
fclose(fr);
}
}
}
Part of server that receive the text:
char buffer[256];
bzero(buffer,256);
int n = 0;
n = read(nsockfd, buffer, 255);
if (n < 0) error("ERROR reading from socket");
printf("msg: %s\n",buffer);
Need some help with that. Thanks...
In this code in your client:
char buffer[256];
int n;
fgets(buffer,255,stdin);
bzero(buffer,256);
n = write(sockfd,buffer, strlen(buffer));
It looks like you are trying to read the file name from the stdin and send it on the sockfd. But. you zero out the buffer before you send it.