1 /*
2  * PgBouncer - Lightweight connection pooler for PostgreSQL.
3  *
4  * Copyright (c) 2007-2009  Marko Kreen, Skype Technologies OÜ
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * event types for protocol handler
21  */
22 typedef enum {
23 	SBUF_EV_READ,		/* got new packet */
24 	SBUF_EV_RECV_FAILED,	/* error */
25 	SBUF_EV_SEND_FAILED,	/* error */
26 	SBUF_EV_CONNECT_FAILED,	/* error */
27 	SBUF_EV_CONNECT_OK,	/* got connection */
28 	SBUF_EV_FLUSH,		/* data is sent, buffer empty */
29 	SBUF_EV_PKT_CALLBACK,	/* next part of pkt data */
30 	SBUF_EV_TLS_READY	/* TLS was established */
31 } SBufEvent;
32 
33 /*
34  * If less than this amount of data is pending, then
35  * prefer to merge it with next recv().
36  *
37  * It needs to be larger than data handler wants
38  * to see completely.  Generally just header,
39  * but currently also ServerParam pkt.
40  */
41 #define SBUF_SMALL_PKT	64
42 
43 struct tls;
44 
45 /* fwd def */
46 typedef struct SBuf SBuf;
47 typedef struct SBufIO SBufIO;
48 
49 /* callback should return true if it used one of sbuf_prepare_* on sbuf,
50    false if it used sbuf_pause(), sbuf_close() or simply wants to wait for
51    next event loop (eg. too few data available). */
52 typedef bool (*sbuf_cb_t)(SBuf *sbuf,
53 			SBufEvent evtype,
54 			struct MBuf *mbuf);
55 
56 struct SBufIO {
57 	ssize_t (*sbufio_recv)(SBuf *sbuf, void *buf, size_t len);
58 	ssize_t (*sbufio_send)(SBuf *sbuf, const void *data, size_t len);
59 	int (*sbufio_close)(SBuf *sbuf);
60 };
61 
62 /*
63  * Stream Buffer.
64  *
65  * Stream is divided to packets.  On each packet start
66  * protocol handler is called that decides what to do.
67  */
68 struct SBuf {
69 	struct event ev;	/* libevent handle */
70 
71 	uint8_t wait_type;	/* track wait state */
72 	uint8_t pkt_action;	/* method for handling current pkt */
73 	uint8_t tls_state;	/* progress of tls */
74 
75 	int sock;		/* fd for this socket */
76 
77 	unsigned pkt_remain;	/* total packet length remaining */
78 
79 	sbuf_cb_t proto_cb;	/* protocol callback */
80 
81 	SBuf *dst;		/* target SBuf for current packet */
82 
83 	IOBuf *io;		/* data buffer, lazily allocated */
84 
85 	const SBufIO *ops;	/* normal vs. TLS */
86 	struct tls *tls;	/* TLS context */
87 	const char *tls_host;	/* target hostname */
88 };
89 
90 #define sbuf_socket(sbuf) ((sbuf)->sock)
91 
92 void sbuf_init(SBuf *sbuf, sbuf_cb_t proto_fn);
93 bool sbuf_accept(SBuf *sbuf, int read_sock, bool is_unix)  _MUSTCHECK;
94 bool sbuf_connect(SBuf *sbuf, const struct sockaddr *sa, socklen_t sa_len, time_t timeout_sec)  _MUSTCHECK;
95 
96 /*
97  * client_accept_sslmode is the currently applied sslmode that is used to
98  * accept client connections. This is usually the same as
99  * cf_client_tls_sslmode, except when changing the TLS configuration failed for
100  * some reason (e.g. cert file not found). In this exceptional case,
101  * cf_client_tls_sslmode will be the new sslmode, which is not actually
102  * applied. And client_accept_sslmode is the still applied previous version. So
103  * usually you should use this variable over cf_client_tls_sslmode.
104  */
105 extern int client_accept_sslmode;
106 /*
107  * Same as client_accept_sslmode, but for server connections.
108  */
109 extern int server_connect_sslmode;
110 
111 bool sbuf_tls_setup(void);
112 bool sbuf_tls_accept(SBuf *sbuf)  _MUSTCHECK;
113 bool sbuf_tls_connect(SBuf *sbuf, const char *hostname)  _MUSTCHECK;
114 
115 bool sbuf_pause(SBuf *sbuf) _MUSTCHECK;
116 void sbuf_continue(SBuf *sbuf);
117 bool sbuf_close(SBuf *sbuf) _MUSTCHECK;
118 
119 /* proto_fn can use those functions to order behaviour */
120 void sbuf_prepare_send(SBuf *sbuf, SBuf *dst, unsigned amount);
121 void sbuf_prepare_skip(SBuf *sbuf, unsigned amount);
122 void sbuf_prepare_fetch(SBuf *sbuf, unsigned amount);
123 
124 bool sbuf_answer(SBuf *sbuf, const void *buf, size_t len)  _MUSTCHECK;
125 
126 bool sbuf_continue_with_callback(SBuf *sbuf, event_callback_fn cb)  _MUSTCHECK;
127 bool sbuf_use_callback_once(SBuf *sbuf, short ev, event_callback_fn user_cb) _MUSTCHECK;
128 
129 /*
130  * Returns true if SBuf is has no data buffered
131  * and is not in a middle of a packet.
132  */
sbuf_is_empty(SBuf * sbuf)133 static inline bool sbuf_is_empty(SBuf *sbuf)
134 {
135 	return iobuf_empty(sbuf->io) && sbuf->pkt_remain == 0;
136 }
137 
sbuf_is_closed(SBuf * sbuf)138 static inline bool sbuf_is_closed(SBuf *sbuf)
139 {
140 	return sbuf->sock == 0;
141 }
142 
143 /*
144  * Lowlevel operations.
145  */
146 
sbuf_op_recv(SBuf * sbuf,void * buf,size_t len)147 static inline ssize_t sbuf_op_recv(SBuf *sbuf, void *buf, size_t len)
148 {
149 	return sbuf->ops->sbufio_recv(sbuf, buf, len);
150 }
151 
sbuf_op_send(SBuf * sbuf,const void * buf,size_t len)152 static inline ssize_t sbuf_op_send(SBuf *sbuf, const void *buf, size_t len)
153 {
154 	return sbuf->ops->sbufio_send(sbuf, buf, len);
155 }
156 
sbuf_op_close(SBuf * sbuf)157 static inline int sbuf_op_close(SBuf *sbuf)
158 {
159 	return sbuf->ops->sbufio_close(sbuf);
160 }
161 
162 void sbuf_cleanup(void);
163