Is this normal socket behavior? - c

I have a small c program which continually accepts data from one server and then translates it and sends it to a second server. The second server (basically a terminal app) then sends back the command prompt characters. When I send data to the second server it works as expected. If I do not read the data returned from the second server, then the second time I send data it never receives the data even though my program sends it and does not generate any errors. If I read the data returned by the second server it works as expected.
Can anyone explain this behavior? I am just curious as to what is going on. Both my process and the remote processes are continually running.
int sendCCL_TCP(unsigned char *buf, struct sockaddr_in *ccladdr){
int n,outfd;
if ((outfd = socket(AF_INET, SOCK_STREAM, 0)) <0) {
fprintf(errorfd,"ERROR creating output socket to send CCL\n");
fclose(errorfd);
return(FALSE);
}
if (connect(outfd, (struct sockaddr *)ccladdr, sizeof(*ccladdr)) < 0) {
fprintf(errorfd,"ERROR connecting to CCL server (%i) %s \n",errno,strerror(errno));
fflush(errorfd);
}
else{
n = write(outfd, buf, strlen(buf));
if (n < 0) {
fprintf(errorfd,"ERROR writing to CCL server (%i) %s\n",errno,strerror(errno));
fflush(errorfd);
}
write(outfd,"\r",1);
//If I comment out the following, the remote server does not
//receive the data the second and subsequent times
n=read(outfd,buf,9);
}
close(outfd);
return(TRUE);
}

Related

How to manage UDP Message Forwarding with 2 Clients and 1 Server in Language C?

