Nmap Development mailing list archives

Re: Next issue (Re: Help: fd_set porting to Win32?)


From: doug () hcsw org
Date: Sun, 1 Jun 2008 14:04:16 -0700

On Sun, Jun 01, 2008 at 10:39:22AM -0700 or thereabouts, bensonk () acm wwu edu wrote:
So, it looks to me like you will have to rewrite ncat with a bunch of
conditional blocks to get around the fact that Microsoft decided to
change the sockets API on their platform.  

I'm afraid we can't completely blaim MSFT for this one. That's the
great thing about standards -- there's so many of them to choose
from. Most (all?) unix systems will let you set socket options
through ioctl() too. Here are my (tested on oBSD and linux) versions:

static void make_socket_non_blocking(int sd) {
  //fcntl(sd, F_SETFL, fcntl(sd, F_GETFL) | O_NONBLOCK);
  int nb=1;
  if (ioctl(sd, FIONBIO, &nb) == -1)
    fatal("make_socket_non_blocking: ioctl: %s", strerror(errno));
}

static void make_socket_blocking(int sd) {
  //fcntl(sd, F_SETFL, fcntl(sd, F_GETFL) | ~O_NONBLOCK);
  int nb=0;
  if (ioctl(sd, FIONBIO, &nb) == -1)
    fatal("make_socket_non_blocking: ioctl: %s", strerror(errno));
}

In fact ioctl() is slightly better than fcntl here because it will
only make 1 system call, not 2. There still are some things you
must (afaik) use fcntl() for though, including making descriptors
close on exec, etc. But win32 doesn't even have fork()/exec() so
I guess you will never need this anyways.

Possibly the code could be converted to use ioctl() everywhere and
then #define ioctl -> ioctlsocket ifdef WIN32.

Doug

PS. Most people think the important aspect of non-blocking IO is that
if you try to read() or write() from a socket when it isn't ready
it will error with EAGAIN and not block. However, a properly written
non-blocking application should NEVER read()/write() to a socket until
the system has informed it that the socket is ready (because it is just
wasting system calls if it does).

The REALLY important part of non-blocking IO is that a write() call will
only fill up the kernel's socket buffer and then will return, informing the
application that it was only able to write PART OF the output (but not
erroring with EAGAIN!). A blocking socket will (usually) block until the
entire contents are transfered. But still ALWAYS check your return values
from read/write. From the oBSD read(2) manpage:

The system
     guarantees to read the number of bytes requested if the descriptor refer-
     ences a normal file that has that many bytes left before the end-of-file,
     but in no other case.

and write(2):

     When using non-blocking I/O on objects such as sockets that are subject
     to flow control, write() and writev() may write fewer bytes than request-
     ed; the return value must be noted, and the remainder of the operation
     should be retried when possible.

Attachment: signature.asc
Description: Digital signature


_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

Current thread: