1
2/*
3 * Copyright (c) 2019, Redis Labs
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of Redis nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#ifndef __REDIS_CONNECTION_H
32#define __REDIS_CONNECTION_H
33
34#include <errno.h>
35#include <sys/uio.h>
36
37#define CONN_INFO_LEN 32
38
39struct aeEventLoop;
40typedef struct connection connection;
41
42typedef enum {
43 CONN_STATE_NONE = 0,
44 CONN_STATE_CONNECTING,
45 CONN_STATE_ACCEPTING,
46 CONN_STATE_CONNECTED,
47 CONN_STATE_CLOSED,
48 CONN_STATE_ERROR
49} ConnectionState;
50
51#define CONN_FLAG_CLOSE_SCHEDULED (1<<0) /* Closed scheduled by a handler */
52#define CONN_FLAG_WRITE_BARRIER (1<<1) /* Write barrier requested */
53
54#define CONN_TYPE_SOCKET 1
55#define CONN_TYPE_TLS 2
56
57typedef void (*ConnectionCallbackFunc)(struct connection *conn);
58
59typedef struct ConnectionType {
60 void (*ae_handler)(struct aeEventLoop *el, int fd, void *clientData, int mask);
61 int (*connect)(struct connection *conn, const char *addr, int port, const char *source_addr, ConnectionCallbackFunc connect_handler);
62 int (*write)(struct connection *conn, const void *data, size_t data_len);
63 int (*writev)(struct connection *conn, const struct iovec *iov, int iovcnt);
64 int (*read)(struct connection *conn, void *buf, size_t buf_len);
65 void (*close)(struct connection *conn);
66 int (*accept)(struct connection *conn, ConnectionCallbackFunc accept_handler);
67 int (*set_write_handler)(struct connection *conn, ConnectionCallbackFunc handler, int barrier);
68 int (*set_read_handler)(struct connection *conn, ConnectionCallbackFunc handler);
69 const char *(*get_last_error)(struct connection *conn);
70 int (*blocking_connect)(struct connection *conn, const char *addr, int port, long long timeout);
71 ssize_t (*sync_write)(struct connection *conn, char *ptr, ssize_t size, long long timeout);
72 ssize_t (*sync_read)(struct connection *conn, char *ptr, ssize_t size, long long timeout);
73 ssize_t (*sync_readline)(struct connection *conn, char *ptr, ssize_t size, long long timeout);
74 int (*get_type)(struct connection *conn);
75} ConnectionType;
76
77struct connection {
78 ConnectionType *type;
79 ConnectionState state;
80 short int flags;
81 short int refs;
82 int last_errno;
83 void *private_data;
84 ConnectionCallbackFunc conn_handler;
85 ConnectionCallbackFunc write_handler;
86 ConnectionCallbackFunc read_handler;
87 int fd;
88};
89
90/* The connection module does not deal with listening and accepting sockets,
91 * so we assume we have a socket when an incoming connection is created.
92 *
93 * The fd supplied should therefore be associated with an already accept()ed
94 * socket.
95 *
96 * connAccept() may directly call accept_handler(), or return and call it
97 * at a later time. This behavior is a bit awkward but aims to reduce the need
98 * to wait for the next event loop, if no additional handshake is required.
99 *
100 * IMPORTANT: accept_handler may decide to close the connection, calling connClose().
101 * To make this safe, the connection is only marked with CONN_FLAG_CLOSE_SCHEDULED
102 * in this case, and connAccept() returns with an error.
103 *
104 * connAccept() callers must always check the return value and on error (C_ERR)
105 * a connClose() must be called.
106 */
107
108static inline int connAccept(connection *conn, ConnectionCallbackFunc accept_handler) {
109 return conn->type->accept(conn, accept_handler);
110}
111
112/* Establish a connection. The connect_handler will be called when the connection
113 * is established, or if an error has occurred.
114 *
115 * The connection handler will be responsible to set up any read/write handlers
116 * as needed.
117 *
118 * If C_ERR is returned, the operation failed and the connection handler shall
119 * not be expected.
120 */
121static inline int connConnect(connection *conn, const char *addr, int port, const char *src_addr,
122 ConnectionCallbackFunc connect_handler) {
123 return conn->type->connect(conn, addr, port, src_addr, connect_handler);
124}
125
126/* Blocking connect.
127 *
128 * NOTE: This is implemented in order to simplify the transition to the abstract
129 * connections, but should probably be refactored out of cluster.c and replication.c,
130 * in favor of a pure async implementation.
131 */
132static inline int connBlockingConnect(connection *conn, const char *addr, int port, long long timeout) {
133 return conn->type->blocking_connect(conn, addr, port, timeout);
134}
135
136/* Write to connection, behaves the same as write(2).
137 *
138 * Like write(2), a short write is possible. A -1 return indicates an error.
139 *
140 * The caller should NOT rely on errno. Testing for an EAGAIN-like condition, use
141 * connGetState() to see if the connection state is still CONN_STATE_CONNECTED.
142 */
143static inline int connWrite(connection *conn, const void *data, size_t data_len) {
144 return conn->type->write(conn, data, data_len);
145}
146
147/* Gather output data from the iovcnt buffers specified by the members of the iov
148 * array: iov[0], iov[1], ..., iov[iovcnt-1] and write to connection, behaves the same as writev(3).
149 *
150 * Like writev(3), a short write is possible. A -1 return indicates an error.
151 *
152 * The caller should NOT rely on errno. Testing for an EAGAIN-like condition, use
153 * connGetState() to see if the connection state is still CONN_STATE_CONNECTED.
154 */
155static inline int connWritev(connection *conn, const struct iovec *iov, int iovcnt) {
156 return conn->type->writev(conn, iov, iovcnt);
157}
158
159/* Read from the connection, behaves the same as read(2).
160 *
161 * Like read(2), a short read is possible. A return value of 0 will indicate the
162 * connection was closed, and -1 will indicate an error.
163 *
164 * The caller should NOT rely on errno. Testing for an EAGAIN-like condition, use
165 * connGetState() to see if the connection state is still CONN_STATE_CONNECTED.
166 */
167static inline int connRead(connection *conn, void *buf, size_t buf_len) {
168 int ret = conn->type->read(conn, buf, buf_len);
169 return ret;
170}
171
172/* Register a write handler, to be called when the connection is writable.
173 * If NULL, the existing handler is removed.
174 */
175static inline int connSetWriteHandler(connection *conn, ConnectionCallbackFunc func) {
176 return conn->type->set_write_handler(conn, func, 0);
177}
178
179/* Register a read handler, to be called when the connection is readable.
180 * If NULL, the existing handler is removed.
181 */
182static inline int connSetReadHandler(connection *conn, ConnectionCallbackFunc func) {
183 return conn->type->set_read_handler(conn, func);
184}
185
186/* Set a write handler, and possibly enable a write barrier, this flag is
187 * cleared when write handler is changed or removed.
188 * With barrier enabled, we never fire the event if the read handler already
189 * fired in the same event loop iteration. Useful when you want to persist
190 * things to disk before sending replies, and want to do that in a group fashion. */
191static inline int connSetWriteHandlerWithBarrier(connection *conn, ConnectionCallbackFunc func, int barrier) {
192 return conn->type->set_write_handler(conn, func, barrier);
193}
194
195static inline void connClose(connection *conn) {
196 conn->type->close(conn);
197}
198
199/* Returns the last error encountered by the connection, as a string. If no error,
200 * a NULL is returned.
201 */
202static inline const char *connGetLastError(connection *conn) {
203 return conn->type->get_last_error(conn);
204}
205
206static inline ssize_t connSyncWrite(connection *conn, char *ptr, ssize_t size, long long timeout) {
207 return conn->type->sync_write(conn, ptr, size, timeout);
208}
209
210static inline ssize_t connSyncRead(connection *conn, char *ptr, ssize_t size, long long timeout) {
211 return conn->type->sync_read(conn, ptr, size, timeout);
212}
213
214static inline ssize_t connSyncReadLine(connection *conn, char *ptr, ssize_t size, long long timeout) {
215 return conn->type->sync_readline(conn, ptr, size, timeout);
216}
217
218/* Return CONN_TYPE_* for the specified connection */
219static inline int connGetType(connection *conn) {
220 return conn->type->get_type(conn);
221}
222
223static inline int connLastErrorRetryable(connection *conn) {
224 return conn->last_errno == EINTR;
225}
226
227connection *connCreateSocket();
228connection *connCreateAcceptedSocket(int fd);
229
230connection *connCreateTLS();
231connection *connCreateAcceptedTLS(int fd, int require_auth);
232
233void connSetPrivateData(connection *conn, void *data);
234void *connGetPrivateData(connection *conn);
235int connGetState(connection *conn);
236int connHasWriteHandler(connection *conn);
237int connHasReadHandler(connection *conn);
238int connGetSocketError(connection *conn);
239
240/* anet-style wrappers to conns */
241int connBlock(connection *conn);
242int connNonBlock(connection *conn);
243int connEnableTcpNoDelay(connection *conn);
244int connDisableTcpNoDelay(connection *conn);
245int connKeepAlive(connection *conn, int interval);
246int connSendTimeout(connection *conn, long long ms);
247int connRecvTimeout(connection *conn, long long ms);
248int connPeerToString(connection *conn, char *ip, size_t ip_len, int *port);
249int connFormatFdAddr(connection *conn, char *buf, size_t buf_len, int fd_to_str_type);
250int connSockName(connection *conn, char *ip, size_t ip_len, int *port);
251const char *connGetInfo(connection *conn, char *buf, size_t buf_len);
252
253/* Helpers for tls special considerations */
254sds connTLSGetPeerCert(connection *conn);
255int tlsHasPendingData();
256int tlsProcessPendingData();
257
258#endif /* __REDIS_CONNECTION_H */
259