Added Ns_SockWaitEx with high resolution timing.
/*
* The contents of this file are subject to the AOLserver Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://aolserver.com/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is AOLserver Code and related documentation
* distributed by AOL.
*
* The Initial Developer of the Original Code is America Online,
* Inc. Portions created by AOL are Copyright (C) 1999 America Online,
* Inc. All Rights Reserved.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License (the "GPL"), in which case the
* provisions of GPL are applicable instead of those above. If you wish
* to allow use of your version of this file only under the terms of the
* GPL and not to allow others to use your version of this file under the
* License, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the GPL.
* If you do not delete the provisions above, a recipient may use your
* version of this file under either the License or the GPL.
*/
/*
* sock.c --
*
* Wrappers and convenience functions for TCP/IP stuff.
*/
static const char *RCSID = "@(#) $Header: /cvsroot/aolserver/aolserver/nsd/sock.c,v 1.13 2005/05/07 23:36:05 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__;
#include "nsd.h"
#ifndef INADDR_NONE
#define INADDR_NONE -1
#endif
/*
* Local functions defined in this file
*/
static SOCKET SockConnect(char *host, int port, char *lhost, int lport, int async);
static SOCKET SockSetup(SOCKET sock);
/*
*----------------------------------------------------------------------
*
* NsSockRecv --
*
* Timed recv() from a non-blocking socket.
*
* Results:
* # bytes read
*
* Side effects:
* May wait for given timeout.
*
*----------------------------------------------------------------------
*/
int
Ns_SockRecv(SOCKET sock, void *buf, int toread, int timeout)
{
int nread;
nread = recv(sock, buf, toread, 0);
if (nread == -1
&& ns_sockerrno == EWOULDBLOCK
&& Ns_SockWait(sock, NS_SOCK_READ, timeout) == NS_OK) {
nread = recv(sock, buf, toread, 0);
}
return nread;
}
/*
*----------------------------------------------------------------------
*
* Ns_SockSend --
*
* Timed send() to a non-blocking socket.
* NOTE: This may not write all of the data you send it!
*
* Results:
* Number of bytes written, -1 for error
*
* Side effects:
* May wait given timeout.
*
*----------------------------------------------------------------------
*/
int
Ns_SockSend(SOCKET sock, void *buf, int towrite, int timeout)
{
int nwrote;
nwrote = send(sock, buf, towrite, 0);
if (nwrote == -1
&& ns_sockerrno == EWOULDBLOCK
&& Ns_SockWait(sock, NS_SOCK_WRITE, timeout) == NS_OK) {
nwrote = send(sock, buf, towrite, 0);
}
return nwrote;
}
/*
*----------------------------------------------------------------------
*
* Ns_SockWait --
*
* Wait for I/O.
*
* Results:
* NS_OK, NS_TIMEOUT, or NS_ERROR.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Ns_SockWait(SOCKET sock, int what, int seconds)
{
return Ns_SockWaitEx(sock, what, seconds * 1000);
}
int
Ns_SockWaitEx(SOCKET sock, int what, int ms)
{
Ns_Time timeout;
struct pollfd pfd;
int n;
if (ms < 0) {
n = 0;
} else {
Ns_GetTime(&timeout);
Ns_IncrTime(&timeout, 0, ms * 1000);
pfd.fd = sock;
switch (what) {
case NS_SOCK_READ:
pfd.events = POLLIN;
break;
case NS_SOCK_WRITE:
pfd.events = POLLOUT;
break;
case NS_SOCK_EXCEPTION:
pfd.events = POLLPRI;
break;
default:
return NS_ERROR;
break;
}
n = NsPoll(&pfd, 1, &timeout);
}
return (n ? NS_OK : NS_TIMEOUT);
}
/*
*----------------------------------------------------------------------
*
* Ns_SockListen --
*
* Listen for connections with default backlog.
*
* Results:
* A socket or -1 on error.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
SOCKET
Ns_SockListen(char *address, int port)
{
return Ns_SockListenEx(address, port, nsconf.backlog);
}
/*
*----------------------------------------------------------------------
*
* Ns_SockAccept --
*
* Accept a TCP socket, setting close on exec.
*
* Results:
* A socket or -1 on error.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
SOCKET
Ns_SockAccept(SOCKET lsock, struct sockaddr *saPtr, int *lenPtr)
{
SOCKET sock;
sock = accept(lsock, saPtr, lenPtr);
if (sock != INVALID_SOCKET) {
sock = SockSetup(sock);
}
return sock;
}
/*
*----------------------------------------------------------------------
*
* Ns_SockBind --
*
* Create a TCP socket and bind it to the passed-in address.
*
* Results:
* A socket or -1 on error.
*
* Side effects:
* Will set SO_REUSEADDR on the socket.
*
*----------------------------------------------------------------------
*/
SOCKET
Ns_BindSock(struct sockaddr_in *saPtr)
{
return Ns_SockBind(saPtr);
}
SOCKET
Ns_SockBind(struct sockaddr_in *saPtr)
{
SOCKET sock;
int n;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock != INVALID_SOCKET) {
sock = SockSetup(sock);
}
if (sock != INVALID_SOCKET) {
n = 1;
if (saPtr->sin_port != 0) {
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n));
}
if (bind(sock, (struct sockaddr *) saPtr,
sizeof(struct sockaddr_in)) != 0) {
ns_sockclose(sock);
sock = INVALID_SOCKET;
}
}
return sock;
}
/*
*----------------------------------------------------------------------
*
* Ns_SockConnect --
*
* Open a TCP connection to a host/port.
*
* Results:
* A socket, or -1 on error.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
SOCKET
Ns_SockConnect(char *host, int port)
{
return SockConnect(host, port, NULL, 0, 0);
}
SOCKET
Ns_SockConnect2(char *host, int port, char *lhost, int lport)
{
return SockConnect(host, port, lhost, lport, 0);
}
/*
*----------------------------------------------------------------------
*
* Ns_SockAsyncConnect --
*
* Like Ns_SockConnect, but uses a nonblocking socket.
*
* Results:
* A socket, or -1 on error.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
SOCKET
Ns_SockAsyncConnect(char *host, int port)
{
return SockConnect(host, port, NULL, 0, 1);
}
SOCKET
Ns_SockAsyncConnect2(char *host, int port, char *lhost, int lport)
{
return SockConnect(host, port, lhost, lport, 1);
}
/*
*----------------------------------------------------------------------
*
* Ns_SockTimedConnect --
*
* Like Ns_SockConnect, but with an optional timeout in seconds.
*
* Results:
* A socket, or -1 on error.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
SOCKET
Ns_SockTimedConnect(char *host, int port, int timeout)
{
return Ns_SockTimedConnect2(host, port, NULL, 0, timeout);
}
SOCKET
Ns_SockTimedConnect2(char *host, int port, char *lhost, int lport, int timeout)
{
SOCKET sock;
int len, err;
/*
* Connect to the host asynchronously and wait for
* it to connect.
*/
sock = SockConnect(host, port, lhost, lport, 1);
if (sock != INVALID_SOCKET) {
len = sizeof(err);
if (Ns_SockWait(sock, NS_SOCK_WRITE, timeout) == NS_OK
&& getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0
&& err == 0) {
return sock;
}
ns_sockclose(sock);
sock = INVALID_SOCKET;
}
return sock;
}
/*
*----------------------------------------------------------------------
*
* Ns_SockSetNonBlocking --
*
* Set a socket nonblocking.
*
* Results:
* NS_OK/NS_ERROR
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Ns_SockSetNonBlocking(SOCKET sock)
{
unsigned long i;
i = 1;
if (ns_sockioctl(sock, FIONBIO, &i) == -1) {
return NS_ERROR;
}
return NS_OK;
}
/*
*----------------------------------------------------------------------
*
* Ns_SockSetBlocking --
*
* Set a socket blocking.
*
* Results:
* NS_OK/NS_ERROR
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Ns_SockSetBlocking(SOCKET sock)
{
unsigned long i;
i = 0;
if (ns_sockioctl(sock, FIONBIO, &i) == -1) {
return NS_ERROR;
}
return NS_OK;
}
/*
*----------------------------------------------------------------------
*
* Ns_GetSockAddr --
*
* Take a host/port and fill in a sockaddr_in structure
* appropriately. Host may be an IP address or a DNS name.
*
* Results:
* NS_OK/NS_ERROR
*
* Side effects:
* May perform DNS query.
*
*----------------------------------------------------------------------
*/
int
Ns_GetSockAddr(struct sockaddr_in *saPtr, char *host, int port)
{
struct in_addr ia;
Ns_DString ds;
if (host == NULL) {
ia.s_addr = htonl(INADDR_ANY);
} else {
ia.s_addr = inet_addr(host);
if (ia.s_addr == INADDR_NONE) {
Ns_DStringInit(&ds);
if (Ns_GetAddrByHost(&ds, host) == NS_TRUE) {
ia.s_addr = inet_addr(ds.string);
}
Ns_DStringFree(&ds);
if (ia.s_addr == INADDR_NONE) {
return NS_ERROR;
}
}
}
memset(saPtr, 0, sizeof(struct sockaddr_in));
saPtr->sin_family = AF_INET;
saPtr->sin_addr = ia;
saPtr->sin_port = htons((unsigned short) port);
return NS_OK;
}
/*
*----------------------------------------------------------------------
*
* Ns_SockPipe --
*
* Create a pair of unix-domain sockets.
*
* Results:
* See socketpair(2)
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Ns_SockPipe(SOCKET socks[2])
{
if (ns_sockpair(socks) != 0) {
return NS_ERROR;
}
return NS_OK;
}
/*
*----------------------------------------------------------------------
*
* SockConnect --
*
* Open a TCP connection to a host/port.
*
* Results:
* A socket or -1 on error.
*
* Side effects:
* If async is true, the returned socket will be nonblocking.
*
*----------------------------------------------------------------------
*/
static SOCKET
SockConnect(char *host, int port, char *lhost, int lport, int async)
{
SOCKET sock;
struct sockaddr_in lsa;
struct sockaddr_in sa;
int err;
if (Ns_GetSockAddr(&sa, host, port) != NS_OK ||
Ns_GetSockAddr(&lsa, lhost, lport) != NS_OK) {
return INVALID_SOCKET;
}
sock = Ns_SockBind(&lsa);
if (sock != INVALID_SOCKET) {
if (async) {
Ns_SockSetNonBlocking(sock);
}
if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) != 0) {
err = ns_sockerrno;
if (!async || (err != EINPROGRESS && err != EWOULDBLOCK)) {
ns_sockclose(sock);
sock = INVALID_SOCKET;
}
}
if (async && sock != INVALID_SOCKET) {
Ns_SockSetBlocking(sock);
}
}
return sock;
}
/*
*----------------------------------------------------------------------
*
* Ns_SockCloseLater --
*
* Register a callback to close a socket when writable. This
* is necessary for timed-out async connecting sockets on NT.
*
* Results:
* NS_OK or NS_ERROR from Ns_SockCallback.
*
* Side effects:
* Socket will be closed sometime in the future.
*
*----------------------------------------------------------------------
*/
static int
CloseLater(SOCKET sock, void *arg, int why)
{
ns_sockclose(sock);
return NS_FALSE;
}
int
Ns_SockCloseLater(SOCKET sock)
{
return Ns_SockCallback(sock, CloseLater, NULL, NS_SOCK_WRITE);
}
/*
*----------------------------------------------------------------------
*
* Ns_SockErrno --
*
* Errno/GetLastError utility routines.
*
* Results:
* See code.
*
* Side effects:
* May set last error.
*
*----------------------------------------------------------------------
*/
void
Ns_ClearSockErrno(void)
{
#ifdef _WIN32
SetLastError(0);
#else
errno = 0;
#endif
}
int
Ns_GetSockErrno(void)
{
#ifdef _WIN32
return (int) WSAGetLastError();
#else
return errno;
#endif
}
void
Ns_SetSockErrno(int err)
{
#ifdef _WIN32
SetLastError((DWORD) err);
#else
errno = err;
#endif
}
char *
Ns_SockStrError(int err)
{
#ifdef _WIN32
return NsWin32ErrMsg(err);
#else
return strerror(err);
#endif
}
/*
*----------------------------------------------------------------------
*
* SockSetup --
*
* Setup new sockets for close-on-exec and possibly duped high.
*
* Results:
* Current or duped socket.
*
* Side effects:
* Original socket is closed if duped.
*
*----------------------------------------------------------------------
*/
static SOCKET
SockSetup(SOCKET sock)
{
#ifdef USE_DUPHIGH
int nsock;
nsock = fcntl(sock, F_DUPFD, 256);
if (nsock != -1) {
close(sock);
sock = nsock;
}
#endif
#ifndef _WIN32
(void) fcntl(sock, F_SETFD, 1);
#endif
return sock;
}
int
NsPoll(struct pollfd *pfds, int nfds, Ns_Time *timeoutPtr)
{
Ns_Time now, diff;
int n, ms;
do {
if (timeoutPtr == NULL) {
ms = -1;
} else {
Ns_GetTime(&now);
if (Ns_DiffTime(timeoutPtr, &now, &diff) <= 0) {
ms = 0;
} else {
ms = diff.sec * 1000 + diff.usec / 1000;
}
}
n = Poll(pfds, (size_t) nfds, ms);
} while (n < 0 && ns_sockerrno == EINTR);
if (n < 0) {
Ns_Fatal("Poll() failed: %s", ns_sockstrerror(ns_sockerrno));
}
return n;
}
#ifndef HAVE_POLL
/* Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Poll the file descriptors described by the NFDS structures starting at
FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
an event to occur; if TIMEOUT is -1, block until an event occurs.
Returns the number of file descriptors with events, zero if timed out,
or -1 for errors. */
int
Poll (fds, nfds, timeout)
struct pollfd *fds;
unsigned long int nfds;
int timeout;
{
struct timeval tv, *tvp;
fd_set rset, wset, xset;
struct pollfd *f;
int ready;
int maxfd = 0;
FD_ZERO (&rset);
FD_ZERO (&wset);
FD_ZERO (&xset);
for (f = fds; f < &fds[nfds]; ++f)
if (f->fd != -1)
{
if (f->events & POLLIN)
FD_SET (f->fd, &rset);
if (f->events & POLLOUT)
FD_SET (f->fd, &wset);
if (f->events & POLLPRI)
FD_SET (f->fd, &xset);
if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
maxfd = f->fd;
}
if (timeout < 0) {
tvp = NULL;
} else {
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
tvp = &tv;
}
ready = select (maxfd + 1, &rset, &wset, &xset, tvp);
if (ready > 0)
for (f = fds; f < &fds[nfds]; ++f)
{
f->revents = 0;
if (f->fd >= 0)
{
if (FD_ISSET (f->fd, &rset))
f->revents |= POLLIN;
if (FD_ISSET (f->fd, &wset))
f->revents |= POLLOUT;
if (FD_ISSET (f->fd, &xset))
f->revents |= POLLPRI;
}
}
return ready;
}
#endif
|
Back to SourceForge.net Powered by ViewCVS 1.0-dev |