/************************************************************************
 *   IRC - Internet Relay Chat, server/s_bsd.c
 *
 *   Copyright (C) 2000-2003 TR-IRCD Development
 *
 *   Copyright (C) 1990 Jarkko Oikarinen and
 *                      University of Oulu, Co Center
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2, or (at your option)
 *   any later version.
 *
 *   This program 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 General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "h.h"
#include "fd.h"
#include "s_bsd.h"
#include "event.h"
#include "listener.h"
#include "numeric.h"
#include "packet.h"
#include "resnew.h"
#include "s_auth.h"
#include "s_conf.h"
#include "hook.h"
#include "dh.h"

#ifndef IN_LOOPBACKNET
#define IN_LOOPBACKNET        0x7f
#endif

#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned int) 0xffffffff)
#endif

time_t timeofday;

char *const NONB_ERROR_MSG = "set_non_blocking failed for %s:%s";
char *const OPT_ERROR_MSG = "disable_sock_options failed for %s:%s";
char *const SETBUF_ERROR_MSG = "set_sock_buffers failed for server %s:%s";

static const char *comm_err_str[] = { 
	"Comm OK", 
	"Error during bind()",
    	"Error during DNS lookup", 	
	"connect timeout", 
	"Error during connect()",
    	"Comm Error"
};

static void comm_connect_callback(int fd, int status);
static PF comm_connect_timeout;
static void comm_connect_dns_callback(void *vptr, adns_answer * reply);
static void comm_tryall_callback(int fd, void *data);
static PF comm_connect_tryconnect;

static int hookid_read_packet = -1;
static int hookid_make_listener_client = -1;

void init_bsd(void) {
    hookid_read_packet = hook_add_event("read packet");
    hookid_make_listener_client = hook_add_event("make listener client");
}

/*
 * get_sockerr - get the error value from the socket or the current errno
 *
 * Get the *real* error from the socket (well try to anyway..).
 * This may only work when SO_DEBUG is enabled but its worth the
 * gamble anyway.
 */
int get_sockerr(int fd)
{
    int errtmp = errno;
#ifdef SO_ERROR
    int err = 0;
    socklen_t len = sizeof(err);

    if (-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *) &err, (int *) &len)) {
	if (err)
	    errtmp = err;
    }
    errno = errtmp;
#endif
    return errtmp;
}

/*
 * report_error - report an error from an errno. 
 * Record error to log and also send a copy to all *LOCAL* opers online.
 *
 *        text        is a *format* string for outputing error. It must
 *                contain only two '%s', the first will be replaced
 *                by the sockhost from the client_p, and the latter will
 *                be taken from sys_errlist[errno].
 *
 *        client_p        if not NULL, is the *LOCAL* client associated with
 *                the error.
 *
 * Cannot use perror() within daemon. stderr is closed in
 * ircd and cannot be used. And, worse yet, it might have
 * been reassigned to a normal connection...
 * 
 * Actually stderr is still there IFF ircd was run with -s --Rodder
 */

void report_error(char *text, const char *who, int error)
{
    char buf[1024];
    who = (who) ? who : "";

    ircsnprintf(buf, 1024, text, who, strerror(error));
    sendto_lev(SNOTICE_LEV, buf);
    logevent_call(LogSys.report_error, buf);
}

/*
 * set_sock_buffers - set send and receive buffers for socket
 * 
 * inputs       - fd file descriptor
 *              - size to set
 * output       - returns true (1) if successful, false (0) otherwise
 * side effects -
 */
int set_sock_buffers(int fd, int size)
{
    if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) ||
	setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &size, sizeof(size)))
	return 0;
    return 1;
}

/*
 * disable_sock_options
 * 
 * inputs       - fd
 * output       - returns true (1) if successful, false (0) otherwise
 * side effects - disable_sock_options - if remote has any socket options set,
 *                disable them 
 */
int disable_sock_options(int fd)
{
#if defined(IP_OPTIONS) && defined(IPPROTO_IP) && !defined(IPV6)
    if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0))
	return 0;
#endif
    return 1;
}

/*
 * set_non_blocking - Set the client connection into non-blocking mode. 
 *
 * inputs       - fd to set into non blocking mode
 * output       - 1 if successful 0 if not
 * side effects - use POSIX compliant non blocking and
 *                be done with it.
 */
