I have this UDP Client-Server chat, a small program that I made for a university course, everything runs just fine. But the professor asked me what would happen if a user crashed while sending a message, the server will keep waiting to receive the message from the client that does not exist anymore, so will wait forever. I tried to think of a solution but couldn't find one and really hope someone can help me.
I will leave just the snippet of code that causes the issue. If needed I can provide more or even the full repo.
void Forward_message(int sockfd, ListHead* head, struct sockaddr_in cliaddr){
Message msg = {0};
int len = sizeof(cliaddr);
if(head->size >1){
int read_bytes;
do{
read_bytes = 0;
read_bytes = recvfrom(sockfd,(Message *)&msg, sizeof(Message),MSG_WAITALL,(struct sockaddr* )&cliaddr, &len );
if(read_bytes == -1)perror("An error occurred while receiving Message from the Client"),exit(1);
}while( (read_bytes != sizeof(Message)) );
Send_msg(&msg,sockfd,head);
printf("\nmessage forwarded\n");
}
}
The issue is caused by the recvfrom inside the do while.
Related
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?
Right now, I'm trying to write a simple client/server application in order to measure the round trip time on a LAN for TCP messages of various sizes (I'm doing the timing client side). The program works fine for small packet sizes (> 1000 bytes) but I end up with a segmentation fault: 11 error for inputs of larger magnitude (10KB or greater).
int main()
{
struct sockaddr_in sin;
char buf[MAX_LINE];
int len;
int s, new_s;
/* build address data structure */
bzero((char *)& sin, sizeof( sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons( SERVER_PORT);
/* setup passive open */
if (( s = socket( PF_INET, SOCK_STREAM, 0)) < 0) {
perror("tcp program: socket");
exit(1);
}
if (( bind(s, (struct sockaddr *)& sin, sizeof(sin))) < 0) {
perror("tcp program: bind");
exit( 1);
}
listen(s, MAX_PENDING);
/* wait for connection, then receive and print text */
while(1) {
socklen_t lent = (unsigned int)&len;
if ((new_s = accept(s, (struct sockaddr *)& sin, &lent)) < 0) {
perror("tcp program: accept");
exit( 1);
}
while ((len = recv(new_s, buf, sizeof(buf), 0))){
char msg[len];
send( new_s, msg, len, 0); //echo message of same length as received message
}
close(new_s);
}
}
Again, the goal was to measure RTT, so I wanted the client to send a message, the above server to receive it, then send back a message of equivalent size. I also wanted the server to continue spinning so that the client could run iteratively, sending messages of 1KB, 10KB,...1000KB, etc. However, such iterations usually result in a segmentation fault.
Oddly enough, if I configure my client to run, for example, a single 12KB message send, the server does fine, and continues to run. And if I wait a couple of seconds, I can even repeatedly call my client and the server keeps up. But if I run the single message send in rapid succession, I end up with the segfault again.
Any ideas? I apologize in advance for any elementary errors in style or format. This is my first real foray into the C language beyond "hello world".
Thanks!
I don't know if this is the only part of the code that is wrong, but this is wrong:
while ((len = recv(new_s, buf, sizeof(buf), 0)))
Please read the man page for recv(), in particular (emphasis added)...
These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an orderly shutdown.
We know that networks are unreliable, and it is fairly common for recv() and friends to return errors.
Additionally, variable-length arrays in C are a fairly dangerous construct, because they perform dynamic allocation on the stack. They're basically alloca() in disguise, and we know how dangerous alloca() is. So this bit:
char msg[len]; // serious problems unless we have good bounds for len
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.
I've been trying to write a POP3 client for yahoo, but whenever I send a valid command, I cannot read from socket . I know it's not safe to create applications that deal in plaintext over the web, but I'm just trying to learn more about POP3 for now.
I'm creating a graphic interface using QT , but I believe this is irrelevant for now.
First of all, I made sure that yahoo supports plaintext communication by running simple commands in the terminal:
telnet pop.mail.yahoo.com 110
+OK hello from popgate-0.8.0.504347 pop011.mail.ir2.yahoo.com
user validuser
+OK password required.
pass validpassword
+OK maildrop ready, 100 messages (134513 octets) (13531)
This is how I handle opening the connection:
int openConnection(char ip[], int port)
{
//descriptor of socket
int sd;
struct sockaddr_in server;
//fill in server structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr (ip);
server.sin_port = htons (port);
//create communication socket
if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
//if cannot create, return error
return -2;
}
if (connect (sd, (struct sockaddr *) &server,sizeof (struct sockaddr)) == -1)
{
return -1;
}
return sd;
//values to be returned
//-2 - could not create socket
//-1 - could not connect to server
//socket descriptor in case of success
}
I get no problem with creating the socket and connecting when I call
int sd = openConnection ("188.125.68.106", 110)
(188.125.68.106 = ip of pop.mail.yahoo.com)
I can even read the welcoming message without using select or epoll.
char message[80];
read (sd, message, 80);
Message:
+OK hello from popgate-0.8.0.504347 pop011.mail.ir2.yahoo.com
I can also send all sorts of invalid commands, and read the error returned
int sd = openConnection ("188.125.68.106", 110)
write (sd,"this command is invalid",80);
char messageFromS [80];
bzero (messageFromS, 80);
read (sd,messageFromS,80);
And I get something between the lines of
-ERR invalid command
But whenever I send a valid command, my client just freezes up after calling read and I have to force quit
write (sd,"user validuser",80);
char messageFromS [80];
bzero (messageFromS, 80);
read (sd,messageFromS,80);
Afterwards, I decided to use select() because I know it's a good practice, and maybe it could give good results
//function returns true (1) if we can read from the socket
bool isClosed(int sock)
{
fd_set rfd;
FD_ZERO(&rfd);
FD_SET(sock, &rfd);
timeval tv;
//timeout value is set to 5 seconds
tv.tv_sec = 5;
select(sock+1, &rfd, 0, 0, &tv);
if (!FD_ISSET(sock, &rfd))
return false;
int n = 0;
ioctl(sock, FIONREAD, &n);
return n == 0;
}
But it seems that whenever I call
isClosed(sd)
It always returns True.
This is the point where I cannot think of any other options. Is there anything that Telnet has that my miniature client doesn't ?
EDIT: Thank you for your answers.
I played around with reading all the messages received byte by byte, until it found a termination character (apparently it wasn't NULL), and, after re-reading the RFC for pop3 (https://www.rfc-editor.org/rfc/rfc1081) closely I realized that I wasn't ending my commands properly. I should have appended '\r' and '\n' to the end of all commands sent.
I also checked the select () command, which returned -1 and set the tv.tv_usec = 0 which pretty much solved it.
Thank you for your answers.
I played around with reading all the messages received byte by byte, until it found a termination character (apparently it wasn't NULL), and, after re-reading the RFC for pop3 (https://www.rfc-editor.org/rfc/rfc1081) closely I realized that I wasn't ending my commands properly. I should have appended '\r' and '\n' to the end of all commands sent.
I also checked the select () command, which returned -1 and set the tv.tv_usec = 0 which pretty much solved it.
– Shoshinsha purogurama
I'm writing a program that's supposed to send C structures via ZeroMQ.
Therefore I'm using Google's ProtocolBuffers to serialize the structs.
I do now have the problem that my subscriber side is not receiving anything.
The Publisher prints out "Message successfully sent" so I think the Error occurs on the Subscribers side.
Publisher:
int main (void)
{
Message protomsg = MESSAGE__INIT;
void *buf;
unsigned len;
void *context = zmq_ctx_new();
void *subscriber = zmq_socket(context, ZMQ_PUB);
zmq_bind(subscriber, "ipc://my.sock");
//Initialising protomsg (not so important)
//sending message
len = message__get_packed_size(&protomsg);
buf = malloc(len);
message__pack(&protomsg, buf);
zmq_msg_t output;
zmq_msg_init_size(&output, len);
zmq_msg_init_data(&output, buf, len, NULL, NULL);
if(zmq_msg_send(&output, subscriber, 0) == -1)
perror("Error sending message \n");
else
printf("Message successfully sent \n");
zmq_msg_close(&output);
free(buf);
zmq_close (subscriber);
zmq_ctx_destroy (context);
return 0;
}
Subscriber:
int main (void){
Message *protomsg;
void *context = zmq_ctx_new ();
void *publisher = zmq_socket (context, ZMQ_SUB);
zmq_connect(publisher, "ipc://my.sock");
zmq_setsockopt(publisher, ZMQ_SUBSCRIBE, "", 0);
// Read packed message from ZMQ.
zmq_msg_t msg;
zmq_msg_init(&msg);
if(zmq_msg_recv(&msg, publisher, 0) == -1)
perror("Error receiving message \n");
else
printf("Message received");
memcpy((void *)protomsg, zmq_msg_data(&msg), zmq_msg_size(&msg));
// Unpack the message using protobuf-c.
protomsg = message__unpack(NULL, zmq_msg_size(&msg), (void *)&data);
if (protomsg == NULL)
{
fprintf(stderr, "error unpacking incoming message\n");
exit(1);
}
printf("Address: %u, Type: %u, Information[0]: %u, Information[1]: %u \n", protomsg->address-48, protomsg->frametype, protomsg->information[0], protomsg->information[1]);
zmq_msg_close (&msg);
// Free the unpacked message
message__free_unpacked(protomsg, NULL);
//close context,socket..
}
Don't know if anyone still cares about this, but here goes... I agree with #Steve-o that this is a timing issue, although I think the problem is that you are closing the publisher socket too soon.
Your publisher code publishes the message then immediately closes the socket and terminates the context. So the message exists in the publisher for milliseconds and then is gone forever.
If you run the publisher first, it does it's thing, exits and the message is gone. When you start the subscriber it attempts to connect to an IPC socket that is no longer there. ZeroMQ allows this and the subscriber will block until there is an IPC socket to connect to.
I have not reviewed the ZeroMQ IPC source code, but I suspect that, under the covers, subscriber is periodically attempting to connect to the publisher socket. Now if you run the publisher again, it might work but you have a serious race condition. If you start the publisher at the exact instant the ZeroMQ worker was attempting to retry, the connect might happen and you might even get your message before the publisher destroys everything.
I am pretty sure the problem has nothing to do with structs and protobuf. From the ZeroMQ point of view you are just sending bytes. There is no difference. If your test cases for ZeroMQ strings were truly identical with the test cases for ZeroMQ structs - then perhaps the code change added or removed a few nano-seconds that was able to break the race condition the wrong way.
Specific suggestions:
rename the socket in publisher to be "publisher" instead of subscriber (copy/paste error)
add a sleep for 30 seconds just before zmq_close (publisher);
hopefully this will fix the problem for your test code
if this does not fix it, consider switching to tcp transport and use wireshark to diagnose what is really going on.