/* 
   socket handling interface
   Copyright (C) 1999-2002, Joe Orton <joe@manyfish.co.uk>

   This 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.
   
   This 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 this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
   MA 02111-1307, USA

*/

#ifndef NE_SOCKET_H
#define NE_SOCKET_H

#ifdef WIN32
#include <winsock2.h>
#include <stddef.h>
#include <sys/types.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#endif

#ifdef NEON_SSL
#include <openssl/ssl.h>
#endif

#include "ne_defs.h"

BEGIN_NEON_DECLS

/* define ssize_t for Win32 */
#if defined(WIN32) && !defined(ssize_t)
#define ssize_t int
#endif

#define NE_SOCK_ERROR -1
/* Read/Write timed out */
#define NE_SOCK_TIMEOUT -2
/* Socket was closed */
#define NE_SOCK_CLOSED -3

typedef struct ne_socket_s ne_socket;

typedef void (*ne_block_reader) (
    void *userdata, const char *buf, size_t len);

typedef void (*ne_progress)(void *userdata, off_t progress, off_t total);

void ne_register_progress(ne_socket *sock, ne_progress cb, void *userdata);

/* While neon itself doesn't require per-process global
 * initialization, some platforms do, and so does the OpenSSL
 * library. */
int ne_sock_init(void);

/* Shutdown any underlying libraries. */
void ne_sock_exit(void);

/* ne_read is read() with a timeout
 * Returns:
 *   NE_SOCK_* on error,
 *    0 on no data to read (due to EOF),
 *   >0 length of data read into buffer.
 */
ssize_t ne_sock_read(ne_socket *sock, char *buffer, size_t count);

/* ne_peek is recv() with a timeout
 * Returns:
 *   NE_SOCK_* on error,
 *    0 on no data to read (due to EOF),
 *   >0 length of data read into buffer.
 */
ssize_t ne_sock_peek(ne_socket *sock, char *buffer, size_t count);

/* Block for up to 'n' seconds until data becomes available for reading
 * on the socket. Returns:
 *  NE_SOCK_* on error,
 *  NE_SOCK_TIMEOUT if no data arrives in 'n' seconds.
 *  0 if data arrived on the socket.
 */
int ne_sock_block(ne_socket *sock, int n);

/* Sends the given block of data down the ne_socket. Returns zero on
 * success, NE_SOCK_* on error. */
int ne_sock_fullwrite(ne_socket *sock, const char *data, size_t length); 

/* Reads a line from given ne_socket */
ssize_t ne_sock_readline(ne_socket *sock, char *line, size_t len);

/* Read exactly 'len' bytes into buffer; returns 0 on success, SOCK_*
 * on error. */
ssize_t ne_sock_fullread(ne_socket *sock, char *buffer, size_t buflen);

/* Creates and connects a ne_socket */
ne_socket *ne_sock_connect(const struct in_addr host, 
			   unsigned short int portnum);

/* Not as good as accept(2), missing parms 2+3.
 * Addings parms 2+3 would probably mean passing socklen_t as an
 * int then casting internally, since we don't really want to
 * autogenerate the header file to be correct for the build platform.
 */
ne_socket *ne_sock_accept(int listener);

/* Returns the file descriptor used for the socket */
int ne_sock_fd(const ne_socket *sock);

/* Closes the socket and frees the ne_socket object.  Returns non-zero
 * on error. */
int ne_sock_close(ne_socket *sock);

const char *ne_sock_error(const ne_socket *sock);

/* Set read timeout for socket. */
void ne_sock_read_timeout(ne_socket *sock, int timeout);

/* Do a name lookup on given hostname, writes the address into
 * given address buffer. Return -1 on failure. */
int ne_name_lookup(const char *hostname, struct in_addr *addr);

/* Returns the standard TCP port for the given service */
int ne_service_lookup(const char *name);

/* Enable SSL/TLS on the socket. Returns non-zero if the SSL
 * negotiation fails. */
int ne_sock_use_ssl(ne_socket *sock);

#ifdef NEON_SSL
/* FIXME: this is a terribly disgusting API. */

/* Enable SSL/TLS, using the given OpenSSL SSL context, and resuming
 * the given session if sess is non-NULL. Returns non-zero if the SSL
 * negotiation fails.  If out is non-NULL, *out is set to the SSL
 * connection structure from OpenSSL. */
int ne_sock_use_ssl_os(ne_socket *sock, SSL_CTX *ctx, 
		       SSL_SESSION *sess, SSL **out, void *appdata);
#endif

END_NEON_DECLS

#endif /* NE_SOCKET_H */