int set_non_blocking(int fd)
{
    int nonb = 0;
    int res;
    nonb |= O_NONBLOCK;

#ifdef USE_SIGIO
    setup_sigio_fd(fd);
#endif

    res = fcntl(fd, F_GETFL, 0);
    if (-1 == res || fcntl(fd, F_SETFL, res | nonb) == -1)
	return 0;

    fd_table[fd].flags.nonblocking = 1;
    return 1;
}

/*
 * add_connection - creates a client which has just connected to us on 
 * the given fd. The sockhost field is initialized with the ip# of the host.
 * The client is sent to the auth module for verification, and not put in
 * any client list yet.
 */
void add_connection(struct Listener *listener, int fd)
{
    aClient *new_client;
#ifdef HAVE_ENCRYPTION_ON
    int new_ssl = 0;
#endif
    socklen_t len = sizeof(struct irc_sockaddr);
    struct irc_sockaddr irn;
    assert(0 != listener);

    /* 
     * get the client socket name from the socket
     * the client has already been checked out in accept_connection
     */
    if (getpeername(fd, (struct sockaddr *) &SOCKADDR(irn), (int *) &len)) {
	report_error("Failed in adding new connection %s :%s", get_listener_name(listener), errno);
	ircstp->is_ref++;
	fd_close(fd);
	return;
    }

    new_client = make_client(NULL);

    /* 
     * copy address to 'sockhost' as a string, copy it to host too
     * so we have something valid to put into error messages...
     */
    copy_s_addr(IN_ADDR(new_client->ip), S_ADDR(irn));
    inetntop(DEF_FAM, &IN_ADDR(new_client->ip), new_client->hostip, HOSTIPLEN);
#ifdef IPV6
    if((!IN6_IS_ADDR_V4MAPPED(&IN_ADDR2(new_client->ip))) &&
        (!IN6_IS_ADDR_V4COMPAT(&IN_ADDR2(new_client->ip))))
        new_client->aftype = AF_INET6;
    else {
        memmove(&new_client->ip.sins.sin.s_addr,&IN_ADDR(new_client->ip)[12], sizeof(struct in_addr));
        new_client->aftype = AF_INET;
    }
#else
    new_client->aftype = AF_INET;
#endif

    new_client->connectport = htons(S_PORT(irn));

    strcpy(new_client->sockhost, new_client->hostip);

    if (IsListenerHttp(listener)) {
	struct hook_data thisdata;
	thisdata.client_p = new_client;
	if (hook_call_event(hookid_make_listener_client, &thisdata)) {
	    dlink_node * ptr;
	    ptr = dlinkFind(&unknown_list, new_client);
	    if (ptr)
		dlinkDeleteNode(ptr, &unknown_list);
	    free_client(new_client);
	    new_client = thisdata.client_p;
	}
    }

    new_client->fd = fd;

    new_client->listener = listener;
    ++listener->ref_count;

#ifdef HAVE_ENCRYPTION_ON
    if (IsListenerClientSSL(listener) && GeneralOpts.doing_ssl && !(new_client->ssl)) {
	new_ssl = 1;
        /*SSL client init */

        if((new_client->ssl = SSL_new(ircdssl_ctx)) == NULL) {
            dlink_node * ptr;
            ptr = dlinkFind(&unknown_list, new_client);
            if (ptr)
                dlinkDeleteNode(ptr, &unknown_list);
            sendto_lev(DEBUG_LEV, "Could not create new ssl connection %s", new_client->hostip);
            ircstp->is_ref++;
            free_client(new_client);
            return;
	}
        SetSSL(new_client);
    }
#endif

    if (!set_non_blocking(new_client->fd))
        report_error(NONB_ERROR_MSG, get_client_name(new_client, TRUE), errno);
    if (!set_sock_buffers(new_client->fd, READBUF_SIZE))
        report_error(SETBUF_ERROR_MSG, get_client_name(new_client, SHOW_IP), errno);
    if (!disable_sock_options(new_client->fd))
        report_error(OPT_ERROR_MSG, get_client_name(new_client, TRUE), errno);

#ifdef HAVE_ENCRYPTION_ON
    if (IsSSL(new_client) && new_ssl) {
   	SSL_set_fd(new_client->ssl, new_client->fd);
        if (!safe_SSL_accept(new_client, new_client->fd)) {
            dlink_node * ptr;
            ptr = dlinkFind(&unknown_list, new_client);
            if (ptr)
                dlinkDeleteNode(ptr, &unknown_list);
            SSL_set_shutdown(new_client->ssl, SSL_RECEIVED_SHUTDOWN);
            SSL_smart_shutdown(new_client->ssl);
            SSL_free(new_client->ssl);
	    ircstp->is_ref++;
	    free_client(new_client);
	    return;
        }
    }
#endif

    if (IsListenerHttp(new_client->listener))
	comm_setselect(fd, FDLIST_HTTPD, COMM_SELECT_WRITE, comm_tryall_callback, new_client, 0);
    else
    	comm_setselect(fd, FDLIST_IRCD, COMM_SELECT_WRITE, comm_tryall_callback, new_client, 0);	
}