i am trying to implement 1 "Server" (broker) and 2 "Clients" in C with UDP Sockets. But i cant get it to work.
What is my Goal:
One of the clients (CLIENT A) can send a word to the Server and the server saves that word in a char[]. After that, everytime if the other Client (CLIENT B) sends a message to the server, and the word of Client A is contained in that message, the whole message will be sent to CLIENT A. If the word isnt in the message, nothing will happen.
The Implementation of the server without multiple Client A´s is no problem. But i cant get it to work with multiple Client A´s.
Lets face the problem:
The Server is listening with a select() to potential Client A and Client B.
if client B is sending a keyword, the code is doing the following:
if(FD_ISSET(server_cli, &server_fd)){
client_length = sizeof(client_addr);
bzero(buffer, sizeof(buffer));
nbytes = recvfrom(server_cli, buffer, sizeof(buffer), 0, (struct sockaddr *) &client_addr, &client_length);
memcpy(&save_ip[counter].client_address, &client_addr, sizeof(client_addr));
strcpy(save_ip[counter].topic, buffer);
fprintf(stderr, "\n[+] Subrequest from: %s - Topic: %s", inet_ntoa(save_ip[counter].client_address.sin_addr), save_ip[counter].topic);
counter = counter + 1;
}
save_ip[counter].client_address is a struct in an array (dont know how that is called - i am relatively new to C). Everytime a Client is sending a keyword, the counter is counter + 1 and the client- socket information from the struct i get from recvfrom() will be saved in there (that is the plan and that is working..)
if Client A is sending a message and the message contains the keyword of any of Client B´s it will do something like that:
else if( !strcmp( pub_topic, save_ip[temp_counter].topic )){
client_addr = save_ip[counter].client_address;
fprintf(stderr, "\nIP: %s", inet_ntoa(client_addr.sin_addr));
nbytes = sendto(server_cli, buffer, sizeof(buffer), 0, (struct sockaddr *) &save_ip[counter].client_address, sizeof(save_ip[counter].client_address));
fprintf(stderr, "\n\t[+] Sent Message to %s (User-Topic: %s)", inet_ntoa(save_ip[temp_counter].client_address.sin_addr), save_ip[temp_counter].topic);
So, as you can see... I am trying to save the sockaddr structs from clients in this:
struct clients {
struct sockaddr_in client_address;
int client_length_long;
char topic[512];
};
But that doesnt work at all. I can get IP Addresses and everything else from the struct (and the values are correct), but i cant integrate them in a sendto(). Nothing is received by Client B.
Is there any other/better solution? (Mine is not a solution - it doesnt work at all). Can you guys advice me something to get it to work?

C - Why does my server socket stop receiving data delivered by send() after one request?

I'm creating a program in c which listens to GET and PUT requests and routes them to an httpserver. The problem is that after about N requests (N = number of servers), the httpserver stops responding because it doesn't receive the data from the client after the first request.
I forward the data by accepting client connections using accept(), read from the client socket and put the data from the client in a buffer using recv until it returns 0. I send this buffer to the server using send():
int connect(int from, int to) {
char buf[BUFFSIZE];
int n = recv(from, buf, BUFFSIZE-1, 0);
if (n == 0) {
return 0;
}
buf[n] = '\0';
n = send(to, buf, n, 0);
if (n == 0) {
return 0;
}
return n;
}
int acceptfd = accept(listenfd, &client_addr, &client_addrlen)
connect(acceptfd, serverfd)
I was wondering if I wasn't properly detecting the end of the client's input, but I print the output of send() returns exactly the number of bytes I expect, but server doesn't receive it.
The server works perfectly every time, when I make requests to it independently. The server receives connections similarly (I can't change the server), it accepts client connections using accept() and it reads from that socket using recv. To clarify, I do not have the server code, but I have my own that works similarly to the one that I am using for this project that I also tested with (the problem persists) :
char buff[BUFF_SIZE + 1];
int client_sockd = accept(server_sockd, &client_addr, &client_addrlen);
int bytes = recv(server_sockd, buff, BUFF_SIZE, 0);
Is there something I could be misunderstanding about send() or maybe buffers? I have tried using the O_NONBLOCK flag and I use select() to determine which socket to read from so I don't know if blocking is the issue.

Multiclient server socket doesn't print the client messages

I'm trying to implement a client-server application with multiclients using threads. Just to try, I would like to print the messages from each client, but when I send messages from a client, the server does not print anything.
Server (thread code)
void comunicationHandler(void *socket)
{
int sock = *(int*) socket;
char msg[2000];
while ((strcmp(msg, "!quit")) != 0) {
if (recv(sock, msg, 2000, 0) < 0)
puts("Error recv");
printf("%s", msg);
}
puts("Client Disconnected\n");
}
when I send "!quit", the Server goes in a infinite loop printing the messages
Client
for(;;) {
printf("\nInserisci il msg: ");
scanf("%s", msg);
if (strcmp(msg, "!quit") == 0)
break;
write(sd, msg, 2000);
}
There are multiple problems with your code:
TCP is stream based, there is no guarantee that all the bytes you send will be received in one shot on the other side. You need to modify code to check what is the number of bytes received and is it atleast equal to the size of "!quit" before you go in for the "strcmp" comparison.
Better to null terminate the buffer once you receive the buffer equal to the size of "!quit"
It is not clear as to why you are sending a 2000 bytes buffer from the client when you intend to send only "!quit". Modify and send only appropriate size as needed
Check recv return value against 0 also
Break out of the loop in both server and client once the Job is done.
Server goes in a infinite loop
You want to test recv()'s result against 0 and quit in this case. 0 indicates that the client orderly closed the connection.

C - accept() accepting the same client twice?

I am facing one of the strangest programming problems in my life.
I've built a few servers in the past and the clients would connect normally, without any problems.
Now I'm creating one which is basically a web server. However, I'm facing a VERY strange situation (at least to me).
Suppose that you connect to localhost:8080 and that accept() accepts your connection and then the code will process your request in a separate thread (the idea is to have multiple forks and threads across each child - that's implemented on another file temporarily but I'm facing this issue on that setup as well so...better make it simple first). So your request gets processed but then after being processed and the socket being closed AND you see the output on your browser, accept() accepts a connection again - but no one connects of course because only one connection was created.
errno = 0 (Success) after recv (that's where the program blows up)
recv returns 0 though - so no bytes read (of course, because the connection was not supposed to exist)
int main(int argc, char * argv[]){
int sock;
int fd_list[2];
int fork_id;
/* Socket */
sock=create_socket(PORT);
int i, active_n=0;
pthread_t tvec;
char address[BUFFSIZE];
thread_buffer t_buffer;
int msgsock;
conf = read_config("./www.config");
if(conf == NULL)
{
conf = (config*)malloc(sizeof(config));
if(conf == NULL)
{
perror("\nError allocating configuration:");
exit(-1);
}
// Set defaults
sprintf(conf->httpdocs, DOCUMENT_ROOT);
sprintf(conf->cgibin, CGI_ROOT);
}
while(cicle) {
printf("\tWaiting for connections\n");
// Waits for a client
msgsock = wait_connection(sock, address);
printf("\nSocket: %d\n", msgsock);
t_buffer.msg = &address;
t_buffer.sock = msgsock;
t_buffer.conf = conf;
/* Send socket to thread */
if (pthread_create(&tvec, NULL, thread_func, (void*)&t_buffer) != 0)
{
perror("Error creating thread: ");
exit(-1);
}
}
free(conf);
return 0;
}
Here are two important functions used:
int create_socket(int port) {
struct sockaddr_in server, remote;
char buffer[BUFF];
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_in))) {
perror("binding stream socket");
exit(1);
}
gethostname(buffer, BUFF);
printf("\n\tServidor a espera de ligações.\n");
printf("\tUse o endereço %s:%d\n\n", buffer,port);
if (listen(sock, MAXPENDING) < 0) {
perror("Impossível criar o socket. O servidor vai sair.\n");
exit(1);
}
return(sock);
}
int wait_connection(int serversock, char *remote_address){
int clientlen;
int clientsock;
struct sockaddr_in echoclient;
clientlen = sizeof(echoclient);
/* Wait for client connection */
if ((clientsock = accept(serversock, (struct sockaddr *) &echoclient, &clientlen)) < 0)
{
perror("Impossivel estabelecer ligacao ao cliente. O servidor vai sair.\n");
exit(-1);
}
printf("\n11111111111111Received request - %d\n", clientsock);
sprintf(remote_address, "%s", inet_ntoa(echoclient.sin_addr));
return clientsock;
}
So basically you'd see:
11111111111111Received request - D
D is different both times so the fd is different definitely.
Twice! One after the other has been processed and then it blows up after recv in the thread function. Some times it takes a bit for the second to be processed and show but it does after a few seconds. Now, this doesn't always happen. Some times it does, some times it doesn't.
It's so weird...
I've rolled out the possibility of being an addon causing it to reconnect or something because Apache's ab tool causes the same issue after a few requests.
I'd like to note that even if I Don't run a thread for the client and simply close the socket, it happens as well! I've considered the possibility of the headers not being fully read and therefore the browsers sends another request. But the browser receives the data back properly otherwise it wouldn't show the result fine and if it shows the result fine, the connection must have been closed well - otherwise a connection reset should appear.
Any tips? I appreciate your help.
EDIT:
If I take out the start thread part of the code, sometimes the connection is accepted 4, 5, 6 times...
EDIT 2: Note that I know that the program blows up after recv failing, I exit on purpose.
This is certainly a bug waiting to happen:
pthread_create(&tvec, NULL, thread_func, (void*)&t_buffer
You're passing t_buffer, a local variable, to your thread. The next time you accept a client, which can happen
before another client finished, you'll pass the same variable to that thread too, leading to a lot of very indeterministic behavior.(e.g. 2 threads reading from the same connection, double close() on a descriptor and other oddities. )
Instead of passing the same local variable to every thread, dynamically allocate a new t_buffer for each new client.
Suppose ... after being processed and the socket being closed AND you see the output on your browser, accept() accepts a connection again - but no one connects of course because only one connection was created.
So if no-one connects, there is nothing to accept(), so this never happens.
So whatever you're seeing, that isn't it.

How do you keep a socket connection open indefinitely in C?

I'm trying to implement a C socket server in Linux using the code from Beej's sockets guide, which is here:
http://beej.us/guide/bgnet/examples/server.c
This works, and I've written a Windows client in C# to communicate with it. Once the client connects, I have it send a byte array to the server, the server reads it, then sends back a byte array. This works.
However, after this, if I have the client try to send another byte array, I get a Windows popup saying "An established connection was aborted by the software in your host machine." Then I have to re-connect with the client again. I want to keep the connection open indefinitely, until the client sends a disconnect command, but despite reading through Beej's guide, I just don't seem to get it. I'm not even trying to implement the disconnect command at present, I'm just trying to keep the connection open until I close the server.
I've tried removing the close() calls in Beej's code:
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
ProcessRequest(new_fd); // this is not Beej's code, I've replaced his code here (which was a simple string send()) with a function call that does a read() call, processes some data, then sends back a byte array to the client using send().
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
But that just gets me an infinite loop of "socket accept: bad file descriptor" (I tried removing both the close(new_fd) lines, together and apart, and the close(sockfd) as well.
Can anyone more versed with C socket programming give me a hint where I should be looking? Thank you.
The reason for the accept() problem is that sockfd isn't valid. You must have closed it somewhere. NB if you get such an error you shouldn't just keep retrying as though it hadn't happened.
The reason for the client problem is that you're only processing one request in ProcessRequest(), as its name suggests, and as you describe in your comment. Use a loop, reading requests until recv() returns zero or an error occurs.
Cause
The reason client faces error is because of close(new_fd) either by the server-parent or server-child.
Solution
At any point of time, a server may get two kind of events:
Connection request from a new client
Data from an existing client
The server have to honor both of them. There are two (major) ways to handle this.
Solution Approach 1
Design the server as a concurrent server. In Beej's guide it is
7.2. select()—Synchronous I/O Multiplexing
http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#select
Since OP's approach is not this one, we do not explore it further.
Solution Approach 2
At server, fork() a process per client. This is the approach OP has taken and we explore here. Essentially, it is fine tuning the ProcessRequest() function in OP's code. Here is a sketch.
void ProcessRequest( int new_fd ) {
char buffer[ N ];
for( ; ; ) { // infinite loop until client disconnects or some error
int const recvLen = recv( new_fd, buffer, sizeof buffer, 0 );
if( recvLen == 0 ) { break; } // client disconnected
else if( recvLen == -1 ) { perror( "recv" ); break; }
int const sendLen = send( new_fd, buffer, recvLen, 0 );
if( sendLen == -1 ) { perror( "send" ); break; }
// TODO if( sendLen < recvLen ) then send() in loop
}
}
Note
I am sorry for having the half-baked solution four few hours. While I was editing the answer, I lost connectivity to stackoverflow.com which lasted for couple of hours.

Resources