views:

319

answers:

2

To avoid relying on the wireless tools I want to get the essid directly from the device with ioctl, in C this wouldn't be a problem, but in Ruby it's quite different.

The problem is following struct from wireless.h that is used as input/reply of ioctl:

struct  iw_point
{
  void __user *pointer; /* Pointer to the data  (in user space) */
  __u16   length;   /* number of fields or size in bytes */
  __u16   flags;    /* Optional params */
};

The pointer part must be a valid address of a memory area, followed by the length in bytes, followed by a flag field. I tried with Array#pack and the bit-struct gem, but haven't found a solution yet.

Is there a way to bypass this memory pointer problem?

+1  A: 

Sure, just define your own Ruby-friendly interface as a wrapper (in C) around ioctl. I do see the problem with the default ioctl in Ruby. I guess ios.ioctl is mostly intended for ioctl "write" calls.

DigitalRoss
Well, guess I have no other choice. Actually ioctl should work in both ways properly and not only segfault when some struct like the above is used. ;)
unexist
I haven't looked at the guts of ioctl recently, but if the loonix version is anything like non-BSD unix, it has a horrible ambiguity in that knowing whether it is reading or writing, or how much, requires knowing both the ioctl and the device. (!)
DigitalRoss
True, but devices normally have to follow a draft to be useable by customers which is most likey applicable for vendors and/or driver writers. The problem in this case is just the lack of pointers in Ruby which probably can't be covered easily by bitstruct.During my work on my window manager I am aware of the C API of Ruby - so this will be no problem at all. :)
unexist
A: 

I finally got it working, the solution was to use the 'p' argument of pack in this way:

require "socket"

# Copied from wireless.h
SIOCGIWESSID      = 0x8B1B
IW_ESSID_MAX_SIZE = 32

iwreq = [ "wlan0", " " * IW_ESSID_MAX_SIZE, IW_ESSID_MAX_SIZE, 0 ].pack("a16pII")

sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)

sock.ioctl(SIOCGIWESSID, iwreq)

interface, essid, len, flags = iwreq.unpack("a16pII")

puts essid
unexist