void dead_link_on_read(struct Client *client_p, int error)
{
    /*
     * ...hmm, with non-blocking sockets we might get
     * here from quite valid reasons, although.. why
     * would select report "data available" when there
     * wasn't... so, this must be an error anyway...  --msa
     * actually, EOF occurs when read() returns 0 and
     * in due course, select() returns that fd as ready
     * for reading even though it ends up being an EOF. -avalon
     */

    char errmsg[255];
    int current_error = get_sockerr(client_p->fd);

    logevent_call(LogSys.read_error, client_p, client_p->fd, current_error, error);
    if (IsServer(client_p) || IsHandshake(client_p)) {
    int connected = timeofday - client_p->firsttime;

	if (error == 0) {
	    sendto_gnotice("Server %s closed the connection", get_client_name(client_p, TRUE));

	} else {
	    report_error("Lost connection to %s: %d",
			 get_client_name(client_p, TRUE), current_error);

	}

	sendto_gnotice("%s had been connected for %d day%s, %2d:%02d:%02d",
		       client_p->name, connected / 86400,
		       (connected / 86400 == 1) ? "" : "s",
		       (connected % 86400) / 3600, (connected % 3600) / 60, connected % 60);
    }
    if (error == 0) {
	strcpy(errmsg, "Remote host closed the connection");
    } else {
	ircsprintf(errmsg, "Read error: %d (%s)", current_error, strerror(current_error));
    }
    exit_client(client_p, &me, errmsg);
}

/*
 * stolen from squid - its a neat (but overused! :) routine which we
 * can use to see whether we can ignore this errno or not. It is
 * generally useful for non-blocking network IO related errnos.
 *     -- adrian
 */
int ignoreErrno(int ierrno)
{
    switch (ierrno) {
	case EINPROGRESS:
	case EWOULDBLOCK:
#if EAGAIN != EWOULDBLOCK
	case EAGAIN:
#endif
	case EALREADY:
	case EINTR:
#ifdef ERESTART
	case ERESTART:
#endif
	    return 1;
	default:
	    return 0;
    }
    /* NOTREACHED */
    return 0;
}

/*
 * comm_settimeout() - set the socket timeout
 *
 * Set the timeout for the fd
 */
void comm_settimeout(int fd, time_t timeout, PF * callback, void *cbdata)
{
    assert(fd > -1);
    assert(fd_table[fd].flags.open);

    fd_table[fd].timeout = timeofday + (timeout / 1000);
    fd_table[fd].timeout_handler = callback;
    fd_table[fd].timeout_data = cbdata;
}

/*
 * comm_setflush() - set a flush function
 *
 * A flush function is simply a function called if found during
 * comm_timeouts(). Its basically a second timeout, except in this case
 * I'm too lazy to implement multiple timeout functions! :-)
 * its kinda nice to have it seperate, since this is designed for
 * flush functions, and when comm_close() is implemented correctly
 * with close functions, we _actually_ don't call comm_close() here ..
 */
