Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
hiredis
Commits
eaf58bd3
Commit
eaf58bd3
authored
Apr 20, 2011
by
Pieter Noordhuis
Browse files
Use pre-allocated buffer for error strings in reader
parent
5d782145
Changes
3
Hide whitespace changes
Inline
Side-by-side
hiredis.c
View file @
eaf58bd3
...
@@ -41,13 +41,10 @@
...
@@ -41,13 +41,10 @@
#include "sds.h"
#include "sds.h"
#include "util.h"
#include "util.h"
#define REDIS_READER_OOM -2
#define REDIS_READER_NEED_MORE_DATA -1
#define REDIS_READER_OK 0
typedef
struct
redisReader
{
typedef
struct
redisReader
{
int
err
;
/* Error flags, 0 when there is no error */
char
errstr
[
128
];
/* String representation of error when applicable */
struct
redisReplyObjectFunctions
*
fn
;
struct
redisReplyObjectFunctions
*
fn
;
sds
error
;
/* holds optional error */
void
*
reply
;
/* holds temporary reply */
void
*
reply
;
/* holds temporary reply */
sds
buf
;
/* read buffer */
sds
buf
;
/* read buffer */
...
@@ -64,7 +61,6 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
...
@@ -64,7 +61,6 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
static
void
*
createArrayObject
(
const
redisReadTask
*
task
,
int
elements
);
static
void
*
createArrayObject
(
const
redisReadTask
*
task
,
int
elements
);
static
void
*
createIntegerObject
(
const
redisReadTask
*
task
,
long
long
value
);
static
void
*
createIntegerObject
(
const
redisReadTask
*
task
,
long
long
value
);
static
void
*
createNilObject
(
const
redisReadTask
*
task
);
static
void
*
createNilObject
(
const
redisReadTask
*
task
);
static
void
redisSetReplyReaderError
(
redisReader
*
r
,
sds
err
);
/* Default set of functions to build the reply. Keep in mind that such a
/* Default set of functions to build the reply. Keep in mind that such a
* function returning NULL is interpreted as OOM. */
* function returning NULL is interpreted as OOM. */
...
@@ -200,6 +196,45 @@ static void *createNilObject(const redisReadTask *task) {
...
@@ -200,6 +196,45 @@ static void *createNilObject(const redisReadTask *task) {
return
r
;
return
r
;
}
}
static
void
__redisReplyReaderSetError
(
redisReader
*
r
,
int
type
,
const
char
*
str
)
{
size_t
len
;
if
(
r
->
reply
!=
NULL
&&
r
->
fn
&&
r
->
fn
->
freeObject
)
{
r
->
fn
->
freeObject
(
r
->
reply
);
r
->
reply
=
NULL
;
}
/* Clear input buffer on errors. */
if
(
r
->
buf
!=
NULL
)
{
sdsfree
(
r
->
buf
);
r
->
buf
=
NULL
;
r
->
pos
=
r
->
len
=
0
;
}
/* Reset task stack. */
r
->
ridx
=
-
1
;
/* Set error. */
r
->
err
=
type
;
len
=
strlen
(
str
);
len
=
len
<
(
sizeof
(
r
->
errstr
)
-
1
)
?
len
:
(
sizeof
(
r
->
errstr
)
-
1
);
memcpy
(
r
->
errstr
,
str
,
len
);
r
->
errstr
[
len
]
=
'\0'
;
}
static
void
__redisReplyReaderSetErrorProtocolByte
(
redisReader
*
r
,
char
byte
)
{
char
cbuf
[
8
],
sbuf
[
128
];
chrtos
(
cbuf
,
sizeof
(
cbuf
),
byte
);
snprintf
(
sbuf
,
sizeof
(
sbuf
),
"Protocol error, got %s as reply type byte"
,
cbuf
);
__redisReplyReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
sbuf
);
}
static
void
__redisReplyReaderSetErrorOOM
(
redisReader
*
r
)
{
__redisReplyReaderSetError
(
r
,
REDIS_ERR_OOM
,
"Out of memory"
);
}
static
char
*
readBytes
(
redisReader
*
r
,
unsigned
int
bytes
)
{
static
char
*
readBytes
(
redisReader
*
r
,
unsigned
int
bytes
)
{
char
*
p
;
char
*
p
;
if
(
r
->
len
-
r
->
pos
>=
bytes
)
{
if
(
r
->
len
-
r
->
pos
>=
bytes
)
{
...
@@ -326,16 +361,18 @@ static int processLineItem(redisReader *r) {
...
@@ -326,16 +361,18 @@ static int processLineItem(redisReader *r) {
obj
=
(
void
*
)(
size_t
)(
cur
->
type
);
obj
=
(
void
*
)(
size_t
)(
cur
->
type
);
}
}
if
(
obj
==
NULL
)
if
(
obj
==
NULL
)
{
return
REDIS_READER_OOM
;
__redisReplyReaderSetErrorOOM
(
r
);
return
REDIS_ERR
;
}
/* Set reply if this is the root object. */
/* Set reply if this is the root object. */
if
(
r
->
ridx
==
0
)
r
->
reply
=
obj
;
if
(
r
->
ridx
==
0
)
r
->
reply
=
obj
;
moveToNextTask
(
r
);
moveToNextTask
(
r
);
return
REDIS_
READER_
OK
;
return
REDIS_OK
;
}
}
return
REDIS_
READER_NEED_MORE_DATA
;
return
REDIS_
ERR
;
}
}
static
int
processBulkItem
(
redisReader
*
r
)
{
static
int
processBulkItem
(
redisReader
*
r
)
{
...
@@ -374,19 +411,21 @@ static int processBulkItem(redisReader *r) {
...
@@ -374,19 +411,21 @@ static int processBulkItem(redisReader *r) {
/* Proceed when obj was created. */
/* Proceed when obj was created. */
if
(
success
)
{
if
(
success
)
{
if
(
obj
==
NULL
)
if
(
obj
==
NULL
)
{
return
REDIS_READER_OOM
;
__redisReplyReaderSetErrorOOM
(
r
);
return
REDIS_ERR
;
}
r
->
pos
+=
bytelen
;
r
->
pos
+=
bytelen
;
/* Set reply if this is the root object. */
/* Set reply if this is the root object. */
if
(
r
->
ridx
==
0
)
r
->
reply
=
obj
;
if
(
r
->
ridx
==
0
)
r
->
reply
=
obj
;
moveToNextTask
(
r
);
moveToNextTask
(
r
);
return
REDIS_
READER_
OK
;
return
REDIS_OK
;
}
}
}
}
return
REDIS_
READER_NEED_MORE_DATA
;
return
REDIS_
ERR
;
}
}
static
int
processMultiBulkItem
(
redisReader
*
r
)
{
static
int
processMultiBulkItem
(
redisReader
*
r
)
{
...
@@ -398,9 +437,9 @@ static int processMultiBulkItem(redisReader *r) {
...
@@ -398,9 +437,9 @@ static int processMultiBulkItem(redisReader *r) {
/* Set error for nested multi bulks with depth > 1 */
/* Set error for nested multi bulks with depth > 1 */
if
(
r
->
ridx
==
2
)
{
if
(
r
->
ridx
==
2
)
{
redis
Set
ReplyReaderError
(
r
,
sdscatprintf
(
sdsempty
()
,
__
redisReplyReader
Set
Error
(
r
,
REDIS_ERR_PROTOCOL
,
"No support for nested multi bulk replies with depth > 1"
)
)
;
"No support for nested multi bulk replies with depth > 1"
);
return
-
1
;
return
REDIS_ERR
;
}
}
if
((
p
=
readLine
(
r
,
NULL
))
!=
NULL
)
{
if
((
p
=
readLine
(
r
,
NULL
))
!=
NULL
)
{
...
@@ -413,8 +452,10 @@ static int processMultiBulkItem(redisReader *r) {
...
@@ -413,8 +452,10 @@ static int processMultiBulkItem(redisReader *r) {
else
else
obj
=
(
void
*
)
REDIS_REPLY_NIL
;
obj
=
(
void
*
)
REDIS_REPLY_NIL
;
if
(
obj
==
NULL
)
if
(
obj
==
NULL
)
{
return
REDIS_READER_OOM
;
__redisReplyReaderSetErrorOOM
(
r
);
return
REDIS_ERR
;
}
moveToNextTask
(
r
);
moveToNextTask
(
r
);
}
else
{
}
else
{
...
@@ -423,8 +464,10 @@ static int processMultiBulkItem(redisReader *r) {
...
@@ -423,8 +464,10 @@ static int processMultiBulkItem(redisReader *r) {
else
else
obj
=
(
void
*
)
REDIS_REPLY_ARRAY
;
obj
=
(
void
*
)
REDIS_REPLY_ARRAY
;
if
(
obj
==
NULL
)
if
(
obj
==
NULL
)
{
return
REDIS_READER_OOM
;
__redisReplyReaderSetErrorOOM
(
r
);
return
REDIS_ERR
;
}
/* Modify task stack when there are more than 0 elements. */
/* Modify task stack when there are more than 0 elements. */
if
(
elements
>
0
)
{
if
(
elements
>
0
)
{
...
@@ -444,16 +487,15 @@ static int processMultiBulkItem(redisReader *r) {
...
@@ -444,16 +487,15 @@ static int processMultiBulkItem(redisReader *r) {
/* Set reply if this is the root object. */
/* Set reply if this is the root object. */
if
(
root
)
r
->
reply
=
obj
;
if
(
root
)
r
->
reply
=
obj
;
return
REDIS_
READER_
OK
;
return
REDIS_OK
;
}
}
return
REDIS_
READER_NEED_MORE_DATA
;
return
REDIS_
ERR
;
}
}
static
int
processItem
(
redisReader
*
r
)
{
static
int
processItem
(
redisReader
*
r
)
{
redisReadTask
*
cur
=
&
(
r
->
rstack
[
r
->
ridx
]);
redisReadTask
*
cur
=
&
(
r
->
rstack
[
r
->
ridx
]);
char
*
p
;
char
*
p
;
sds
byte
;
/* check if we need to read type */
/* check if we need to read type */
if
(
cur
->
type
<
0
)
{
if
(
cur
->
type
<
0
)
{
...
@@ -475,15 +517,12 @@ static int processItem(redisReader *r) {
...
@@ -475,15 +517,12 @@ static int processItem(redisReader *r) {
cur
->
type
=
REDIS_REPLY_ARRAY
;
cur
->
type
=
REDIS_REPLY_ARRAY
;
break
;
break
;
default:
default:
byte
=
sdscatrepr
(
sdsempty
(),
p
,
1
);
__redisReplyReaderSetErrorProtocolByte
(
r
,
*
p
);
redisSetReplyReaderError
(
r
,
sdscatprintf
(
sdsempty
(),
return
REDIS_ERR
;
"Protocol error, got %s as reply type byte"
,
byte
));
sdsfree
(
byte
);
return
-
1
;
}
}
}
else
{
}
else
{
/* could not consume 1 byte */
/* could not consume 1 byte */
return
-
1
;
return
REDIS_ERR
;
}
}
}
}
...
@@ -499,13 +538,14 @@ static int processItem(redisReader *r) {
...
@@ -499,13 +538,14 @@ static int processItem(redisReader *r) {
return
processMultiBulkItem
(
r
);
return
processMultiBulkItem
(
r
);
default:
default:
assert
(
NULL
);
assert
(
NULL
);
return
-
1
;
return
REDIS_ERR
;
/* Avoid warning. */
}
}
}
}
void
*
redisReplyReaderCreate
(
void
)
{
void
*
redisReplyReaderCreate
(
void
)
{
redisReader
*
r
=
calloc
(
sizeof
(
redisReader
),
1
);
redisReader
*
r
=
calloc
(
sizeof
(
redisReader
),
1
);
r
->
error
=
NULL
;
r
->
err
=
0
;
r
->
errstr
[
0
]
=
'\0'
;
r
->
fn
=
&
defaultFunctions
;
r
->
fn
=
&
defaultFunctions
;
r
->
buf
=
sdsempty
();
r
->
buf
=
sdsempty
();
r
->
ridx
=
-
1
;
r
->
ridx
=
-
1
;
...
@@ -545,8 +585,6 @@ void *redisReplyReaderGetObject(void *reader) {
...
@@ -545,8 +585,6 @@ void *redisReplyReaderGetObject(void *reader) {
void
redisReplyReaderFree
(
void
*
reader
)
{
void
redisReplyReaderFree
(
void
*
reader
)
{
redisReader
*
r
=
reader
;
redisReader
*
r
=
reader
;
if
(
r
->
error
!=
NULL
)
sdsfree
(
r
->
error
);
if
(
r
->
reply
!=
NULL
&&
r
->
fn
)
if
(
r
->
reply
!=
NULL
&&
r
->
fn
)
r
->
fn
->
freeObject
(
r
->
reply
);
r
->
fn
->
freeObject
(
r
->
reply
);
if
(
r
->
buf
!=
NULL
)
if
(
r
->
buf
!=
NULL
)
...
@@ -554,23 +592,9 @@ void redisReplyReaderFree(void *reader) {
...
@@ -554,23 +592,9 @@ void redisReplyReaderFree(void *reader) {
free
(
r
);
free
(
r
);
}
}
static
void
redisSetReplyReaderError
(
redisReader
*
r
,
sds
err
)
{
if
(
r
->
reply
!=
NULL
)
r
->
fn
->
freeObject
(
r
->
reply
);
/* Clear remaining buffer when we see a protocol error. */
if
(
r
->
buf
!=
NULL
)
{
sdsfree
(
r
->
buf
);
r
->
buf
=
sdsempty
();
r
->
pos
=
r
->
len
=
0
;
}
r
->
ridx
=
-
1
;
r
->
error
=
err
;
}
char
*
redisReplyReaderGetError
(
void
*
reader
)
{
char
*
redisReplyReaderGetError
(
void
*
reader
)
{
redisReader
*
r
=
reader
;
redisReader
*
r
=
reader
;
return
r
->
err
o
r
;
return
r
->
err
st
r
;
}
}
void
redisReplyReaderFeed
(
void
*
reader
,
const
char
*
buf
,
size_t
len
)
{
void
redisReplyReaderFeed
(
void
*
reader
,
const
char
*
buf
,
size_t
len
)
{
...
@@ -592,9 +616,14 @@ void redisReplyReaderFeed(void *reader, const char *buf, size_t len) {
...
@@ -592,9 +616,14 @@ void redisReplyReaderFeed(void *reader, const char *buf, size_t len) {
int
redisReplyReaderGetReply
(
void
*
reader
,
void
**
reply
)
{
int
redisReplyReaderGetReply
(
void
*
reader
,
void
**
reply
)
{
redisReader
*
r
=
reader
;
redisReader
*
r
=
reader
;
int
ret
=
REDIS_READER_OK
;
if
(
reply
!=
NULL
)
*
reply
=
NULL
;
/* Default target pointer to NULL. */
if
(
reply
!=
NULL
)
*
reply
=
NULL
;
/* Return early when this reader is in an erroneous state. */
if
(
r
->
err
)
return
REDIS_ERR
;
/* When the buffer is empty, there will never be a reply. */
/* When the buffer is empty, there will never be a reply. */
if
(
r
->
len
==
0
)
if
(
r
->
len
==
0
)
...
@@ -613,11 +642,11 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
...
@@ -613,11 +642,11 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
/* Process items in reply. */
/* Process items in reply. */
while
(
r
->
ridx
>=
0
)
while
(
r
->
ridx
>=
0
)
if
(
(
ret
=
processItem
(
r
)
)
!=
REDIS_
READER_
OK
)
if
(
processItem
(
r
)
!=
REDIS_OK
)
break
;
break
;
/*
Set
error
s
o
n OOM
. */
/*
Return ASAP when an
error o
ccurred
. */
if
(
r
et
==
REDIS_READER_OOM
)
if
(
r
->
err
)
return
REDIS_ERR
;
return
REDIS_ERR
;
/* Discard part of the buffer when we've consumed at least 1k, to avoid
/* Discard part of the buffer when we've consumed at least 1k, to avoid
...
@@ -630,15 +659,9 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
...
@@ -630,15 +659,9 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
/* Emit a reply when there is one. */
/* Emit a reply when there is one. */
if
(
r
->
ridx
==
-
1
)
{
if
(
r
->
ridx
==
-
1
)
{
void
*
aux
=
r
->
reply
;
if
(
reply
!=
NULL
)
*
reply
=
r
->
reply
;
r
->
reply
=
NULL
;
r
->
reply
=
NULL
;
/* Check if there actually *is* a reply. */
if
(
r
->
error
!=
NULL
)
{
return
REDIS_ERR
;
}
else
{
if
(
reply
!=
NULL
)
*
reply
=
aux
;
}
}
}
return
REDIS_OK
;
return
REDIS_OK
;
}
}
...
@@ -1024,7 +1047,7 @@ int redisGetReplyFromReader(redisContext *c, void **reply) {
...
@@ -1024,7 +1047,7 @@ int redisGetReplyFromReader(redisContext *c, void **reply) {
__redisCreateReplyReader
(
c
);
__redisCreateReplyReader
(
c
);
if
(
redisReplyReaderGetReply
(
c
->
reader
,
reply
)
==
REDIS_ERR
)
{
if
(
redisReplyReaderGetReply
(
c
->
reader
,
reply
)
==
REDIS_ERR
)
{
__redisSetError
(
c
,
REDIS_ERR_PROTOCOL
,
__redisSetError
(
c
,
REDIS_ERR_PROTOCOL
,
sdsnew
(((
redisReader
*
)
c
->
reader
)
->
err
o
r
));
sdsnew
(((
redisReader
*
)
c
->
reader
)
->
err
st
r
));
return
REDIS_ERR
;
return
REDIS_ERR
;
}
}
return
REDIS_OK
;
return
REDIS_OK
;
...
...
hiredis.h
View file @
eaf58bd3
...
@@ -46,10 +46,11 @@
...
@@ -46,10 +46,11 @@
* error that occured. REDIS_ERR_IO means there was an I/O error and you
* error that occured. REDIS_ERR_IO means there was an I/O error and you
* should use the "errno" variable to find out what is wrong.
* should use the "errno" variable to find out what is wrong.
* For other values, the "errstr" field will hold a description. */
* For other values, the "errstr" field will hold a description. */
#define REDIS_ERR_IO 1
/* error in read or write */
#define REDIS_ERR_IO 1
/* Error in read or write */
#define REDIS_ERR_EOF 3
/* eof */
#define REDIS_ERR_EOF 3
/* End of file */
#define REDIS_ERR_PROTOCOL 4
/* protocol error */
#define REDIS_ERR_PROTOCOL 4
/* Protocol error */
#define REDIS_ERR_OTHER 2
/* something else */
#define REDIS_ERR_OOM 5
/* Out of memory */
#define REDIS_ERR_OTHER 2
/* Everything else... */
/* Connection type can be blocking or non-blocking and is set in the
/* Connection type can be blocking or non-blocking and is set in the
* least significant bit of the flags field in redisContext. */
* least significant bit of the flags field in redisContext. */
...
...
util.h
View file @
eaf58bd3
...
@@ -30,6 +30,7 @@
...
@@ -30,6 +30,7 @@
#ifndef __UTIL_H
#ifndef __UTIL_H
#define __UTIL_H
#define __UTIL_H
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
/* Abort on out of memory */
/* Abort on out of memory */
static
void
redisOOM
(
void
)
{
static
void
redisOOM
(
void
)
{
...
@@ -37,4 +38,28 @@ static void redisOOM(void) {
...
@@ -37,4 +38,28 @@ static void redisOOM(void) {
exit
(
1
);
exit
(
1
);
}
}
static
size_t
chrtos
(
char
*
buf
,
size_t
size
,
char
byte
)
{
size_t
len
=
0
;
switch
(
byte
)
{
case
'\\'
:
case
'"'
:
len
=
snprintf
(
buf
,
size
,
"
\"\\
%c
\"
"
,
byte
);
break
;
case
'\n'
:
len
=
snprintf
(
buf
,
size
,
"
\"\\
n
\"
"
);
break
;
case
'\r'
:
len
=
snprintf
(
buf
,
size
,
"
\"\\
r
\"
"
);
break
;
case
'\t'
:
len
=
snprintf
(
buf
,
size
,
"
\"\\
t
\"
"
);
break
;
case
'\a'
:
len
=
snprintf
(
buf
,
size
,
"
\"\\
a
\"
"
);
break
;
case
'\b'
:
len
=
snprintf
(
buf
,
size
,
"
\"\\
b
\"
"
);
break
;
default:
if
(
isprint
(
byte
))
len
=
snprintf
(
buf
,
size
,
"
\"
%c
\"
"
,
byte
);
else
len
=
snprintf
(
buf
,
size
,
"
\"\\
x%02x
\"
"
,(
unsigned
char
)
byte
);
break
;
}
return
len
;
}
#endif
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment