alanxz / rabbitmq-c

RabbitMQ C client
MIT License
1.76k stars 665 forks source link

"recv_with_timeout" in "amqp_try_recv" set timeout to 0,cause infinite waiting for message! #788

Open carbinmeng opened 1 year ago

carbinmeng commented 1 year ago

hello, as line 732 in amqp_socket.c the flollowing code within amqp_try_recv return the amqp_time_infinite(),and then recv_with_timeout will wait infinitely.

res = amqp_time_from_now(&timeout, &(struct timeval){0});

I am currently pushing messages to the RabbitMQ server via VPN. If the VPN connection is unexpectedly disconnected during the communication process, the amqp_basic_publish function will not immediately return an error message. By checking the underlying TCP connection status using "netstat", it can be observed that the status remains as "ESTABLISHED",and it will close automaticlly in 15 to 20 minutes which is decided by linux. Upon examining the source code, it appears that an infinite wait is set in the mentioned section, though the reasoning behind it is unclear. Could you please confirm if it is appropriate to modify it as follows, or would there be any other implications? Thank you.

res = amqp_time_s_from_now(&timeout, amqp_heartbeat_recv(state));

alanxz commented 1 year ago

What version of rabbitmq-c are you using? #614 changed the behavior of amqp_time_from_now, which introduced the bug I think you're having (released in v0.11). #780 fixed this bug (which is not in a released version yet).

Does the current master branch work correctly?

carbinmeng commented 11 months ago

i am using version 0.13.0 now. i also checked the latest source code on the master branch in Aug(last month).the file amqp_socket.c i quoted in my question earlier is taken from this version. both versions have the same issue as i mentioned.

alanxz commented 7 months ago

I've had a chance to look at the code path in question. The intent of amqp_try_recv is to determine whether if there's any data available to read from underlying socket (e.g., can the read heartbeat be satisfied). amqp_time_from_now(&timeout, &(struct timeval){0}) should return a timestamp for the current time, which is later should be turned into a value passed into poll here or select here that means return immediately.

Note that amqp_time_from_now(&timeout, &(struct timeval){0}) defined here should return an amqp_time_t representing the current timestamp.

amqp_time_tv_until defined here should set an a struct timeval{0, 0} when the time parameter is in the past

amqp_time_ms_until defined here should return a 0-value when the time parameter is in the past.

If you still happen to have the example in question: where in the rabbitmq-c code is it being blocked (if you have a stack-trace that'd be helpful)? And if its blocked in poll or select, what is the value of the timeout parameter?