void comm_setflush(int fd, time_t timeout, PF * callback, void *cbdata)
{
    if (fd < 1)
	return;

    fd_table[fd].flush_timeout = timeofday + (timeout / 1000);
    fd_table[fd].flush_handler = callback;
    fd_table[fd].flush_data = cbdata;
}

/*
 * comm_checktimeouts() - check the socket timeouts
 *
 * All this routine does is call the given callback/cbdata, without closing
 * down the file descriptor. When close handlers have been implemented,
 * this will happen.
 */
void comm_checktimeouts(void *notused)
{
    int fd;
    PF *hdl;
    void *data;

    for (fd = 0; fd <= highest_fd; fd++) {
	if (!fd_table[fd].flags.open)
	    continue;
	if (fd_table[fd].flags.closing)
	    continue;

	/* check flush functions */
	if (fd_table[fd].flush_handler &&
	    fd_table[fd].flush_timeout > 0 && fd_table[fd].flush_timeout < timeofday) {
	    hdl = fd_table[fd].flush_handler;
	    data = fd_table[fd].flush_data;
	    comm_setflush(fd, 0, NULL, NULL);
	    hdl(fd, data);
	}

	/* check timeouts */
	if (fd_table[fd].timeout_handler &&
	    fd_table[fd].timeout > 0 && fd_table[fd].timeout < timeofday) {
	    /* Call timeout handler */
	    hdl = fd_table[fd].timeout_handler;
	    data = fd_table[fd].timeout_data;
	    comm_settimeout(fd, 0, NULL, NULL);
	    hdl(fd, fd_table[fd].timeout_data);
	}
    }
}

/*
 * void comm_connect_tcp(int fd, const char *host, u_short port,
 *                       struct sockaddr *clocal, int socklen,
 *                       CNCB *callback, void *data, int aftype)
 * Input: An fd to connect with, a host and port to connect to,
 *        a local sockaddr to connect from + length(or NULL to use the
 *        default), a callback, the data to pass into the callback, the
 *        address family.
 * Output: None.
 * Side-effects: A non-blocking connection to the host is started, and
 *               if necessary, set up for selection. The callback given
 *               may be called now, or it may be called later.
 */
void
comm_connect_tcp(int fd, const char *host, u_short port,
		 struct sockaddr *clocal, int socklen, CNCB * callback, 
		 void *data, int aftype, int timeout)
{
    fd_table[fd].flags.called_connect = 1;
    assert(callback != NULL);
    fd_table[fd].connect.callback = callback;
    fd_table[fd].connect.data = data;

    S_FAM(fd_table[fd].connect.hostaddr) = DEF_FAM;
    S_PORT(fd_table[fd].connect.hostaddr) = htons(port);

    /* Note that we're using a passed sockaddr here. This is because
     * generally you'll be bind()ing to a sockaddr grabbed from
     * getsockname(), so this makes things easier.
     * XXX If NULL is passed as local, we should later on bind() to the
     * virtual host IP, for completeness.
     *   -- adrian
     */

    if ((clocal != NULL) && (bind(fd, clocal, socklen) < 0)) {
	/* Failure, call the callback with COMM_ERR_BIND */
	comm_connect_callback(fd, COMM_ERR_BIND);
	/* ... and quit */
	return;
    }

    /* Next, if we have been given an IP, get the addr and skip the
     * DNS check (and head direct to comm_connect_tryconnect().
     */

    if (inetpton(DEF_FAM, host, S_ADDR(&fd_table[fd].connect.hostaddr)) <= 0) {
	/* Send the DNS request, for the next level */
	fd_table[fd].dns_query = (struct DNSQuery *) MyMalloc(sizeof(struct DNSQuery));
	fd_table[fd].dns_query->ptr = &fd_table[fd];
	fd_table[fd].dns_query->callback = comm_connect_dns_callback;
	adns_gethost(host, aftype, fd_table[fd].dns_query);
    } else {
	/* We have a valid IP, so we just call tryconnect */
	/* Make sure we actually set the timeout here .. */
	comm_settimeout(fd, timeout * 1000, comm_connect_timeout, NULL);
	comm_connect_tryconnect(fd, NULL);
    }
}

/*
 * comm_connect_callback() - call the callback, and continue with life
 */
