/*
*	(wb) bufferedSock.h provides generic buffered sockets
*
*  Created by: Win Bausch and Bettina Kemme
*
*/
#ifndef BUFSOCK_H
#define BUFSOCK_H

#include "libpq/libpq-be.h"

#define MAX_ERRORMSG_LEN 256

/*
* fixes the buffer size when socket is created
* New memory block is allocated whenever inbuffer
* free space is less than a REALLOC_FRACTION part of 
* its initial size. Buffer size is then doubled.
*/ 
#define	AF_INET_BUFSIZE 8192
//#define AF_UNIX_BUFSIZE 1024
#define AF_UNIX_BUFSIZE 8192
#define EBUF_DEFAULT_SIZE 1024 
/* 
* defines the amount of buffer that must
* be available before a recv 
* operation is issued. For example:
* if the buffer size is AF_INET_BUFSIZE,
* then new buffer will be allocated if 
* free space is less than 2048 bytes,
* 2048 being roughly the size of an 
* incoming IP packet. 
* 
*	choose these numbers wisely...
*/
#define REALLOC_FRACTION 4

/* (mc) */
#define INT_SIZE	4
/**/

typedef enum
{
	NOT_CONNECTED,
	CONNECTION_OK,
	CONNECTION_ERROR,
} status_t;

typedef struct
{
	/*Connection Data*/
	int 		sock;
	SockAddr	laddr;		/* Local address */
	SockAddr	raddr;		/* Remote address */
	int			raddr_len;	/* Length of remote address */
	status_t	status; 	/* Connection status */
	
	/* Buffer for data received from backend and not yet processed */
	char		*inBuffer;	/* currently allocated buffer */
	int			inBufSize;	/* allocated size of buffer */
	int			inStart;	/* offset to first unconsumed data in buffer */
	int			inCursor;	/* next byte to tentatively consume */
	int			inEnd;		/* offset to first position after avail data */

	/* Buffer for data not yet sent to backend */
	char		*outBuffer;	/* currently allocated buffer */
	int			outBufSize;	/* allocated size of buffer */
	int			outCount;	/* number of chars waiting in buffer */
	
	/* error message field */
	char		errorMessage[MAX_ERRORMSG_LEN];
} buf_sock;

/*
* External buffers can be used to construct a message outside 
* a buffered socket. It can be flushed directly to a socket
* without copying it into the outBuffer of the corresponding socket
*	Use: if for example a message is constructed and the message size
*	must be prepended to the message itself. The message can
*	then be constructed in an external buffer. Its size is computed on 
*	the fly, put into the outbuffer of the corresponding buffered socket
*	and is then flushed. The external buffer is flushed immediatly afterwards 
*	to the same socket. This allows us to 'prepend' data to a message, which is
*	not possible with the conventional buffered socket. The latter
*	only allows sequential writes 
*/
typedef struct
{
	char 	*buf;
	int 	buflen;
	int		currindex;
} ebuf;

typedef ebuf *ebufptr;

typedef buf_sock *bufsockptr;

extern bufsockptr sockInit(int bufsize);
extern void sockDestroy(bufsockptr bsock);
extern int sockGetc(char *result, bufsockptr bsock);
extern int sockGets(char *s, int maxlen, bufsockptr bsock);
extern int sockPuts(const char *s, bufsockptr bsock);
extern int sockGetSlen(bufsockptr bsock);
extern int sockGetnchar(char *s, int len, bufsockptr bsock);
extern int sockPutnchar(const char *s, int len, bufsockptr bsock);
extern int sockGetInt(int *result, int bytes, bufsockptr bsock);
extern int sockPutInt(int value, int bytes, bufsockptr bsock);
extern int sockReadData(bufsockptr bsock, int maxbytes, bool useLimit);
extern int sockFlush(bufsockptr bsock);

#ifdef REPL_UPDATE_EVERYWHERE
/*  swu */
extern int sockWaitWithCheckAbort(bufsockptr bsock, bool forRead, bool forWrite, 
					struct timeval *wait_time);
#endif

extern int sockWait(bufsockptr bsock, bool forRead, bool forWrite);
extern void sockResetBuffers(bool in, bool out, bufsockptr bsock);
extern void sockResetCursor(bufsockptr bsock);
extern void sockConsume(bufsockptr bsock);
extern int sockIsConnected(bufsockptr bsock);
extern int sockNumLeft(bufsockptr bsock);
extern int sockPeekHeader(int nbytes, bufsockptr bsock, char *header);
extern int sockTransfer(bufsockptr dest, bufsockptr src, int len);
extern int sockIgnoreData(int nbytes, bufsockptr bsock);

extern void sockInitE(ebufptr extbuf, int buflen);
extern void sockDestroyE(ebufptr extbuf);
extern int sockGetCountE(ebufptr extbuf);
extern void sockPutsE(const char *s, ebufptr extbuf);
extern void sockPutncharE(const char *s, int len, ebufptr extbuf);
extern void sockPutIntE(int value, int bytes, ebufptr extbuf);
extern void sockFlushE(ebufptr extbuf, bufsockptr bsock, bool flushBeforePipe);

extern int sockServerPort(const char *hostName, short portNumber, int *fdP, struct sockaddr *serverAddr);
extern int sockServerAccept(int server_fd, bufsockptr bsock);
extern int sockClientConnect(const char *hostName, short portName, bufsockptr bsock);
extern void sockClose(bufsockptr bsock);
extern void sockUnlink(char path[]);

extern int sockCheck(bufsockptr bsock, bool *forRead, bool *forWrite, bool *forExcept);

#endif /*BUFSOCK_H*/
