Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

SIGIO and sockets

868 views
Skip to first unread message

Shekhar Mahadevan

unread,
Mar 25, 2003, 6:47:20 PM3/25/03
to

Hi:

I'm trying to write a program that receives I/O on many sockets. I want the
program to be notified by the kernel via SIGIO and I want the kernel to also
to tell the program which descriptor the I/O condition has changed on.

Solaris 2.7 man pages say the __data.__file.__fd field is not available for
SIGPOLL (aka SIGIO on Solaris). Linux 2.2.14-5.0 seems to send back an fd of
0 all the time.

Is there a way this can be done? To get an idea of what I'm trying to do see
code below.

Any help will be greatly appreciated,

-sm

ps> Please cc: shekharm...@yahoo.com if you can.

sample code: sigio.c (Solaris 2.7 version, found on net and modified, thanks
Andrew Gierth)
----------------------------------------------------------------------------
--------------------
/* SIGIO and SIGURG example. (C) 1997 Andrew Gierth. */
/* Tested on FreeBSD. Please report any changes required for other */
/* systems. #ifdefs are speculative, but should work. */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include <sys/filio.h>
#include <sys/sockio.h>

#include <netinet/in.h>

#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#define TCP_PORT 8888

/* This example uses SIGIO and SIGURG on a TCP socket for convenience. */
/* In practice, SIGIO is almost useless on stream sockets, because it */
/* gets generated by far too many different events. */
/* To test, just telnet to port 8888. Use telnet's 'synch' command to */
/* generate OOB data for SIGURG. */
/* The program simply echos data in hex, bracketing all 'urgent' data */
/* in []. */

/* I say again: USE SIGIO ON STREAM SOCKETS ONLY AS A LAST RESORT. */

/* handle cruft */

#if EWOULDBLOCK == EAGAIN
# define IS_WOULDBLOCK(err) ((err)==EAGAIN)
#else
# define IS_WOULDBLOCK(err) (((err)==EAGAIN)||((err)==EWOULDBLOCK))
#endif

/* useful functions */

void errexit(const char *msg)
{
perror(msg);
exit(1);
}

/* this is done this way in an attempt to be safe in a signal handler. */

void complain(const char *msg,...)
{
va_list va;
char buf[1024];

va_start(va,msg);
vsprintf(buf, msg, va);
va_end(va);

write(STDERR_FILENO, buf, strlen(buf));
}

/* might need fcntl(F_SETFL), or ioctl(FIONBIO) */
/* Posix.1g says fcntl */
/* NEVER, EVER USE O_NDELAY HERE */

#ifdef O_NONBLOCK

int set_nonblock(int fd)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1)
return -1;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

#else

int set_nonblock(int fd)
{
int yes = 1;
return ioctl(fd, FIONBIO, &yes);
}

#endif

/* might need fcntl(F_SETOWN), or ioctl(FIOSETOWN), or ioctl(SIOCSPGRP) */
/* Posix.1g says fcntl */

#ifdef F_SETOWN

int set_owner(int fd)
{
return fcntl(fd, F_SETOWN, getpid());
}

#else

int set_owner(int fd)
{
pid_t pid = getpid();
return ioctl(fd, FIOSETOWN, &pid);
}

#endif

/* might need fcntl(F_SETFL), or ioctl(FIOASYNC) */
/* Posix.1g says fcntl */
/* DONT use I_SETSIG unless portability isn't an issue - remember, */
/* SOCKETS ARE NOT STREAMS! */

#ifdef O_ASYNC

int set_async(int fd)
{
int flags = fcntl(fd, F_GETFL, 0);
fprintf(stderr,"Using O_ASYNC\n");
if (flags == -1)
return -1;
return fcntl(fd, F_SETFL, flags | O_ASYNC);
}

#else

int set_async(int fd)
{
int yes = 1;
fprintf(stderr,"Using FIOASYNC\n");
return ioctl(fd, FIOASYNC, &yes);
}

#endif

int sockatmark(int sock)
{
int flag = 0;
if (ioctl(sock, SIOCATMARK, &flag) < 0)
return -1;
return (flag != 0) ? 1 : 0;
}

/* Ought to be able to do this with SIOCATMARK, but on my FreeBSD system */
/* it wasn't behaving in any sort of consistent fashion. */

int urgent_pending(int sock)
{
struct timeval tv;
fd_set fds;

FD_ZERO(&fds);
FD_SET(sock,&fds);
tv.tv_sec = 0;
tv.tv_usec = 0;

return select(sock+1,NULL,NULL,&fds,&tv);
}

