2012-11-08 12:25:23 -05:00
/*
* Copyright ( c ) 2009 - 2012 , Salvatore Sanfilippo < antirez at gmail dot com >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* * Redistributions of source code must retain the above copyright notice ,
* this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE .
*/
2015-07-26 09:14:57 -04:00
# include "server.h"
2017-05-09 05:57:09 -04:00
# include "atomicvar.h"
2010-06-21 18:07:48 -04:00
# include <sys/uio.h>
2013-07-17 09:04:22 -04:00
# include <math.h>
2016-11-25 04:55:16 -05:00
# include <ctype.h>
2010-06-21 18:07:48 -04:00
2017-12-21 04:10:48 -05:00
static void setProtocolError ( const char * errstr , client * c , long pos ) ;
2011-12-31 10:09:46 -05:00
2015-07-25 11:25:44 -04:00
/* Return the size consumed from the allocator, for the specified SDS string,
* including internal fragmentation . This function is used in order to compute
* the client output buffer size . */
size_t sdsZmallocSize ( sds s ) {
void * sh = sdsAllocPtr ( s ) ;
return zmalloc_size ( sh ) ;
}
2012-02-07 11:41:31 -05:00
2013-07-23 05:50:17 -04:00
/* Return the amount of memory used by the sds string at object->ptr
* for a string object . */
size_t getStringObjectSdsUsedMemory ( robj * o ) {
2015-07-26 09:29:53 -04:00
serverAssertWithInfo ( NULL , o , o - > type = = OBJ_STRING ) ;
2013-07-23 05:50:17 -04:00
switch ( o - > encoding ) {
2015-07-26 09:28:00 -04:00
case OBJ_ENCODING_RAW : return sdsZmallocSize ( o - > ptr ) ;
case OBJ_ENCODING_EMBSTR : return zmalloc_size ( o ) - sizeof ( robj ) ;
2013-07-23 05:50:17 -04:00
default : return 0 ; /* Just integer encoding for now. */
}
}
2015-07-31 08:59:54 -04:00
/* Client.reply list dup and free methods. */
2010-06-21 18:07:48 -04:00
void * dupClientReplyValue ( void * o ) {
2015-07-31 08:59:54 -04:00
return sdsdup ( o ) ;
}
void freeClientReplyValue ( void * o ) {
sdsfree ( o ) ;
2010-06-21 18:07:48 -04:00
}
int listMatchObjects ( void * a , void * b ) {
return equalStringObjects ( a , b ) ;
}
2017-12-05 09:59:56 -05:00
/* This function links the client to the global linked list of clients.
* unlinkClient ( ) does the opposite , among other things . */
void linkClient ( client * c ) {
listAddNodeTail ( server . clients , c ) ;
/* Note that we remember the linked list node where the client is stored,
* this way removing the client in unlinkClient ( ) will not require
* a linear scan , but just a constant time operation . */
c - > client_list_node = listLast ( server . clients ) ;
}
2015-07-26 09:20:46 -04:00
client * createClient ( int fd ) {
client * c = zmalloc ( sizeof ( client ) ) ;
2010-06-21 18:07:48 -04:00
2011-04-30 16:29:21 -04:00
/* passing -1 as fd it is possible to create a non connected client.
2015-07-27 03:41:48 -04:00
* This is useful since all the commands needs to be executed
2011-04-30 16:29:21 -04:00
* in the context of a client . When commands are executed in other
* contexts ( for instance a Lua script ) we need a non connected client . */
if ( fd ! = - 1 ) {
anetNonBlock ( NULL , fd ) ;
2013-01-31 05:14:15 -05:00
anetEnableTcpNoDelay ( NULL , fd ) ;
2013-02-08 10:40:59 -05:00
if ( server . tcpkeepalive )
anetKeepAlive ( NULL , fd , server . tcpkeepalive ) ;
2011-04-30 16:29:21 -04:00
if ( aeCreateFileEvent ( server . el , fd , AE_READABLE ,
readQueryFromClient , c ) = = AE_ERR )
{
close ( fd ) ;
zfree ( c ) ;
return NULL ;
}
2010-09-06 05:27:22 -04:00
}
2010-06-21 18:07:48 -04:00
selectDb ( c , 0 ) ;
2017-05-09 05:57:09 -04:00
uint64_t client_id ;
atomicGetIncr ( server . next_client_id , client_id , 1 ) ;
c - > id = client_id ;
2010-06-21 18:07:48 -04:00
c - > fd = fd ;
2013-01-11 12:43:28 -05:00
c - > name = NULL ;
2012-03-13 07:59:27 -04:00
c - > bufpos = 0 ;
2010-06-21 18:07:48 -04:00
c - > querybuf = sdsempty ( ) ;
Fix PSYNC2 incomplete command bug as described in #3899.
This bug was discovered by @kevinmcgehee and constituted a major hidden
bug in the PSYNC2 implementation, caused by the propagation from the
master of incomplete commands to slaves.
The bug had several results:
1. Borrowing from Kevin text in the issue: "Given that slaves blindly
copy over their master's input into their own replication backlog over
successive read syscalls, it's possible that with large commands or
small TCP buffers, partial commands are present in this buffer. If the
master were to fail before successfully propagating the entire command
to a slave, the slaves will never execute the partial command (since the
client is invalidated) but will copy it to replication backlog which may
relay those invalid bytes to its slaves on PSYNC2, corrupting the
backlog and possibly other valid commands that follow the failover.
Simple command boundaries aren't sufficient to capture this, either,
because in the case of a MULTI/EXEC block, if the master successfully
propagates a subset of the commands but not the EXEC, then the
transaction in the backlog becomes corrupt and could corrupt other
slaves that consume this data."
2. As identified by @yangsiran later, there is another effect of the
bug. For the same mechanism of the first problem, a slave having another
slave, could receive a full resynchronization request with an already
half-applied command in the backlog. Once the RDB is ready, it will be
sent to the slave, and the replication will continue sending to the
sub-slave the other half of the command, which is not valid.
The fix, designed by @yangsiran and @antirez, and implemented by
@antirez, uses a secondary buffer in order to feed the sub-masters and
update the replication backlog and offsets, only when a given part of
the query buffer is actually *applied* to the state of the instance,
that is, when the command gets processed and the command is not pending
in the Redis transaction buffer because of CLIENT_MULTI state.
Given that now the backlog and offsets representation are in agreement
with the actual processed commands, both issue 1 and 2 should no longer
be possible.
Thanks to @kevinmcgehee, @yangsiran and @oranagra for their work in
identifying and designing a fix for this problem.
2017-04-19 04:25:45 -04:00
c - > pending_querybuf = sdsempty ( ) ;
2012-03-14 10:32:30 -04:00
c - > querybuf_peak = 0 ;
2010-10-15 09:40:25 -04:00
c - > reqtype = 0 ;
2010-06-21 18:07:48 -04:00
c - > argc = 0 ;
c - > argv = NULL ;
2011-11-24 08:56:34 -05:00
c - > cmd = c - > lastcmd = NULL ;
2010-10-15 09:40:25 -04:00
c - > multibulklen = 0 ;
2010-06-21 18:07:48 -04:00
c - > bulklen = - 1 ;
c - > sentlen = 0 ;
c - > flags = 0 ;
2012-03-27 11:39:58 -04:00
c - > ctime = c - > lastinteraction = server . unixtime ;
2010-06-21 18:07:48 -04:00
c - > authenticated = 0 ;
2015-07-27 03:41:48 -04:00
c - > replstate = REPL_STATE_NONE ;
2014-11-11 11:12:12 -05:00
c - > repl_put_online_on_ack = 0 ;
2013-01-30 12:33:16 -05:00
c - > reploff = 0 ;
Fix PSYNC2 incomplete command bug as described in #3899.
This bug was discovered by @kevinmcgehee and constituted a major hidden
bug in the PSYNC2 implementation, caused by the propagation from the
master of incomplete commands to slaves.
The bug had several results:
1. Borrowing from Kevin text in the issue: "Given that slaves blindly
copy over their master's input into their own replication backlog over
successive read syscalls, it's possible that with large commands or
small TCP buffers, partial commands are present in this buffer. If the
master were to fail before successfully propagating the entire command
to a slave, the slaves will never execute the partial command (since the
client is invalidated) but will copy it to replication backlog which may
relay those invalid bytes to its slaves on PSYNC2, corrupting the
backlog and possibly other valid commands that follow the failover.
Simple command boundaries aren't sufficient to capture this, either,
because in the case of a MULTI/EXEC block, if the master successfully
propagates a subset of the commands but not the EXEC, then the
transaction in the backlog becomes corrupt and could corrupt other
slaves that consume this data."
2. As identified by @yangsiran later, there is another effect of the
bug. For the same mechanism of the first problem, a slave having another
slave, could receive a full resynchronization request with an already
half-applied command in the backlog. Once the RDB is ready, it will be
sent to the slave, and the replication will continue sending to the
sub-slave the other half of the command, which is not valid.
The fix, designed by @yangsiran and @antirez, and implemented by
@antirez, uses a secondary buffer in order to feed the sub-masters and
update the replication backlog and offsets, only when a given part of
the query buffer is actually *applied* to the state of the instance,
that is, when the command gets processed and the command is not pending
in the Redis transaction buffer because of CLIENT_MULTI state.
Given that now the backlog and offsets representation are in agreement
with the actual processed commands, both issue 1 and 2 should no longer
be possible.
Thanks to @kevinmcgehee, @yangsiran and @oranagra for their work in
identifying and designing a fix for this problem.
2017-04-19 04:25:45 -04:00
c - > read_reploff = 0 ;
2013-05-24 18:37:56 -04:00
c - > repl_ack_off = 0 ;
c - > repl_ack_time = 0 ;
2012-06-26 03:47:47 -04:00
c - > slave_listening_port = 0 ;
2016-07-27 10:41:20 -04:00
c - > slave_ip [ 0 ] = ' \0 ' ;
2015-08-06 03:23:23 -04:00
c - > slave_capa = SLAVE_CAPA_NONE ;
2010-06-21 18:07:48 -04:00
c - > reply = listCreate ( ) ;
2011-12-25 10:32:54 -05:00
c - > reply_bytes = 0 ;
2012-01-23 10:12:37 -05:00
c - > obuf_soft_limit_reached_time = 0 ;
2015-07-31 08:59:54 -04:00
listSetFreeMethod ( c - > reply , freeClientReplyValue ) ;
2010-06-21 18:07:48 -04:00
listSetDupMethod ( c - > reply , dupClientReplyValue ) ;
2015-07-27 03:41:48 -04:00
c - > btype = BLOCKED_NONE ;
2010-11-09 13:06:25 -05:00
c - > bpop . timeout = 0 ;
2017-09-06 09:43:28 -04:00
c - > bpop . keys = dictCreate ( & objectKeyHeapPointerValueDictType , NULL ) ;
2010-11-09 13:06:25 -05:00
c - > bpop . target = NULL ;
2017-09-07 03:30:50 -04:00
c - > bpop . xread_group = NULL ;
2018-01-19 10:39:09 -05:00
c - > bpop . xread_consumer = NULL ;
2013-12-03 11:43:53 -05:00
c - > bpop . numreplicas = 0 ;
c - > bpop . reploffset = 0 ;
2013-12-04 09:52:20 -05:00
c - > woff = 0 ;
2010-06-21 18:07:48 -04:00
c - > watched_keys = listCreate ( ) ;
2015-07-31 12:01:23 -04:00
c - > pubsub_channels = dictCreate ( & objectKeyPointerValueDictType , NULL ) ;
2010-06-21 18:07:48 -04:00
c - > pubsub_patterns = listCreate ( ) ;
2014-04-28 11:36:57 -04:00
c - > peerid = NULL ;
2017-12-05 09:59:56 -05:00
c - > client_list_node = NULL ;
2013-01-24 05:27:10 -05:00
listSetFreeMethod ( c - > pubsub_patterns , decrRefCountVoid ) ;
2010-06-21 18:07:48 -04:00
listSetMatchMethod ( c - > pubsub_patterns , listMatchObjects ) ;
2017-12-05 09:59:56 -05:00
if ( fd ! = - 1 ) linkClient ( c ) ;
2010-06-21 18:07:48 -04:00
initClientMultiState ( c ) ;
return c ;
}
2012-01-23 11:15:49 -05:00
/* This function is called every time we are going to transmit new data
* to the client . The behavior is the following :
*
* If the client should receive new data ( normal clients will ) the function
2015-07-26 17:17:55 -04:00
* returns C_OK , and make sure to install the write handler in our event
2012-01-23 11:15:49 -05:00
* loop so that when the socket is writable new data gets written .
*
2015-04-01 04:07:08 -04:00
* If the client should not receive new data , because it is a fake client
* ( used to load AOF in memory ) , a master or because the setup of the write
2015-07-26 17:17:55 -04:00
* handler failed , the function returns C_ERR .
2015-04-01 04:07:08 -04:00
*
2015-07-26 17:17:55 -04:00
* The function may return C_OK without actually installing the write
2015-04-01 04:07:08 -04:00
* event handler in the following cases :
*
* 1 ) The event handler should already be installed since the output buffer
2015-07-31 08:59:54 -04:00
* already contains something .
2015-04-01 04:07:08 -04:00
* 2 ) The client is a slave but not yet online , so we want to just accumulate
* writes in the buffer but not actually sending them yet .
2012-01-23 11:15:49 -05:00
*
* Typically gets called every time a reply is built , before adding more
2015-07-26 17:17:55 -04:00
* data to the clients output buffers . If the function returns C_ERR no
2012-01-23 11:15:49 -05:00
* data should be appended to the output buffers . */
2015-07-26 09:20:46 -04:00
int prepareClientToWrite ( client * c ) {
2015-04-01 04:07:08 -04:00
/* If it's the Lua client we always return ok without installing any
* handler since there is no socket at all . */
2016-03-06 07:44:24 -05:00
if ( c - > flags & ( CLIENT_LUA | CLIENT_MODULE ) ) return C_OK ;
2015-04-01 04:07:08 -04:00
CLIENT REPLY command implemented: ON, OFF and SKIP modes.
Sometimes it can be useful for clients to completely disable replies
from the Redis server. For example when the client sends fire and forget
commands or performs a mass loading of data, or in caching contexts
where new data is streamed constantly. In such contexts to use server
time and bandwidth in order to send back replies to clients, which are
going to be ignored, is a shame.
Multiple mechanisms are possible to implement such a feature. For
example it could be a feature of MULTI/EXEC, or a command prefix
such as "NOREPLY SADD myset foo", or a different mechanism that allows
to switch on/off requests using the CLIENT command.
The MULTI/EXEC approach has the problem that transactions are not
strictly part of the no-reply semantics, and if we want to insert a lot
of data in a bulk way, creating a huge MULTI/EXEC transaction in the
server memory is bad.
The prefix is the best in this specific use case since it does not allow
desynchronizations, and is pretty clear semantically. However Redis
internals and client libraries are not prepared to handle this
currently.
So the implementation uses the CLIENT command, providing a new REPLY
subcommand with three options:
CLIENT REPLY OFF disables the replies, and does not reply itself.
CLIENT REPLY ON re-enables the replies, replying +OK.
CLIENT REPLY SKIP only discards the reply of the next command, and
like OFF does not reply anything itself.
The reason to add the SKIP command is that it allows to have an easy
way to send conceptually "single" commands that don't need a reply
as the sum of two pipelined commands:
CLIENT REPLY SKIP
SET key value
Note that CLIENT REPLY ON replies with +OK so it should be used when
sending multiple commands that don't need a reply. However since it
replies with +OK the client can check that the connection is still
active and all the previous commands were received.
This is currently just into Redis "unstable" so the proposal can be
modified or abandoned based on users inputs.
2015-10-21 14:43:37 -04:00
/* CLIENT REPLY OFF / SKIP handling: don't send replies. */
if ( c - > flags & ( CLIENT_REPLY_OFF | CLIENT_REPLY_SKIP ) ) return C_ERR ;
2015-07-27 03:41:48 -04:00
/* Masters don't receive replies, unless CLIENT_MASTER_FORCE_REPLY flag
2015-04-01 04:07:08 -04:00
* is set . */
2015-07-27 03:41:48 -04:00
if ( ( c - > flags & CLIENT_MASTER ) & &
! ( c - > flags & CLIENT_MASTER_FORCE_REPLY ) ) return C_ERR ;
2015-04-01 04:07:08 -04:00
2015-07-26 17:17:55 -04:00
if ( c - > fd < = 0 ) return C_ERR ; /* Fake client for AOF loading. */
2015-04-01 04:07:08 -04:00
2015-09-30 10:41:48 -04:00
/* Schedule the client to write the output buffers to the socket only
2015-11-27 10:17:21 -05:00
* if not already done ( there were no pending writes already and the client
2015-09-30 10:41:48 -04:00
* was yet not flagged ) , and , for slaves , if the slave can actually
* receive writes at this stage . */
if ( ! clientHasPendingReplies ( c ) & &
2015-09-28 12:25:57 -04:00
! ( c - > flags & CLIENT_PENDING_WRITE ) & &
2015-07-27 03:41:48 -04:00
( c - > replstate = = REPL_STATE_NONE | |
( c - > replstate = = SLAVE_STATE_ONLINE & & ! c - > repl_put_online_on_ack ) ) )
2015-04-01 04:07:08 -04:00
{
2015-09-28 12:25:57 -04:00
/* Here instead of installing the write handler, we just flag the
* client and put it into a list of clients that have something
* to write to the socket . This way before re - entering the event
* loop , we can try to directly write to the client sockets avoiding
* a system call . We ' ll only really install the write handler if
* we ' ll not be able to write the whole reply at once . */
c - > flags | = CLIENT_PENDING_WRITE ;
2015-09-28 17:25:52 -04:00
listAddNodeHead ( server . clients_pending_write , c ) ;
2015-04-01 04:07:08 -04:00
}
/* Authorize the caller to queue in the output buffer of this client. */
2015-07-26 17:17:55 -04:00
return C_OK ;
2010-08-30 08:44:34 -04:00
}
2011-03-31 10:44:43 -04:00
/* -----------------------------------------------------------------------------
* Low level functions to add more data to output buffers .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-07-26 09:20:46 -04:00
int _addReplyToBuffer ( client * c , const char * s , size_t len ) {
2010-09-16 05:59:53 -04:00
size_t available = sizeof ( c - > buf ) - c - > bufpos ;
2010-09-02 13:18:55 -04:00
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_CLOSE_AFTER_REPLY ) return C_OK ;
2011-03-31 10:44:43 -04:00
2010-09-02 13:18:55 -04:00
/* If there already are entries in the reply list, we cannot
* add anything more to the static buffer . */
2015-07-26 17:17:55 -04:00
if ( listLength ( c - > reply ) > 0 ) return C_ERR ;
2010-09-02 13:18:55 -04:00
/* Check that the buffer has enough space available for this string. */
2015-07-26 17:17:55 -04:00
if ( len > available ) return C_ERR ;
2010-06-21 18:07:48 -04:00
2010-09-02 13:18:55 -04:00
memcpy ( c - > buf + c - > bufpos , s , len ) ;
c - > bufpos + = len ;
2015-07-26 17:17:55 -04:00
return C_OK ;
2010-08-30 08:44:34 -04:00
}
2015-07-26 09:20:46 -04:00
void _addReplyObjectToList ( client * c , robj * o ) {
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_CLOSE_AFTER_REPLY ) return ;
2011-03-31 10:44:43 -04:00
2010-09-02 13:18:55 -04:00
if ( listLength ( c - > reply ) = = 0 ) {
2015-07-31 08:59:54 -04:00
sds s = sdsdup ( o - > ptr ) ;
listAddNodeTail ( c - > reply , s ) ;
c - > reply_bytes + = sdslen ( s ) ;
2010-09-02 13:18:55 -04:00
} else {
2015-07-31 08:59:54 -04:00
listNode * ln = listLast ( c - > reply ) ;
sds tail = listNodeValue ( ln ) ;
/* Append to this object when possible. If tail == NULL it was
* set via addDeferredMultiBulkLength ( ) . */
if ( tail & & sdslen ( tail ) + sdslen ( o - > ptr ) < = PROTO_REPLY_CHUNK_BYTES ) {
tail = sdscatsds ( tail , o - > ptr ) ;
listNodeValue ( ln ) = tail ;
c - > reply_bytes + = sdslen ( o - > ptr ) ;
2010-09-02 13:18:55 -04:00
} else {
2015-07-31 08:59:54 -04:00
sds s = sdsdup ( o - > ptr ) ;
listAddNodeTail ( c - > reply , s ) ;
c - > reply_bytes + = sdslen ( s ) ;
2010-09-02 13:18:55 -04:00
}
}
2012-01-23 10:12:37 -05:00
asyncCloseClientOnOutputBufferLimitReached ( c ) ;
2010-09-02 13:18:55 -04:00
}
2010-08-30 08:44:34 -04:00
2010-09-02 13:18:55 -04:00
/* This method takes responsibility over the sds. When it is no longer
* needed it will be free ' d , otherwise it ends up in a robj . */
2015-07-26 09:20:46 -04:00
void _addReplySdsToList ( client * c , sds s ) {
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_CLOSE_AFTER_REPLY ) {
2011-03-31 13:52:15 -04:00
sdsfree ( s ) ;
return ;
}
2011-03-31 10:44:43 -04:00
2010-09-02 13:18:55 -04:00
if ( listLength ( c - > reply ) = = 0 ) {
2015-07-31 08:59:54 -04:00
listAddNodeTail ( c - > reply , s ) ;
c - > reply_bytes + = sdslen ( s ) ;
2010-09-02 13:18:55 -04:00
} else {
2015-07-31 08:59:54 -04:00
listNode * ln = listLast ( c - > reply ) ;
sds tail = listNodeValue ( ln ) ;
/* Append to this object when possible. If tail == NULL it was
* set via addDeferredMultiBulkLength ( ) . */
if ( tail & & sdslen ( tail ) + sdslen ( s ) < = PROTO_REPLY_CHUNK_BYTES ) {
tail = sdscatsds ( tail , s ) ;
listNodeValue ( ln ) = tail ;
c - > reply_bytes + = sdslen ( s ) ;
2010-09-02 13:18:55 -04:00
sdsfree ( s ) ;
2010-08-30 08:44:34 -04:00
} else {
2015-07-31 08:59:54 -04:00
listAddNodeTail ( c - > reply , s ) ;
c - > reply_bytes + = sdslen ( s ) ;
2010-08-30 08:44:34 -04:00
}
2010-09-02 13:18:55 -04:00
}
2012-01-23 10:12:37 -05:00
asyncCloseClientOnOutputBufferLimitReached ( c ) ;
2010-09-02 13:18:55 -04:00
}
2015-07-26 09:20:46 -04:00
void _addReplyStringToList ( client * c , const char * s , size_t len ) {
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_CLOSE_AFTER_REPLY ) return ;
2011-03-31 10:44:43 -04:00
2010-09-02 13:18:55 -04:00
if ( listLength ( c - > reply ) = = 0 ) {
2015-07-31 08:59:54 -04:00
sds node = sdsnewlen ( s , len ) ;
listAddNodeTail ( c - > reply , node ) ;
c - > reply_bytes + = len ;
2010-08-30 08:44:34 -04:00
} else {
2015-07-31 08:59:54 -04:00
listNode * ln = listLast ( c - > reply ) ;
sds tail = listNodeValue ( ln ) ;
/* Append to this object when possible. If tail == NULL it was
* set via addDeferredMultiBulkLength ( ) . */
if ( tail & & sdslen ( tail ) + len < = PROTO_REPLY_CHUNK_BYTES ) {
tail = sdscatlen ( tail , s , len ) ;
listNodeValue ( ln ) = tail ;
c - > reply_bytes + = len ;
2010-08-30 08:44:34 -04:00
} else {
2015-07-31 08:59:54 -04:00
sds node = sdsnewlen ( s , len ) ;
listAddNodeTail ( c - > reply , node ) ;
c - > reply_bytes + = len ;
2010-08-30 08:44:34 -04:00
}
}
2012-01-23 10:12:37 -05:00
asyncCloseClientOnOutputBufferLimitReached ( c ) ;
2010-08-30 08:44:34 -04:00
}
2010-06-21 18:07:48 -04:00
2011-03-31 10:44:43 -04:00
/* -----------------------------------------------------------------------------
* Higher level functions to queue data on the client output buffer .
* The following functions are the ones that commands implementations will call .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-07-26 09:20:46 -04:00
void addReply ( client * c , robj * obj ) {
2015-07-26 17:17:55 -04:00
if ( prepareClientToWrite ( c ) ! = C_OK ) return ;
2010-09-16 07:08:40 -04:00
/* This is an important place where we can avoid copy-on-write
* when there is a saving child running , avoiding touching the
* refcount field of the object if it ' s not needed .
*
* If the encoding is RAW and there is room in the static buffer
* we ' ll be able to send the object to the client without
* messing with its page . */
2012-06-05 15:50:10 -04:00
if ( sdsEncodedObject ( obj ) ) {
2015-07-26 17:17:55 -04:00
if ( _addReplyToBuffer ( c , obj - > ptr , sdslen ( obj - > ptr ) ) ! = C_OK )
2010-09-16 07:08:40 -04:00
_addReplyObjectToList ( c , obj ) ;
2015-07-26 09:28:00 -04:00
} else if ( obj - > encoding = = OBJ_ENCODING_INT ) {
2012-01-23 11:15:49 -05:00
/* Optimization: if there is room in the static buffer for 32 bytes
* ( more than the max chars a 64 bit integer can take as string ) we
* avoid decoding the object and go for the lower level approach . */
if ( listLength ( c - > reply ) = = 0 & & ( sizeof ( c - > buf ) - c - > bufpos ) > = 32 ) {
char buf [ 32 ] ;
int len ;
len = ll2string ( buf , sizeof ( buf ) , ( long ) obj - > ptr ) ;
2015-07-26 17:17:55 -04:00
if ( _addReplyToBuffer ( c , buf , len ) = = C_OK )
2012-01-23 11:15:49 -05:00
return ;
/* else... continue with the normal code path, but should never
* happen actually since we verified there is room . */
}
2010-08-30 08:44:34 -04:00
obj = getDecodedObject ( obj ) ;
2015-07-26 17:17:55 -04:00
if ( _addReplyToBuffer ( c , obj - > ptr , sdslen ( obj - > ptr ) ) ! = C_OK )
2010-09-16 07:08:40 -04:00
_addReplyObjectToList ( c , obj ) ;
decrRefCount ( obj ) ;
2012-01-23 11:15:49 -05:00
} else {
2015-07-27 03:41:48 -04:00
serverPanic ( " Wrong obj->encoding in addReply() " ) ;
2010-06-21 18:07:48 -04:00
}
}
2015-07-26 09:20:46 -04:00
void addReplySds ( client * c , sds s ) {
2015-07-26 17:17:55 -04:00
if ( prepareClientToWrite ( c ) ! = C_OK ) {
2010-09-02 08:19:15 -04:00
/* The caller expects the sds to be free'd. */
sdsfree ( s ) ;
return ;
}
2015-07-26 17:17:55 -04:00
if ( _addReplyToBuffer ( c , s , sdslen ( s ) ) = = C_OK ) {
2010-08-30 08:44:34 -04:00
sdsfree ( s ) ;
} else {
2010-09-02 13:18:55 -04:00
/* This method free's the sds when it is no longer needed. */
_addReplySdsToList ( c , s ) ;
2010-08-30 08:44:34 -04:00
}
2010-06-21 18:07:48 -04:00
}
PSYNC2: different improvements to Redis replication.
The gist of the changes is that now, partial resynchronizations between
slaves and masters (without the need of a full resync with RDB transfer
and so forth), work in a number of cases when it was impossible
in the past. For instance:
1. When a slave is promoted to mastrer, the slaves of the old master can
partially resynchronize with the new master.
2. Chained slalves (slaves of slaves) can be moved to replicate to other
slaves or the master itsef, without requiring a full resync.
3. The master itself, after being turned into a slave, is able to
partially resynchronize with the new master, when it joins replication
again.
In order to obtain this, the following main changes were operated:
* Slaves also take a replication backlog, not just masters.
* Same stream replication for all the slaves and sub slaves. The
replication stream is identical from the top level master to its slaves
and is also the same from the slaves to their sub-slaves and so forth.
This means that if a slave is later promoted to master, it has the
same replication backlong, and can partially resynchronize with its
slaves (that were previously slaves of the old master).
* A given replication history is no longer identified by the `runid` of
a Redis node. There is instead a `replication ID` which changes every
time the instance has a new history no longer coherent with the past
one. So, for example, slaves publish the same replication history of
their master, however when they are turned into masters, they publish
a new replication ID, but still remember the old ID, so that they are
able to partially resynchronize with slaves of the old master (up to a
given offset).
* The replication protocol was slightly modified so that a new extended
+CONTINUE reply from the master is able to inform the slave of a
replication ID change.
* REPLCONF CAPA is used in order to notify masters that a slave is able
to understand the new +CONTINUE reply.
* The RDB file was extended with an auxiliary field that is able to
select a given DB after loading in the slave, so that the slave can
continue receiving the replication stream from the point it was
disconnected without requiring the master to insert "SELECT" statements.
This is useful in order to guarantee the "same stream" property, because
the slave must be able to accumulate an identical backlog.
* Slave pings to sub-slaves are now sent in a special form, when the
top-level master is disconnected, in order to don't interfer with the
replication stream. We just use out of band "\n" bytes as in other parts
of the Redis protocol.
An old design document is available here:
https://gist.github.com/antirez/ae068f95c0d084891305
However the implementation is not identical to the description because
during the work to implement it, different changes were needed in order
to make things working well.
2016-11-09 05:31:06 -05:00
/* This low level function just adds whatever protocol you send it to the
* client buffer , trying the static buffer initially , and using the string
* of objects if not possible .
*
* It is efficient because does not create an SDS object nor an Redis object
* if not needed . The object will only be created by calling
* _addReplyStringToList ( ) if we fail to extend the existing tail object
* in the list of objects . */
2015-07-26 09:20:46 -04:00
void addReplyString ( client * c , const char * s , size_t len ) {
2015-07-26 17:17:55 -04:00
if ( prepareClientToWrite ( c ) ! = C_OK ) return ;
if ( _addReplyToBuffer ( c , s , len ) ! = C_OK )
2010-09-02 13:18:55 -04:00
_addReplyStringToList ( c , s , len ) ;
2010-08-30 08:44:34 -04:00
}
2010-06-21 18:07:48 -04:00
2015-07-26 09:20:46 -04:00
void addReplyErrorLength ( client * c , const char * s , size_t len ) {
2010-09-02 13:52:24 -04:00
addReplyString ( c , " -ERR " , 5 ) ;
addReplyString ( c , s , len ) ;
addReplyString ( c , " \r \n " , 2 ) ;
2018-02-13 10:01:31 -05:00
if ( c - > flags & CLIENT_MASTER ) {
char * cmdname = c - > lastcmd ? c - > lastcmd - > name : " <unknown> " ;
serverLog ( LL_WARNING , " == CRITICAL == This slave is sending an error "
" to its master: '%s' after processing the command "
" '%s' " , s , cmdname ) ;
}
2010-06-21 18:07:48 -04:00
}
2015-07-26 09:20:46 -04:00
void addReplyError ( client * c , const char * err ) {
2012-01-23 11:15:49 -05:00
addReplyErrorLength ( c , err , strlen ( err ) ) ;
2010-09-02 13:52:24 -04:00
}
2010-06-21 18:07:48 -04:00
2015-07-26 09:20:46 -04:00
void addReplyErrorFormat ( client * c , const char * fmt , . . . ) {
2011-05-24 13:43:11 -04:00
size_t l , j ;
2010-09-02 13:52:24 -04:00
va_list ap ;
va_start ( ap , fmt ) ;
sds s = sdscatvprintf ( sdsempty ( ) , fmt , ap ) ;
va_end ( ap ) ;
2011-05-24 13:43:11 -04:00
/* Make sure there are no newlines in the string, otherwise invalid protocol
* is emitted . */
l = sdslen ( s ) ;
for ( j = 0 ; j < l ; j + + ) {
if ( s [ j ] = = ' \r ' | | s [ j ] = = ' \n ' ) s [ j ] = ' ' ;
}
2012-01-23 11:15:49 -05:00
addReplyErrorLength ( c , s , sdslen ( s ) ) ;
2010-09-02 13:52:24 -04:00
sdsfree ( s ) ;
}
2015-07-26 09:20:46 -04:00
void addReplyStatusLength ( client * c , const char * s , size_t len ) {
2010-09-02 13:52:24 -04:00
addReplyString ( c , " + " , 1 ) ;
addReplyString ( c , s , len ) ;
addReplyString ( c , " \r \n " , 2 ) ;
}
2015-07-26 09:20:46 -04:00
void addReplyStatus ( client * c , const char * status ) {
2012-01-23 11:15:49 -05:00
addReplyStatusLength ( c , status , strlen ( status ) ) ;
2010-09-02 13:52:24 -04:00
}
2015-07-26 09:20:46 -04:00
void addReplyStatusFormat ( client * c , const char * fmt , . . . ) {
2010-09-02 13:52:24 -04:00
va_list ap ;
va_start ( ap , fmt ) ;
sds s = sdscatvprintf ( sdsempty ( ) , fmt , ap ) ;
va_end ( ap ) ;
2012-01-23 11:15:49 -05:00
addReplyStatusLength ( c , s , sdslen ( s ) ) ;
2010-09-02 13:52:24 -04:00
sdsfree ( s ) ;
}
2010-08-30 10:02:06 -04:00
/* Adds an empty object to the reply list that will contain the multi bulk
* length , which is not known when this function is called . */
2015-07-26 09:20:46 -04:00
void * addDeferredMultiBulkLength ( client * c ) {
2010-09-16 07:08:40 -04:00
/* Note that we install the write event here even if the object is not
* ready to be sent , since we are sure that before returning to the
* event loop setDeferredMultiBulkLength ( ) will be called . */
2015-07-26 17:17:55 -04:00
if ( prepareClientToWrite ( c ) ! = C_OK ) return NULL ;
2015-07-31 08:59:54 -04:00
listAddNodeTail ( c - > reply , NULL ) ; /* NULL is our placeholder. */
2010-08-30 10:02:06 -04:00
return listLast ( c - > reply ) ;
}
2013-01-16 12:00:20 -05:00
/* Populate the length object and try gluing it to the next chunk. */
2015-07-26 09:20:46 -04:00
void setDeferredMultiBulkLength ( client * c , void * node , long length ) {
2010-08-30 10:02:06 -04:00
listNode * ln = ( listNode * ) node ;
2015-07-31 08:59:54 -04:00
sds len , next ;
2010-08-30 10:02:06 -04:00
2015-07-31 08:59:54 -04:00
/* Abort when *node is NULL: when the client should not accept writes
* we return NULL in addDeferredMultiBulkLength ( ) */
2010-08-30 10:02:06 -04:00
if ( node = = NULL ) return ;
2015-07-31 08:59:54 -04:00
len = sdscatprintf ( sdsnewlen ( " * " , 1 ) , " %ld \r \n " , length ) ;
listNodeValue ( ln ) = len ;
c - > reply_bytes + = sdslen ( len ) ;
2010-08-30 10:02:06 -04:00
if ( ln - > next ! = NULL ) {
next = listNodeValue ( ln - > next ) ;
2010-09-02 13:18:55 -04:00
2010-09-02 17:34:32 -04:00
/* Only glue when the next node is non-NULL (an sds in this case) */
2015-07-31 08:59:54 -04:00
if ( next ! = NULL ) {
len = sdscatsds ( len , next ) ;
2010-08-30 10:02:06 -04:00
listDelNode ( c - > reply , ln - > next ) ;
2015-07-31 08:59:54 -04:00
listNodeValue ( ln ) = len ;
/* No need to update c->reply_bytes: we are just moving the same
* amount of bytes from one node to another . */
2010-08-30 10:02:06 -04:00
}
2010-06-21 18:07:48 -04:00
}
2012-01-23 10:12:37 -05:00
asyncCloseClientOnOutputBufferLimitReached ( c ) ;
2010-08-30 10:02:06 -04:00
}
2013-01-16 12:00:20 -05:00
/* Add a double as a bulk reply */
2015-07-26 09:20:46 -04:00
void addReplyDouble ( client * c , double d ) {
2010-08-30 08:44:34 -04:00
char dbuf [ 128 ] , sbuf [ 128 ] ;
int dlen , slen ;
2013-07-17 09:04:22 -04:00
if ( isinf ( d ) ) {
/* Libc in odd systems (Hi Solaris!) will format infinite in a
* different way , so better to handle it in an explicit way . */
addReplyBulkCString ( c , d > 0 ? " inf " : " -inf " ) ;
} else {
dlen = snprintf ( dbuf , sizeof ( dbuf ) , " %.17g " , d ) ;
slen = snprintf ( sbuf , sizeof ( sbuf ) , " $%d \r \n %s \r \n " , dlen , dbuf ) ;
addReplyString ( c , sbuf , slen ) ;
}
2010-06-21 18:07:48 -04:00
}
2016-02-18 16:08:47 -05:00
/* Add a long double as a bulk reply, but uses a human readable formatting
* of the double instead of exposing the crude behavior of doubles to the
* dear user . */
void addReplyHumanLongDouble ( client * c , long double d ) {
robj * o = createStringObjectFromLongDouble ( d , 1 ) ;
addReplyBulk ( c , o ) ;
decrRefCount ( o ) ;
}
2010-12-07 10:33:13 -05:00
/* Add a long long as integer reply or bulk len / multi bulk count.
* Basically this is used to output < prefix > < long long > < crlf > . */
2015-07-26 09:20:46 -04:00
void addReplyLongLongWithPrefix ( client * c , long long ll , char prefix ) {
2010-06-21 18:07:48 -04:00
char buf [ 128 ] ;
2010-08-30 08:44:34 -04:00
int len ;
2012-02-04 02:58:37 -05:00
/* Things like $3\r\n or *2\r\n are emitted very often by the protocol
* so we have a few shared objects to use if the integer is small
* like it is most of the times . */
2015-07-27 03:41:48 -04:00
if ( prefix = = ' * ' & & ll < OBJ_SHARED_BULKHDR_LEN & & ll > = 0 ) {
2012-02-04 02:58:37 -05:00
addReply ( c , shared . mbulkhdr [ ll ] ) ;
return ;
2015-07-27 03:41:48 -04:00
} else if ( prefix = = ' $ ' & & ll < OBJ_SHARED_BULKHDR_LEN & & ll > = 0 ) {
2012-02-04 02:58:37 -05:00
addReply ( c , shared . bulkhdr [ ll ] ) ;
return ;
}
2010-08-30 08:44:34 -04:00
buf [ 0 ] = prefix ;
2010-06-21 18:07:48 -04:00
len = ll2string ( buf + 1 , sizeof ( buf ) - 1 , ll ) ;
buf [ len + 1 ] = ' \r ' ;
buf [ len + 2 ] = ' \n ' ;
2010-08-30 08:44:34 -04:00
addReplyString ( c , buf , len + 3 ) ;
2010-06-21 18:07:48 -04:00
}
2015-07-26 09:20:46 -04:00
void addReplyLongLong ( client * c , long long ll ) {
2011-04-15 12:08:24 -04:00
if ( ll = = 0 )
addReply ( c , shared . czero ) ;
else if ( ll = = 1 )
addReply ( c , shared . cone ) ;
else
2012-01-23 11:15:49 -05:00
addReplyLongLongWithPrefix ( c , ll , ' : ' ) ;
2010-08-30 08:44:34 -04:00
}
2010-06-21 18:07:48 -04:00
2015-07-26 09:20:46 -04:00
void addReplyMultiBulkLen ( client * c , long length ) {
2015-07-27 03:41:48 -04:00
if ( length < OBJ_SHARED_BULKHDR_LEN )
2013-08-12 06:43:26 -04:00
addReply ( c , shared . mbulkhdr [ length ] ) ;
else
addReplyLongLongWithPrefix ( c , length , ' * ' ) ;
2010-06-21 18:07:48 -04:00
}
2010-12-07 10:33:13 -05:00
/* Create the length prefix of a bulk reply, example: $2234 */
2015-07-26 09:20:46 -04:00
void addReplyBulkLen ( client * c , robj * obj ) {
2010-08-30 08:44:34 -04:00
size_t len ;
2010-06-21 18:07:48 -04:00
2012-06-05 15:50:10 -04:00
if ( sdsEncodedObject ( obj ) ) {
2010-06-21 18:07:48 -04:00
len = sdslen ( obj - > ptr ) ;
} else {
long n = ( long ) obj - > ptr ;
/* Compute how many bytes will take this integer as a radix 10 string */
len = 1 ;
if ( n < 0 ) {
len + + ;
n = - n ;
}
while ( ( n = n / 10 ) ! = 0 ) {
len + + ;
}
}
2013-08-12 06:43:26 -04:00
2015-07-27 03:41:48 -04:00
if ( len < OBJ_SHARED_BULKHDR_LEN )
2013-08-12 06:43:26 -04:00
addReply ( c , shared . bulkhdr [ len ] ) ;
else
addReplyLongLongWithPrefix ( c , len , ' $ ' ) ;
2010-06-21 18:07:48 -04:00
}
2010-12-07 10:33:13 -05:00
/* Add a Redis Object as a bulk reply */
2015-07-26 09:20:46 -04:00
void addReplyBulk ( client * c , robj * obj ) {
2010-06-21 18:07:48 -04:00
addReplyBulkLen ( c , obj ) ;
addReply ( c , obj ) ;
addReply ( c , shared . crlf ) ;
}
2010-12-07 10:33:13 -05:00
/* Add a C buffer as bulk reply */
2015-07-26 09:20:46 -04:00
void addReplyBulkCBuffer ( client * c , const void * p , size_t len ) {
2012-01-23 11:15:49 -05:00
addReplyLongLongWithPrefix ( c , len , ' $ ' ) ;
2010-12-07 10:33:13 -05:00
addReplyString ( c , p , len ) ;
addReply ( c , shared . crlf ) ;
}
2014-11-16 13:03:54 -05:00
/* Add sds to reply (takes ownership of sds and frees it) */
2015-07-26 09:20:46 -04:00
void addReplyBulkSds ( client * c , sds s ) {
2017-07-05 10:25:05 -04:00
addReplyLongLongWithPrefix ( c , sdslen ( s ) , ' $ ' ) ;
2014-11-16 13:03:54 -05:00
addReplySds ( c , s ) ;
addReply ( c , shared . crlf ) ;
}
2017-12-06 06:05:11 -05:00
/* Add a C null term string as bulk reply */
2015-07-26 09:20:46 -04:00
void addReplyBulkCString ( client * c , const char * s ) {
2010-06-21 18:07:48 -04:00
if ( s = = NULL ) {
addReply ( c , shared . nullbulk ) ;
} else {
2010-12-07 10:33:13 -05:00
addReplyBulkCBuffer ( c , s , strlen ( s ) ) ;
2010-06-21 18:07:48 -04:00
}
}
2010-12-07 10:33:13 -05:00
/* Add a long long as a bulk reply */
2015-07-26 09:20:46 -04:00
void addReplyBulkLongLong ( client * c , long long ll ) {
2010-12-07 10:33:13 -05:00
char buf [ 64 ] ;
int len ;
len = ll2string ( buf , 64 , ll ) ;
addReplyBulkCBuffer ( c , buf , len ) ;
}
2017-12-06 06:05:11 -05:00
/* Add an array of C strings as status replies with a heading.
2017-11-27 10:57:44 -05:00
* This function is typically invoked by from commands that support
* subcommands in response to the ' help ' subcommand . The help array
* is terminated by NULL sentinel . */
void addReplyHelp ( client * c , const char * * help ) {
sds cmd = sdsnew ( ( char * ) c - > argv [ 0 ] - > ptr ) ;
void * blenp = addDeferredMultiBulkLength ( c ) ;
int blen = 0 ;
sdstoupper ( cmd ) ;
addReplyStatusFormat ( c ,
" %s <subcommand> arg arg ... arg. Subcommands are: " , cmd ) ;
sdsfree ( cmd ) ;
2017-12-06 06:05:11 -05:00
2017-12-05 12:09:19 -05:00
while ( help [ blen ] ) addReplyStatus ( c , help [ blen + + ] ) ;
2017-11-27 10:57:44 -05:00
2017-12-05 12:09:19 -05:00
blen + + ; /* Account for the header line(s). */
2017-11-27 10:57:44 -05:00
setDeferredMultiBulkLength ( c , blenp , blen ) ;
}
2011-12-30 13:34:40 -05:00
/* Copy 'src' client output buffers into 'dst' client output buffers.
* The function takes care of freeing the old output buffers of the
* destination client . */
2015-07-26 09:20:46 -04:00
void copyClientOutputBuffer ( client * dst , client * src ) {
2011-12-30 13:34:40 -05:00
listRelease ( dst - > reply ) ;
dst - > reply = listDup ( src - > reply ) ;
memcpy ( dst - > buf , src - > buf , src - > bufpos ) ;
dst - > bufpos = src - > bufpos ;
2011-12-25 10:32:54 -05:00
dst - > reply_bytes = src - > reply_bytes ;
2011-12-30 13:34:40 -05:00
}
2015-09-30 10:41:48 -04:00
/* Return true if the specified client has pending reply buffers to write to
* the socket . */
int clientHasPendingReplies ( client * c ) {
return c - > bufpos | | listLength ( c - > reply ) ;
}
2014-04-24 11:33:57 -04:00
# define MAX_ACCEPTS_PER_CALL 1000
New security feature: Redis protected mode.
An exposed Redis instance on the internet can be cause of serious
issues. Since Redis, by default, binds to all the interfaces, it is easy
to forget an instance without any protection layer, for error.
Protected mode try to address this feature in a soft way, providing a
layer of protection, but giving clues to Redis users about why the
server is not accepting connections.
When protected mode is enabeld (the default), and if there are no
minumum hints about the fact the server is properly configured (no
"bind" directive is used in order to restrict the server to certain
interfaces, nor a password is set), clients connecting from external
intefaces are refused with an error explaining what to do in order to
fix the issue.
Clients connecting from the IPv4 and IPv6 lookback interfaces are still
accepted normally, similarly Unix domain socket connections are not
restricted in any way.
2016-01-07 07:00:08 -05:00
static void acceptCommonHandler ( int fd , int flags , char * ip ) {
2015-07-26 09:20:46 -04:00
client * c ;
2010-10-13 12:34:24 -04:00
if ( ( c = createClient ( fd ) ) = = NULL ) {
2015-07-27 03:41:48 -04:00
serverLog ( LL_WARNING ,
2013-01-03 08:22:55 -05:00
" Error registering fd event for the new client: %s (fd=%d) " ,
strerror ( errno ) , fd ) ;
2012-11-01 06:14:55 -04:00
close ( fd ) ; /* May be already closed, just ignore errors */
2010-06-21 18:07:48 -04:00
return ;
}
/* If maxclient directive is set and this is one client more... close the
* connection . Note that we create the client instead to check before
2013-01-16 12:00:20 -05:00
* for this condition , since now the socket is already set in non - blocking
2010-06-21 18:07:48 -04:00
* mode and we can send an error for free using the Kernel I / O */
2011-10-31 05:48:41 -04:00
if ( listLength ( server . clients ) > server . maxclients ) {
2010-06-21 18:07:48 -04:00
char * err = " -ERR max number of clients reached \r \n " ;
/* That's a best effort error message, don't check write errors */
if ( write ( c - > fd , err , strlen ( err ) ) = = - 1 ) {
/* Nothing to do, Just to avoid the warning... */
}
2011-11-23 12:38:12 -05:00
server . stat_rejected_conn + + ;
2010-06-21 18:07:48 -04:00
freeClient ( c ) ;
return ;
}
New security feature: Redis protected mode.
An exposed Redis instance on the internet can be cause of serious
issues. Since Redis, by default, binds to all the interfaces, it is easy
to forget an instance without any protection layer, for error.
Protected mode try to address this feature in a soft way, providing a
layer of protection, but giving clues to Redis users about why the
server is not accepting connections.
When protected mode is enabeld (the default), and if there are no
minumum hints about the fact the server is properly configured (no
"bind" directive is used in order to restrict the server to certain
interfaces, nor a password is set), clients connecting from external
intefaces are refused with an error explaining what to do in order to
fix the issue.
Clients connecting from the IPv4 and IPv6 lookback interfaces are still
accepted normally, similarly Unix domain socket connections are not
restricted in any way.
2016-01-07 07:00:08 -05:00
/* If the server is running in protected mode (the default) and there
* is no password set , nor a specific interface is bound , we don ' t accept
* requests from non loopback interfaces . Instead we try to explain the
* user what to do to fix it if needed . */
if ( server . protected_mode & &
server . bindaddr_count = = 0 & &
server . requirepass = = NULL & &
! ( flags & CLIENT_UNIX_SOCKET ) & &
ip ! = NULL )
{
if ( strcmp ( ip , " 127.0.0.1 " ) & & strcmp ( ip , " ::1 " ) ) {
char * err =
" -DENIED Redis is running in protected mode because protected "
" mode is enabled, no bind address was specified, no "
" authentication password is requested to clients. In this mode "
2016-01-07 08:35:07 -05:00
" connections are only accepted from the loopback interface. "
New security feature: Redis protected mode.
An exposed Redis instance on the internet can be cause of serious
issues. Since Redis, by default, binds to all the interfaces, it is easy
to forget an instance without any protection layer, for error.
Protected mode try to address this feature in a soft way, providing a
layer of protection, but giving clues to Redis users about why the
server is not accepting connections.
When protected mode is enabeld (the default), and if there are no
minumum hints about the fact the server is properly configured (no
"bind" directive is used in order to restrict the server to certain
interfaces, nor a password is set), clients connecting from external
intefaces are refused with an error explaining what to do in order to
fix the issue.
Clients connecting from the IPv4 and IPv6 lookback interfaces are still
accepted normally, similarly Unix domain socket connections are not
restricted in any way.
2016-01-07 07:00:08 -05:00
" If you want to connect from external computers to Redis you "
" may adopt one of the following solutions: "
" 1) Just disable protected mode sending the command "
" 'CONFIG SET protected-mode no' from the loopback interface "
" by connecting to Redis from the same host the server is "
2016-01-20 10:08:28 -05:00
" running, however MAKE SURE Redis is not publicly accessible "
New security feature: Redis protected mode.
An exposed Redis instance on the internet can be cause of serious
issues. Since Redis, by default, binds to all the interfaces, it is easy
to forget an instance without any protection layer, for error.
Protected mode try to address this feature in a soft way, providing a
layer of protection, but giving clues to Redis users about why the
server is not accepting connections.
When protected mode is enabeld (the default), and if there are no
minumum hints about the fact the server is properly configured (no
"bind" directive is used in order to restrict the server to certain
interfaces, nor a password is set), clients connecting from external
intefaces are refused with an error explaining what to do in order to
fix the issue.
Clients connecting from the IPv4 and IPv6 lookback interfaces are still
accepted normally, similarly Unix domain socket connections are not
restricted in any way.
2016-01-07 07:00:08 -05:00
" from internet if you do so. Use CONFIG REWRITE to make this "
" change permanent. "
" 2) Alternatively you can just disable the protected mode by "
" editing the Redis configuration file, and setting the protected "
" mode option to 'no', and then restarting the server. "
" 3) If you started the server manually just for testing, restart "
2016-01-07 16:42:43 -05:00
" it with the '--protected-mode no' option. "
New security feature: Redis protected mode.
An exposed Redis instance on the internet can be cause of serious
issues. Since Redis, by default, binds to all the interfaces, it is easy
to forget an instance without any protection layer, for error.
Protected mode try to address this feature in a soft way, providing a
layer of protection, but giving clues to Redis users about why the
server is not accepting connections.
When protected mode is enabeld (the default), and if there are no
minumum hints about the fact the server is properly configured (no
"bind" directive is used in order to restrict the server to certain
interfaces, nor a password is set), clients connecting from external
intefaces are refused with an error explaining what to do in order to
fix the issue.
Clients connecting from the IPv4 and IPv6 lookback interfaces are still
accepted normally, similarly Unix domain socket connections are not
restricted in any way.
2016-01-07 07:00:08 -05:00
" 4) Setup a bind address or an authentication password. "
" NOTE: You only need to do one of the above things in order for "
" the server to start accepting connections from the outside. \r \n " ;
if ( write ( c - > fd , err , strlen ( err ) ) = = - 1 ) {
/* Nothing to do, Just to avoid the warning... */
}
server . stat_rejected_conn + + ;
freeClient ( c ) ;
return ;
}
}
2010-06-21 18:07:48 -04:00
server . stat_numconnections + + ;
2012-11-01 17:10:45 -04:00
c - > flags | = flags ;
2010-06-21 18:07:48 -04:00
}
2010-10-13 12:34:24 -04:00
void acceptTcpHandler ( aeEventLoop * el , int fd , void * privdata , int mask ) {
2014-04-24 11:33:57 -04:00
int cport , cfd , max = MAX_ACCEPTS_PER_CALL ;
2015-07-27 03:41:48 -04:00
char cip [ NET_IP_STR_LEN ] ;
UNUSED ( el ) ;
UNUSED ( mask ) ;
UNUSED ( privdata ) ;
2010-10-13 12:34:24 -04:00
2014-04-24 11:33:57 -04:00
while ( max - - ) {
cfd = anetTcpAccept ( server . neterr , fd , cip , sizeof ( cip ) , & cport ) ;
if ( cfd = = ANET_ERR ) {
if ( errno ! = EWOULDBLOCK )
2015-07-27 03:41:48 -04:00
serverLog ( LL_WARNING ,
2014-04-24 11:33:57 -04:00
" Accepting client connection: %s " , server . neterr ) ;
return ;
}
2015-07-27 03:41:48 -04:00
serverLog ( LL_VERBOSE , " Accepted %s:%d " , cip , cport ) ;
New security feature: Redis protected mode.
An exposed Redis instance on the internet can be cause of serious
issues. Since Redis, by default, binds to all the interfaces, it is easy
to forget an instance without any protection layer, for error.
Protected mode try to address this feature in a soft way, providing a
layer of protection, but giving clues to Redis users about why the
server is not accepting connections.
When protected mode is enabeld (the default), and if there are no
minumum hints about the fact the server is properly configured (no
"bind" directive is used in order to restrict the server to certain
interfaces, nor a password is set), clients connecting from external
intefaces are refused with an error explaining what to do in order to
fix the issue.
Clients connecting from the IPv4 and IPv6 lookback interfaces are still
accepted normally, similarly Unix domain socket connections are not
restricted in any way.
2016-01-07 07:00:08 -05:00
acceptCommonHandler ( cfd , 0 , cip ) ;
2010-10-13 12:34:24 -04:00
}
}
void acceptUnixHandler ( aeEventLoop * el , int fd , void * privdata , int mask ) {
2014-04-24 11:33:57 -04:00
int cfd , max = MAX_ACCEPTS_PER_CALL ;
2015-07-27 03:41:48 -04:00
UNUSED ( el ) ;
UNUSED ( mask ) ;
UNUSED ( privdata ) ;
2010-10-13 12:34:24 -04:00
2014-04-24 11:33:57 -04:00
while ( max - - ) {
cfd = anetUnixAccept ( server . neterr , fd ) ;
if ( cfd = = ANET_ERR ) {
if ( errno ! = EWOULDBLOCK )
2015-07-27 03:41:48 -04:00
serverLog ( LL_WARNING ,
2014-04-24 11:33:57 -04:00
" Accepting client connection: %s " , server . neterr ) ;
return ;
}
2015-07-27 03:41:48 -04:00
serverLog ( LL_VERBOSE , " Accepted connection to %s " , server . unixsocket ) ;
New security feature: Redis protected mode.
An exposed Redis instance on the internet can be cause of serious
issues. Since Redis, by default, binds to all the interfaces, it is easy
to forget an instance without any protection layer, for error.
Protected mode try to address this feature in a soft way, providing a
layer of protection, but giving clues to Redis users about why the
server is not accepting connections.
When protected mode is enabeld (the default), and if there are no
minumum hints about the fact the server is properly configured (no
"bind" directive is used in order to restrict the server to certain
interfaces, nor a password is set), clients connecting from external
intefaces are refused with an error explaining what to do in order to
fix the issue.
Clients connecting from the IPv4 and IPv6 lookback interfaces are still
accepted normally, similarly Unix domain socket connections are not
restricted in any way.
2016-01-07 07:00:08 -05:00
acceptCommonHandler ( cfd , CLIENT_UNIX_SOCKET , NULL ) ;
2010-10-13 12:34:24 -04:00
}
}
2015-07-26 09:20:46 -04:00
static void freeClientArgv ( client * c ) {
2010-06-21 18:07:48 -04:00
int j ;
for ( j = 0 ; j < c - > argc ; j + + )
decrRefCount ( c - > argv [ j ] ) ;
c - > argc = 0 ;
2011-07-08 06:59:30 -04:00
c - > cmd = NULL ;
2010-06-21 18:07:48 -04:00
}
2012-03-29 03:24:02 -04:00
/* Close all the slaves connections. This is useful in chained replication
* when we resync with our own master and want to force all our slaves to
* resync with us as well . */
void disconnectSlaves ( void ) {
while ( listLength ( server . slaves ) ) {
listNode * ln = listFirst ( server . slaves ) ;
2015-07-26 09:20:46 -04:00
freeClient ( ( client * ) ln - > value ) ;
2012-03-29 03:24:02 -04:00
}
}
2015-09-30 10:56:02 -04:00
/* Remove the specified client from global lists where the client could
* be referenced , not including the Pub / Sub channels .
* This is used by freeClient ( ) and replicationCacheMaster ( ) . */
void unlinkClient ( client * c ) {
2010-06-21 18:07:48 -04:00
listNode * ln ;
2015-09-30 10:56:02 -04:00
/* If this is marked as current client unset it. */
2012-01-12 10:02:57 -05:00
if ( server . current_client = = c ) server . current_client = NULL ;
2015-09-30 10:56:02 -04:00
/* Certain operations must be done only if the client has an active socket.
* If the client was already unlinked or if it ' s a " fake client " the
* fd is already set to - 1. */
if ( c - > fd ! = - 1 ) {
/* Remove from the list of active clients. */
2017-11-30 05:11:05 -05:00
if ( c - > client_list_node ) {
listDelNode ( server . clients , c - > client_list_node ) ;
c - > client_list_node = NULL ;
}
2015-09-30 10:56:02 -04:00
/* Unregister async I/O handlers and close the socket. */
aeDeleteFileEvent ( server . el , c - > fd , AE_READABLE ) ;
aeDeleteFileEvent ( server . el , c - > fd , AE_WRITABLE ) ;
close ( c - > fd ) ;
c - > fd = - 1 ;
}
/* Remove from the list of pending writes if needed. */
if ( c - > flags & CLIENT_PENDING_WRITE ) {
ln = listSearchKey ( server . clients_pending_write , c ) ;
serverAssert ( ln ! = NULL ) ;
listDelNode ( server . clients_pending_write , ln ) ;
2015-12-09 17:06:44 -05:00
c - > flags & = ~ CLIENT_PENDING_WRITE ;
2015-09-30 10:56:02 -04:00
}
/* When client was just unblocked because of a blocking operation,
* remove it from the list of unblocked clients . */
if ( c - > flags & CLIENT_UNBLOCKED ) {
ln = listSearchKey ( server . unblocked_clients , c ) ;
serverAssert ( ln ! = NULL ) ;
listDelNode ( server . unblocked_clients , ln ) ;
2015-12-09 17:06:44 -05:00
c - > flags & = ~ CLIENT_UNBLOCKED ;
2015-09-30 10:56:02 -04:00
}
}
void freeClient ( client * c ) {
listNode * ln ;
2013-01-30 12:33:16 -05:00
/* If it is our master that's beging disconnected we should make sure
* to cache the state to try a partial resynchronization later .
*
* Note that before doing this we make sure that the client is not in
* some unexpected state , by checking its flags . */
2015-07-27 03:41:48 -04:00
if ( server . master & & c - > flags & CLIENT_MASTER ) {
serverLog ( LL_WARNING , " Connection with master lost. " ) ;
if ( ! ( c - > flags & ( CLIENT_CLOSE_AFTER_REPLY |
CLIENT_CLOSE_ASAP |
CLIENT_BLOCKED |
CLIENT_UNBLOCKED ) ) )
2013-12-20 18:23:37 -05:00
{
replicationCacheMaster ( c ) ;
return ;
}
2013-01-30 12:33:16 -05:00
}
2013-12-22 04:15:35 -05:00
/* Log link disconnection with slave */
2015-07-27 03:41:48 -04:00
if ( ( c - > flags & CLIENT_SLAVE ) & & ! ( c - > flags & CLIENT_MONITOR ) ) {
serverLog ( LL_WARNING , " Connection with slave %s lost. " ,
2014-10-27 06:58:20 -04:00
replicationGetSlaveName ( c ) ) ;
2013-12-22 04:15:35 -05:00
}
2013-12-03 07:54:06 -05:00
/* Free the query buffer */
2010-06-21 18:07:48 -04:00
sdsfree ( c - > querybuf ) ;
Fix PSYNC2 incomplete command bug as described in #3899.
This bug was discovered by @kevinmcgehee and constituted a major hidden
bug in the PSYNC2 implementation, caused by the propagation from the
master of incomplete commands to slaves.
The bug had several results:
1. Borrowing from Kevin text in the issue: "Given that slaves blindly
copy over their master's input into their own replication backlog over
successive read syscalls, it's possible that with large commands or
small TCP buffers, partial commands are present in this buffer. If the
master were to fail before successfully propagating the entire command
to a slave, the slaves will never execute the partial command (since the
client is invalidated) but will copy it to replication backlog which may
relay those invalid bytes to its slaves on PSYNC2, corrupting the
backlog and possibly other valid commands that follow the failover.
Simple command boundaries aren't sufficient to capture this, either,
because in the case of a MULTI/EXEC block, if the master successfully
propagates a subset of the commands but not the EXEC, then the
transaction in the backlog becomes corrupt and could corrupt other
slaves that consume this data."
2. As identified by @yangsiran later, there is another effect of the
bug. For the same mechanism of the first problem, a slave having another
slave, could receive a full resynchronization request with an already
half-applied command in the backlog. Once the RDB is ready, it will be
sent to the slave, and the replication will continue sending to the
sub-slave the other half of the command, which is not valid.
The fix, designed by @yangsiran and @antirez, and implemented by
@antirez, uses a secondary buffer in order to feed the sub-masters and
update the replication backlog and offsets, only when a given part of
the query buffer is actually *applied* to the state of the instance,
that is, when the command gets processed and the command is not pending
in the Redis transaction buffer because of CLIENT_MULTI state.
Given that now the backlog and offsets representation are in agreement
with the actual processed commands, both issue 1 and 2 should no longer
be possible.
Thanks to @kevinmcgehee, @yangsiran and @oranagra for their work in
identifying and designing a fix for this problem.
2017-04-19 04:25:45 -04:00
sdsfree ( c - > pending_querybuf ) ;
2010-06-21 18:07:48 -04:00
c - > querybuf = NULL ;
2013-12-03 07:54:06 -05:00
/* Deallocate structures used to block on blocking ops. */
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_BLOCKED ) unblockClient ( c ) ;
2012-12-03 06:12:53 -05:00
dictRelease ( c - > bpop . keys ) ;
2010-06-21 18:07:48 -04:00
/* UNWATCH all the keys */
unwatchAllKeys ( c ) ;
listRelease ( c - > watched_keys ) ;
2013-12-03 07:54:06 -05:00
2010-06-21 18:07:48 -04:00
/* Unsubscribe from all the pubsub channels */
pubsubUnsubscribeAllChannels ( c , 0 ) ;
pubsubUnsubscribeAllPatterns ( c , 0 ) ;
dictRelease ( c - > pubsub_channels ) ;
listRelease ( c - > pubsub_patterns ) ;
2013-12-03 07:54:06 -05:00
2015-09-30 10:56:02 -04:00
/* Free data structures. */
2010-06-21 18:07:48 -04:00
listRelease ( c - > reply ) ;
freeClientArgv ( c ) ;
2013-12-03 07:54:06 -05:00
2015-09-30 10:56:02 -04:00
/* Unlink the client: this will close the socket, remove the I/O
* handlers , and remove references of the client from different
* places where active clients may be referenced . */
unlinkClient ( c ) ;
2013-12-03 07:54:06 -05:00
/* Master/slave cleanup Case 1:
* we lost the connection with a slave . */
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_SLAVE ) {
if ( c - > replstate = = SLAVE_STATE_SEND_BULK ) {
2013-08-12 04:29:14 -04:00
if ( c - > repldbfd ! = - 1 ) close ( c - > repldbfd ) ;
if ( c - > replpreamble ) sdsfree ( c - > replpreamble ) ;
}
2015-07-27 03:41:48 -04:00
list * l = ( c - > flags & CLIENT_MONITOR ) ? server . monitors : server . slaves ;
2010-06-21 18:07:48 -04:00
ln = listSearchKey ( l , c ) ;
2015-07-26 09:29:53 -04:00
serverAssert ( ln ! = NULL ) ;
2010-06-21 18:07:48 -04:00
listDelNode ( l , ln ) ;
2013-01-30 12:33:16 -05:00
/* We need to remember the time when we started to have zero
* attached slaves , as after some time we ' ll free the replication
* backlog . */
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_SLAVE & & listLength ( server . slaves ) = = 0 )
2013-01-30 12:33:16 -05:00
server . repl_no_slaves_since = server . unixtime ;
2013-05-29 05:36:44 -04:00
refreshGoodSlavesCount ( ) ;
2010-06-21 18:07:48 -04:00
}
2010-08-24 10:04:13 -04:00
2013-12-03 07:54:06 -05:00
/* Master/slave cleanup Case 2:
* we lost the connection with the master . */
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_MASTER ) replicationHandleMasterDisconnection ( ) ;
2012-01-23 10:12:37 -05:00
/* If this client was scheduled for async freeing we need to remove it
* from the queue . */
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_CLOSE_ASAP ) {
2012-01-23 10:12:37 -05:00
ln = listSearchKey ( server . clients_to_close , c ) ;
2015-07-26 09:29:53 -04:00
serverAssert ( ln ! = NULL ) ;
2012-01-23 10:12:37 -05:00
listDelNode ( server . clients_to_close , ln ) ;
}
2013-12-03 07:54:06 -05:00
/* Release other dynamically allocated client structure fields,
* and finally release the client structure itself . */
2013-01-11 12:43:28 -05:00
if ( c - > name ) decrRefCount ( c - > name ) ;
2010-06-21 18:07:48 -04:00
zfree ( c - > argv ) ;
freeClientMultiState ( c ) ;
2014-04-28 11:36:57 -04:00
sdsfree ( c - > peerid ) ;
2010-06-21 18:07:48 -04:00
zfree ( c ) ;
}
2012-01-23 10:12:37 -05:00
/* Schedule a client to free it at a safe time in the serverCron() function.
* This function is useful when we need to terminate a client but we are in
* a context where calling freeClient ( ) is not possible , because the client
* should be valid for the continuation of the flow of the program . */
2015-07-26 09:20:46 -04:00
void freeClientAsync ( client * c ) {
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_CLOSE_ASAP | | c - > flags & CLIENT_LUA ) return ;
c - > flags | = CLIENT_CLOSE_ASAP ;
2012-01-23 10:12:37 -05:00
listAddNodeTail ( server . clients_to_close , c ) ;
}
void freeClientsInAsyncFreeQueue ( void ) {
while ( listLength ( server . clients_to_close ) ) {
listNode * ln = listFirst ( server . clients_to_close ) ;
2015-07-26 09:20:46 -04:00
client * c = listNodeValue ( ln ) ;
2012-01-23 10:12:37 -05:00
2015-07-27 03:41:48 -04:00
c - > flags & = ~ CLIENT_CLOSE_ASAP ;
2012-01-23 10:12:37 -05:00
freeClient ( c ) ;
listDelNode ( server . clients_to_close , ln ) ;
}
}
2015-09-28 13:27:51 -04:00
/* Write data in output buffers to client. Return C_OK if the client
* is still valid after the call , C_ERR if it was freed . */
2015-09-28 13:33:09 -04:00
int writeToClient ( int fd , client * c , int handler_installed ) {
2015-01-18 16:46:25 -05:00
ssize_t nwritten = 0 , totwritten = 0 ;
size_t objlen ;
2015-07-31 08:59:54 -04:00
sds o ;
2010-06-21 18:07:48 -04:00
2015-09-30 10:41:48 -04:00
while ( clientHasPendingReplies ( c ) ) {
2010-08-30 08:44:34 -04:00
if ( c - > bufpos > 0 ) {
2013-05-24 12:58:57 -04:00
nwritten = write ( fd , c - > buf + c - > sentlen , c - > bufpos - c - > sentlen ) ;
if ( nwritten < = 0 ) break ;
2010-08-30 08:44:34 -04:00
c - > sentlen + = nwritten ;
totwritten + = nwritten ;
/* If the buffer was sent, set bufpos to zero to continue with
* the remainder of the reply . */
2015-02-25 04:33:37 -05:00
if ( ( int ) c - > sentlen = = c - > bufpos ) {
2010-08-30 08:44:34 -04:00
c - > bufpos = 0 ;
c - > sentlen = 0 ;
}
} else {
o = listNodeValue ( listFirst ( c - > reply ) ) ;
2015-07-31 08:59:54 -04:00
objlen = sdslen ( o ) ;
2010-06-21 18:07:48 -04:00
2010-08-30 08:44:34 -04:00
if ( objlen = = 0 ) {
listDelNode ( c - > reply , listFirst ( c - > reply ) ) ;
continue ;
}
2010-06-21 18:07:48 -04:00
2015-07-31 08:59:54 -04:00
nwritten = write ( fd , o + c - > sentlen , objlen - c - > sentlen ) ;
2013-05-24 12:58:57 -04:00
if ( nwritten < = 0 ) break ;
2010-08-30 08:44:34 -04:00
c - > sentlen + = nwritten ;
totwritten + = nwritten ;
2010-06-21 18:07:48 -04:00
2010-08-30 08:44:34 -04:00
/* If we fully sent the object on head go to the next one */
if ( c - > sentlen = = objlen ) {
listDelNode ( c - > reply , listFirst ( c - > reply ) ) ;
c - > sentlen = 0 ;
2015-07-31 08:59:54 -04:00
c - > reply_bytes - = objlen ;
2017-07-04 05:55:05 -04:00
/* If there are no longer objects in the list, we expect
* the count of reply bytes to be exactly zero . */
if ( listLength ( c - > reply ) = = 0 )
serverAssert ( c - > reply_bytes = = 0 ) ;
2010-08-30 08:44:34 -04:00
}
2010-06-21 18:07:48 -04:00
}
2015-07-27 03:41:48 -04:00
/* Note that we avoid to send more than NET_MAX_WRITES_PER_EVENT
2010-06-21 18:07:48 -04:00
* bytes , in a single threaded server it ' s a good idea to serve
* other clients as well , even if a very large request comes from
* super fast link that is always able to accept data ( in real world
2012-02-04 08:05:54 -05:00
* scenario think about ' KEYS * ' against the loopback interface ) .
*
* However if we are over the maxmemory limit we ignore that and
2017-03-06 11:42:52 -05:00
* just deliver as much data as it is possible to deliver .
*
* Moreover , we also send as much as possible if the client is
* a slave ( otherwise , on high - speed traffic , the replication
* buffer will grow indefinitely ) */
2015-07-27 03:41:48 -04:00
if ( totwritten > NET_MAX_WRITES_PER_EVENT & &
2012-02-04 08:05:54 -05:00
( server . maxmemory = = 0 | |
2017-03-06 11:42:52 -05:00
zmalloc_used_memory ( ) < server . maxmemory ) & &
! ( c - > flags & CLIENT_SLAVE ) ) break ;
2010-06-21 18:07:48 -04:00
}
2017-02-10 07:13:01 -05:00
server . stat_net_output_bytes + = totwritten ;
2010-06-21 18:07:48 -04:00
if ( nwritten = = - 1 ) {
if ( errno = = EAGAIN ) {
nwritten = 0 ;
} else {
2015-07-27 03:41:48 -04:00
serverLog ( LL_VERBOSE ,
2010-06-21 18:07:48 -04:00
" Error writing to client: %s " , strerror ( errno ) ) ;
freeClient ( c ) ;
2015-09-28 13:27:51 -04:00
return C_ERR ;
2010-06-21 18:07:48 -04:00
}
}
2013-10-04 06:59:24 -04:00
if ( totwritten > 0 ) {
/* For clients representing masters we don't count sending data
* as an interaction , since we always send REPLCONF ACK commands
* that take some time to just fill the socket output buffer .
* We just rely on data / pings received for timeout detection . */
2015-07-27 03:41:48 -04:00
if ( ! ( c - > flags & CLIENT_MASTER ) ) c - > lastinteraction = server . unixtime ;
2013-10-04 06:59:24 -04:00
}
2015-09-30 10:41:48 -04:00
if ( ! clientHasPendingReplies ( c ) ) {
2010-06-21 18:07:48 -04:00
c - > sentlen = 0 ;
2015-09-28 13:33:09 -04:00
if ( handler_installed ) aeDeleteFileEvent ( server . el , c - > fd , AE_WRITABLE ) ;
2010-10-13 05:25:40 -04:00
/* Close connection after entire reply has been sent. */
2015-09-28 13:27:51 -04:00
if ( c - > flags & CLIENT_CLOSE_AFTER_REPLY ) {
freeClient ( c ) ;
return C_ERR ;
}
2010-06-21 18:07:48 -04:00
}
2015-09-28 13:27:51 -04:00
return C_OK ;
}
/* Write event handler. Just send data to the client. */
void sendReplyToClient ( aeEventLoop * el , int fd , void * privdata , int mask ) {
UNUSED ( el ) ;
UNUSED ( mask ) ;
2015-09-28 13:33:09 -04:00
writeToClient ( fd , privdata , 1 ) ;
2010-06-21 18:07:48 -04:00
}
2015-09-28 13:06:36 -04:00
/* This function is called just before entering the event loop, in the hope
* we can just write the replies to the client output buffer without any
* need to use a syscall in order to install the writable event handler ,
* get it called , and so forth . */
2015-09-30 11:23:34 -04:00
int handleClientsWithPendingWrites ( void ) {
2015-09-28 13:06:36 -04:00
listIter li ;
listNode * ln ;
2015-09-30 11:23:34 -04:00
int processed = listLength ( server . clients_pending_write ) ;
2015-09-28 13:06:36 -04:00
listRewind ( server . clients_pending_write , & li ) ;
while ( ( ln = listNext ( & li ) ) ) {
client * c = listNodeValue ( ln ) ;
c - > flags & = ~ CLIENT_PENDING_WRITE ;
listDelNode ( server . clients_pending_write , ln ) ;
/* Try to write buffers to the client socket. */
2015-09-28 13:33:09 -04:00
if ( writeToClient ( c - > fd , c , 0 ) = = C_ERR ) continue ;
2015-09-28 13:06:36 -04:00
2018-02-27 04:40:40 -05:00
/* If after the synchronous writes above we still have data to
* output to the client , we need to install the writable handler . */
if ( clientHasPendingReplies ( c ) ) {
int ae_flags = AE_WRITABLE ;
/* For the fsync=always policy, we want that a given FD is never
* served for reading and writing in the same event loop iteration ,
* so that in the middle of receiving the query , and serving it
* to the client , we ' ll call beforeSleep ( ) that will do the
* actual fsync of AOF to disk . AE_BARRIER ensures that . */
if ( server . aof_state = = AOF_ON & &
server . aof_fsync = = AOF_FSYNC_ALWAYS )
{
ae_flags | = AE_BARRIER ;
}
2018-02-28 12:03:51 -05:00
if ( aeCreateFileEvent ( server . el , c - > fd , ae_flags ,
2015-09-28 13:06:36 -04:00
sendReplyToClient , c ) = = AE_ERR )
2018-02-27 04:40:40 -05:00
{
freeClientAsync ( c ) ;
}
2015-09-28 13:06:36 -04:00
}
}
2015-09-30 11:23:34 -04:00
return processed ;
2015-09-28 13:06:36 -04:00
}
2010-06-21 18:07:48 -04:00
/* resetClient prepare the client to process the next command */
2015-07-26 09:20:46 -04:00
void resetClient ( client * c ) {
2013-02-20 11:07:52 -05:00
redisCommandProc * prevcmd = c - > cmd ? c - > cmd - > proc : NULL ;
2010-06-21 18:07:48 -04:00
freeClientArgv ( c ) ;
2010-10-15 09:40:25 -04:00
c - > reqtype = 0 ;
c - > multibulklen = 0 ;
2010-06-21 18:07:48 -04:00
c - > bulklen = - 1 ;
CLIENT REPLY command implemented: ON, OFF and SKIP modes.
Sometimes it can be useful for clients to completely disable replies
from the Redis server. For example when the client sends fire and forget
commands or performs a mass loading of data, or in caching contexts
where new data is streamed constantly. In such contexts to use server
time and bandwidth in order to send back replies to clients, which are
going to be ignored, is a shame.
Multiple mechanisms are possible to implement such a feature. For
example it could be a feature of MULTI/EXEC, or a command prefix
such as "NOREPLY SADD myset foo", or a different mechanism that allows
to switch on/off requests using the CLIENT command.
The MULTI/EXEC approach has the problem that transactions are not
strictly part of the no-reply semantics, and if we want to insert a lot
of data in a bulk way, creating a huge MULTI/EXEC transaction in the
server memory is bad.
The prefix is the best in this specific use case since it does not allow
desynchronizations, and is pretty clear semantically. However Redis
internals and client libraries are not prepared to handle this
currently.
So the implementation uses the CLIENT command, providing a new REPLY
subcommand with three options:
CLIENT REPLY OFF disables the replies, and does not reply itself.
CLIENT REPLY ON re-enables the replies, replying +OK.
CLIENT REPLY SKIP only discards the reply of the next command, and
like OFF does not reply anything itself.
The reason to add the SKIP command is that it allows to have an easy
way to send conceptually "single" commands that don't need a reply
as the sum of two pipelined commands:
CLIENT REPLY SKIP
SET key value
Note that CLIENT REPLY ON replies with +OK so it should be used when
sending multiple commands that don't need a reply. However since it
replies with +OK the client can check that the connection is still
active and all the previous commands were received.
This is currently just into Redis "unstable" so the proposal can be
modified or abandoned based on users inputs.
2015-10-21 14:43:37 -04:00
2013-02-20 11:07:52 -05:00
/* We clear the ASKING flag as well if we are not inside a MULTI, and
* if what we just executed is not the ASKING command itself . */
2015-07-27 03:41:48 -04:00
if ( ! ( c - > flags & CLIENT_MULTI ) & & prevcmd ! = askingCommand )
CLIENT REPLY command implemented: ON, OFF and SKIP modes.
Sometimes it can be useful for clients to completely disable replies
from the Redis server. For example when the client sends fire and forget
commands or performs a mass loading of data, or in caching contexts
where new data is streamed constantly. In such contexts to use server
time and bandwidth in order to send back replies to clients, which are
going to be ignored, is a shame.
Multiple mechanisms are possible to implement such a feature. For
example it could be a feature of MULTI/EXEC, or a command prefix
such as "NOREPLY SADD myset foo", or a different mechanism that allows
to switch on/off requests using the CLIENT command.
The MULTI/EXEC approach has the problem that transactions are not
strictly part of the no-reply semantics, and if we want to insert a lot
of data in a bulk way, creating a huge MULTI/EXEC transaction in the
server memory is bad.
The prefix is the best in this specific use case since it does not allow
desynchronizations, and is pretty clear semantically. However Redis
internals and client libraries are not prepared to handle this
currently.
So the implementation uses the CLIENT command, providing a new REPLY
subcommand with three options:
CLIENT REPLY OFF disables the replies, and does not reply itself.
CLIENT REPLY ON re-enables the replies, replying +OK.
CLIENT REPLY SKIP only discards the reply of the next command, and
like OFF does not reply anything itself.
The reason to add the SKIP command is that it allows to have an easy
way to send conceptually "single" commands that don't need a reply
as the sum of two pipelined commands:
CLIENT REPLY SKIP
SET key value
Note that CLIENT REPLY ON replies with +OK so it should be used when
sending multiple commands that don't need a reply. However since it
replies with +OK the client can check that the connection is still
active and all the previous commands were received.
This is currently just into Redis "unstable" so the proposal can be
modified or abandoned based on users inputs.
2015-10-21 14:43:37 -04:00
c - > flags & = ~ CLIENT_ASKING ;
/* Remove the CLIENT_REPLY_SKIP flag if any so that the reply
* to the next command will be sent , but set the flag if the command
* we just processed was " CLIENT REPLY SKIP " . */
c - > flags & = ~ CLIENT_REPLY_SKIP ;
if ( c - > flags & CLIENT_REPLY_SKIP_NEXT ) {
c - > flags | = CLIENT_REPLY_SKIP ;
c - > flags & = ~ CLIENT_REPLY_SKIP_NEXT ;
}
2010-06-21 18:07:48 -04:00
}
2017-04-12 04:12:27 -04:00
/* Like processMultibulkBuffer(), but for the inline protocol instead of RESP,
* this function consumes the client query buffer and creates a command ready
* to be executed inside the client structure . Returns C_OK if the command
* is ready to be executed , or C_ERR if there is still protocol to read to
* have a well formed command . The function also returns C_ERR when there is
* a protocol error : in such a case the client structure is setup to reply
* with the error and close the connection . */
2015-07-26 09:20:46 -04:00
int processInlineBuffer ( client * c ) {
2013-12-09 07:28:39 -05:00
char * newline ;
2010-10-15 09:40:25 -04:00
int argc , j ;
2013-07-24 04:37:55 -04:00
sds * argv , aux ;
2016-11-28 11:54:04 -05:00
size_t querylen ;
2010-10-15 09:40:25 -04:00
2013-12-09 07:28:39 -05:00
/* Search for end of line */
newline = strchr ( c - > querybuf , ' \n ' ) ;
2010-10-15 09:40:25 -04:00
/* Nothing to do without a \r\n */
2011-12-31 10:09:46 -05:00
if ( newline = = NULL ) {
2015-07-27 03:41:48 -04:00
if ( sdslen ( c - > querybuf ) > PROTO_INLINE_MAX_SIZE ) {
2011-12-31 10:09:46 -05:00
addReplyError ( c , " Protocol error: too big inline request " ) ;
2016-11-25 04:55:16 -05:00
setProtocolError ( " too big inline request " , c , 0 ) ;
2011-12-31 10:09:46 -05:00
}
2015-07-26 17:17:55 -04:00
return C_ERR ;
2011-12-31 10:09:46 -05:00
}
2010-10-15 09:40:25 -04:00
2013-12-09 07:28:39 -05:00
/* Handle the \r\n case. */
if ( newline & & newline ! = c - > querybuf & & * ( newline - 1 ) = = ' \r ' )
newline - - ;
2010-10-15 09:40:25 -04:00
/* Split the input buffer up to the \r\n */
querylen = newline - ( c - > querybuf ) ;
2013-07-24 04:37:55 -04:00
aux = sdsnewlen ( c - > querybuf , querylen ) ;
argv = sdssplitargs ( aux , & argc ) ;
sdsfree ( aux ) ;
2013-12-08 05:57:03 -05:00
if ( argv = = NULL ) {
addReplyError ( c , " Protocol error: unbalanced quotes in request " ) ;
2016-11-25 04:55:16 -05:00
setProtocolError ( " unbalanced quotes in inline request " , c , 0 ) ;
2015-07-26 17:17:55 -04:00
return C_ERR ;
2013-12-08 05:57:03 -05:00
}
2010-10-15 09:40:25 -04:00
2013-12-09 07:32:44 -05:00
/* Newline from slaves can be used to refresh the last ACK time.
* This is useful for a slave to ping back while loading a big
* RDB file . */
2015-07-27 03:41:48 -04:00
if ( querylen = = 0 & & c - > flags & CLIENT_SLAVE )
2013-12-09 07:32:44 -05:00
c - > repl_ack_time = server . unixtime ;
2010-10-15 09:40:25 -04:00
/* Leave data after the first line of the query in the buffer */
2013-07-24 05:21:39 -04:00
sdsrange ( c - > querybuf , querylen + 2 , - 1 ) ;
2010-10-15 09:40:25 -04:00
/* Setup argv array on client structure */
2014-11-25 08:48:30 -05:00
if ( argc ) {
if ( c - > argv ) zfree ( c - > argv ) ;
c - > argv = zmalloc ( sizeof ( robj * ) * argc ) ;
}
2010-10-15 09:40:25 -04:00
/* Create redis objects for all arguments. */
for ( c - > argc = 0 , j = 0 ; j < argc ; j + + ) {
if ( sdslen ( argv [ j ] ) ) {
2015-07-26 09:28:00 -04:00
c - > argv [ c - > argc ] = createObject ( OBJ_STRING , argv [ j ] ) ;
2010-10-15 09:40:25 -04:00
c - > argc + + ;
} else {
sdsfree ( argv [ j ] ) ;
}
}
zfree ( argv ) ;
2015-07-26 17:17:55 -04:00
return C_OK ;
2010-10-15 09:40:25 -04:00
}
/* Helper function. Trims query buffer to make the function that processes
* multi bulk requests idempotent . */
2016-11-25 04:55:16 -05:00
# define PROTO_DUMP_LEN 128
2017-12-21 04:10:48 -05:00
static void setProtocolError ( const char * errstr , client * c , long pos ) {
2015-07-27 03:41:48 -04:00
if ( server . verbosity < = LL_VERBOSE ) {
2014-04-28 11:36:57 -04:00
sds client = catClientInfoString ( sdsempty ( ) , c ) ;
2016-11-25 04:55:16 -05:00
/* Sample some protocol to given an idea about what was inside. */
char buf [ 256 ] ;
if ( sdslen ( c - > querybuf ) < PROTO_DUMP_LEN ) {
snprintf ( buf , sizeof ( buf ) , " Query buffer during protocol error: '%s' " , c - > querybuf ) ;
} else {
snprintf ( buf , sizeof ( buf ) , " Query buffer during protocol error: '%.*s' (... more %zu bytes ...) '%.*s' " , PROTO_DUMP_LEN / 2 , c - > querybuf , sdslen ( c - > querybuf ) - PROTO_DUMP_LEN , PROTO_DUMP_LEN / 2 , c - > querybuf + sdslen ( c - > querybuf ) - PROTO_DUMP_LEN / 2 ) ;
}
/* Remove non printable chars. */
char * p = buf ;
while ( * p ! = ' \0 ' ) {
if ( ! isprint ( * p ) ) * p = ' . ' ;
p + + ;
}
/* Log all the client and protocol info. */
2015-07-27 03:41:48 -04:00
serverLog ( LL_VERBOSE ,
2016-11-25 04:55:16 -05:00
" Protocol error (%s) from client: %s. %s " , errstr , client , buf ) ;
2011-11-25 10:09:16 -05:00
sdsfree ( client ) ;
}
2015-07-27 03:41:48 -04:00
c - > flags | = CLIENT_CLOSE_AFTER_REPLY ;
2013-07-24 05:21:39 -04:00
sdsrange ( c - > querybuf , pos , - 1 ) ;
2010-10-15 09:40:25 -04:00
}
2017-04-12 04:12:27 -04:00
/* Process the query buffer for client 'c', setting up the client argument
* vector for command execution . Returns C_OK if after running the function
* the client has a well - formed ready to be processed command , otherwise
* C_ERR if there is still to read more buffer to get the full command .
* The function also returns C_ERR when there is a protocol error : in such a
* case the client structure is setup to reply with the error and close
* the connection .
*
* This function is called if processInputBuffer ( ) detects that the next
* command is in RESP format , so the first byte in the command is found
* to be ' * ' . Otherwise for inline commands processInlineBuffer ( ) is called . */
2015-07-26 09:20:46 -04:00
int processMultibulkBuffer ( client * c ) {
2010-10-15 09:40:25 -04:00
char * newline = NULL ;
2017-12-21 04:10:48 -05:00
long pos = 0 ;
int ok ;
2011-04-18 15:09:12 -04:00
long long ll ;
2010-10-15 09:40:25 -04:00
if ( c - > multibulklen = = 0 ) {
/* The client should have been reset */
2015-07-26 09:29:53 -04:00
serverAssertWithInfo ( c , NULL , c - > argc = = 0 ) ;
2010-10-15 09:40:25 -04:00
/* Multi bulk length cannot be read without a \r\n */
2011-04-18 15:09:12 -04:00
newline = strchr ( c - > querybuf , ' \r ' ) ;
2011-12-31 10:09:46 -05:00
if ( newline = = NULL ) {
2015-07-27 03:41:48 -04:00
if ( sdslen ( c - > querybuf ) > PROTO_INLINE_MAX_SIZE ) {
2011-12-31 10:09:46 -05:00
addReplyError ( c , " Protocol error: too big mbulk count string " ) ;
2016-11-25 04:55:16 -05:00
setProtocolError ( " too big mbulk count string " , c , 0 ) ;
2011-12-31 10:09:46 -05:00
}
2015-07-26 17:17:55 -04:00
return C_ERR ;
2011-12-31 10:09:46 -05:00
}
2010-10-15 09:40:25 -04:00
2011-04-27 08:29:27 -04:00
/* Buffer should also contain \n */
if ( newline - ( c - > querybuf ) > ( ( signed ) sdslen ( c - > querybuf ) - 2 ) )
2015-07-26 17:17:55 -04:00
return C_ERR ;
2011-04-27 08:29:27 -04:00
2010-10-15 09:40:25 -04:00
/* We know for sure there is a whole line since newline != NULL,
* so go ahead and find out the multi bulk length . */
2015-07-26 09:29:53 -04:00
serverAssertWithInfo ( c , NULL , c - > querybuf [ 0 ] = = ' * ' ) ;
2011-04-18 15:09:12 -04:00
ok = string2ll ( c - > querybuf + 1 , newline - ( c - > querybuf + 1 ) , & ll ) ;
if ( ! ok | | ll > 1024 * 1024 ) {
2010-10-15 13:15:38 -04:00
addReplyError ( c , " Protocol error: invalid multibulk length " ) ;
2016-11-25 04:55:16 -05:00
setProtocolError ( " invalid mbulk count " , c , pos ) ;
2015-07-26 17:17:55 -04:00
return C_ERR ;
2010-10-15 09:40:25 -04:00
}
2011-04-27 07:16:23 -04:00
pos = ( newline - c - > querybuf ) + 2 ;
if ( ll < = 0 ) {
2013-07-24 05:21:39 -04:00
sdsrange ( c - > querybuf , pos , - 1 ) ;
2015-07-26 17:17:55 -04:00
return C_OK ;
2011-04-27 07:16:23 -04:00
}
2011-04-18 15:09:12 -04:00
c - > multibulklen = ll ;
2010-10-15 09:40:25 -04:00
/* Setup argv array on client structure */
if ( c - > argv ) zfree ( c - > argv ) ;
c - > argv = zmalloc ( sizeof ( robj * ) * c - > multibulklen ) ;
}
2015-07-26 09:29:53 -04:00
serverAssertWithInfo ( c , NULL , c - > multibulklen > 0 ) ;
2010-10-15 09:40:25 -04:00
while ( c - > multibulklen ) {
/* Read bulk length if unknown */
if ( c - > bulklen = = - 1 ) {
2011-04-18 15:09:12 -04:00
newline = strchr ( c - > querybuf + pos , ' \r ' ) ;
2011-12-31 10:09:46 -05:00
if ( newline = = NULL ) {
2015-07-27 03:41:48 -04:00
if ( sdslen ( c - > querybuf ) > PROTO_INLINE_MAX_SIZE ) {
2014-04-23 04:19:43 -04:00
addReplyError ( c ,
" Protocol error: too big bulk count string " ) ;
2016-11-25 04:55:16 -05:00
setProtocolError ( " too big bulk count string " , c , 0 ) ;
2015-07-26 17:17:55 -04:00
return C_ERR ;
2011-12-31 10:09:46 -05:00
}
2011-04-27 08:29:27 -04:00
break ;
2011-12-31 10:09:46 -05:00
}
2011-04-27 08:29:27 -04:00
/* Buffer should also contain \n */
if ( newline - ( c - > querybuf ) > ( ( signed ) sdslen ( c - > querybuf ) - 2 ) )
2010-10-15 09:40:25 -04:00
break ;
2011-04-27 08:29:27 -04:00
if ( c - > querybuf [ pos ] ! = ' $ ' ) {
addReplyErrorFormat ( c ,
" Protocol error: expected '$', got '%c' " ,
c - > querybuf [ pos ] ) ;
2016-11-25 04:55:16 -05:00
setProtocolError ( " expected $ but got something else " , c , pos ) ;
2015-07-26 17:17:55 -04:00
return C_ERR ;
2010-06-21 18:07:48 -04:00
}
2011-04-27 08:29:27 -04:00
ok = string2ll ( c - > querybuf + pos + 1 , newline - ( c - > querybuf + pos + 1 ) , & ll ) ;
2018-01-11 05:27:03 -05:00
if ( ! ok | | ll < 0 | | ll > server . proto_max_bulk_len ) {
2011-04-27 08:29:27 -04:00
addReplyError ( c , " Protocol error: invalid bulk length " ) ;
2016-11-25 04:55:16 -05:00
setProtocolError ( " invalid bulk length " , c , pos ) ;
2015-07-26 17:17:55 -04:00
return C_ERR ;
2011-04-27 08:29:27 -04:00
}
pos + = newline - ( c - > querybuf + pos ) + 2 ;
2015-07-27 03:41:48 -04:00
if ( ll > = PROTO_MBULK_BIG_ARG ) {
2013-08-27 07:00:06 -04:00
size_t qblen ;
2011-11-03 10:53:40 -04:00
/* If we are going to read a large object from network
* try to make it likely that it will start at c - > querybuf
2013-08-27 05:54:38 -04:00
* boundary so that we can optimize object creation
2011-11-03 10:53:40 -04:00
* avoiding a large copy of data . */
2013-07-24 05:21:39 -04:00
sdsrange ( c - > querybuf , pos , - 1 ) ;
2011-11-03 10:53:40 -04:00
pos = 0 ;
2013-08-27 07:00:06 -04:00
qblen = sdslen ( c - > querybuf ) ;
2011-11-08 05:26:06 -05:00
/* Hint the sds library about the amount of bytes this string is
* going to contain . */
2014-08-13 05:44:38 -04:00
if ( qblen < ( size_t ) ll + 2 )
2013-08-27 07:00:06 -04:00
c - > querybuf = sdsMakeRoomFor ( c - > querybuf , ll + 2 - qblen ) ;
2011-11-08 05:26:06 -05:00
}
2011-04-27 08:29:27 -04:00
c - > bulklen = ll ;
2010-10-15 09:40:25 -04:00
}
/* Read bulk argument */
2017-12-21 04:10:48 -05:00
if ( sdslen ( c - > querybuf ) - pos < ( size_t ) ( c - > bulklen + 2 ) ) {
2010-10-15 09:40:25 -04:00
/* Not enough data (+2 == trailing \r\n) */
break ;
} else {
2013-01-19 07:46:14 -05:00
/* Optimization: if the buffer contains JUST our bulk element
2011-11-02 12:30:19 -04:00
* instead of creating a new object by * copying * the sds we
* just use the current sds string . */
if ( pos = = 0 & &
2015-07-27 03:41:48 -04:00
c - > bulklen > = PROTO_MBULK_BIG_ARG & &
2017-12-21 04:10:48 -05:00
sdslen ( c - > querybuf ) = = ( size_t ) ( c - > bulklen + 2 ) )
2011-11-02 12:30:19 -04:00
{
2015-07-26 09:28:00 -04:00
c - > argv [ c - > argc + + ] = createObject ( OBJ_STRING , c - > querybuf ) ;
2011-11-02 12:30:19 -04:00
sdsIncrLen ( c - > querybuf , - 2 ) ; /* remove CRLF */
/* Assume that if we saw a fat argument we'll see another one
* likely . . . */
2017-02-23 06:04:08 -05:00
c - > querybuf = sdsnewlen ( SDS_NOINIT , c - > bulklen + 2 ) ;
2016-04-25 09:48:09 -04:00
sdsclear ( c - > querybuf ) ;
2011-11-02 12:30:19 -04:00
pos = 0 ;
} else {
c - > argv [ c - > argc + + ] =
createStringObject ( c - > querybuf + pos , c - > bulklen ) ;
pos + = c - > bulklen + 2 ;
}
2010-10-15 09:40:25 -04:00
c - > bulklen = - 1 ;
c - > multibulklen - - ;
}
}
/* Trim to pos */
2013-07-24 05:21:39 -04:00
if ( pos ) sdsrange ( c - > querybuf , pos , - 1 ) ;
2010-10-15 09:40:25 -04:00
/* We're done when c->multibulk == 0 */
2015-07-26 17:17:55 -04:00
if ( c - > multibulklen = = 0 ) return C_OK ;
2011-12-31 10:09:46 -05:00
2017-04-12 04:12:27 -04:00
/* Still not ready to process the command */
2015-07-26 17:17:55 -04:00
return C_ERR ;
2010-10-15 09:40:25 -04:00
}
2017-04-12 04:12:27 -04:00
/* This function is called every time, in the client structure 'c', there is
* more query buffer to process , because we read more data from the socket
* or because a client was blocked and later reactivated , so there could be
* pending query buffer , already representing a full command , to process . */
2015-07-26 09:20:46 -04:00
void processInputBuffer ( client * c ) {
2015-02-26 12:31:06 -05:00
server . current_client = c ;
2010-10-15 09:40:25 -04:00
/* Keep processing while there is something in the input buffer */
while ( sdslen ( c - > querybuf ) ) {
2014-02-04 09:52:09 -05:00
/* Return if clients are paused. */
2015-07-27 03:41:48 -04:00
if ( ! ( c - > flags & CLIENT_SLAVE ) & & clientsArePaused ( ) ) break ;
2014-02-04 09:52:09 -05:00
2011-07-28 05:20:42 -04:00
/* Immediately abort if the client is in the middle of something. */
2015-07-27 03:41:48 -04:00
if ( c - > flags & CLIENT_BLOCKED ) break ;
2011-07-28 05:20:42 -04:00
2015-07-27 03:41:48 -04:00
/* CLIENT_CLOSE_AFTER_REPLY closes the connection once the reply is
2010-10-28 10:07:45 -04:00
* written to the client . Make sure to not let the reply grow after
2016-08-03 05:12:13 -04:00
* this flag has been set ( i . e . don ' t process more commands ) .
*
* The same applies for clients we want to terminate ASAP . */
if ( c - > flags & ( CLIENT_CLOSE_AFTER_REPLY | CLIENT_CLOSE_ASAP ) ) break ;
2010-10-15 09:40:25 -04:00
/* Determine request type when unknown. */
if ( ! c - > reqtype ) {
if ( c - > querybuf [ 0 ] = = ' * ' ) {
2015-07-27 03:41:48 -04:00
c - > reqtype = PROTO_REQ_MULTIBULK ;
2010-06-21 18:07:48 -04:00
} else {
2015-07-27 03:41:48 -04:00
c - > reqtype = PROTO_REQ_INLINE ;
2010-06-21 18:07:48 -04:00
}
}
2010-10-15 09:40:25 -04:00
2015-07-27 03:41:48 -04:00
if ( c - > reqtype = = PROTO_REQ_INLINE ) {
2015-07-26 17:17:55 -04:00
if ( processInlineBuffer ( c ) ! = C_OK ) break ;
2015-07-27 03:41:48 -04:00
} else if ( c - > reqtype = = PROTO_REQ_MULTIBULK ) {
2015-07-26 17:17:55 -04:00
if ( processMultibulkBuffer ( c ) ! = C_OK ) break ;
2010-10-15 09:40:25 -04:00
} else {
2015-07-27 03:41:48 -04:00
serverPanic ( " Unknown request type " ) ;
2010-06-21 18:07:48 -04:00
}
2010-10-15 09:40:25 -04:00
/* Multibulk processing could see a <= 0 length. */
2010-10-15 11:27:05 -04:00
if ( c - > argc = = 0 ) {
resetClient ( c ) ;
} else {
/* Only reset the client when the command was executed. */
Fix PSYNC2 incomplete command bug as described in #3899.
This bug was discovered by @kevinmcgehee and constituted a major hidden
bug in the PSYNC2 implementation, caused by the propagation from the
master of incomplete commands to slaves.
The bug had several results:
1. Borrowing from Kevin text in the issue: "Given that slaves blindly
copy over their master's input into their own replication backlog over
successive read syscalls, it's possible that with large commands or
small TCP buffers, partial commands are present in this buffer. If the
master were to fail before successfully propagating the entire command
to a slave, the slaves will never execute the partial command (since the
client is invalidated) but will copy it to replication backlog which may
relay those invalid bytes to its slaves on PSYNC2, corrupting the
backlog and possibly other valid commands that follow the failover.
Simple command boundaries aren't sufficient to capture this, either,
because in the case of a MULTI/EXEC block, if the master successfully
propagates a subset of the commands but not the EXEC, then the
transaction in the backlog becomes corrupt and could corrupt other
slaves that consume this data."
2. As identified by @yangsiran later, there is another effect of the
bug. For the same mechanism of the first problem, a slave having another
slave, could receive a full resynchronization request with an already
half-applied command in the backlog. Once the RDB is ready, it will be
sent to the slave, and the replication will continue sending to the
sub-slave the other half of the command, which is not valid.
The fix, designed by @yangsiran and @antirez, and implemented by
@antirez, uses a secondary buffer in order to feed the sub-masters and
update the replication backlog and offsets, only when a given part of
the query buffer is actually *applied* to the state of the instance,
that is, when the command gets processed and the command is not pending
in the Redis transaction buffer because of CLIENT_MULTI state.
Given that now the backlog and offsets representation are in agreement
with the actual processed commands, both issue 1 and 2 should no longer
be possible.
Thanks to @kevinmcgehee, @yangsiran and @oranagra for their work in
identifying and designing a fix for this problem.
2017-04-19 04:25:45 -04:00
if ( processCommand ( c ) = = C_OK ) {
if ( c - > flags & CLIENT_MASTER & & ! ( c - > flags & CLIENT_MULTI ) ) {
/* Update the applied replication offset of our master. */
c - > reploff = c - > read_reploff - sdslen ( c - > querybuf ) ;
}
2017-07-11 06:33:00 -04:00
/* Don't reset the client structure for clients blocked in a
* module blocking command , so that the reply callback will
* still be able to access the client argv and argc field .
* The client will be reset in unblockClientFromModule ( ) . */
if ( ! ( c - > flags & CLIENT_BLOCKED ) | | c - > btype ! = BLOCKED_MODULE )
resetClient ( c ) ;
Fix PSYNC2 incomplete command bug as described in #3899.
This bug was discovered by @kevinmcgehee and constituted a major hidden
bug in the PSYNC2 implementation, caused by the propagation from the
master of incomplete commands to slaves.
The bug had several results:
1. Borrowing from Kevin text in the issue: "Given that slaves blindly
copy over their master's input into their own replication backlog over
successive read syscalls, it's possible that with large commands or
small TCP buffers, partial commands are present in this buffer. If the
master were to fail before successfully propagating the entire command
to a slave, the slaves will never execute the partial command (since the
client is invalidated) but will copy it to replication backlog which may
relay those invalid bytes to its slaves on PSYNC2, corrupting the
backlog and possibly other valid commands that follow the failover.
Simple command boundaries aren't sufficient to capture this, either,
because in the case of a MULTI/EXEC block, if the master successfully
propagates a subset of the commands but not the EXEC, then the
transaction in the backlog becomes corrupt and could corrupt other
slaves that consume this data."
2. As identified by @yangsiran later, there is another effect of the
bug. For the same mechanism of the first problem, a slave having another
slave, could receive a full resynchronization request with an already
half-applied command in the backlog. Once the RDB is ready, it will be
sent to the slave, and the replication will continue sending to the
sub-slave the other half of the command, which is not valid.
The fix, designed by @yangsiran and @antirez, and implemented by
@antirez, uses a secondary buffer in order to feed the sub-masters and
update the replication backlog and offsets, only when a given part of
the query buffer is actually *applied* to the state of the instance,
that is, when the command gets processed and the command is not pending
in the Redis transaction buffer because of CLIENT_MULTI state.
Given that now the backlog and offsets representation are in agreement
with the actual processed commands, both issue 1 and 2 should no longer
be possible.
Thanks to @kevinmcgehee, @yangsiran and @oranagra for their work in
identifying and designing a fix for this problem.
2017-04-19 04:25:45 -04:00
}
2017-07-11 06:33:00 -04:00
/* freeMemoryIfNeeded may flush slave output buffers. This may
* result into a slave , that may be the active client , to be
* freed . */
2016-04-25 07:18:40 -04:00
if ( server . current_client = = NULL ) break ;
2010-10-15 11:27:05 -04:00
}
2010-06-21 18:07:48 -04:00
}
2015-02-26 12:31:06 -05:00
server . current_client = NULL ;
2010-06-21 18:07:48 -04:00
}
void readQueryFromClient ( aeEventLoop * el , int fd , void * privdata , int mask ) {
2015-07-26 09:20:46 -04:00
client * c = ( client * ) privdata ;
2011-11-03 10:53:40 -04:00
int nread , readlen ;
2011-11-02 11:52:45 -04:00
size_t qblen ;
2015-07-27 03:41:48 -04:00
UNUSED ( el ) ;
UNUSED ( mask ) ;
2010-06-21 18:07:48 -04:00
2015-07-27 03:41:48 -04:00
readlen = PROTO_IOBUF_LEN ;
2011-11-03 10:53:40 -04:00
/* If this is a multi bulk request, and we are processing a bulk reply
2012-11-01 06:14:55 -04:00
* that is large enough , try to maximize the probability that the query
* buffer contains exactly the SDS string representing the object , even
* at the risk of requiring more read ( 2 ) calls . This way the function
2011-11-03 10:53:40 -04:00
* processMultiBulkBuffer ( ) can avoid copying buffers to create the
* Redis Object representing the argument . */
2015-07-27 03:41:48 -04:00
if ( c - > reqtype = = PROTO_REQ_MULTIBULK & & c - > multibulklen & & c - > bulklen ! = - 1
& & c - > bulklen > = PROTO_MBULK_BIG_ARG )
2011-11-03 10:53:40 -04:00
{
2017-12-21 04:10:48 -05:00
ssize_t remaining = ( size_t ) ( c - > bulklen + 2 ) - sdslen ( c - > querybuf ) ;
2011-11-03 10:53:40 -04:00
if ( remaining < readlen ) readlen = remaining ;
}
2011-11-02 11:52:45 -04:00
qblen = sdslen ( c - > querybuf ) ;
2012-03-14 10:32:30 -04:00
if ( c - > querybuf_peak < qblen ) c - > querybuf_peak = qblen ;
2011-11-03 10:53:40 -04:00
c - > querybuf = sdsMakeRoomFor ( c - > querybuf , readlen ) ;
nread = read ( fd , c - > querybuf + qblen , readlen ) ;
2010-06-21 18:07:48 -04:00
if ( nread = = - 1 ) {
if ( errno = = EAGAIN ) {
2015-02-26 12:31:06 -05:00
return ;
2010-06-21 18:07:48 -04:00
} else {
2015-07-27 03:41:48 -04:00
serverLog ( LL_VERBOSE , " Reading from client: %s " , strerror ( errno ) ) ;
2010-06-21 18:07:48 -04:00
freeClient ( c ) ;
return ;
}
} else if ( nread = = 0 ) {
2015-07-27 03:41:48 -04:00
serverLog ( LL_VERBOSE , " Client closed connection " ) ;
2010-06-21 18:07:48 -04:00
freeClient ( c ) ;
return ;
Fix PSYNC2 incomplete command bug as described in #3899.
This bug was discovered by @kevinmcgehee and constituted a major hidden
bug in the PSYNC2 implementation, caused by the propagation from the
master of incomplete commands to slaves.
The bug had several results:
1. Borrowing from Kevin text in the issue: "Given that slaves blindly
copy over their master's input into their own replication backlog over
successive read syscalls, it's possible that with large commands or
small TCP buffers, partial commands are present in this buffer. If the
master were to fail before successfully propagating the entire command
to a slave, the slaves will never execute the partial command (since the
client is invalidated) but will copy it to replication backlog which may
relay those invalid bytes to its slaves on PSYNC2, corrupting the
backlog and possibly other valid commands that follow the failover.
Simple command boundaries aren't sufficient to capture this, either,
because in the case of a MULTI/EXEC block, if the master successfully
propagates a subset of the commands but not the EXEC, then the
transaction in the backlog becomes corrupt and could corrupt other
slaves that consume this data."
2. As identified by @yangsiran later, there is another effect of the
bug. For the same mechanism of the first problem, a slave having another
slave, could receive a full resynchronization request with an already
half-applied command in the backlog. Once the RDB is ready, it will be
sent to the slave, and the replication will continue sending to the
sub-slave the other half of the command, which is not valid.
The fix, designed by @yangsiran and @antirez, and implemented by
@antirez, uses a secondary buffer in order to feed the sub-masters and
update the replication backlog and offsets, only when a given part of
the query buffer is actually *applied* to the state of the instance,
that is, when the command gets processed and the command is not pending
in the Redis transaction buffer because of CLIENT_MULTI state.
Given that now the backlog and offsets representation are in agreement
with the actual processed commands, both issue 1 and 2 should no longer
be possible.
Thanks to @kevinmcgehee, @yangsiran and @oranagra for their work in
identifying and designing a fix for this problem.
2017-04-19 04:25:45 -04:00
} else if ( c - > flags & CLIENT_MASTER ) {
/* Append the query buffer to the pending (not applied) buffer
* of the master . We ' ll use this buffer later in order to have a
* copy of the string applied by the last command executed . */
c - > pending_querybuf = sdscatlen ( c - > pending_querybuf ,
c - > querybuf + qblen , nread ) ;
2010-06-21 18:07:48 -04:00
}
2015-02-26 12:31:06 -05:00
sdsIncrLen ( c - > querybuf , nread ) ;
c - > lastinteraction = server . unixtime ;
Fix PSYNC2 incomplete command bug as described in #3899.
This bug was discovered by @kevinmcgehee and constituted a major hidden
bug in the PSYNC2 implementation, caused by the propagation from the
master of incomplete commands to slaves.
The bug had several results:
1. Borrowing from Kevin text in the issue: "Given that slaves blindly
copy over their master's input into their own replication backlog over
successive read syscalls, it's possible that with large commands or
small TCP buffers, partial commands are present in this buffer. If the
master were to fail before successfully propagating the entire command
to a slave, the slaves will never execute the partial command (since the
client is invalidated) but will copy it to replication backlog which may
relay those invalid bytes to its slaves on PSYNC2, corrupting the
backlog and possibly other valid commands that follow the failover.
Simple command boundaries aren't sufficient to capture this, either,
because in the case of a MULTI/EXEC block, if the master successfully
propagates a subset of the commands but not the EXEC, then the
transaction in the backlog becomes corrupt and could corrupt other
slaves that consume this data."
2. As identified by @yangsiran later, there is another effect of the
bug. For the same mechanism of the first problem, a slave having another
slave, could receive a full resynchronization request with an already
half-applied command in the backlog. Once the RDB is ready, it will be
sent to the slave, and the replication will continue sending to the
sub-slave the other half of the command, which is not valid.
The fix, designed by @yangsiran and @antirez, and implemented by
@antirez, uses a secondary buffer in order to feed the sub-masters and
update the replication backlog and offsets, only when a given part of
the query buffer is actually *applied* to the state of the instance,
that is, when the command gets processed and the command is not pending
in the Redis transaction buffer because of CLIENT_MULTI state.
Given that now the backlog and offsets representation are in agreement
with the actual processed commands, both issue 1 and 2 should no longer
be possible.
Thanks to @kevinmcgehee, @yangsiran and @oranagra for their work in
identifying and designing a fix for this problem.
2017-04-19 04:25:45 -04:00
if ( c - > flags & CLIENT_MASTER ) c - > read_reploff + = nread ;
2015-02-26 12:31:06 -05:00
server . stat_net_input_bytes + = nread ;
2011-11-21 10:17:51 -05:00
if ( sdslen ( c - > querybuf ) > server . client_max_querybuf_len ) {
2014-04-28 11:36:57 -04:00
sds ci = catClientInfoString ( sdsempty ( ) , c ) , bytes = sdsempty ( ) ;
2011-11-25 11:08:25 -05:00
bytes = sdscatrepr ( bytes , c - > querybuf , 64 ) ;
2015-07-27 03:41:48 -04:00
serverLog ( LL_WARNING , " Closing client that reached max query buffer length: %s (qbuf initial bytes: %s) " , ci , bytes ) ;
2011-11-21 10:17:51 -05:00
sdsfree ( ci ) ;
2011-11-25 11:08:25 -05:00
sdsfree ( bytes ) ;
2011-11-21 10:17:51 -05:00
freeClient ( c ) ;
return ;
}
Fix PSYNC2 incomplete command bug as described in #3899.
This bug was discovered by @kevinmcgehee and constituted a major hidden
bug in the PSYNC2 implementation, caused by the propagation from the
master of incomplete commands to slaves.
The bug had several results:
1. Borrowing from Kevin text in the issue: "Given that slaves blindly
copy over their master's input into their own replication backlog over
successive read syscalls, it's possible that with large commands or
small TCP buffers, partial commands are present in this buffer. If the
master were to fail before successfully propagating the entire command
to a slave, the slaves will never execute the partial command (since the
client is invalidated) but will copy it to replication backlog which may
relay those invalid bytes to its slaves on PSYNC2, corrupting the
backlog and possibly other valid commands that follow the failover.
Simple command boundaries aren't sufficient to capture this, either,
because in the case of a MULTI/EXEC block, if the master successfully
propagates a subset of the commands but not the EXEC, then the
transaction in the backlog becomes corrupt and could corrupt other
slaves that consume this data."
2. As identified by @yangsiran later, there is another effect of the
bug. For the same mechanism of the first problem, a slave having another
slave, could receive a full resynchronization request with an already
half-applied command in the backlog. Once the RDB is ready, it will be
sent to the slave, and the replication will continue sending to the
sub-slave the other half of the command, which is not valid.
The fix, designed by @yangsiran and @antirez, and implemented by
@antirez, uses a secondary buffer in order to feed the sub-masters and
update the replication backlog and offsets, only when a given part of
the query buffer is actually *applied* to the state of the instance,
that is, when the command gets processed and the command is not pending
in the Redis transaction buffer because of CLIENT_MULTI state.
Given that now the backlog and offsets representation are in agreement
with the actual processed commands, both issue 1 and 2 should no longer
be possible.
Thanks to @kevinmcgehee, @yangsiran and @oranagra for their work in
identifying and designing a fix for this problem.
2017-04-19 04:25:45 -04:00
/* Time to process the buffer. If the client is a master we need to
* compute the difference between the applied offset before and after
* processing the buffer , to understand how much of the replication stream
* was actually applied to the master state : this quantity , and its
* corresponding part of the replication stream , will be propagated to
* the sub - slaves and to the replication backlog . */
if ( ! ( c - > flags & CLIENT_MASTER ) ) {
processInputBuffer ( c ) ;
} else {
size_t prev_offset = c - > reploff ;
processInputBuffer ( c ) ;
size_t applied = c - > reploff - prev_offset ;
if ( applied ) {
replicationFeedSlavesFromMasterStream ( server . slaves ,
c - > pending_querybuf , applied ) ;
sdsrange ( c - > pending_querybuf , applied , - 1 ) ;
}
}
2010-06-21 18:07:48 -04:00
}
2011-01-14 04:20:02 -05:00
void getClientsMaxBuffers ( unsigned long * longest_output_list ,
unsigned long * biggest_input_buffer ) {
2015-07-26 09:20:46 -04:00
client * c ;
2011-01-14 04:20:02 -05:00
listNode * ln ;
listIter li ;
unsigned long lol = 0 , bib = 0 ;
listRewind ( server . clients , & li ) ;
while ( ( ln = listNext ( & li ) ) ! = NULL ) {
c = listNodeValue ( ln ) ;
if ( listLength ( c - > reply ) > lol ) lol = listLength ( c - > reply ) ;
if ( sdslen ( c - > querybuf ) > bib ) bib = sdslen ( c - > querybuf ) ;
}
* longest_output_list = lol ;
* biggest_input_buffer = bib ;
}
2013-07-09 06:49:20 -04:00
/* A Redis "Peer ID" is a colon separated ip:port pair.
2014-09-15 13:40:11 -04:00
* For IPv4 it ' s in the form x . y . z . k : port , example : " 127.0.0.1:1234 " .
2013-07-09 06:49:20 -04:00
* For IPv6 addresses we use [ ] around the IP part , like in " [::1]:1234 " .
2014-09-15 13:40:11 -04:00
* For Unix sockets we use path : 0 , like in " /tmp/redis:0 " .
2013-07-09 06:49:20 -04:00
*
2015-07-27 03:41:48 -04:00
* A Peer ID always fits inside a buffer of NET_PEER_ID_LEN bytes , including
2013-07-09 06:49:20 -04:00
* the null term .
*
2013-07-09 09:28:30 -04:00
* On failure the function still populates ' peerid ' with the " ?:0 " string
* in case you want to relax error checking or need to display something
* anyway ( see anetPeerToString implementation for more info ) . */
2015-07-26 09:20:46 -04:00
void genClientPeerId ( client * client , char * peerid ,
2014-10-23 13:09:58 -04:00
size_t peerid_len ) {
2015-07-27 03:41:48 -04:00
if ( client - > flags & CLIENT_UNIX_SOCKET ) {
2013-07-09 06:49:20 -04:00
/* Unix socket client. */
snprintf ( peerid , peerid_len , " %s:0 " , server . unixsocket ) ;
} else {
/* TCP client. */
2014-10-23 13:09:58 -04:00
anetFormatPeer ( client - > fd , peerid , peerid_len ) ;
2013-07-09 06:49:20 -04:00
}
}
2014-04-28 11:36:57 -04:00
/* This function returns the client peer id, by creating and caching it
2014-09-15 13:40:11 -04:00
* if client - > peerid is NULL , otherwise returning the cached value .
2014-04-28 11:36:57 -04:00
* The Peer ID never changes during the life of the client , however it
* is expensive to compute . */
2015-07-26 09:20:46 -04:00
char * getClientPeerId ( client * c ) {
2015-07-27 03:41:48 -04:00
char peerid [ NET_PEER_ID_LEN ] ;
2014-04-28 11:36:57 -04:00
if ( c - > peerid = = NULL ) {
genClientPeerId ( c , peerid , sizeof ( peerid ) ) ;
c - > peerid = sdsnew ( peerid ) ;
}
return c - > peerid ;
}
/* Concatenate a string representing the state of a client in an human
* readable format , into the sds string ' s ' . */
2015-07-26 09:20:46 -04:00
sds catClientInfoString ( sds s , client * client ) {
2014-04-28 11:36:57 -04:00
char flags [ 16 ] , events [ 3 ] , * p ;
2011-11-21 10:06:03 -05:00
int emask ;
2011-11-21 09:34:32 -05:00
p = flags ;
2015-07-27 03:41:48 -04:00
if ( client - > flags & CLIENT_SLAVE ) {
if ( client - > flags & CLIENT_MONITOR )
2011-11-21 09:34:32 -05:00
* p + + = ' O ' ;
else
* p + + = ' S ' ;
}
2015-07-27 03:41:48 -04:00
if ( client - > flags & CLIENT_MASTER ) * p + + = ' M ' ;
if ( client - > flags & CLIENT_MULTI ) * p + + = ' x ' ;
if ( client - > flags & CLIENT_BLOCKED ) * p + + = ' b ' ;
if ( client - > flags & CLIENT_DIRTY_CAS ) * p + + = ' d ' ;
if ( client - > flags & CLIENT_CLOSE_AFTER_REPLY ) * p + + = ' c ' ;
if ( client - > flags & CLIENT_UNBLOCKED ) * p + + = ' u ' ;
if ( client - > flags & CLIENT_CLOSE_ASAP ) * p + + = ' A ' ;
if ( client - > flags & CLIENT_UNIX_SOCKET ) * p + + = ' U ' ;
if ( client - > flags & CLIENT_READONLY ) * p + + = ' r ' ;
2011-11-21 10:19:30 -05:00
if ( p = = flags ) * p + + = ' N ' ;
2011-11-21 09:34:32 -05:00
* p + + = ' \0 ' ;
2011-11-21 10:06:03 -05:00
emask = client - > fd = = - 1 ? 0 : aeGetFileEvents ( server . el , client - > fd ) ;
p = events ;
if ( emask & AE_READABLE ) * p + + = ' r ' ;
if ( emask & AE_WRITABLE ) * p + + = ' w ' ;
* p = ' \0 ' ;
2014-04-28 11:36:57 -04:00
return sdscatfmt ( s ,
2014-06-16 08:22:55 -04:00
" id=%U addr=%s fd=%i name=%s age=%I idle=%I flags=%s db=%i sub=%i psub=%i multi=%i qbuf=%U qbuf-free=%U obl=%U oll=%U omem=%U events=%s cmd=%s " ,
( unsigned long long ) client - > id ,
2014-04-28 11:36:57 -04:00
getClientPeerId ( client ) ,
2013-01-11 12:43:28 -05:00
client - > fd ,
client - > name ? ( char * ) client - > name - > ptr : " " ,
2014-04-28 10:41:38 -04:00
( long long ) ( server . unixtime - client - > ctime ) ,
( long long ) ( server . unixtime - client - > lastinteraction ) ,
2011-11-21 09:34:32 -05:00
flags ,
client - > db - > id ,
( int ) dictSize ( client - > pubsub_channels ) ,
2011-11-21 09:54:49 -05:00
( int ) listLength ( client - > pubsub_patterns ) ,
2015-07-27 03:41:48 -04:00
( client - > flags & CLIENT_MULTI ) ? client - > mstate . count : - 1 ,
2014-04-28 10:41:38 -04:00
( unsigned long long ) sdslen ( client - > querybuf ) ,
( unsigned long long ) sdsavail ( client - > querybuf ) ,
( unsigned long long ) client - > bufpos ,
( unsigned long long ) listLength ( client - > reply ) ,
( unsigned long long ) getClientOutputBufferMemoryUsage ( client ) ,
2011-11-24 08:56:34 -05:00
events ,
client - > lastcmd ? client - > lastcmd - > name : " NULL " ) ;
2011-11-21 09:34:32 -05:00
}
2011-11-24 09:04:42 -05:00
sds getAllClientsInfoString ( void ) {
listNode * ln ;
listIter li ;
2015-07-26 09:20:46 -04:00
client * client ;
2017-02-23 06:04:08 -05:00
sds o = sdsnewlen ( SDS_NOINIT , 200 * listLength ( server . clients ) ) ;
2016-04-25 09:48:09 -04:00
sdsclear ( o ) ;
2011-11-24 09:04:42 -05:00
listRewind ( server . clients , & li ) ;
while ( ( ln = listNext ( & li ) ) ! = NULL ) {
client = listNodeValue ( ln ) ;
2014-04-28 11:36:57 -04:00
o = catClientInfoString ( o , client ) ;
2011-11-24 09:04:42 -05:00
o = sdscatlen ( o , " \n " , 1 ) ;
}
return o ;
}
2015-07-26 09:20:46 -04:00
void clientCommand ( client * c ) {
2011-04-21 09:47:47 -04:00
listNode * ln ;
listIter li ;
2015-07-26 09:20:46 -04:00
client * client ;
2011-04-21 09:47:47 -04:00
2017-12-03 09:49:29 -05:00
if ( c - > argc = = 2 & & ! strcasecmp ( c - > argv [ 1 ] - > ptr , " help " ) ) {
const char * help [ ] = {
2017-12-06 06:05:11 -05:00
" getname -- Return the name of the current connection. " ,
" kill <ip:port> -- Kill connection made from <ip:port>. " ,
" kill <option> <value> [option value ...] -- Kill connections. Options are: " ,
" addr <ip:port> -- Kill connection made from <ip:port>. " ,
" type (normal|master|slave|pubsub) -- Kill connections by type. " ,
" skipme (yes|no) -- Skip killing current connection (default: yes). " ,
" list -- Return information about client connections. " ,
" pause <timeout> -- Suspend all Redis clients for <timout> milliseconds. " ,
" reply (on|off|skip) -- Control the replies sent to the current connection. " ,
" setname <name> -- Assign the name <name> to the current connection. " ,
NULL
2017-12-03 09:49:29 -05:00
} ;
addReplyHelp ( c , help ) ;
} else if ( ! strcasecmp ( c - > argv [ 1 ] - > ptr , " list " ) & & c - > argc = = 2 ) {
2014-06-16 08:24:28 -04:00
/* CLIENT LIST */
2011-11-24 09:04:42 -05:00
sds o = getAllClientsInfoString ( ) ;
2011-04-21 09:38:02 -04:00
addReplyBulkCBuffer ( c , o , sdslen ( o ) ) ;
sdsfree ( o ) ;
CLIENT REPLY command implemented: ON, OFF and SKIP modes.
Sometimes it can be useful for clients to completely disable replies
from the Redis server. For example when the client sends fire and forget
commands or performs a mass loading of data, or in caching contexts
where new data is streamed constantly. In such contexts to use server
time and bandwidth in order to send back replies to clients, which are
going to be ignored, is a shame.
Multiple mechanisms are possible to implement such a feature. For
example it could be a feature of MULTI/EXEC, or a command prefix
such as "NOREPLY SADD myset foo", or a different mechanism that allows
to switch on/off requests using the CLIENT command.
The MULTI/EXEC approach has the problem that transactions are not
strictly part of the no-reply semantics, and if we want to insert a lot
of data in a bulk way, creating a huge MULTI/EXEC transaction in the
server memory is bad.
The prefix is the best in this specific use case since it does not allow
desynchronizations, and is pretty clear semantically. However Redis
internals and client libraries are not prepared to handle this
currently.
So the implementation uses the CLIENT command, providing a new REPLY
subcommand with three options:
CLIENT REPLY OFF disables the replies, and does not reply itself.
CLIENT REPLY ON re-enables the replies, replying +OK.
CLIENT REPLY SKIP only discards the reply of the next command, and
like OFF does not reply anything itself.
The reason to add the SKIP command is that it allows to have an easy
way to send conceptually "single" commands that don't need a reply
as the sum of two pipelined commands:
CLIENT REPLY SKIP
SET key value
Note that CLIENT REPLY ON replies with +OK so it should be used when
sending multiple commands that don't need a reply. However since it
replies with +OK the client can check that the connection is still
active and all the previous commands were received.
This is currently just into Redis "unstable" so the proposal can be
modified or abandoned based on users inputs.
2015-10-21 14:43:37 -04:00
} else if ( ! strcasecmp ( c - > argv [ 1 ] - > ptr , " reply " ) & & c - > argc = = 3 ) {
/* CLIENT REPLY ON|OFF|SKIP */
if ( ! strcasecmp ( c - > argv [ 2 ] - > ptr , " on " ) ) {
c - > flags & = ~ ( CLIENT_REPLY_SKIP | CLIENT_REPLY_OFF ) ;
addReply ( c , shared . ok ) ;
} else if ( ! strcasecmp ( c - > argv [ 2 ] - > ptr , " off " ) ) {
c - > flags | = CLIENT_REPLY_OFF ;
} else if ( ! strcasecmp ( c - > argv [ 2 ] - > ptr , " skip " ) ) {
if ( ! ( c - > flags & CLIENT_REPLY_OFF ) )
c - > flags | = CLIENT_REPLY_SKIP_NEXT ;
} else {
addReply ( c , shared . syntaxerr ) ;
return ;
}
2014-06-16 08:24:28 -04:00
} else if ( ! strcasecmp ( c - > argv [ 1 ] - > ptr , " kill " ) ) {
/* CLIENT KILL <ip:port>
2014-06-16 08:50:15 -04:00
* CLIENT KILL < option > [ value ] . . . < option > [ value ] */
2014-06-16 08:24:28 -04:00
char * addr = NULL ;
int type = - 1 ;
uint64_t id = 0 ;
2014-06-16 08:50:15 -04:00
int skipme = 1 ;
int killed = 0 , close_this_client = 0 ;
2014-06-16 08:24:28 -04:00
if ( c - > argc = = 3 ) {
2014-06-16 08:50:15 -04:00
/* Old style syntax: CLIENT KILL <addr> */
2014-06-16 08:24:28 -04:00
addr = c - > argv [ 2 ] - > ptr ;
2014-06-24 06:49:18 -04:00
skipme = 0 ; /* With the old form, you can kill yourself. */
2014-06-16 08:50:15 -04:00
} else if ( c - > argc > 3 ) {
int i = 2 ; /* Next option index. */
/* New style syntax: parse options. */
while ( i < c - > argc ) {
int moreargs = c - > argc > i + 1 ;
if ( ! strcasecmp ( c - > argv [ i ] - > ptr , " id " ) & & moreargs ) {
long long tmp ;
if ( getLongLongFromObjectOrReply ( c , c - > argv [ i + 1 ] , & tmp , NULL )
2015-07-26 17:17:55 -04:00
! = C_OK ) return ;
2014-06-16 08:50:15 -04:00
id = tmp ;
} else if ( ! strcasecmp ( c - > argv [ i ] - > ptr , " type " ) & & moreargs ) {
type = getClientTypeByName ( c - > argv [ i + 1 ] - > ptr ) ;
if ( type = = - 1 ) {
addReplyErrorFormat ( c , " Unknown client type '%s' " ,
( char * ) c - > argv [ i + 1 ] - > ptr ) ;
return ;
}
} else if ( ! strcasecmp ( c - > argv [ i ] - > ptr , " addr " ) & & moreargs ) {
addr = c - > argv [ i + 1 ] - > ptr ;
} else if ( ! strcasecmp ( c - > argv [ i ] - > ptr , " skipme " ) & & moreargs ) {
if ( ! strcasecmp ( c - > argv [ i + 1 ] - > ptr , " yes " ) ) {
skipme = 1 ;
} else if ( ! strcasecmp ( c - > argv [ i + 1 ] - > ptr , " no " ) ) {
skipme = 0 ;
} else {
addReply ( c , shared . syntaxerr ) ;
return ;
}
} else {
addReply ( c , shared . syntaxerr ) ;
2014-06-16 08:24:28 -04:00
return ;
}
2014-06-16 08:50:15 -04:00
i + = 2 ;
2014-06-16 08:24:28 -04:00
}
} else {
addReply ( c , shared . syntaxerr ) ;
return ;
}
/* Iterate clients killing all the matching clients. */
2011-04-21 09:47:47 -04:00
listRewind ( server . clients , & li ) ;
while ( ( ln = listNext ( & li ) ) ! = NULL ) {
client = listNodeValue ( ln ) ;
2014-06-16 08:24:28 -04:00
if ( addr & & strcmp ( getClientPeerId ( client ) , addr ) ! = 0 ) continue ;
2015-07-28 11:01:19 -04:00
if ( type ! = - 1 & & getClientType ( client ) ! = type ) continue ;
2014-06-16 08:24:28 -04:00
if ( id ! = 0 & & client - > id ! = id ) continue ;
2014-06-16 08:50:15 -04:00
if ( c = = client & & skipme ) continue ;
2014-06-16 08:24:28 -04:00
/* Kill it. */
if ( c = = client ) {
2014-06-16 08:28:23 -04:00
close_this_client = 1 ;
2014-06-16 08:24:28 -04:00
} else {
freeClient ( client ) ;
2011-04-21 09:47:47 -04:00
}
2014-06-16 08:24:28 -04:00
killed + + ;
}
/* Reply according to old/new format. */
if ( c - > argc = = 3 ) {
if ( killed = = 0 )
addReplyError ( c , " No such client " ) ;
else
addReply ( c , shared . ok ) ;
} else {
addReplyLongLong ( c , killed ) ;
2011-04-21 09:47:47 -04:00
}
2014-06-16 08:28:23 -04:00
/* If this client has to be closed, flag it as CLOSE_AFTER_REPLY
* only after we queued the reply to its output buffers . */
2015-07-27 03:41:48 -04:00
if ( close_this_client ) c - > flags | = CLIENT_CLOSE_AFTER_REPLY ;
2013-01-11 12:43:28 -05:00
} else if ( ! strcasecmp ( c - > argv [ 1 ] - > ptr , " setname " ) & & c - > argc = = 3 ) {
int j , len = sdslen ( c - > argv [ 2 ] - > ptr ) ;
char * p = c - > argv [ 2 ] - > ptr ;
/* Setting the client name to an empty string actually removes
* the current name . */
if ( len = = 0 ) {
if ( c - > name ) decrRefCount ( c - > name ) ;
c - > name = NULL ;
addReply ( c , shared . ok ) ;
return ;
}
/* Otherwise check if the charset is ok. We need to do this otherwise
* CLIENT LIST format will break . You should always be able to
* split by space to get the different fields . */
for ( j = 0 ; j < len ; j + + ) {
2013-01-11 12:50:40 -05:00
if ( p [ j ] < ' ! ' | | p [ j ] > ' ~ ' ) { /* ASCII is assumed. */
2013-01-11 12:43:28 -05:00
addReplyError ( c ,
" Client names cannot contain spaces, "
" newlines or special characters. " ) ;
return ;
}
}
if ( c - > name ) decrRefCount ( c - > name ) ;
c - > name = c - > argv [ 2 ] ;
incrRefCount ( c - > name ) ;
addReply ( c , shared . ok ) ;
} else if ( ! strcasecmp ( c - > argv [ 1 ] - > ptr , " getname " ) & & c - > argc = = 2 ) {
if ( c - > name )
addReplyBulk ( c , c - > name ) ;
else
addReply ( c , shared . nullbulk ) ;
2014-02-04 09:52:09 -05:00
} else if ( ! strcasecmp ( c - > argv [ 1 ] - > ptr , " pause " ) & & c - > argc = = 3 ) {
long long duration ;
if ( getTimeoutFromObjectOrReply ( c , c - > argv [ 2 ] , & duration , UNIT_MILLISECONDS )
2015-07-26 17:17:55 -04:00
! = C_OK ) return ;
2014-02-04 09:52:09 -05:00
pauseClients ( duration ) ;
addReply ( c , shared . ok ) ;
2011-04-21 09:38:02 -04:00
} else {
2017-12-06 06:05:11 -05:00
addReplyErrorFormat ( c , " Unknown subcommand or wrong number of arguments for '%s'. Try CLIENT HELP " , ( char * ) c - > argv [ 1 ] - > ptr ) ;
}
2011-04-21 09:38:02 -04:00
}
2011-06-20 11:07:18 -04:00
2016-08-03 05:12:13 -04:00
/* This callback is bound to POST and "Host:" command names. Those are not
* really commands , but are used in security attacks in order to talk to
* Redis instances via HTTP , with a technique called " cross protocol scripting "
* which exploits the fact that services like Redis will discard invalid
* HTTP headers and will process what follows .
*
* As a protection against this attack , Redis will terminate the connection
* when a POST or " Host: " header is seen , and will log the event from
* time to time ( to avoid creating a DOS as a result of too many logs ) . */
void securityWarningCommand ( client * c ) {
static time_t logged_time ;
time_t now = time ( NULL ) ;
if ( labs ( now - logged_time ) > 60 ) {
serverLog ( LL_WARNING , " Possible SECURITY ATTACK detected. It looks like somebody is sending POST or Host: commands to Redis. This is likely due to an attacker attempting to use Cross Protocol Scripting to compromise your Redis instance. Connection aborted. " ) ;
logged_time = now ;
}
freeClientAsync ( c ) ;
}
2011-07-13 09:38:03 -04:00
/* Rewrite the command vector of the client. All the new objects ref count
* is incremented . The old command vector is freed , and the old objects
* ref count is decremented . */
2015-07-26 09:20:46 -04:00
void rewriteClientCommandVector ( client * c , int argc , . . . ) {
2011-06-20 11:07:18 -04:00
va_list ap ;
int j ;
robj * * argv ; /* The new argument vector */
argv = zmalloc ( sizeof ( robj * ) * argc ) ;
va_start ( ap , argc ) ;
for ( j = 0 ; j < argc ; j + + ) {
robj * a ;
2014-06-26 12:48:40 -04:00
2011-06-20 11:07:18 -04:00
a = va_arg ( ap , robj * ) ;
argv [ j ] = a ;
incrRefCount ( a ) ;
}
/* We free the objects in the original vector at the end, so we are
* sure that if the same objects are reused in the new vector the
* refcount gets incremented before it gets decremented . */
for ( j = 0 ; j < c - > argc ; j + + ) decrRefCount ( c - > argv [ j ] ) ;
zfree ( c - > argv ) ;
/* Replace argv and argc with our new versions. */
c - > argv = argv ;
c - > argc = argc ;
2013-03-06 10:28:26 -05:00
c - > cmd = lookupCommandOrOriginal ( c - > argv [ 0 ] - > ptr ) ;
2015-07-26 09:29:53 -04:00
serverAssertWithInfo ( c , NULL , c - > cmd ! = NULL ) ;
2011-06-20 11:07:18 -04:00
va_end ( ap ) ;
}
2011-07-13 09:38:03 -04:00
2015-06-23 04:18:23 -04:00
/* Completely replace the client command vector with the provided one. */
2015-07-26 09:20:46 -04:00
void replaceClientCommandVector ( client * c , int argc , robj * * argv ) {
2015-06-23 04:18:23 -04:00
freeClientArgv ( c ) ;
zfree ( c - > argv ) ;
c - > argv = argv ;
c - > argc = argc ;
c - > cmd = lookupCommandOrOriginal ( c - > argv [ 0 ] - > ptr ) ;
2015-07-26 09:29:53 -04:00
serverAssertWithInfo ( c , NULL , c - > cmd ! = NULL ) ;
2015-06-23 04:18:23 -04:00
}
2011-07-13 09:38:03 -04:00
/* Rewrite a single item in the command vector.
2015-12-11 07:48:41 -05:00
* The new val ref count is incremented , and the old decremented .
*
* It is possible to specify an argument over the current size of the
* argument vector : in this case the array of objects gets reallocated
* and c - > argc set to the max value . However it ' s up to the caller to
*
* 1. Make sure there are no " holes " and all the arguments are set .
* 2. If the original argument vector was longer than the one we
* want to end with , it ' s up to the caller to set c - > argc and
* free the no longer used objects on c - > argv . */
2015-07-26 09:20:46 -04:00
void rewriteClientCommandArgument ( client * c , int i , robj * newval ) {
2011-07-13 09:38:03 -04:00
robj * oldval ;
2014-06-26 12:48:40 -04:00
2015-12-11 07:48:41 -05:00
if ( i > = c - > argc ) {
c - > argv = zrealloc ( c - > argv , sizeof ( robj * ) * ( i + 1 ) ) ;
c - > argc = i + 1 ;
c - > argv [ i ] = NULL ;
}
2011-07-13 09:38:03 -04:00
oldval = c - > argv [ i ] ;
c - > argv [ i ] = newval ;
incrRefCount ( newval ) ;
2015-12-11 07:48:41 -05:00
if ( oldval ) decrRefCount ( oldval ) ;
2011-07-13 09:38:03 -04:00
/* If this is the command name make sure to fix c->cmd. */
if ( i = = 0 ) {
2013-03-06 10:28:26 -05:00
c - > cmd = lookupCommandOrOriginal ( c - > argv [ 0 ] - > ptr ) ;
2015-07-26 09:29:53 -04:00
serverAssertWithInfo ( c , NULL , c - > cmd ! = NULL ) ;
2011-07-13 09:38:03 -04:00
}
}
2011-12-25 10:32:54 -05:00
/* This function returns the number of bytes that Redis is virtually
* using to store the reply still not read by the client .
* It is " virtual " since the reply output list may contain objects that
* are shared and are not really using additional memory .
*
* The function returns the total sum of the length of all the objects
* stored in the output list , plus the memory used to allocate every
* list node . The static reply buffer is not taken into account since it
* is allocated anyway .
*
* Note : this function is very fast so can be called as many time as
* the caller wishes . The main usage of this function currently is
2012-01-24 09:33:15 -05:00
* enforcing the client output length limits . */
2015-07-26 09:20:46 -04:00
unsigned long getClientOutputBufferMemoryUsage ( client * c ) {
2015-07-31 08:59:54 -04:00
unsigned long list_item_size = sizeof ( listNode ) + 5 ;
/* The +5 above means we assume an sds16 hdr, may not be true
* but is not going to be a problem . */
2011-12-25 10:32:54 -05:00
return c - > reply_bytes + ( list_item_size * listLength ( c - > reply ) ) ;
}
2012-01-17 06:43:01 -05:00
2012-11-01 06:14:55 -04:00
/* Get the class of a client, used in order to enforce limits to different
2012-01-17 06:43:01 -05:00
* classes of clients .
*
* The function will return one of the following :
2015-07-27 03:41:48 -04:00
* CLIENT_TYPE_NORMAL - > Normal client
* CLIENT_TYPE_SLAVE - > Slave or client executing MONITOR command
* CLIENT_TYPE_PUBSUB - > Client subscribed to Pub / Sub channels
2015-07-28 10:58:04 -04:00
* CLIENT_TYPE_MASTER - > The client representing our replication master .
2012-01-17 06:43:01 -05:00
*/
2015-07-26 09:20:46 -04:00
int getClientType ( client * c ) {
2015-07-28 10:58:04 -04:00
if ( c - > flags & CLIENT_MASTER ) return CLIENT_TYPE_MASTER ;
2015-07-27 03:41:48 -04:00
if ( ( c - > flags & CLIENT_SLAVE ) & & ! ( c - > flags & CLIENT_MONITOR ) )
return CLIENT_TYPE_SLAVE ;
2015-07-28 10:58:04 -04:00
if ( c - > flags & CLIENT_PUBSUB ) return CLIENT_TYPE_PUBSUB ;
2015-07-27 03:41:48 -04:00
return CLIENT_TYPE_NORMAL ;
2012-01-17 06:43:01 -05:00
}
2012-01-23 10:12:37 -05:00
2014-06-16 04:43:05 -04:00
int getClientTypeByName ( char * name ) {
2015-07-27 03:41:48 -04:00
if ( ! strcasecmp ( name , " normal " ) ) return CLIENT_TYPE_NORMAL ;
else if ( ! strcasecmp ( name , " slave " ) ) return CLIENT_TYPE_SLAVE ;
else if ( ! strcasecmp ( name , " pubsub " ) ) return CLIENT_TYPE_PUBSUB ;
2015-07-28 10:58:04 -04:00
else if ( ! strcasecmp ( name , " master " ) ) return CLIENT_TYPE_MASTER ;
2012-01-24 04:43:30 -05:00
else return - 1 ;
}
2014-06-16 04:43:05 -04:00
char * getClientTypeName ( int class ) {
2012-01-24 04:43:30 -05:00
switch ( class ) {
2015-07-27 03:41:48 -04:00
case CLIENT_TYPE_NORMAL : return " normal " ;
case CLIENT_TYPE_SLAVE : return " slave " ;
case CLIENT_TYPE_PUBSUB : return " pubsub " ;
2015-07-28 10:58:04 -04:00
case CLIENT_TYPE_MASTER : return " master " ;
2014-06-16 04:43:05 -04:00
default : return NULL ;
2012-01-24 04:43:30 -05:00
}
}
2012-01-23 10:12:37 -05:00
/* The function checks if the client reached output buffer soft or hard
* limit , and also update the state needed to check the soft limit as
* a side effect .
*
* Return value : non - zero if the client reached the soft or the hard limit .
* Otherwise zero is returned . */
2015-07-26 09:20:46 -04:00
int checkClientOutputBufferLimits ( client * c ) {
2012-01-23 10:12:37 -05:00
int soft = 0 , hard = 0 , class ;
unsigned long used_mem = getClientOutputBufferMemoryUsage ( c ) ;
2014-06-16 04:43:05 -04:00
class = getClientType ( c ) ;
2015-07-28 10:58:04 -04:00
/* For the purpose of output buffer limiting, masters are handled
* like normal clients . */
if ( class = = CLIENT_TYPE_MASTER ) class = CLIENT_TYPE_NORMAL ;
2012-01-23 10:12:37 -05:00
if ( server . client_obuf_limits [ class ] . hard_limit_bytes & &
used_mem > = server . client_obuf_limits [ class ] . hard_limit_bytes )
hard = 1 ;
if ( server . client_obuf_limits [ class ] . soft_limit_bytes & &
used_mem > = server . client_obuf_limits [ class ] . soft_limit_bytes )
soft = 1 ;
/* We need to check if the soft limit is reached continuously for the
* specified amount of seconds . */
if ( soft ) {
if ( c - > obuf_soft_limit_reached_time = = 0 ) {
c - > obuf_soft_limit_reached_time = server . unixtime ;
soft = 0 ; /* First time we see the soft limit reached */
} else {
time_t elapsed = server . unixtime - c - > obuf_soft_limit_reached_time ;
if ( elapsed < =
server . client_obuf_limits [ class ] . soft_limit_seconds ) {
soft = 0 ; /* The client still did not reached the max number of
seconds for the soft limit to be considered
reached . */
}
}
} else {
c - > obuf_soft_limit_reached_time = 0 ;
}
return soft | | hard ;
}
/* Asynchronously close a client if soft or hard limit is reached on the
2012-01-24 03:32:39 -05:00
* output buffer size . The caller can check if the client will be closed
2015-07-27 03:41:48 -04:00
* checking if the client CLIENT_CLOSE_ASAP flag is set .
2012-01-23 10:12:37 -05:00
*
* Note : we need to close the client asynchronously because this function is
* called from contexts where the client can ' t be freed safely , i . e . from the
* lower level functions pushing data inside the client output buffers . */
2015-07-26 09:20:46 -04:00
void asyncCloseClientOnOutputBufferLimitReached ( client * c ) {
2015-07-26 09:29:53 -04:00
serverAssert ( c - > reply_bytes < SIZE_MAX - ( 1024 * 64 ) ) ;
2015-07-27 03:41:48 -04:00
if ( c - > reply_bytes = = 0 | | c - > flags & CLIENT_CLOSE_ASAP ) return ;
2012-01-23 10:12:37 -05:00
if ( checkClientOutputBufferLimits ( c ) ) {
2014-04-28 11:36:57 -04:00
sds client = catClientInfoString ( sdsempty ( ) , c ) ;
2012-01-23 10:12:37 -05:00
freeClientAsync ( c ) ;
2015-07-27 03:41:48 -04:00
serverLog ( LL_WARNING , " Client %s scheduled to be closed ASAP for overcoming of output buffer limits. " , client ) ;
2012-01-23 10:12:37 -05:00
sdsfree ( client ) ;
}
}
2012-02-06 10:56:42 -05:00
/* Helper function used by freeMemoryIfNeeded() in order to flush slaves
2015-11-09 11:26:56 -05:00
* output buffers without returning control to the event loop .
* This is also called by SHUTDOWN for a best - effort attempt to send
* slaves the latest writes . */
2012-02-06 10:56:42 -05:00
void flushSlavesOutputBuffers ( void ) {
listIter li ;
listNode * ln ;
listRewind ( server . slaves , & li ) ;
while ( ( ln = listNext ( & li ) ) ) {
2015-07-26 09:20:46 -04:00
client * slave = listNodeValue ( ln ) ;
2012-02-06 10:56:42 -05:00
int events ;
2015-08-06 09:08:54 -04:00
/* Note that the following will not flush output buffers of slaves
* in STATE_ONLINE but having put_online_on_ack set to true : in this
* case the writable event is never installed , since the purpose
* of put_online_on_ack is to postpone the moment it is installed .
* This is what we want since slaves in this state should not receive
* writes before the first ACK . */
2012-02-06 10:56:42 -05:00
events = aeGetFileEvents ( server . el , slave - > fd ) ;
if ( events & AE_WRITABLE & &
2015-07-27 03:41:48 -04:00
slave - > replstate = = SLAVE_STATE_ONLINE & &
2015-11-09 11:07:46 -05:00
clientHasPendingReplies ( slave ) )
2012-02-06 10:56:42 -05:00
{
2015-09-30 11:41:52 -04:00
writeToClient ( slave - > fd , slave , 0 ) ;
2012-02-06 10:56:42 -05:00
}
}
}
2014-02-04 09:52:09 -05:00
/* Pause clients up to the specified unixtime (in ms). While clients
* are paused no command is processed from clients , so the data set can ' t
* change during that time .
*
* However while this function pauses normal and Pub / Sub clients , slaves are
* still served , so this function can be used on server upgrades where it is
* required that slaves process the latest bytes from the replication stream
* before being turned to masters .
*
* This function is also internally used by Redis Cluster for the manual
* failover procedure implemented by CLUSTER FAILOVER .
*
* The function always succeed , even if there is already a pause in progress .
* In such a case , the pause is extended if the duration is more than the
* time left for the previous duration . However if the duration is smaller
* than the time left for the previous pause , no change is made to the
* left duration . */
void pauseClients ( mstime_t end ) {
if ( ! server . clients_paused | | end > server . clients_pause_end_time )
server . clients_pause_end_time = end ;
server . clients_paused = 1 ;
}
/* Return non-zero if clients are currently paused. As a side effect the
* function checks if the pause time was reached and clear it . */
int clientsArePaused ( void ) {
2015-03-21 04:13:29 -04:00
if ( server . clients_paused & &
server . clients_pause_end_time < server . mstime )
{
2014-02-04 09:52:09 -05:00
listNode * ln ;
listIter li ;
2015-07-26 09:20:46 -04:00
client * c ;
2014-02-04 09:52:09 -05:00
server . clients_paused = 0 ;
/* Put all the clients in the unblocked clients queue in order to
* force the re - processing of the input buffer if any . */
listRewind ( server . clients , & li ) ;
while ( ( ln = listNext ( & li ) ) ! = NULL ) {
c = listNodeValue ( ln ) ;
2015-03-21 04:13:29 -04:00
/* Don't touch slaves and blocked clients. The latter pending
* requests be processed when unblocked . */
2015-07-27 03:41:48 -04:00
if ( c - > flags & ( CLIENT_SLAVE | CLIENT_BLOCKED ) ) continue ;
c - > flags | = CLIENT_UNBLOCKED ;
2014-02-04 09:52:09 -05:00
listAddNodeTail ( server . unblocked_clients , c ) ;
}
}
return server . clients_paused ;
}
2014-04-24 11:36:47 -04:00
/* This function is called by Redis in order to process a few events from
* time to time while blocked into some not interruptible operation .
* This allows to reply to clients with the - LOADING error while loading the
* data set at startup or after a full resynchronization with the master
* and so forth .
*
* It calls the event loop in order to process a few events . Specifically we
2016-04-25 09:48:09 -04:00
* try to call the event loop 4 times as long as we receive acknowledge that
2014-04-24 11:36:47 -04:00
* some event was processed , in order to go forward with the accept , read ,
* write , close sequence needed to serve a client .
*
* The function returns the total number of events processed . */
int processEventsWhileBlocked ( void ) {
int iterations = 4 ; /* See the function top-comment. */
int count = 0 ;
while ( iterations - - ) {
2015-09-30 11:23:34 -04:00
int events = 0 ;
events + = aeProcessEvents ( server . el , AE_FILE_EVENTS | AE_DONT_WAIT ) ;
events + = handleClientsWithPendingWrites ( ) ;
2014-04-24 11:36:47 -04:00
if ( ! events ) break ;
count + = events ;
}
return count ;
}