static void comm_connect_callback(int fd, int status)
{
    CNCB *hdl;
    /* This check is gross..but probably necessary */
    if (fd_table[fd].connect.callback == NULL)
	return;
    /* Clear the connect flag + handler */
    hdl = fd_table[fd].connect.callback;
    fd_table[fd].connect.callback = NULL;
    fd_table[fd].flags.called_connect = 0;

    /* Clear the timeout handler */
    comm_settimeout(fd, 0, NULL, NULL);

    /* Call the handler */
    hdl(fd, status, fd_table[fd].connect.data);
}

/*
 * comm_tryall_callback - This does ensure the finishing of an ssl
 * accept routine before we continue with identd lookups.
 * -TimeMr14C
 */

static void comm_tryall_callback(int fd, void *data)
{
    int doauth = -1;
    aClient *cptr = data;
    struct hook_data thisdata;

    fdlist_t fdlist = FDLIST_NONE;

    if (IsListenerHttp(cptr->listener)) {
 	fdlist = FDLIST_HTTPD;
	doauth = 0;
    } else if (IsListenerClient(cptr->listener)) {
        fdlist = FDLIST_IRCD;
        doauth = 2;
    } else if (IsListenerServer(cptr->listener)) { 
	fdlist = FDLIST_IRCD;
	doauth = 1;
    } else if (IsListenerService(cptr->listener)) {
        fdlist = FDLIST_IRCD;
        doauth = 1;
    }

#ifdef HAVE_ENCRYPTION_ON
    if (IsSSL(cptr)) {
	if (!SSL_is_init_finished(cptr->ssl)) {
	    if (!safe_SSL_accept(cptr, cptr->fd)) {
		dead_link_on_read(cptr, errno);
		return;
	    } else {
		comm_setselect(fd, fdlist, COMM_SELECT_WRITE, comm_tryall_callback, cptr, 0);
		return;
	    }
	}
    }
#endif

    if (doauth == 2) {
    	start_auth(cptr);
    } else if (doauth == 1) {
	start_lookup(cptr);
    } else if (doauth == 0) {
	thisdata.check = fd;
	thisdata.client_p = cptr;
	hook_call_event(hookid_read_packet, &thisdata);
    }
}

/*
 * comm_connect_timeout() - this gets called when the socket connection
 * times out. This *only* can be called once connect() is initially
 * called ..
 */
static void comm_connect_timeout(int fd, void *notused)
{
    /* error! */
    comm_connect_callback(fd, COMM_ERR_TIMEOUT);
}

/*
 * comm_connect_dns_callback() - called at the completion of the DNS request
 *
 * The DNS request has completed, so if we've got an error, return it,
 * otherwise we initiate the connect()
 */
static void comm_connect_dns_callback(void *vptr, adns_answer * reply)
{
    fde_t *F = vptr;

    if (!reply) {
	comm_connect_callback(F->fd, COMM_ERR_DNS);
	return;
    }

    if (reply->status != adns_s_ok) {
	/* Yes, callback + return */
	comm_connect_callback(F->fd, COMM_ERR_DNS);
	MyFree(reply);
	MyFree(F->dns_query);
	return;
    }

    /* No error, set a 10 second timeout */
    comm_settimeout(F->fd, 30 * 1000, comm_connect_timeout, NULL);

    /* Copy over the DNS reply info so we can use it in the connect() */
    /*
     * Note we don't fudge the refcount here, because we aren't keeping
     * the DNS record around, and the DNS cache is gone anyway.. 
     *     -- adrian
     */
#ifdef IPV6
    if(reply->rrs.addr->addr.sa.sa_family == AF_INET6) {
        copy_s_addr(S_ADDR(F->connect.hostaddr), reply->rrs.addr->addr.inet6.sin6_addr.s6_addr);
    } else {
        /* IPv4 mapped address */
        /* This is lazy... */
        memset(&F->connect.hostaddr.sins.sin6.sin6_addr.s6_addr, 0x0000, 10);
        memset(&F->connect.hostaddr.sins.sin6.sin6_addr.s6_addr[10], 0xffff, 2);
        memcpy(&F->connect.hostaddr.sins.sin6.sin6_addr.s6_addr[12], &reply->rrs.addr->addr.inet.sin_addr.s_addr, 4);
    }
#else
    F->connect.hostaddr.sins.sin.sin_addr.s_addr = reply->rrs.addr->addr.inet.sin_addr.s_addr;
#endif

    /* Now, call the tryconnect() routine to try a connect() */
    MyFree(reply);
    comm_connect_tryconnect(F->fd, NULL);
}

