You are on page 1of 71

Network Programming and

Management
UNIT II
Socket Options
File Control
I/O Control
Signal Driven I/O
Server Example
#define MYPORT 3490 // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold

int main(void) {
int sockfd, new_fd; // listen on sockfd, new connection on new_fd
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
int sin_size;

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {


perror("socket");
exit(1);
}

my_addr.sin_family = AF_INET; // host byte order


my_addr.sin_port = htons(MYPORT); // short, network byte
order
my_addr.sin_addr.s_addr = INADDR_ANY; // auto. filled with local IP
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}

if (listen(sockfd, BACKLOG) == -1) {


perror("listen");
exit(1);
}

while(1) { // main accept() loop


sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
continue;
}

printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));

if (send(new_fd, "Hello, world!\n", 14, 0) == -1)


perror("send");

close(new_fd);
}
return 0;
}
#include <netinet/in.h>
Client Example
#include <sys/socket.h>

#define PORT 3490 // the port client will be connecting to


#define MAXDATASIZE 100 // max number of bytes we can get
// at once
int main(int argc, char *argv[]) {
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct hostent *he;
struct sockaddr_in their_addr;// server's address information

if (argc != 2) {
fprintf(stderr,"usage: client hostname\n");
exit(1);
}

if ((he=gethostbyname(argv[1])) == NULL) { // get the host info


perror("gethostbyname");
exit(1);
}

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {


perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET; // host byte order
their_addr.sin_port = htons(PORT); // short, network byte order
their_addr.sin_addr = *((struct in_addr *)he->h_addr); // already network byte order
memset(&(their_addr.sin_zero), '\0', 8); // zero the rest of the struct

if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1){


perror("connect");
exit(1);
}

if ((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {


perror("recv");
exit(1);
}

buf[numbytes] = '\0';
printf("Received: %s",buf);
close(sockfd);
return 0;
}
Signals
• Introduced in UNIX systems to simplify IPC.
• Signal is a software interrupt
• Used by the kernel to notify processes of system
events or can be used for inter proccess
communication.
• A signal is a short message sent to a process, or
group of processes, containing the number
identifying the signal.
– No data is delivered with traditional signals.
– POSIX.4 defines i/f for queueing & ordering
RT signals arguments.
Signal Transmission
• Signal sending:
– Kernel updates descriptor of destination process.
• Signal receiving:
– Kernel forces target process to “handle” signal.
• Pending signals are sent but not yet received.
– Up to one pending signal per type for each process,
except for POSIX.4 signals.
– Subsequent signals are discarded.
– Signals can be blocked, i.e., prevented from being
received.
Signal-Related Data Structures
• sigset_t stores array of signals sent to a process.
• The process descriptor (struct task_struct in
<linux/sched.h>) has several fields for tracking sent,
blocked and pending signals.
Signal handling system call :
struct sigaction {
void (*sa_handler)();/* handler address, or
SIG_IGN(ignore),
or SIG_DFL(default) */
sigset_t sa_mask; /* blocked signal list */
int sa_flags; /* options e.g., SA_RESTART */
}
Signal Disposition
Disposition : Action associated with signals
• Ignore the signal (most signals can simply be ignored,
except SIGKILL and SIGSTOP)
• Handle the signal disposition via a signal handler routine.
This allows us to gracefully shutdown a program when
the user presses Ctrl-C (SIGINT).
• Block the signal. In this case, the OS queues signals for
possible later delivery
• Let the default apply SIG_DFL (usually process
termination)
• Signals can be ignored SIG_IGN
Original Signal Handling (Version 7)
• Two includes: <sys/types.h> and <signal.h>
• handler can either be:
– a function (that takes a single int which is the
signal)
– the constant SIG_IGN
– the constant SIG_DFL
• signal will return SIG_ERR in case of error
Signal Handling System Calls
• int sigaction(int sig, const
struct sigaction *act, struct
sigaction *oact);
– Replaces the old signal() function.
– Used to bind a handler to a signal.
– For RT signals, the handler’s prototype is of
form:
• void (*sa_sigaction)(int,
siginfo_t *, void *);
Common Signals
• SIGHUP (1):sent to a process when its controlling
terminal has disconnected
• SIGINT (2) : Ctrl-C (or DELETE key)
• SIGQUIT (3):Ctrl-\ (default produces core)
• SIGSEGV (11):Segmentation fault
• SIGKILL (4):Illegal instruction (default core)
• SIGUSR[1,2]:User-defined signals (10,12)
• kill –l will list all signals
• SIGFPE (8):Floating Point Exception (divide by 0;
integer overflow; floating-point underflow)
Alarming Signals
• SIGALRM can be used as a kind of “alarm clock”
for a process
• By setting a disposition for SIGALRM, a process
can set an alarm to go off in x seconds with the
call:
– unsigned int alarm(unsigned int numseconds)
• Alarms can be interrupted by other signals
• Examples: mysleep.c, impatient.c
• SIGCHLD signals – Sent by kernel when a process terminates
to the parent of the child
• When Child is in zombie state it maintains information about
the child termination status, process ID… to the parent to be
fetched later.
• wait - wait for a child process to stop or terminate. Returns
process ID and status of terminated child
• #include <sys/wait.h>
pid_t wait(int *stat_loc);
- waits untill first child terminates
• pid_t waitpid(pid_t pid, int *stat_loc, int options);
- specifies process ID we want to wait for WNOHANG option
tells waitpid not to block if there exist running children that have
not yet terminated
-Difference between wait() and waitpid(): It is used since unix
signals are not queued. Can be used when the same client has
multiple (n) connections with the concurrent server and when
the child terminates n FIN signals sent to child process which
responds by sending n SIGCHLD to parent.As unix signals are
not queued the parent leaves zombie child if wait is used.
Hence waitpid must be used within loop
I/O Blocking

socket();
bind() ;
listen();
while
accept();
recv() ;
send() ;
• Simple server has blocking problem
– Suppose 5 connections accepted.
– Suppose next accept() blocks.
– Other connections cannot send and receive.
– Cannot get keyboard input either.
select() :I/O Multiplexing
• waits on multiple file descriptors and timeout
• returns when any file descriptor
– is ready to be read or
– written or
– indicate an error, or
– timeout exceeded
• advantages
– simple
– application does not consume CPU cycles while
waiting
• disadvantages
– does not scale to large number of file descriptors
Example:
Server Programming

• create stream socket (socket() )


• Bind port to socket (bind() )
• Listen for new client (listen() )
• While
– Wait for (select() )
(depending on which file descriptors are ready)
– accept user connection and create a new socket
(accept() )
– data arrives from client (recv() )
– data has to be send to client (send() )
Server: Alternative Ways of
Handling Many Clients

• Forking a new process for each client:


fork()
• But, creating new process is expensive.
• Multithreaded implementation: have one
thread handling each client.
• Thread is like a process but light-
weighted.
Network Programmer’s
Mistakes

• byte ordering
• separating records in streams
• use of select()
• misinterpreting the project specification
• not knowing all available system calls
There are more System Calls

• Depends on communication type


– Datagram sockets use recvfrom() and sendto() for
receiving and sending data
• Closing connection: close(), shutdown()
• Convenient functions (on UNIX)
– inet_aton, inet_ntoa
– inet_pton, inet_ntop
inet_ntop, inet_pton –
• convert IPv4 and IPv6 addresses between binary and text form

• #include <arpa/inet.h>

• int inet_pton(int af, const char *src, void *dst);


• const char *inet_ntop(int af, const void *src, char *dst, socklen_t
size);

• af : Specifies the family of the address to be converted. AF_INET and AF_INET6 .

• src
– (Input) The pointer to the null-terminated character string that contains the text
presentation form of an IPv4 / IPV6 address.

dst
– (Output) The pointer to a buffer into which the function stores the numeric
address. The calling application must ensure that the buffer referred to by dst is
large enough to hold the numeric address (4 bytes for AF_INET or 16 bytes for
AF_INET6).
size
• (Input) The size of the buffer pointed at by dst.
• sock_ntop
- takes a pointer to a socket address structure, looks
inside the structure, and calls the appropriate function to
return the presentation format of the address.
• #include "unp.h“

• char *sock_ntop(const struct sockaddr *sockaddr,


socklen_t addrlen);

• Returns: non-null pointer if OK, NULL on error


• sockaddr points to a socket address structure whose length is
addrlen.
• The function uses its own static buffer to hold the result and a
pointer to this buffer is the return value.
readn, writen, and readline Functions
• A read or write on a stream socket might input or output fewer bytes
than requested.
• The reason is that buffer limits might be reached for the socket in
the kernel.
• All that is required to input or output the remaining bytes is for the
caller to invoke the read or write function again.
• This scenario is always a possibility on a stream socket with read,
but is normally seen with write only if the socket is nonblocking.
#include "unp.h“

• ssize_t readn(int filedes, void *buff, size_t nbytes);


• ssize_t writen(int filedes, const void *buff, size_t nbytes);
• ssize_t readline(int filedes, void *buff, size_t maxlen);

• All return: number of bytes read or written, –1 on error


• Note that our readline function calls the system’s read function once
for every byte of data.
• #include <unistd.h>
int execl(const char *path, const char *arg0, ... /*, (char *)0
*/);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg0, ... /*,
       (char *)0, char *const envp[]*/);
int execve(const char *path, char *const argv[], char *const
envp[]);
int execlp(const char *file, const char *arg0, ... /*, (char *)0
*/);
int execvp(const char *file, char *const argv[]);

• The arguments specified by a program with one of the exec


functions shall be passed on to the new process image in
the corresponding main() arguments.
• The argument path points to a pathname that identifies the
new process image file.
• #include <sys/socket.h>

• int getsockname(int socket, struct sockaddr


*address, socklen_t *address_len);
• The getsockname() function retrieves the locally-bound name of
the specified socket, stores this address in the sockaddr structure
pointed to by the address argument, and stores the length of this
address in the object pointed to by the address_len argument.
• If the actual length of the address is greater than the length of the
supplied sockaddr structure, the stored address will be truncated.
• If the socket has not been bound to a local name, the value stored
in the object pointed to by address is unspecified.
• #include <sys/socket.h>
• int getpeername(int socket, struct sockaddr
*address, socklen_t *address_len);

• The getpeername() function retrieves the peer address of the


specified socket, stores this address in the sockaddr structure
pointed to by the address argument, and stores the length of this
address in the object pointed to by the address_len argument.
• If the actual length of the address is greater than the length of the
supplied sockaddr structure, the stored address will be truncated.
• If the protocol permits connections by unbound clients, and the peer
is not bound, then the value stored in the object pointed to by
address is unspecified.
Socket Options
Managing socket options – 3 ways

• getsockopt() and setsockopt()


• fcntl()
• ioctl()
getsockopt() and setsockopt()

int getsockopt(
int sockfd,
int level, /* SOL_SOCKET, IPPROTO_IP, IPPROTO_TCP etc */
int optname, /* option name */
void *optval, /* option value */
socklen_t *optlen); /* data length of option*/

int setsockopt(
int sockfd,
int level,
int optname,
const void *optval,
socklen_t optlen);
Two types of socket options

• Flag options
– Enable or disable a feature
– Optval points to an integer which can be zero or non-zero

• Value options
– Pass a value to/from the OS
– Optval points to some structure
Level of an Option

• Level of protocol hierarchy at which the option


applies

• Socket layer level – SOL_SOCKET


• TCP Layer – IPPROTO_TCP
• IPv4 Layer – IPPROTO_IP
• IPv6 Layer – IPPROTO_IPV6
Some socket options
• SO_BROADCAST
– Enable socket for sending broadcast

• SO_KEEPALIVE
– Regularly probes if connection is alive

• SO_LINGER
– Linger till all data is sent before returning from close() on a
TCP connection.

• SO_RCVBUF/ SO_SNDBUF
– Size of receive/send buffers on socket.

• SO_RCVTIMEO/SO_SNDTIMEO
– Place timeout on receive/send operation.
Some more socket options

• IP_TOS
– Set type of service field in IP datagram

• IP_TTL
– Set time-to-live field in IP datagram

• IP_ADD_MEMBERSHIP / IP_DROP_MEMBERSHIP
– Join/Drop a multicast group

• TCP_KEEPALIVE
– Probe timer for TCP connection probing

• TCP_MAXSEG / TCP_MAXRT
– TCP maximum segment size, maximum retransmit time

• More on Page 179 Steven’s book.


Non-Blocking I/O (polling)
Application Operating system

System call
recvfrom() No datagram ready
EWOULDBLOCK

Time System call


recvfrom() No datagram ready
EWOULDBLOCK

System call datagram ready


recvfrom()
Copy datagram

Process blocks Copy data to user

Return ok
Process datagram Copy complete
Signal driven I/O
Application Operating system

Establish SIGIO System call


Signal handler No datagram ready
return
Time
Process continues Wait for data

Deliver SIGIO
Signal Handler datagram ready
System call
recvfrom() Copy datagram

Process blocks Copy data to user

Return ok
Process datagram Copy complete
fcntl()

• int fcntl(int fd, int cmd, long arg);

• Miscellaneous file control operations

– Non-blocking I/O (O_NONBLOCK, F_SETFL)


– Signal-driven I/O (O_ASYNC, F_SETFL)
– Set/Get socket owner (F_SETOWN, F_GETOWN)
Enabling Non-Blocking I/O
int flags;

/* Set socket nonblocking */


if( (flags = fcntl(fd, F_GETFL, 0)) < 0){
perror(“fcntl”);
exit(1);
}

flags |= O_NONBLOCK;

if( fcntl(fd, F_SETFL, flags) < 0){


perror(“fcntl”);
exit(1);
}
ioctl()
ioctl()
• Handles miscellaneous properties of a file/device
referenced by a descriptor.
– In our case, network interfaces.

• int ioctl(int fd, int request, void * arg)


– Socket operations
– File operations
– Interface configuration
– ARP cache
– Routing table
ioctl()
– SIOSPGRP/SIOGPGRP
• set/get process/group ID of a socket owner (same as fcntl)

– FIONREAD
• Return number of bytes in socket buffer

– SIOCGIFCONF
• Get list of all interfaces

– SIOCGIFBRDADDR/ SIOCSIFBRDADDR
• Get/set broadcast address

– SIOCGARP/SIOCSARP/SIOCDARP
• Get/modify/delete ARP cache entry.

– SIOCADDRT/SIOCDELRT
• Add/delete routes
Signal-driven I/O
Signal driven I/O
Application Operating system

Establish SIGIO System call


Signal handler No datagram ready
return
Time
Process continues Wait for data

Deliver SIGIO
Signal Handler datagram ready
System call
recvfrom() Copy datagram

Process blocks Copy data to user

Return ok
Process datagram Copy complete
Conditions that generate SIGIO
• UDP
– Datagram arrival
– Socket errors

• TCP (too many conditions! Mostly useless for TCP)


– Connection complete on listening socket
– Disconnect initiated
– Disconnect complete
– Half shutdown
– Data arrival
No way to distinguish!
– Data sent (free o/p buffer)
– Socket error
Steps to Set Up
Signal-Driven I/O
• Establish signal handler for SIGIO

• Set socket owner using fcntl() with F_SETOWN

• Enable signal-driven I/O for socket


– Using fcntl( ) or ioctl( )

• Make socket Non-blocking


– Don’t want to block inside signal handler.
Architecture for UDP
Main
Server
Loop

Datagram queue

SIGIO
Handler

User Space

Kernel Data Arrival


sigio_handler

void sigio_handler(int arg) {


int ret;
while(1) {
/ * read data from socket */
ret = recvfrom(sockfd, …);
if( ret < 0 ) {
if( errno == EWOULDBLOCK )
break; /* done reading all packets */
else {
perror(“recvfrom”);
exit(0); /* read error */
}
}
Insert datagram in server queue…
}
}
Main Loop

sigset_t newmask, oldmask;


int on;

/* Step 1: set up handler for SIGIO */


Signal(SIGIO, sigio_handler);

/* Step 2: Set socket owner */


Fcntl(sockfd, F_SETOWN, getpid());

/* Step 3: Set up socket for signal driven I/O */


on = 1
Ioctl(sockfd, FIOASYNC, &on);
/* Alternately, use fcntl() */

/* Step 4: Make socket non-blocking! */


Ioctl(sockfd, FIONBIO, &on);
/* Alternatively, use fcntl() */
Main Loop (contd.)
Sigemptyset(&oldmask);
Sigemptyset(&newmask);
Sigaddset(&newmask, SIGIO);

while(1) {
/* Block SIGIO temporarily */
Sigprocmask(SIG_BLOCK, &newmask, &oldmask);

if(queue is not empty)


Process datagrams in server queue…

/* Unblock SIGIO */
Sigprocmask(SIG_SETMASK, &oldmask, NULL);

Do something else…
}
I/O Models
I/O Multiplexing
Chapter 6 (UNP Book)
I/O Models
1. Blocking I/O
2. Non-blocking I/O
3. I/O multiplexing – select()
4. Signal driven I/O
5. Asynchronous I/O
Two steps in data reception

User Level Application


Buffer 2. Copy

System Call Interface

1.Data Arrival (local)


Kernel
Kernel Level Buffer

1. Data Arrival (network)

Overheads: Context switching, Data copying


Blocking I/O
Application Operating system
System call
recvfrom() No datagram ready

Time Wait for data

Process blocks datagram ready


Copy datagram

Copy data to user

Return ok
Read datagram Copy complete
Non-Blocking I/O (polling)
Application Operating system
System call
recvfrom() No datagram ready
EWOULDBLOCK
Time System call
recvfrom() No datagram ready
EWOULDBLOCK

recvfrom() System call datagram ready


Copy datagram

Process blocks Copy data to user

Return ok
Read datagram Copy complete
I/O Multiplexing
Concurrent Server

select() listenfd

Sockets or fd1 fd2 fd3 fd4 fd5


Files descriptors
Or Pipe descriptors

Remote Clients C1 C2 F3 F4 P5
Or files
Or pipes
I/O Multiplexing
Application Operating system

select() System call No datagram ready


on multiple fds

Time
Process blocks Wait for data
on any fd
Return readable
datagram ready
recvfrom() System call Copy datagram

Process blocks Copy data to user

Return ok
Read datagram Copy complete
Signal driven I/O
Application Operating system

Establish SIGIO System call


Signal handler No datagram ready
return
Time
Process continues Wait for data
Deliver SIGIO
Signal Handler datagram ready
recvfrom() System call Copy datagram
Copy data to user
Process blocks

Read datagram Return ok


Copy complete
Asynchronous I/O
Application Operating system
System call
aio_read() No datagram ready
return
Time Wait for data

Process continues datagram ready


Copy datagram

Copy data to user

Signal handler Deliver signal


specified in
Copy complete
Read datagram
aio_read()
I/O Multiplexing
What is I/O multiplexing?
• When an application needs to handle
multiple I/O descriptors at the same time
– E.g. file and socket descriptors, multiple socket
descriptors

• When I/O on any one descriptor can result in


blocking
Non-forking concurrent server

Concurrent Server

select() listenfd

Sockets  fd1 fd2 fd3 fd4 fd5

Clients  C1 C2 C3 C4 C5
select() call

• Allows a process to wait for an event to occur on


any one of its descriptors.

• Types of event
– ready for read
– ready for write
– Exception condition
select() call
int select(
int maxfdp1, /* max. fd + 1 */
fd_set *readfds, /* read ready? */
fd_set *writefds, /* write ready? */
fd_set *exceptfds, /* exceptions? */
struct timeval *timeout);

struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
}
struct fd_set
• Set of descriptors that we want to wait
on for events.

