mirror of
https://github.com/fluencelabs/redis
synced 2025-06-15 02:01:21 +00:00
TLS: Connections refactoring and TLS support.
* Introduce a connection abstraction layer for all socket operations and integrate it across the code base. * Provide an optional TLS connections implementation based on OpenSSL. * Pull a newer version of hiredis with TLS support. * Tests, redis-cli updates for TLS support.
This commit is contained in:
@ -39,7 +39,7 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
void replicationDiscardCachedMaster(void);
|
||||
void replicationResurrectCachedMaster(int newfd);
|
||||
void replicationResurrectCachedMaster(connection *conn);
|
||||
void replicationSendAck(void);
|
||||
void putSlaveOnline(client *slave);
|
||||
int cancelReplicationHandshake(void);
|
||||
@ -57,7 +57,7 @@ char *replicationGetSlaveName(client *c) {
|
||||
ip[0] = '\0';
|
||||
buf[0] = '\0';
|
||||
if (c->slave_ip[0] != '\0' ||
|
||||
anetPeerToString(c->fd,ip,sizeof(ip),NULL) != -1)
|
||||
connPeerToString(c->conn,ip,sizeof(ip),NULL) != -1)
|
||||
{
|
||||
/* Note that the 'ip' buffer is always larger than 'c->slave_ip' */
|
||||
if (c->slave_ip[0] != '\0') memcpy(ip,c->slave_ip,sizeof(c->slave_ip));
|
||||
@ -432,7 +432,7 @@ int replicationSetupSlaveForFullResync(client *slave, long long offset) {
|
||||
if (!(slave->flags & CLIENT_PRE_PSYNC)) {
|
||||
buflen = snprintf(buf,sizeof(buf),"+FULLRESYNC %s %lld\r\n",
|
||||
server.replid,offset);
|
||||
if (write(slave->fd,buf,buflen) != buflen) {
|
||||
if (connWrite(slave->conn,buf,buflen) != buflen) {
|
||||
freeClientAsync(slave);
|
||||
return C_ERR;
|
||||
}
|
||||
@ -519,7 +519,7 @@ int masterTryPartialResynchronization(client *c) {
|
||||
} else {
|
||||
buflen = snprintf(buf,sizeof(buf),"+CONTINUE\r\n");
|
||||
}
|
||||
if (write(c->fd,buf,buflen) != buflen) {
|
||||
if (connWrite(c->conn,buf,buflen) != buflen) {
|
||||
freeClientAsync(c);
|
||||
return C_OK;
|
||||
}
|
||||
@ -685,7 +685,7 @@ void syncCommand(client *c) {
|
||||
* paths will change the state if we handle the slave differently. */
|
||||
c->replstate = SLAVE_STATE_WAIT_BGSAVE_START;
|
||||
if (server.repl_disable_tcp_nodelay)
|
||||
anetDisableTcpNoDelay(NULL, c->fd); /* Non critical if it fails. */
|
||||
connDisableTcpNoDelay(c->conn); /* Non critical if it fails. */
|
||||
c->repldbfd = -1;
|
||||
c->flags |= CLIENT_SLAVE;
|
||||
listAddNodeTail(server.slaves,c);
|
||||
@ -862,8 +862,7 @@ void putSlaveOnline(client *slave) {
|
||||
slave->replstate = SLAVE_STATE_ONLINE;
|
||||
slave->repl_put_online_on_ack = 0;
|
||||
slave->repl_ack_time = server.unixtime; /* Prevent false timeout. */
|
||||
if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
|
||||
sendReplyToClient, slave) == AE_ERR) {
|
||||
if (connSetWriteHandler(slave->conn, sendReplyToClient) == C_ERR) {
|
||||
serverLog(LL_WARNING,"Unable to register writable event for replica bulk transfer: %s", strerror(errno));
|
||||
freeClient(slave);
|
||||
return;
|
||||
@ -873,10 +872,8 @@ void putSlaveOnline(client *slave) {
|
||||
replicationGetSlaveName(slave));
|
||||
}
|
||||
|
||||
void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
client *slave = privdata;
|
||||
UNUSED(el);
|
||||
UNUSED(mask);
|
||||
void sendBulkToSlave(connection *conn) {
|
||||
client *slave = connGetPrivateData(conn);
|
||||
char buf[PROTO_IOBUF_LEN];
|
||||
ssize_t nwritten, buflen;
|
||||
|
||||
@ -884,7 +881,7 @@ void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
* replication process. Currently the preamble is just the bulk count of
|
||||
* the file in the form "$<length>\r\n". */
|
||||
if (slave->replpreamble) {
|
||||
nwritten = write(fd,slave->replpreamble,sdslen(slave->replpreamble));
|
||||
nwritten = connWrite(conn,slave->replpreamble,sdslen(slave->replpreamble));
|
||||
if (nwritten == -1) {
|
||||
serverLog(LL_VERBOSE,"Write error sending RDB preamble to replica: %s",
|
||||
strerror(errno));
|
||||
@ -911,8 +908,8 @@ void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
freeClient(slave);
|
||||
return;
|
||||
}
|
||||
if ((nwritten = write(fd,buf,buflen)) == -1) {
|
||||
if (errno != EAGAIN) {
|
||||
if ((nwritten = connWrite(conn,buf,buflen)) == -1) {
|
||||
if (connGetState(conn) != CONN_STATE_CONNECTED) {
|
||||
serverLog(LL_WARNING,"Write error sending DB to replica: %s",
|
||||
strerror(errno));
|
||||
freeClient(slave);
|
||||
@ -924,7 +921,7 @@ void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
if (slave->repldboff == slave->repldbsize) {
|
||||
close(slave->repldbfd);
|
||||
slave->repldbfd = -1;
|
||||
aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
|
||||
connSetWriteHandler(slave->conn,NULL);
|
||||
putSlaveOnline(slave);
|
||||
}
|
||||
}
|
||||
@ -1015,8 +1012,8 @@ void updateSlavesWaitingBgsave(int bgsaveerr, int type) {
|
||||
slave->replpreamble = sdscatprintf(sdsempty(),"$%lld\r\n",
|
||||
(unsigned long long) slave->repldbsize);
|
||||
|
||||
aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
|
||||
if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
|
||||
connSetWriteHandler(slave->conn,NULL);
|
||||
if (connSetWriteHandler(slave->conn,sendBulkToSlave) == C_ERR) {
|
||||
freeClient(slave);
|
||||
continue;
|
||||
}
|
||||
@ -1084,9 +1081,8 @@ void replicationSendNewlineToMaster(void) {
|
||||
static time_t newline_sent;
|
||||
if (time(NULL) != newline_sent) {
|
||||
newline_sent = time(NULL);
|
||||
if (write(server.repl_transfer_s,"\n",1) == -1) {
|
||||
/* Pinging back in this stage is best-effort. */
|
||||
}
|
||||
/* Pinging back in this stage is best-effort. */
|
||||
if (server.repl_transfer_s) connWrite(server.repl_transfer_s, "\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1100,8 +1096,10 @@ void replicationEmptyDbCallback(void *privdata) {
|
||||
/* Once we have a link with the master and the synchroniziation was
|
||||
* performed, this function materializes the master client we store
|
||||
* at server.master, starting from the specified file descriptor. */
|
||||
void replicationCreateMasterClient(int fd, int dbid) {
|
||||
server.master = createClient(fd);
|
||||
void replicationCreateMasterClient(connection *conn, int dbid) {
|
||||
server.master = createClient(conn);
|
||||
if (conn)
|
||||
connSetReadHandler(server.master->conn, readQueryFromClient);
|
||||
server.master->flags |= CLIENT_MASTER;
|
||||
server.master->authenticated = 1;
|
||||
server.master->reploff = server.master_initial_offset;
|
||||
@ -1189,7 +1187,7 @@ void disklessLoadRestoreBackups(redisDb *backup, int restore, int empty_db_flags
|
||||
|
||||
/* Asynchronously read the SYNC payload we receive from a master */
|
||||
#define REPL_MAX_WRITTEN_BEFORE_FSYNC (1024*1024*8) /* 8 MB */
|
||||
void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
void readSyncBulkPayload(connection *conn) {
|
||||
char buf[4096];
|
||||
ssize_t nread, readlen, nwritten;
|
||||
int use_diskless_load;
|
||||
@ -1197,9 +1195,6 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
int empty_db_flags = server.repl_slave_lazy_flush ? EMPTYDB_ASYNC :
|
||||
EMPTYDB_NO_FLAGS;
|
||||
off_t left;
|
||||
UNUSED(el);
|
||||
UNUSED(privdata);
|
||||
UNUSED(mask);
|
||||
|
||||
/* Static vars used to hold the EOF mark, and the last bytes received
|
||||
* form the server: when they match, we reached the end of the transfer. */
|
||||
@ -1210,7 +1205,7 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
/* If repl_transfer_size == -1 we still have to read the bulk length
|
||||
* from the master reply. */
|
||||
if (server.repl_transfer_size == -1) {
|
||||
if (syncReadLine(fd,buf,1024,server.repl_syncio_timeout*1000) == -1) {
|
||||
if (connSyncReadLine(conn,buf,1024,server.repl_syncio_timeout*1000) == -1) {
|
||||
serverLog(LL_WARNING,
|
||||
"I/O error reading bulk count from MASTER: %s",
|
||||
strerror(errno));
|
||||
@ -1275,7 +1270,7 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
readlen = (left < (signed)sizeof(buf)) ? left : (signed)sizeof(buf);
|
||||
}
|
||||
|
||||
nread = read(fd,buf,readlen);
|
||||
nread = connRead(conn,buf,readlen);
|
||||
if (nread <= 0) {
|
||||
serverLog(LL_WARNING,"I/O error trying to sync with MASTER: %s",
|
||||
(nread == -1) ? strerror(errno) : "connection lost");
|
||||
@ -1383,17 +1378,17 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
* handler, otherwise it will get called recursively since
|
||||
* rdbLoad() will call the event loop to process events from time to
|
||||
* time for non blocking loading. */
|
||||
aeDeleteFileEvent(server.el,server.repl_transfer_s,AE_READABLE);
|
||||
connSetReadHandler(conn, NULL);
|
||||
serverLog(LL_NOTICE, "MASTER <-> REPLICA sync: Loading DB in memory");
|
||||
rdbSaveInfo rsi = RDB_SAVE_INFO_INIT;
|
||||
if (use_diskless_load) {
|
||||
rio rdb;
|
||||
rioInitWithFd(&rdb,fd,server.repl_transfer_size);
|
||||
rioInitWithConn(&rdb,conn,server.repl_transfer_size);
|
||||
|
||||
/* Put the socket in blocking mode to simplify RDB transfer.
|
||||
* We'll restore it when the RDB is received. */
|
||||
anetBlock(NULL,fd);
|
||||
anetRecvTimeout(NULL,fd,server.repl_timeout*1000);
|
||||
connBlock(conn);
|
||||
connRecvTimeout(conn, server.repl_timeout*1000);
|
||||
startLoading(server.repl_transfer_size);
|
||||
|
||||
if (rdbLoadRio(&rdb,&rsi,0) != C_OK) {
|
||||
@ -1403,7 +1398,7 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
"Failed trying to load the MASTER synchronization DB "
|
||||
"from socket");
|
||||
cancelReplicationHandshake();
|
||||
rioFreeFd(&rdb, NULL);
|
||||
rioFreeConn(&rdb, NULL);
|
||||
if (server.repl_diskless_load == REPL_DISKLESS_LOAD_SWAPDB) {
|
||||
/* Restore the backed up databases. */
|
||||
disklessLoadRestoreBackups(diskless_load_backup,1,
|
||||
@ -1436,16 +1431,16 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
{
|
||||
serverLog(LL_WARNING,"Replication stream EOF marker is broken");
|
||||
cancelReplicationHandshake();
|
||||
rioFreeFd(&rdb, NULL);
|
||||
rioFreeConn(&rdb, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup and restore the socket to the original state to continue
|
||||
* with the normal replication. */
|
||||
rioFreeFd(&rdb, NULL);
|
||||
anetNonBlock(NULL,fd);
|
||||
anetRecvTimeout(NULL,fd,0);
|
||||
rioFreeConn(&rdb, NULL);
|
||||
connNonBlock(conn);
|
||||
connRecvTimeout(conn,0);
|
||||
} else {
|
||||
/* Ensure background save doesn't overwrite synced data */
|
||||
if (server.rdb_child_pid != -1) {
|
||||
@ -1522,7 +1517,7 @@ error:
|
||||
#define SYNC_CMD_READ (1<<0)
|
||||
#define SYNC_CMD_WRITE (1<<1)
|
||||
#define SYNC_CMD_FULL (SYNC_CMD_READ|SYNC_CMD_WRITE)
|
||||
char *sendSynchronousCommand(int flags, int fd, ...) {
|
||||
char *sendSynchronousCommand(int flags, connection *conn, ...) {
|
||||
|
||||
/* Create the command to send to the master, we use redis binary
|
||||
* protocol to make sure correct arguments are sent. This function
|
||||
@ -1533,7 +1528,7 @@ char *sendSynchronousCommand(int flags, int fd, ...) {
|
||||
sds cmd = sdsempty();
|
||||
sds cmdargs = sdsempty();
|
||||
size_t argslen = 0;
|
||||
va_start(ap,fd);
|
||||
va_start(ap,conn);
|
||||
|
||||
while(1) {
|
||||
arg = va_arg(ap, char*);
|
||||
@ -1550,12 +1545,12 @@ char *sendSynchronousCommand(int flags, int fd, ...) {
|
||||
sdsfree(cmdargs);
|
||||
|
||||
/* Transfer command to the server. */
|
||||
if (syncWrite(fd,cmd,sdslen(cmd),server.repl_syncio_timeout*1000)
|
||||
if (connSyncWrite(conn,cmd,sdslen(cmd),server.repl_syncio_timeout*1000)
|
||||
== -1)
|
||||
{
|
||||
sdsfree(cmd);
|
||||
return sdscatprintf(sdsempty(),"-Writing to master: %s",
|
||||
strerror(errno));
|
||||
connGetLastError(conn));
|
||||
}
|
||||
sdsfree(cmd);
|
||||
}
|
||||
@ -1564,7 +1559,7 @@ char *sendSynchronousCommand(int flags, int fd, ...) {
|
||||
if (flags & SYNC_CMD_READ) {
|
||||
char buf[256];
|
||||
|
||||
if (syncReadLine(fd,buf,sizeof(buf),server.repl_syncio_timeout*1000)
|
||||
if (connSyncReadLine(conn,buf,sizeof(buf),server.repl_syncio_timeout*1000)
|
||||
== -1)
|
||||
{
|
||||
return sdscatprintf(sdsempty(),"-Reading from master: %s",
|
||||
@ -1630,7 +1625,7 @@ char *sendSynchronousCommand(int flags, int fd, ...) {
|
||||
#define PSYNC_FULLRESYNC 3
|
||||
#define PSYNC_NOT_SUPPORTED 4
|
||||
#define PSYNC_TRY_LATER 5
|
||||
int slaveTryPartialResynchronization(int fd, int read_reply) {
|
||||
int slaveTryPartialResynchronization(connection *conn, int read_reply) {
|
||||
char *psync_replid;
|
||||
char psync_offset[32];
|
||||
sds reply;
|
||||
@ -1655,18 +1650,18 @@ int slaveTryPartialResynchronization(int fd, int read_reply) {
|
||||
}
|
||||
|
||||
/* Issue the PSYNC command */
|
||||
reply = sendSynchronousCommand(SYNC_CMD_WRITE,fd,"PSYNC",psync_replid,psync_offset,NULL);
|
||||
reply = sendSynchronousCommand(SYNC_CMD_WRITE,conn,"PSYNC",psync_replid,psync_offset,NULL);
|
||||
if (reply != NULL) {
|
||||
serverLog(LL_WARNING,"Unable to send PSYNC to master: %s",reply);
|
||||
sdsfree(reply);
|
||||
aeDeleteFileEvent(server.el,fd,AE_READABLE);
|
||||
connSetReadHandler(conn, NULL);
|
||||
return PSYNC_WRITE_ERROR;
|
||||
}
|
||||
return PSYNC_WAIT_REPLY;
|
||||
}
|
||||
|
||||
/* Reading half */
|
||||
reply = sendSynchronousCommand(SYNC_CMD_READ,fd,NULL);
|
||||
reply = sendSynchronousCommand(SYNC_CMD_READ,conn,NULL);
|
||||
if (sdslen(reply) == 0) {
|
||||
/* The master may send empty newlines after it receives PSYNC
|
||||
* and before to reply, just to keep the connection alive. */
|
||||
@ -1674,7 +1669,7 @@ int slaveTryPartialResynchronization(int fd, int read_reply) {
|
||||
return PSYNC_WAIT_REPLY;
|
||||
}
|
||||
|
||||
aeDeleteFileEvent(server.el,fd,AE_READABLE);
|
||||
connSetReadHandler(conn, NULL);
|
||||
|
||||
if (!strncmp(reply,"+FULLRESYNC",11)) {
|
||||
char *replid = NULL, *offset = NULL;
|
||||
@ -1748,7 +1743,7 @@ int slaveTryPartialResynchronization(int fd, int read_reply) {
|
||||
|
||||
/* Setup the replication to continue. */
|
||||
sdsfree(reply);
|
||||
replicationResurrectCachedMaster(fd);
|
||||
replicationResurrectCachedMaster(conn);
|
||||
|
||||
/* If this instance was restarted and we read the metadata to
|
||||
* PSYNC from the persistence file, our replication backlog could
|
||||
@ -1790,29 +1785,23 @@ int slaveTryPartialResynchronization(int fd, int read_reply) {
|
||||
|
||||
/* This handler fires when the non blocking connect was able to
|
||||
* establish a connection with the master. */
|
||||
void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
void syncWithMaster(connection *conn) {
|
||||
char tmpfile[256], *err = NULL;
|
||||
int dfd = -1, maxtries = 5;
|
||||
int sockerr = 0, psync_result;
|
||||
socklen_t errlen = sizeof(sockerr);
|
||||
UNUSED(el);
|
||||
UNUSED(privdata);
|
||||
UNUSED(mask);
|
||||
int psync_result;
|
||||
|
||||
/* If this event fired after the user turned the instance into a master
|
||||
* with SLAVEOF NO ONE we must just return ASAP. */
|
||||
if (server.repl_state == REPL_STATE_NONE) {
|
||||
close(fd);
|
||||
connClose(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for errors in the socket: after a non blocking connect() we
|
||||
* may find that the socket is in error state. */
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &errlen) == -1)
|
||||
sockerr = errno;
|
||||
if (sockerr) {
|
||||
if (connGetState(conn) != CONN_STATE_CONNECTED) {
|
||||
serverLog(LL_WARNING,"Error condition on socket for SYNC: %s",
|
||||
strerror(sockerr));
|
||||
connGetLastError(conn));
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1821,18 +1810,19 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
serverLog(LL_NOTICE,"Non blocking connect for SYNC fired the event.");
|
||||
/* Delete the writable event so that the readable event remains
|
||||
* registered and we can wait for the PONG reply. */
|
||||
aeDeleteFileEvent(server.el,fd,AE_WRITABLE);
|
||||
connSetReadHandler(conn, syncWithMaster);
|
||||
connSetWriteHandler(conn, NULL);
|
||||
server.repl_state = REPL_STATE_RECEIVE_PONG;
|
||||
/* Send the PING, don't check for errors at all, we have the timeout
|
||||
* that will take care about this. */
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,fd,"PING",NULL);
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,conn,"PING",NULL);
|
||||
if (err) goto write_error;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Receive the PONG command. */
|
||||
if (server.repl_state == REPL_STATE_RECEIVE_PONG) {
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,fd,NULL);
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,conn,NULL);
|
||||
|
||||
/* We accept only two replies as valid, a positive +PONG reply
|
||||
* (we just check for "+") or an authentication error.
|
||||
@ -1857,13 +1847,13 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
/* AUTH with the master if required. */
|
||||
if (server.repl_state == REPL_STATE_SEND_AUTH) {
|
||||
if (server.masteruser && server.masterauth) {
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,fd,"AUTH",
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,conn,"AUTH",
|
||||
server.masteruser,server.masterauth,NULL);
|
||||
if (err) goto write_error;
|
||||
server.repl_state = REPL_STATE_RECEIVE_AUTH;
|
||||
return;
|
||||
} else if (server.masterauth) {
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,fd,"AUTH",server.masterauth,NULL);
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,conn,"AUTH",server.masterauth,NULL);
|
||||
if (err) goto write_error;
|
||||
server.repl_state = REPL_STATE_RECEIVE_AUTH;
|
||||
return;
|
||||
@ -1874,7 +1864,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
/* Receive AUTH reply. */
|
||||
if (server.repl_state == REPL_STATE_RECEIVE_AUTH) {
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,fd,NULL);
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,conn,NULL);
|
||||
if (err[0] == '-') {
|
||||
serverLog(LL_WARNING,"Unable to AUTH to MASTER: %s",err);
|
||||
sdsfree(err);
|
||||
@ -1889,7 +1879,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
if (server.repl_state == REPL_STATE_SEND_PORT) {
|
||||
sds port = sdsfromlonglong(server.slave_announce_port ?
|
||||
server.slave_announce_port : server.port);
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,fd,"REPLCONF",
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,conn,"REPLCONF",
|
||||
"listening-port",port, NULL);
|
||||
sdsfree(port);
|
||||
if (err) goto write_error;
|
||||
@ -1900,7 +1890,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
/* Receive REPLCONF listening-port reply. */
|
||||
if (server.repl_state == REPL_STATE_RECEIVE_PORT) {
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,fd,NULL);
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,conn,NULL);
|
||||
/* Ignore the error if any, not all the Redis versions support
|
||||
* REPLCONF listening-port. */
|
||||
if (err[0] == '-') {
|
||||
@ -1921,7 +1911,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
/* Set the slave ip, so that Master's INFO command can list the
|
||||
* slave IP address port correctly in case of port forwarding or NAT. */
|
||||
if (server.repl_state == REPL_STATE_SEND_IP) {
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,fd,"REPLCONF",
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,conn,"REPLCONF",
|
||||
"ip-address",server.slave_announce_ip, NULL);
|
||||
if (err) goto write_error;
|
||||
sdsfree(err);
|
||||
@ -1931,7 +1921,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
/* Receive REPLCONF ip-address reply. */
|
||||
if (server.repl_state == REPL_STATE_RECEIVE_IP) {
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,fd,NULL);
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,conn,NULL);
|
||||
/* Ignore the error if any, not all the Redis versions support
|
||||
* REPLCONF listening-port. */
|
||||
if (err[0] == '-') {
|
||||
@ -1949,7 +1939,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
*
|
||||
* The master will ignore capabilities it does not understand. */
|
||||
if (server.repl_state == REPL_STATE_SEND_CAPA) {
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,fd,"REPLCONF",
|
||||
err = sendSynchronousCommand(SYNC_CMD_WRITE,conn,"REPLCONF",
|
||||
"capa","eof","capa","psync2",NULL);
|
||||
if (err) goto write_error;
|
||||
sdsfree(err);
|
||||
@ -1959,7 +1949,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
/* Receive CAPA reply. */
|
||||
if (server.repl_state == REPL_STATE_RECEIVE_CAPA) {
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,fd,NULL);
|
||||
err = sendSynchronousCommand(SYNC_CMD_READ,conn,NULL);
|
||||
/* Ignore the error if any, not all the Redis versions support
|
||||
* REPLCONF capa. */
|
||||
if (err[0] == '-') {
|
||||
@ -1976,7 +1966,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
* and the global offset, to try a partial resync at the next
|
||||
* reconnection attempt. */
|
||||
if (server.repl_state == REPL_STATE_SEND_PSYNC) {
|
||||
if (slaveTryPartialResynchronization(fd,0) == PSYNC_WRITE_ERROR) {
|
||||
if (slaveTryPartialResynchronization(conn,0) == PSYNC_WRITE_ERROR) {
|
||||
err = sdsnew("Write error sending the PSYNC command.");
|
||||
goto write_error;
|
||||
}
|
||||
@ -1992,7 +1982,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
psync_result = slaveTryPartialResynchronization(fd,1);
|
||||
psync_result = slaveTryPartialResynchronization(conn,1);
|
||||
if (psync_result == PSYNC_WAIT_REPLY) return; /* Try again later... */
|
||||
|
||||
/* If the master is in an transient error, we should try to PSYNC
|
||||
@ -2021,7 +2011,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
* already populated. */
|
||||
if (psync_result == PSYNC_NOT_SUPPORTED) {
|
||||
serverLog(LL_NOTICE,"Retrying with SYNC...");
|
||||
if (syncWrite(fd,"SYNC\r\n",6,server.repl_syncio_timeout*1000) == -1) {
|
||||
if (connSyncWrite(conn,"SYNC\r\n",6,server.repl_syncio_timeout*1000) == -1) {
|
||||
serverLog(LL_WARNING,"I/O error writing to MASTER: %s",
|
||||
strerror(errno));
|
||||
goto error;
|
||||
@ -2046,12 +2036,13 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
}
|
||||
|
||||
/* Setup the non blocking download of the bulk file. */
|
||||
if (aeCreateFileEvent(server.el,fd, AE_READABLE,readSyncBulkPayload,NULL)
|
||||
== AE_ERR)
|
||||
if (connSetReadHandler(conn, readSyncBulkPayload)
|
||||
== C_ERR)
|
||||
{
|
||||
char conninfo[CONN_INFO_LEN];
|
||||
serverLog(LL_WARNING,
|
||||
"Can't create readable event for SYNC: %s (fd=%d)",
|
||||
strerror(errno),fd);
|
||||
"Can't create readable event for SYNC: %s (%s)",
|
||||
strerror(errno), connGetInfo(conn, conninfo, sizeof(conninfo)));
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2063,16 +2054,15 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
return;
|
||||
|
||||
error:
|
||||
aeDeleteFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE);
|
||||
if (dfd != -1) close(dfd);
|
||||
close(fd);
|
||||
connClose(conn);
|
||||
server.repl_transfer_s = NULL;
|
||||
if (server.repl_transfer_fd != -1)
|
||||
close(server.repl_transfer_fd);
|
||||
if (server.repl_transfer_tmpfile)
|
||||
zfree(server.repl_transfer_tmpfile);
|
||||
server.repl_transfer_tmpfile = NULL;
|
||||
server.repl_transfer_fd = -1;
|
||||
server.repl_transfer_s = -1;
|
||||
server.repl_state = REPL_STATE_CONNECT;
|
||||
return;
|
||||
|
||||
@ -2083,26 +2073,18 @@ write_error: /* Handle sendSynchronousCommand(SYNC_CMD_WRITE) errors. */
|
||||
}
|
||||
|
||||
int connectWithMaster(void) {
|
||||
int fd;
|
||||
|
||||
fd = anetTcpNonBlockBestEffortBindConnect(NULL,
|
||||
server.masterhost,server.masterport,NET_FIRST_BIND_ADDR);
|
||||
if (fd == -1) {
|
||||
server.repl_transfer_s = server.tls_replication ? connCreateTLS() : connCreateSocket();
|
||||
if (connConnect(server.repl_transfer_s, server.masterhost, server.masterport,
|
||||
NET_FIRST_BIND_ADDR, syncWithMaster) == C_ERR) {
|
||||
serverLog(LL_WARNING,"Unable to connect to MASTER: %s",
|
||||
strerror(errno));
|
||||
connGetLastError(server.repl_transfer_s));
|
||||
connClose(server.repl_transfer_s);
|
||||
server.repl_transfer_s = NULL;
|
||||
return C_ERR;
|
||||
}
|
||||
|
||||
if (aeCreateFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE,syncWithMaster,NULL) ==
|
||||
AE_ERR)
|
||||
{
|
||||
close(fd);
|
||||
serverLog(LL_WARNING,"Can't create readable event for SYNC");
|
||||
return C_ERR;
|
||||
}
|
||||
|
||||
server.repl_transfer_lastio = server.unixtime;
|
||||
server.repl_transfer_s = fd;
|
||||
server.repl_state = REPL_STATE_CONNECTING;
|
||||
return C_OK;
|
||||
}
|
||||
@ -2112,11 +2094,8 @@ int connectWithMaster(void) {
|
||||
* Never call this function directly, use cancelReplicationHandshake() instead.
|
||||
*/
|
||||
void undoConnectWithMaster(void) {
|
||||
int fd = server.repl_transfer_s;
|
||||
|
||||
aeDeleteFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE);
|
||||
close(fd);
|
||||
server.repl_transfer_s = -1;
|
||||
connClose(server.repl_transfer_s);
|
||||
server.repl_transfer_s = NULL;
|
||||
}
|
||||
|
||||
/* Abort the async download of the bulk dataset while SYNC-ing with master.
|
||||
@ -2301,7 +2280,7 @@ void roleCommand(client *c) {
|
||||
char ip[NET_IP_STR_LEN], *slaveip = slave->slave_ip;
|
||||
|
||||
if (slaveip[0] == '\0') {
|
||||
if (anetPeerToString(slave->fd,ip,sizeof(ip),NULL) == -1)
|
||||
if (connPeerToString(slave->conn,ip,sizeof(ip),NULL) == -1)
|
||||
continue;
|
||||
slaveip = ip;
|
||||
}
|
||||
@ -2423,7 +2402,7 @@ void replicationCacheMasterUsingMyself(void) {
|
||||
/* The master client we create can be set to any DBID, because
|
||||
* the new master will start its replication stream with SELECT. */
|
||||
server.master_initial_offset = server.master_repl_offset;
|
||||
replicationCreateMasterClient(-1,-1);
|
||||
replicationCreateMasterClient(NULL,-1);
|
||||
|
||||
/* Use our own ID / offset. */
|
||||
memcpy(server.master->replid, server.replid, sizeof(server.replid));
|
||||
@ -2452,10 +2431,11 @@ void replicationDiscardCachedMaster(void) {
|
||||
* This function is called when successfully setup a partial resynchronization
|
||||
* so the stream of data that we'll receive will start from were this
|
||||
* master left. */
|
||||
void replicationResurrectCachedMaster(int newfd) {
|
||||
void replicationResurrectCachedMaster(connection *conn) {
|
||||
server.master = server.cached_master;
|
||||
server.cached_master = NULL;
|
||||
server.master->fd = newfd;
|
||||
server.master->conn = conn;
|
||||
connSetPrivateData(server.master->conn, server.master);
|
||||
server.master->flags &= ~(CLIENT_CLOSE_AFTER_REPLY|CLIENT_CLOSE_ASAP);
|
||||
server.master->authenticated = 1;
|
||||
server.master->lastinteraction = server.unixtime;
|
||||
@ -2464,8 +2444,7 @@ void replicationResurrectCachedMaster(int newfd) {
|
||||
|
||||
/* Re-add to the list of clients. */
|
||||
linkClient(server.master);
|
||||
if (aeCreateFileEvent(server.el, newfd, AE_READABLE,
|
||||
readQueryFromClient, server.master)) {
|
||||
if (connSetReadHandler(server.master->conn, readQueryFromClient)) {
|
||||
serverLog(LL_WARNING,"Error resurrecting the cached master, impossible to add the readable handler: %s", strerror(errno));
|
||||
freeClientAsync(server.master); /* Close ASAP. */
|
||||
}
|
||||
@ -2473,8 +2452,7 @@ void replicationResurrectCachedMaster(int newfd) {
|
||||
/* We may also need to install the write handler as well if there is
|
||||
* pending data in the write buffers. */
|
||||
if (clientHasPendingReplies(server.master)) {
|
||||
if (aeCreateFileEvent(server.el, newfd, AE_WRITABLE,
|
||||
sendReplyToClient, server.master)) {
|
||||
if (connSetWriteHandler(server.master->conn, sendReplyToClient)) {
|
||||
serverLog(LL_WARNING,"Error resurrecting the cached master, impossible to add the writable handler: %s", strerror(errno));
|
||||
freeClientAsync(server.master); /* Close ASAP. */
|
||||
}
|
||||
@ -2844,9 +2822,7 @@ void replicationCron(void) {
|
||||
server.rdb_child_type != RDB_CHILD_TYPE_SOCKET));
|
||||
|
||||
if (is_presync) {
|
||||
if (write(slave->fd, "\n", 1) == -1) {
|
||||
/* Don't worry about socket errors, it's just a ping. */
|
||||
}
|
||||
connWrite(slave->conn, "\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user