/*-------------------------------------------------------------------------*
/

int sock;

sigset_t sigio_set;
sigset_t sigurg_set;
sigset_t empty_set;

volatile sig_atomic_t urgmode = 0;
volatile sig_atomic_t sigiocount = 0;
volatile sig_atomic_t sigurgcount = 0;

void sigio_handler(int sig, siginfo_t* si, void* v)
{
char inbuf[64];
char outbuf[4];
int i,rc,flag;
sigset_t sigs;

sigiocount++;

if (si) {
if (si->si_code == SI_NOINFO)
fprintf(stderr, "no info returned in siginfo :(\n");
else
fprintf(stderr, "received SIGIO with fd=%d, signo=%d\n",
si->__data.__file.__fd, si->si_signo);
}
else fprintf(stderr, "siginfo is null\n");

for (;;)
{
rc = read(sock, inbuf, sizeof(inbuf));
if (rc < 0 && IS_WOULDBLOCK(errno))
return;

if (rc < 0)
{
complain("error on read: %d (%s)\n", errno, strerror(errno));
_exit(1);
}
if (rc == 0)
{
complain("Done.\n");
complain("Total SIGIOs : %ld\n", (long) sigiocount);
complain("Total SIGURGs: %ld\n", (long) sigurgcount);
_exit(0);
}

for (i = 0; i < rc; i++)
{
outbuf[0] = ' ';
outbuf[1] = "0123456789ABCDEF"[(inbuf[i] >> 4) & 0x0F];
outbuf[2] = "0123456789ABCDEF"[inbuf[i] & 0x0F];
write(sock, outbuf, 3);
}

sigprocmask(SIG_BLOCK, &sigurg_set, &sigs);

if (urgmode && !urgent_pending(sock))
{
write(sock, "]", 1);
urgmode = 0;
}

sigprocmask(SIG_SETMASK, &sigs, NULL);
}
}

void sigurg_handler(int sig)
{
sigurgcount++;
urgmode = 1;
write(sock, " [", 2);
}


main()
{
struct sigaction sa;
struct sockaddr_in addr;
int addrlen = sizeof(addr);
int fd = socket(AF_INET, SOCK_STREAM, 0);
int yes = 1;

if (fd < 0)
errexit("socket");

fprintf(stderr, "listen socket created, fd = %d\n", fd);

sigemptyset(&empty_set);
sigemptyset(&sigio_set);
sigaddset(&sigio_set,SIGIO);
sigemptyset(&sigurg_set);
sigaddset(&sigurg_set,SIGURG);

if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0)
errexit("setsockopt");

/* set this in the listen socket; it will be inherited. */

if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &yes, sizeof(int)) < 0)
errexit("setsockopt");

addr.sin_family = AF_INET;
addr.sin_port = htons(TCP_PORT);
addr.sin_addr.s_addr = INADDR_ANY;

if (bind(fd, (struct sockaddr *) &addr, addrlen) < 0)
errexit("bind");

if (listen(fd,5) < 0)
errexit("listen");

sock = accept(fd, (struct sockaddr *) &addr, &addrlen);

fprintf(stderr, "accept socket created, fd = %d\n", sock);

if (sock < 0)
errexit("accept");

close(fd);

/* block SIGIO and SIGURG while we set everything up. */

sigprocmask(SIG_BLOCK, &sigio_set, NULL);
sigprocmask(SIG_BLOCK, &sigurg_set, NULL);

if (set_nonblock(sock) < 0)
errexit("set_nonblock");

if (set_owner(sock) < 0)
errexit("set_owner");

if (set_async(sock) < 0)
errexit("set_async");

sa.sa_handler = sigio_handler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sigaction(SIGIO, &sa, NULL);

sa.sa_handler = sigurg_handler;
sa.sa_flags = SA_SIGINFO;
sa.sa_mask = sigio_set;
sigaction(SIGURG, &sa, NULL);

/* data may have arrived while we were setting up, so generate */
/* SIGIO now. */

raise(SIGIO);

/* unblock everything, then pause. */

sigprocmask(SIG_SETMASK, &empty_set, NULL);

for(;;)
pause();

/*NOTREACHED*/

return 0;
}

/* end */


Michael Kerrisk

unread,
Mar 26, 2003, 1:39:35 AM3/26/03
to
On Tue, 25 Mar 2003 15:47:20 -0800, "Shekhar Mahadevan"
<shek...@adhesiontech.com> wrote:

>Hi:
>
>I'm trying to write a program that receives I/O on many sockets. I want the
>program to be notified by the kernel via SIGIO and I want the kernel to also
>to tell the program which descriptor the I/O condition has changed on.
>
>Solaris 2.7 man pages say the __data.__file.__fd field is not available for
>SIGPOLL (aka SIGIO on Solaris). Linux 2.2.14-5.0 seems to send back an fd of
>0 all the time.

Much of siginfo_t argument to signal handlers is not filled in in
Linux 2.2. Things work correctly in 2.4.

Cheers

Michael

0 new messages