Specify packet size with Ruby TCPSocket - ruby

I am using Ruby to test a C# networking application, which uses sockets. I open the connection with #socket = TCPSocket.new(IP,PORT) and it works - until the text I want to send is longer than 1024 characters. Then Ruby splits the message into 2 parts. C++ and C# send the message as one packet, so the C# application doesn't need to join the parts.
The messages never get longer than approx. 2000 chars. Is there a possibility to set the packet size for TCPSocket?
EDIT:
All of your answers are correct, but after reading a lot of ruby socket questions here on SO I found the solution:
socket.send(msg,0x4)
does not split the message. The option for direct send makes the difference.
I don't know if this works over the internet, but it works in my test lab.
Thx for the help.

TCP is a stream protocol. It does not care about application "messages". TCP can theoretically send your 1024 bytes in one packet, or in 1024 packets.
That said, keep in mind that Ethernet MTU is 1500 bytes. Factor in IP header, which is normally 20, and TCP header, which is at least 20. Then your 2000-char message will have to be sent in at least two packets. TCP also does flow control, which might be relevant to the issue. The best way to find out what's going on on the wire is to use tcpdump or wireshark.

The number of packets required to transmit your data should have very little effect on the stream in practice. What you might be encountering is a buffering problem in your implementation.
A socket should only be written to when it's in a "writeable" state, otherwise you risk overflowing the output buffer and causing the connection to be dropped by your networking stack.
As a TCP/IP socket functions as a simple stream, where data goes in, and comes out in order, the effect of packet fragmentation should be mostly irrelevant except for extremely time-sensitive applications.
Make sure you flush your output buffer when writing to the socket or you may have some data left waiting to transmit:
#socket.write(my_data)
#socket.flush

Related

Is there any way to use IOCP to notify when a socket is readable / writeable?

I'm looking for some way to get a signal on an I/O completion port when a socket becomes readable/writeable (i.e. the next send/recv will complete immediately). Basically I want an overlapped version of WSASelect.
(Yes, I know that for many applications, this is unnecessary, and you can just keep issuing overlapped send calls. But in other applications you want to delay generating the message to send until the last moment possible, as discussed e.g. here. In these cases it's useful to do (a) wait for socket to be writeable, (b) generate the next message, (c) send the next message.)
So far the best solution I've been able to come up with is to spawn a thread just to call select and then PostQueuedCompletionStatus, which is awful and not particularly scalable... is there any better way?
It turns out that this is possible!
Basically the trick is:
Use the WSAIoctl SIO_BASE_HANDLE to peek through any "layered service providers"
Use DeviceIoControl to submit an AFD_POLL request for the base handle, to the AFD driver (this is what select does internally)
There are many, many complications that are probably worth understanding, but at the end of the day the above should just work in practice. This is supposed to be a private API, but libuv uses it, and MS's compatibility policies mean that they will never break libuv, so you're fine. For details, read the thread starting from this message: https://github.com/python-trio/trio/issues/52#issuecomment-424591743
For detecting that a socket is readable, it turns out that there is an undocumented but well-known piece of folklore: you can issue a "zero byte read", i.e., an overlapped WSARecv with a zero-byte receive buffer, and that will not complete until there is some data to be read. This has been recommended for servers that are trying to do simultaneous reads from a large number of mostly-idle sockets, in order to avoid problems with memory usage (apparently IOCP receive buffers get pinned into RAM). An example of this technique can be seen in the libuv source code. They also have an additional refinement, which is that to use this with UDP sockets, they issue a zero-byte receive with MSG_PEEK set. (This is important because without that flag, the zero-byte receive would consume a packet, truncating it to zero bytes.) MSDN claims that you can't combine MSG_PEEK with overlapped I/O, but apparently it works for them...
Of course, that's only half of an answer, because there's still the question of detecting writability.
It's possible that a similar "zero-byte send" trick would work? (Used directly for TCP, and adding the MSG_PARTIAL flag on UDP sockets, to avoid actually sending a zero-byte packet.) Experimentally I've checked that attempting to do a zero-byte send on a non-writable non-blocking TCP socket returns WSAEWOULDBLOCK, so that's a promising sign, but I haven't tried with overlapped I/O. I'll get around to it eventually and update this answer; or alternatively if someone wants to try it first and post their own consolidated answer then I'll probably accept it :-)

UDP Packets, Seen by Wireshark, Dropped by (do not even reach) WSARecvFrom

I have quite a bewildering problem.
I'm using a big C++ library for handling some proprietary protocol over UDP on Windows XP/7. It listens on one port throughout the run of the program, and waits for connections from distant peers.
Most of the time, this works well. However, due to some problems I'd experienced, I've decided to add a simple debug print directly after the call to WSARecvFrom (the win32 function used in the library to recv datagrams from my socket of interest, and tell what IP and port they came from).
Strangely enough, in some cases, I've discovered packets are dropped at the OS level (i.e. I see them in Wireshark, they have the right dst-port, all checksums are correct - but they never appear in the debug prints I've implanted into the code).
Now, I'm fully of the fact (people tend to mention a bit too often) that "UDP doesn't guarantee delivery" - but this is not relevant, as the packets are received by the machine - I see them in Wireshark.
Also, I'm familiar with OS buffers and the potential to fill up, but here comes the weird part...
I've done some research trying to find out which packets are dropped exactly. What I've discovered, is that all dropped packets share two things in common (though some, but definitely not most, of the packets that aren't dropped share these as well):
They are small. Many of the packets in the protocol are large, close to MTU - but all packets that are dropped are under 100 bytes (gross).
They are always one of two: a SYN-equivalent (i.e. the first packet a peer sends to us in order to initiate communications) or a FIN-equivalent (i.e. a packet a peer sends when it is no longer interested in talking to us).
Can either one of these two qualities affect the OS buffers, and cause packets to be randomly (or even more interesting - selectively) dropped?
Any light shed on this strange issue would be very appreciated.
Many thanks.
EDIT (24/10/12):
I think I may have missed an important detail. It seems that the packets dropped before arrival share something else in common: They (and I'm starting to believe, only they) are sent to the server by "new" peers, i.e. peers that it hasn't tried to contact before.
For example, if a syn-equivalent packet arrives from a peer* we've never seen before, it will not be seen by WSARecvFrom. However, if we have sent a syn-equivalent packet to that peer ourselves (even if it didn't reply at the time), and now it sends us a syn-equivalent, we will see it.
(*) I'm not sure whether this is a peer we haven't seen (i.e. ip:port) or just a port we haven't seen before.
Does this help?
Is this some kind of WinSock option I've never heard of? (as I stated above, the code is not mine, so it may be using socket options I'm not aware of)
Thanks again!
The OS has a fixed size buffer for data that has arrived at your socket but hasn't yet been read by you. When this buffer is exhausted, it'll start to discard data. Debug logging may exacerbate this by delaying the rate you pull data from the socket at, increasing the chances of overflows.
If this is the problem, you could at least reduce the instances of it by requesting a larger recv buffer.
You can check the size of your socket's recv buffer using
int recvBufSize;
int err = getsockopt(socket, SOL_SOCKET, SO_RCVBUF,
(char*)&recvBufSize, sizeof(recvBufSize));
and you can set it to a larger size using
int recvBufSize = /* usage specific size */;
int err = setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
(const char*)&recvBufSize, sizeof(recvBufSize));
If you still see data being received by the OS but not delivered to your socket client, you could think about different approaches to logging. e.g.
Log to a RAM buffer and only print it occasionally (at whatever size you profile to be most efficient)
Log from a low priority thread, either accepting that the memory requirements for this will be unpredictable or adding code to discard data from the log's buffer when it gets full
I had a very similar issue, after confirming that the receive buffer wasn't causing drops, I learned that it was because I had the receive timeout set too low at 1ms. Setting the socket to non-blocking and not setting the receive timeout fixed the issue for me.
Turn off the Windows Firewall.
Does that fix it? If so, you can likely enable the Firewall back on and just add a rule for your program.
That's my most logical guess based on what you said here in your update:
It seems that the packets dropped before arrival share something else
in common: They (and I'm starting to believe, only they) are sent to
the server by "new" peers, i.e. peers that it hasn't tried to contact
before.
Faced same kind of problem on the redhat-linux as well.
This turn out to be a routing issue.
RCA is as follows:
True that UDP is able to reach destination machine(seen on Wireshark).
Now route to source is not found so there is no reply can be seen on the Wireshark.
On some OS you can see the request packet on the Wireshark but OS does not actually delivers the packets socket (You can see this socket in the netstat-nap).
In these case please check ping always (ping <dest ip> -I<source ip>)

Is there a way to monitor socket buffer size of a running application under Windows?

I am trying to guess what the size is used for UDP input socket of a running application and couldn't find any piece of software able to do it.
The closer Ifound is TracePlus/Winsock but it only works with 32bits applications and mine is 64bits...
Rather than trying to guess what buffer sizes the app is actually using in its code, I would suggest you instead use a packet sniffer, such as Wireshark, to see the actual size of the packets that are actually being transmitted over the wire. The app has to be using buffer sizes that are at least at large as the packets, or else WinSock would report WSAEMSGSIZE errors and data would get truncated/discarded.
Have you tryied using hooking techniques?I think detours can help you
getsockopt() with the SO_RCVBUF option gives you the size of your socket receive buffer. Not sure that's whzt you really want though.

Kernel module to get network jitter and bandwidth?

I need to get a list of interfaces on my local machine, along with their IP addresses, MACs and a set of QoS measurements ( Delay, Jitter, Error rate, Loss Rate, Bandwidth)...
I'm writing a kernel module to read these information from local network devices,So far I've extracted every thing mentioned above except for both Jitter and Bandwidth...
I'm using linux kernel 2.6.35
It depends what you mean by bandwidth. In most cases you only get from the PHY something that is better called bitrate. I guess you rather need some kind of information on the available bandwidth at a higher layer, which you can't get without active or passive measurements done, e.g. sending ICMP echo-like probe packets, and investigating replies. You should also make clear what the two points in the network are (both the actual endpoints and the communication layer) between which you would like to measure available bandwidth.
As for jitter you also need to do some kind of measurements, basically the same way as above.
I know this is an old post, but you could accomplish at least getting jitter by inspecting the RTCP packets if they're available. They come in on the +1 of the RTP port and come along with any RTP stream as far as I've seen. A lot of information can be gotten from RTCP, but for your purposes just the basic source description would do it:
EDIT: (didn't look at the preview)
Just check out this link for the details of the protocol, but you can get the jitter pretty easily from an RTCP packet.
Depending on what you're using the RTP stream for too there are a lot of other resources, like the VoIP Metrics Report Block in the Extended Report (https://www.rfc-editor.org/rfc/rfc3611#page-25).
EDIT:
As per Artem's request here is a basic flow of how you might do it:
An RTP stream is started on say port 16400 (the needed drivers/mechanism for this to happen are most likely already in place).
Tell the kernel to start listening on port 16401 (1 above your RTP stream's port) as well; this is where the RTCP pkts will start coming in.
As the RTCP pkts come in send them wherever you want to handle them (ie, if you're wanting to parse it in userspace or something).
Parse the pkts for the desired data. I'm not aware of a particular lib to do this, but it's pretty easy to just point some struct at it (in C) and dereference, watching out for Endianess.

How to check return packet contents in ICMP Ping / Echo?

When validating ping echo's, it seems that utilities / libraries often only check the checksum of the packet, and don't actually confirm that the payload sent out matches the payload that was returned. For instance, Wireshark's ICMP parser only checks for bad checksums, and that's all that Ruby's net-ruby checks as well.
I'm debugging a low-level network driver issue, and I need to confirm that the data isn't being mangled when received, so I want to test my driver using a low-level request such as ICMP Echo. However, my existing Ping tools are insufficient, because I fear that while the checksum may match the data contained in the echo response, the data in the echo response doesn't match the data in the echo request. So even though they both have valid checksums (there's no error in the checksum code), there's an error in the data receive portion, such that my driver isn't receiving what the host thinks it's sending out.
How might I check the echo payload to confirm that it's the same as what I sent out? If there's a standalone "paranoid ping" utility that I could use, that's fine too -- I just need to be able to vary the ping lengths and frequencies as I'm only seeing the problem when the network's flooded.
I'd prefer it in the form of a Ruby library / snippet, but any language or standalone app is acceptable, in so long as I can shoehorn it into running on Windows.
Thanks!
I think you're missing the point of the checksum. The purpose of the checksum is to validate that the data is intact. The sender calculates the checksum from the data and transmits it with the data. The receiver re-calculates a checksum from the data and compares it to the one that was sent. If they don't match, then the data isn't intact or one of the two is calculating it wrong. Most often bad checksums don't result in dropped packets because there's lots of broken protocol stacks out there, and of course packet manglers and that don't fix up the checksum, but if both sides do happen to do it properly then the checksum check tells you that the data is intact.
Are you looking at the TCP checksum or the ICMP checksum? The ICMP checksum doesn't include the TCP headers, only the ICMP type, code, checksum and data fields. A TCP checksum failure doesn't necessarily mean the ICMP contents aren't intact, it could just mean that the TCP headers were messed with (by a broken NAT, perhaps).
#Tom: Thanks for the answer. You said:
The receiver re-calculates a checksum from the data and compares it to the one that was sent.
But then you also said:
The ICMP checksum doesn't include the TCP headers, only the ICMP type, code, checksum and data fields.
The ICMP type is different between the echo request / response (one is 0, the other is I think 8). So by definition (and in practice, if you take a peek with Wireshark) the ICMP checksums don't match between the send request and the echo response.
My problem was that if ping utilities / libraries checked anything (and often they didn't), they only checked to make sure that the checksum matched the data. It seems that only rarely do people actually check the sent data with the echo'd response to make sure that the two payloads are identical. It's possible that both a request and a response could have valid checksums, but different payloads, and most Ping routines I've seen haven't checked for such a condition (but it happens to be the sort of bug I'm having on my device at the moment).
Thanks for looking at my question and responding though -- it is much appreciated.
#All:
In answer to my own question, I was able to use the robust .Net Ping class, as it gives me ready access to the received response buffer (unlike most other Ping libraries I found).

Resources