/* static void comm_connect_tryconnect(int fd, void *notused)
 * Input: The fd, the handler data(unused).
 * Output: None.
 * Side-effects: Try and connect with pending connect data for the FD. If
 *               we succeed or get a fatal error, call the callback.
 *               Otherwise, it is still blocking or something, so register
 *               to select for a write event on this FD.
 */
static void comm_connect_tryconnect(int fd, void *notused)
{
    int retval;
    assert(fd_table[fd].connect.callback != NULL);
    /* Try the connect() */
    retval =
	connect(fd,
		(struct sockaddr *) &SOCKADDR(fd_table[fd].connect.hostaddr),
		sizeof(struct irc_sockaddr));
    /* Error? */
    if (retval < 0) {
	/*
	 * If we get EISCONN, then we've already connect()ed the socket,
	 * which is a good thing.
	 *   -- adrian
	 */
	if (errno == EISCONN)
	    comm_connect_callback(fd, COMM_OK);
	else if (ignoreErrno(errno))
	    /* Ignore error? Reschedule */
	    comm_setselect(fd, FDLIST_IRCD, COMM_SELECT_WRITE, comm_connect_tryconnect, NULL, 0);
	else
	    /* Error? Fail with COMM_ERR_CONNECT */
	    comm_connect_callback(fd, COMM_ERR_CONNECT);
	return;
    }
    /* If we get here, we've suceeded, so call with COMM_OK */
    comm_connect_callback(fd, COMM_OK);
}

/*
 * comm_error_str() - return an error string for the given error condition
 */
const char *comm_errstr(int error)
{
    if (error < 0 || error >= COMM_ERR_MAX)
	return "Invalid error number!";
    return comm_err_str[error];
}

/*
 * comm_open() - open a socket
 *
 * This is a highly highly cut down version of squid's comm_open() which
 * for the most part emulates socket(), *EXCEPT* it fails if we're about
 * to run out of file descriptors.
 */
int comm_open(int family, int sock_type, int proto, const char *note)
{
    int fd;
    /* First, make sure we aren't going to run out of file descriptors */
    if (number_fd >= MAXCONNECTIONS) {
	errno = ENFILE;
	return -1;
    }

    /*
     * Next, we try to open the socket. We *should* drop the reserved FD
     * limit if/when we get an error, but we can deal with that later.
     * XXX !!! -- adrian
     */

    fd = socket(family, sock_type, proto);
    if (fd < 0)
	return -1;		/* errno will be passed through, yay.. */

    /* Set the socket non-blocking, and other wonderful bits */
    if (!set_non_blocking(fd)) {
	close(fd);
	return -1;
    }

    /* Next, update things in our fd tracking */
    fd_open(fd, FD_SOCKET, note);
    return fd;
}

/*
 * comm_accept() - accept an incoming connection
 *
 * This is a simple wrapper for accept() which enforces FD limits like
 * comm_open() does.
 */
int comm_accept(int fd, struct irc_sockaddr *pn)
{
    int newfd;
    socklen_t addrlen = sizeof(struct irc_sockaddr);
    if (number_fd >= MAXCONNECTIONS) {
	errno = ENFILE;
	return -1;
    }

    /*
     * Next, do the accept(). if we get an error, we should drop the
     * reserved fd limit, but we can deal with that when comm_open()
     * also does it. XXX -- adrian
     */

    newfd = accept(fd, (struct sockaddr *) &PSOCKADDR(pn), (int *) &addrlen);

    if (newfd < 0)
	return -1;

    /* Set the socket non-blocking, and other wonderful bits */
    if (!set_non_blocking(newfd)) {
	close(newfd);
	return -1;
    }
    /* Next, tag the FD as an incoming connection */
    fd_open(newfd, FD_SOCKET, "Incoming connection");

    /* .. and return */
    return newfd;
}


syntax highlighted by Code2HTML, v. 0.9.1