-
Notifications
You must be signed in to change notification settings - Fork 266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UTP_Write not writing? #47
Comments
From the README:
And from the header:
So you would copy |
Ok, I think I understand this, but if I call UTP_Write(utp_socket, 100), I would expect a call of my UTPOnWriteProc, but the function that I register never seems to be called (I put printf statements in my UTPOnWriteProc). My UTPOnWriteProc looks like this: void utp_write(void* socket, byte* bytes, size_t count)
{
int i;
// copy data over to bytes
for (i = 0; i < count; i++) {
bytes[i] = *(g_dbuf++);
}
printf("did some writn\n");
g_total_count += count;
} where g_dbuf is a global variable holding the bytes, and g_total_count is a global variable counting how many bytes have been sent total. Why doesn't the utp_write get called? |
It's possible the socket is not writable at this time. What does UTP_Write return? To answer your previous question; you call UTP_IsIncomingUTP to process the received packet with libutp. This is necessary as all uTP packets are UDP packets, including the connection handshakes, ACKs, etc. You can't send on a uTP socket until it is connected, and you can't connect without processing the replied ACK. So my guess is that you aren't calling UTP_Connect at all. When forming an outgoing connection you must call UTP_Connect and then wait for the on_state callback to give you UTP_STATE_CONNECT (and in the future, UTP_STATE_WRITABLE as the write buffer has more room available). |
Thanks so much for the help thus far. I have set up a recvfrom / UTP_IsIncomingUTP loop on both my send side and receive side. I think it's in some sort of deadlock state however. My program needs to send chunks of data at a time. From what I can tell, I call UTP_Connect, my send side goes into the recvfrom loop, acknowledges the handshake from the receive side, the state changes to UTP_STATE_CONNECT which triggers a UTP_Write (a la utp_file/utp_send.cpp), and I write a chunk. However, whenever I call UTP_Write outside of the utp_state function, it returns 0. Is the state changing without me knowing it? While I'm connected, shouldn't I be fine? Why are these UTP_Writes failing? Is it possible the buffer is full, and if so, is there a way to check that state, or increase the buffer? Thanks again. |
UTP_Write returning 0 does mean the buffer is full. When there is space in the buffer again, on_state will be called with UTP_STATE_WRITABLE. |
I can't understand why the buffer would be full though. The utp_write callback only gets called once (corresponding, I suppose, with the one UTP_Write function that actually works). Do the failed UTP_Write calls fill up the buffer as well? Is there a way to flush the buffer? |
The buffer automatically flushes. It can also be quite small to start - it is related to the number of packets in flight on the network, which is adjusted according to latency and packet loss. The odd write system libutp has is designed to minimize the size of buffers, and fetch data only when it needs it, with excessive copying. |
Can this buffer flush or change size while blocking in the recv call? If not, that may be causing the problem I have where both the receiver and the sender are stuck in their recv calls at the same time, and neither can break out because the sender is not sending. If so, it still doesn't seem to be automatically flushing or changing size for me. Is it possible that the receive buffer is the problem? Because I don't do anything with the received bytes except count them. Do *bytes in on_read need to be freed? |
The on_read call doesn't need to do anything at all. It is your opportunity to read the bytes from the network, but you can just ignore them if you like. See the utp_file directory for an example of a sender and a receiver. |
Sorry for all the questions: I found the solution to my problems. I needed to alternate between UTP_CheckTimeouts() as well as checking my socket for new data, which I wasn't doing previously. Making sure there was no blocking on the recv call as well as using UTP_CheckTimeouts() made everything work like a charm. I should have known that since the library isn't threadsafe, something would need to call something actively for the previously registered callbacks to work. Many thanks once again. |
Hi; Largely got everything to work, as I mentioned in my previous comments. However, in situations with high packet loss, I am running up against an issue. I am running my two programs on VMs connected by a bridge. I place a delay of 50ms +- 10ms and a 10% chance of packet drop. They send and receive normally, but then a weird state is achieved. My code is in the select/CheckTimeouts loop, and, after no reaction for a few cycles of the loop, it will keep calling utp_state with a state of UTP_STATE_WRITABLE. In response, and similarly to the utp_file example, in such cases, I call UTP_Write(). However, utp_write is never called, and utp_state keeps getting called and calling UTP_Write, but no progress is ever made. Thanks |
What happens if you let it sit for minutes? Does the connection eventually time out? |
I've let it run for circa 10 minutes now and it hasn't yet timed out. Occasionally acks are sent/received, but as far as I can tell, nothing else is happening. |
Those might be the keep-alives. What does UTP_Write return? |
It's returning 0. But shouldn't it be writable? |
Returning 0 just means it can accept some, but not all, of your data. You should get a corresponding utp_write later. Are you passing <= 0 to UTP_Write by accident? Can you trace into UTP_Write and see how many bytes it's figured out it can take? |
After a little investigation, it seems as if it is never entering the loop in line 2727, while(conn->is_writeable(num_to_send) { When looking into that function, I have used a few helpful print statements for diagnosis when in the looped state: 6910 < 100 (send_quota / 100 < (int32)to_write) satisfaction returns false These results repeat without variation. |
Why is max_send so low? What are the values of max_window, opt_sndbuf and max_window_user? |
opt_sndbuf and max_window_user are far larger. max_window on the other hand, on a recent run, repeated at the value 565. Immediately before this its value was 10. I have seen it at multitude of values. It seems the take away here is that the value is less than 1382, which is the packet size I have always encountered. I decided to investigate where the value of max_window is set immediately before the bad state. It's set in the function apply_ledbat_ccontrol. Here's a standard run before it fails. scaled gain is -2915.819943 and max_window is 13747 |
Hm. Well, that seems like a bug. However if packet pacing is on, it seems it should allow you to send anyway. What are the values of USE_PACKET_PACING, max_window, to_write, cur_window, and cur_window_packets at the end of is_writable? |
USE_PACKET_PACING: 1, max_window: 607, to_write: 100, cur_window: 0, cur_window_packets:0 are all various values that I have gotten stuck in. Each one repeats ad nauseum. |
Hm. The error seems to be that is_writable is checking to see if we have room for a full packet, not the amount to be written. If you replace instances of packet_size in is_writable with to_write instead, does the problem go away? |
Sorry if this is the wrong place for this, but I think I may not be understanding the API of libutp, but my UTP_Write call is not writing. My general flow in the program is:
UTP_Create with my send_to function registered. send_to calls a udp sendto function, using the provided const byte *p as the data sent by the sendto function.
UTP_SetCallbacks with a utp_write function registered. utp_write only does housekeeping/ data statistics
UTP_Write with the socket and number of bytes I want to send.
Where does UTP_Write get the specific bytes that I want to write?
The test applications use a recv loop with a UTP_IsIncomingUTP, but I don't understand what the latter function does, or why I would need to receive if all I want to do is send.
Thanks.
The text was updated successfully, but these errors were encountered: