Build UDP datagram in Ruby - ruby

Is there anything in the Ruby library, or as a Ruby gem, that would help me construct a UDP datagram? I've looked into sockets, but there doesn't seem to be a way to simply build one and not send it.
My use case is this:
I need to build a single UDP datagram, and then pass it off to another module which will be responsible for sending it out. Simply put, I just need to be able to specify the src/dst address and port, as well as the payload.
I suppose in the worse case I can build some kind of a struct and fill in respective bits by hand, but it feels like reinventing the wheel as well as a lot of work. The underlying stuff in the sockets API should have something similar that I can make use of, shouldn't it?

The so called socket API is inherently a very low-level C-language API. When you create a UDP socket the connection information is stored in the kernel. You're never "building UDP datagrams", you're writing data into a UDP socket file descriptor, and the physical data packets to be sent over the wire are then constructed inside the kernel.
So yes, if you want a data structure that you can pass around your application that contains a destination address and some data, then you need to create this structure yourself since it doesn't exist by itself anywhere else.
It's not that much work. Just two (or three) data elements. You could use a simple Struct to do the job, unless you need more elaborate functionality and then you just build a normal class.
EDIT
Looks like I misunderstood your question. See my comment below for resources. For example here's some code from the Racket library docs, which probably is closer to what you were looking for:
# tack on UDP
n.l4 = UDP.new
# randomize source port
n.l4.src_port = 1024 + rand(65535-1024)
# take destination port from the commandline
n.l4.dst_port = ARGV[2].to_i
# build a random amount of garbage for the payload
n.l4.payload = Misc.randstring(ARGV[3].to_i)
# fix 'er up (checksum, length) prior to sending
n.l4.fix!(n.l3.src_ip, n.l3.dst_ip)

Related

How can I attach a header to a datagram in c++ for networking?

I have a
struct ip ipHeader;
that I want to attach in front of the actual data, which is
string data;
so that I can send it in one packet via the send function, which takes in a char* buffer. How would I go about trying to concatenate these? I need to attach this ipHeader because it's a custom header that's different from the UDP header that's automatically attached when sending messages.
edit* A clarification is that I need to attach this header along with the UDP header that's attached when sending. Hence, SOCK_RAW is not necessarily what I need/want.
In order to send two pieces of data as a single packet, you have two main choices:
Copy them both into a new buffer, and send that.
Use writev() (WSASend() on Windows).
The second approach is appealing because it seems to be designed for exactly what you're doing: sending two (or more) buffers at once. But in my own testing, it was not actually faster (on Linux) than the first approach.
The fastest and simplest solution is often to simply embed the header in your data from the start. So whenever you allocate a message, add space for the header at the start. You can then use "placement new" to invoke the header constructor if there is one, or simply assign its fields.

For what do I need the Socket::MSG_* constants in ruby?

I want to develop a p2p app which communicates via UDPSockets. I'm just starting to read the docs for that and I couldn't understand that piece of ruby's socket management.
Specifically it's possible to add those "flags", as ruby-doc calls them, to every send call. (http://www.ruby-doc.org/stdlib-1.9.3/libdoc/socket/rdoc/UDPSocket.html#method-i-send)
But when do I use those and how?
You'll probably know if you need to use them as you'll have an example or some documentation that refers to them.
Some of the more common options used with recvfrom are: MSG_OOB to process out-of-band data, MSG_PEEK to peek at the incoming message without de-queueing it, and MSG_WAITALL to wait for the receive buffer to fill up.
These are really quite edge-case so you probably won't ever see one used.
Those flags come from the low-level recv call on which Socket is based.

How to read from and write to a Unix domain socket in Pharo?

my application needs to read and write to a Unix domain socket. How can I do that from Pharo?
I don't think you can do it with the Socket library. The primitives have AF_INET hard-coded in the calls to socket() (you need AF_LOCAL). Also, there is no way to set the sun_path field of the struct sockaddr_un that gets passed to connect().
It looks like you'll have to use FFI or write your own plugin.
Actually, the new SocketPlugin primitives allow to access all socket families, not just AF_INET. I know it can do AF_INET6 besides AF_INET for sure, and I'm almost sure it can do all others as well. Pharo may be lacking the new in-image code to access those primitives, I don't know. But e.g. Squeak Etoys was using them on the OLPC XO machine to do IPv6 mesh networking.
Apparently someone implement it recently: http://samadhiweb.com/blog/2013.07.27.unixdomainsockets.html

Streaming files from EventMachine handler?

I am creating a streaming eventmachine server. I'm concerned about avoiding blocking IO or doing anything else to muck up the event loop.
From what I've read, ruby's non-blocking IO can be used to stream files in a non-blocking way, or I can call next_tick, but I'm a little unclear about which of these approaches is preferable.
Part of the problem is that I have not found a good explanation of non-blocking IO library functions in ruby.
Short version:
Assuming a long-lived network IO operation, several wall clock minutes of streaming per file, transfer, what is the best way to do this in eventmachine without gumming up the event loop?
while 1 do
file.read do |bytes|
#conn.send_data bytes
end
end
I understand that the above code will block and I'm wondering what to put in its place. Also, I cannot use the FileStreamer class that is part of eventmachine as is, because I need to manipulate the data after it's read but before it's sent.
I think you can still use FileStreamer. FileStreamer expects its first argument to be a Connection, but this is a loose contract. As long as you implement the methods that FileStreamer expects, it should work. Take a look at this
https://gist.github.com/f4d997c3eeb6bdc5a9f3
The methods you'll need to handle are send_data and send_file_data. You can perform your manipulations here. Then pass the result along to EM::Connection.
Also, from my reading of the code, the special property of FileStreamer is that it allocates a memory mapped file (unless the file is small). You could do essentially the same thing by opening a regular Ruby File, reading blocks out of it, doing your manipulation, and emulating the behavior of FileStreamer.stream_one_chunk. Which is basically:
Each iteration must either send some data to the Connection, or reschedule itself using next_tick
Data can be repeatedly written to the Connection until the outbound buffer is full (according to get_outbound_data_size)
Once the file has been fully read, it should be closed (of course)
In fact, it seems to me that you had better not use FileStreamer unless your file will comfortably fit in memory.
You can look at the EM::Protocols for ideas about how to transform the data as it is streaming through.

How do I send Hex data?

I am trying to communicate with a modbus slave via either modbusTCP or modbus serial. The manuf. (partlow) has an ASCII communications manual (http://www.partlow.com/uploadedFiles/Downloads/1160%20ASCII%20Comms%20Manual.pdf) which, looks like it differs from the standard communication methods (http://en.wikipedia.org/wiki/Modbus). A lot of existing code out there is setup to work with normal modbus addressing of coils and such, where it seems (at least to me) to be different with these guys.
So, via ruby or perl, how can I send hex data? I may be doing everything fine, but, if I write "0DFA" to a serial port... is that ok? or do I need to convert it into a lower layer first, or denote it somehow?
Been working on this a lot and may have myself mixed up (making things out to be more complicated than they are) but, i am trying to establish comm with this meter, and I can see the TX activity light blink but no RX, which means my data format is wrong...
Been working off this mostly (and a few perl snippets here and there, trying to find something that works):
http://www.messen-und-deuten.de/modbus.html
I am communicating through a terminal server, which accepts modbusTCP (which this script uses) but i'm having trouble applying whats in the comm manual to the code above, to get the packet formatted correctly.
Are you talking about raw data? There are several ways, including
print HANDLE "\x{OD}\x{FA}";
printf HANDLE "%c%c", 0x0D, 0xFA;
print HANDLE "\015\372"; # octal notation
print HANDLE pack("C*", 0x0D, 0xFA);
syswrite HANDLE, "\x{OD}\x{FA}", 2;
I would recommend you look at the RModBus library to help handle some of the intricacies of packet formation over TCP/IP from inside the Ruby language.
It is always possible that the device you are communicating with requires, or conversely avoids the modicon notation. That was a bit of a hiccup when I first tried reading registers from a PLC. The other "gotcha" that I've found with Modbus is that some of the addressing systems are offset by one due to quirkiness in their implementation.

Resources