• Typically holds 256 descriptor states.

• Manipulation macros
– void FD_ZERO(fd_set *fds)
– void FD_SET (int fd, fd_set *fds)
– void FD_CLR (int fd, fd_set *fds)
– int FD_ISSET(int fd, fd_set *fds)
Non-forking Concurrent
Server
fdset rdset, wrset;
int listenfd, connfd1, connfd2;
int maxfdp1;
………
Connection establishment etc.
………

/* initialize */
FD_ZERO(&rdset);
FD_ZERO(&wrset);
for( ;; ) {
FD_SET(connfd1, &rdset);
FD_SET(connfd2, &wrset);
FD_SET(listenfd, &rdset);

maxfdp1 = max(connfd1, connfd2, listenfd) + 1;

/* wait for some event */


Select(maxfdp1, &rdset, &wrset, NULL, NULL);

if( FD_ISSET(connfd1, &rdset) ) {


Read data from connfd1…
}
if( FD_ISSET(connfd2, &wrset) ) {
Write data to connfd2…
}
if( FD_ISSET(listenfd, &rdset) {
Process a new connection…
}
Pselect()
• Int pselect(int maxfdp1,fd_set *readset,fd_set *writeset,
fd_set *exceptset, const struct timespec *timeout, const
sigset_t *sigmask);

• Reads count of ready descriptors,o on timeout, -1 on error


• Struct timespec{
Time _t tv_sec;
Long tv_nsec;
};
Sigmask enables the program to disable the delivery of
certain signals, test global variables for dis abled signals,
then calls pselect to reset the signal mask.
poll()
• Test for events on multiple sockets
simultaneously
• Prototypes
• #include <sys/poll.h>
int poll(struct pollfd *ufds, unsigned int nfds, int
timeout);
• Description
• The basic idea is that you pass an array of nfds
struct pollfds in ufds, along with a timeout in
milliseconds
• Each element in the array of struct pollfds
represents one socket descriptor, and contains
the following fields:
• struct pollfd {
• int fd; // the socket descriptor
• short events; // bitmap of events we’re interested in
• short revents; // when poll() returns, bitmap of events that occurred
• };

• Before calling poll(), load fd with the socket descriptor


• POLLIN Alert me when data is ready to recv() on this socket.
• POLLOUT Alert me when I can send() data to this socket without
blocking.
• POLLPRI Alert me when outofband data is ready to recv() on this
socket.
• POLLERR An error has occurred on this socket.
• POLLHUP The remote side of the connection hung up.
• POLLNVAL Something was wrong with the socket descriptor fd–
maybe it’s

• Return Value
• Returns the number of elements in the ufds array that have had event
occur on them; this can be zero if the timeout occurred. Also returns
-1 on error (and errno will be set accordingly.)
Shutdown()
• Close – Decrements descriptors reference count
and closes socket when count reaches 0
• Close terminates both direction of data transfer
• Shutdown does half close- other end can still send
data after one end of the connection closes.

• Int Shutdown(int sockfd, int howto)


• SHUT_RD : READ HALF OF CONNECTION IS CLOSED
• SHUT_WR : WRITE HALF OF CONNECTION IS CLOSED
• READ AND WRITE HALF OF CONNECTION CLOSED
• SHUT_RDWR
poll()
Test for events on multiple sockets simultaneously
Prototypes
#include <sys/poll.h>
int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
Description
This function is very similar to select() in that they both watch sets of file descriptors forevents, such as incoming data ready
to recv(), socket ready to send() data to, outofband data ready to recv(), errors, etc.The basic idea is that you pass an array of
nfds struct pollfds in ufds, along with a timeout in milliseconds (1000 milliseconds in a second.) The timeout can be
negative if you want to wait forever. If no event happen on any of the socket descriptors by the timeout, poll() will
return.Each element in the array of struct pollfds represents one socket descriptor, and contains the following fields:
struct pollfd {
int fd; // the socket descriptor
short events; // bitmap of events we’re interested in
short revents; // when poll() returns, bitmap of events that occurred
};
Before calling poll(), load fd with the socket descriptor
POLLIN Alert me when data is ready to recv() on this socket.
POLLOUT Alert me when I can send() data to this socket without blocking.
POLLPRI Alert me when outofband data is ready to recv() on this socket.
POLLERR An error has occurred on this socket.
POLLHUP The remote side of the connection hung up.
POLLNVAL Something was wrong with the socket descriptor fd–maybe it’s
uninitialized?
Return Value
Returns the number of elements in the ufds array that have had event occur on them; this can be zero if the timeout occurred.
Also returns -1 on error (and errno will be set accordingly.)

You might also like