char *redisProtocolToLuaType_Int(lua_State *lua, char *reply) { char *p = strchr(reply+1,'\r'); long long value; string2ll(reply+1,p-reply-1,&value); lua_pushnumber(lua,(lua_Number)value); return p+2; }
int isObjectRepresentableAsLongLong(robj *o, long long *llval) { redisAssert(o->type == REDIS_STRING); if (o->encoding == REDIS_ENCODING_INT) { if (llval) *llval = (long) o->ptr; return REDIS_OK; } else { return string2ll(o->ptr,sdslen(o->ptr),llval) ? REDIS_OK : REDIS_ERR; } }
int isObjectRepresentableAsLongLong(robj *o, long long *llval) { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); if (o->encoding == OBJ_ENCODING_INT) { if (llval) *llval = (long) o->ptr; return C_OK; } else { return string2ll(o->ptr,sdslen(o->ptr),llval) ? C_OK : C_ERR; } }
//判断对象的ptr指向的值能否转换为long long类型,如果可以保存在llval中 int isObjectRepresentableAsLongLong(robj *o, long long *llval) { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); if (o->encoding == OBJ_ENCODING_INT) { //如果本身就是整数 if (llval) *llval = (long) o->ptr; return C_OK; //成功返回0 } else { //字符串转换为longlong类型,成功返回0,失败返回-1 return string2ll(o->ptr,sdslen(o->ptr),llval) ? C_OK : C_ERR; } }
/* Convert a string into a long. Returns 1 if the string could be parsed into a * (non-overflowing) long, 0 otherwise. The value will be set to the parsed * value when appropriate. */ int string2l(const char *s, size_t slen, long *lval) { long long llval; if (!string2ll(s,slen,&llval)) return 0; if (llval < LONG_MIN || llval > LONG_MAX) return 0; *lval = (long)llval; return 1; }
/* Convert a string into a long. Returns 1 if the string could be parsed into a * (non-overflowing) long, 0 otherwise. The value will be set to the parsed * value when appropriate. */ int string2l(const char *s, size_t slen, PORT_LONG *lval) { PORT_LONGLONG llval; if (!string2ll(s,slen,&llval)) return 0; if (llval < PORT_LONG_MIN || llval > PORT_LONG_MAX) return 0; *lval = (PORT_LONG) llval; return 1; }
char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply) { char *p = strchr(reply+1,'\r'); long long bulklen; string2ll(reply+1,p-reply-1,&bulklen); if (bulklen == -1) { lua_pushboolean(lua,0); return p+2; } else { lua_pushlstring(lua,p+2,bulklen); return p+2+bulklen+2; } }
int isObjectRepresentableAsLongLong(robj *o, long long *llval) { redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); // INT 编码的 long 值总是能保存为 long long if (o->encoding == REDIS_ENCODING_INT) { if (llval) *llval = (long) o->ptr; return REDIS_OK; // 如果是字符串的话,那么尝试将它转换为 long long } else { return string2ll(o->ptr,sdslen(o->ptr),llval) ? REDIS_OK : REDIS_ERR; } }
int getLongLongFromObject(robj *o, long long *target) { long long value; if (o == NULL) { value = 0; } else { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); if (sdsEncodedObject(o)) { if (string2ll(o->ptr,sdslen(o->ptr),&value) == 0) return C_ERR; } else if (o->encoding == OBJ_ENCODING_INT) { value = (long)o->ptr; } else { serverPanic("Unknown string encoding"); } } if (target) *target = value; return C_OK; }
char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply) { char *p = strchr(reply+1,'\r'); long long mbulklen; int j = 0; string2ll(reply+1,p-reply-1,&mbulklen); p += 2; if (mbulklen == -1) { lua_pushboolean(lua,0); return p; } lua_newtable(lua); for (j = 0; j < mbulklen; j++) { lua_pushnumber(lua,j+1); p = redisProtocolToLuaType(lua,p); lua_settable(lua,-3); } return p; }
//从对象中将字符串值转换为long long并存储在target中 int getLongLongFromObject(robj *o, long long *target) { long long value; if (o == NULL) { //对象不存在 value = 0; } else { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); //如果是字符串编码的两种类型 if (sdsEncodedObject(o)) { //转换失败发送-1,成功保存值到value中 if (string2ll(o->ptr,sdslen(o->ptr),&value) == 0) return C_ERR; } else if (o->encoding == OBJ_ENCODING_INT) { //整型编码 value = (long)o->ptr; //保存整数值 } else { serverPanic("Unknown string encoding"); } } if (target) *target = value; //将值存到传入参数中,返回0成功 return C_OK; }
static int processMultiBulk (client_t * c) { char *newline = NULL; int pos = 0, ok; long long ll; if (c->multibulklen == 0) { newline = strchr (c->querybuf, '\r'); if (newline == NULL) { if (sdslen (c->querybuf) > REDIS_INLINE_MAX_SIZE) { addReplyStr (c, "-ERR Protocol error: too big mbulk count string\r\n"); c->flags |= REDIS_CLOSE_AFTER_REPLY; } return -1; } if (newline - c->querybuf > sdslen (c->querybuf) - 2) return -1; ok = string2ll (c->querybuf + 1, newline - (c->querybuf + 1), &ll); if (!ok || ll > 1024 * 1024) { addReplyStr (c, "-ERR Protocol error: invalid multibulk length\r\n"); c->flags |= REDIS_CLOSE_AFTER_REPLY; return -1; } c->multibulklen = ll; c->argv = malloc (sizeof (sds) * c->multibulklen); c->argvlen = malloc (sizeof (size_t) * c->multibulklen); pos = (newline - c->querybuf) + 2; if (ll <= 0) { sdsrange (c->querybuf, pos, -1); return 0; } } while (c->multibulklen) { if (c->bulklen == -1) { newline = strchr (c->querybuf + pos, '\r'); if (newline == NULL) { if (sdslen (c->querybuf) > REDIS_INLINE_MAX_SIZE) { addReplyStr (c, "-ERR Protocol error: too big bulk count string\r\n"); c->flags |= REDIS_CLOSE_AFTER_REPLY; } break; } if (newline - (c->querybuf) > (sdslen (c->querybuf) - 2)) break; if (c->querybuf[pos] != '$') { addReplyStr (c, "-ERR Protocol error: expected '$', got '"); addReplyStrLen (c, c->querybuf + pos, 1); addReplyStr (c, "'\r\n"); c->flags |= REDIS_CLOSE_AFTER_REPLY; return -1; } ok = string2ll (c->querybuf + pos + 1, newline - (c->querybuf + pos + 1), &ll); if (!ok || ll < 0 || ll > 512 * 1024 * 1024) { addReplyStr (c, "-ERR Protocol error: invalid bulk length\r\n"); c->flags |= REDIS_CLOSE_AFTER_REPLY; return -1; } pos += newline - (c->querybuf + pos) + 2; c->bulklen = ll; } if (sdslen (c->querybuf) - pos < (unsigned) (c->bulklen + 2)) break; c->argvlen[c->argc] = c->bulklen; c->argv[c->argc++] = sdsnewlen (c->querybuf + pos, c->bulklen); pos += c->bulklen + 2; c->bulklen = -1; c->multibulklen--; } if (pos) sdsrange (c->querybuf, pos, -1); if (c->multibulklen) return -1; if (c->argc == 1 && sdslen (c->argv[0]) == 4 && !strcasecmp (c->argv[0], "quit")) { addReplyStrLen (c, "+OK\r\n", 5); c->flags |= REDIS_CLOSE_AFTER_REPLY; return -1; } arc_append_commandcv (c->rqst, c->argc, (const char **) c->argv, c->argvlen); c->total_append_command++; return 0; }
int isSdsRepresentableAsLongLong(sds s, long long *llval) { return string2ll(s,sdslen(s),llval) ? RR_OK : RR_ERROR; }
void test_string2ll(void) { char buf[32]; long long v; /* May not start with +. */ strcpy(buf,"+1"); assert(string2ll(buf,strlen(buf),&v) == 0); /* Leading space. */ strcpy(buf," 1"); assert(string2ll(buf,strlen(buf),&v) == 0); /* Trailing space. */ strcpy(buf,"1 "); assert(string2ll(buf,strlen(buf),&v) == 0); /* May not start with 0. */ strcpy(buf,"01"); assert(string2ll(buf,strlen(buf),&v) == 0); strcpy(buf,"-1"); assert(string2ll(buf,strlen(buf),&v) == 1); assert(v == -1); strcpy(buf,"0"); assert(string2ll(buf,strlen(buf),&v) == 1); assert(v == 0); strcpy(buf,"1"); assert(string2ll(buf,strlen(buf),&v) == 1); assert(v == 1); strcpy(buf,"99"); assert(string2ll(buf,strlen(buf),&v) == 1); assert(v == 99); strcpy(buf,"-99"); assert(string2ll(buf,strlen(buf),&v) == 1); assert(v == -99); strcpy(buf,"-9223372036854775808"); assert(string2ll(buf,strlen(buf),&v) == 1); assert(v == LLONG_MIN); strcpy(buf,"-9223372036854775809"); /* overflow */ assert(string2ll(buf,strlen(buf),&v) == 0); strcpy(buf,"9223372036854775807"); assert(string2ll(buf,strlen(buf),&v) == 1); assert(v == LLONG_MAX); strcpy(buf,"9223372036854775808"); /* overflow */ assert(string2ll(buf,strlen(buf),&v) == 0); }
int processMultibulkBuffer(client *c) { char *newline = NULL; int pos = 0, ok; long long ll; if (c->multibulklen == 0) { /* The client should have been reset */ serverAssertWithInfo(c,NULL,c->argc == 0); /* Multi bulk length cannot be read without a \r\n */ newline = strchr(c->querybuf,'\r'); if (newline == NULL) { if (sdslen(c->querybuf) > PROTO_INLINE_MAX_SIZE) { addReplyError(c,"Protocol error: too big mbulk count string"); setProtocolError(c,0); } return C_ERR; } /* Buffer should also contain \n */ if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2)) return C_ERR; /* We know for sure there is a whole line since newline != NULL, * so go ahead and find out the multi bulk length. */ serverAssertWithInfo(c,NULL,c->querybuf[0] == '*'); ok = string2ll(c->querybuf+1,newline-(c->querybuf+1),&ll); if (!ok || ll > 1024*1024) { addReplyError(c,"Protocol error: invalid multibulk length"); setProtocolError(c,pos); return C_ERR; } pos = (newline-c->querybuf)+2; if (ll <= 0) { sdsrange(c->querybuf,pos,-1); return C_OK; } c->multibulklen = ll; /* Setup argv array on client structure */ if (c->argv) free(c->argv); c->argv = malloc(sizeof(sds*)*c->multibulklen); } serverAssertWithInfo(c,NULL,c->multibulklen > 0); while(c->multibulklen) { /* Read bulk length if unknown */ if (c->bulklen == -1) { newline = strchr(c->querybuf+pos,'\r'); if (newline == NULL) { if (sdslen(c->querybuf) > PROTO_INLINE_MAX_SIZE) { addReplyError(c, "Protocol error: too big bulk count string"); setProtocolError(c,0); return C_ERR; } break; } /* Buffer should also contain \n */ if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2)) break; if (c->querybuf[pos] != '$') { addReplyErrorFormat(c, "Protocol error: expected '$', got '%c'", c->querybuf[pos]); setProtocolError(c,pos); return C_ERR; } ok = string2ll(c->querybuf+pos+1,newline-(c->querybuf+pos+1),&ll); if (!ok || ll < 0 || ll > 512*1024*1024) { addReplyError(c,"Protocol error: invalid bulk length"); setProtocolError(c,pos); return C_ERR; } pos += newline-(c->querybuf+pos)+2; if (ll >= PROTO_MBULK_BIG_ARG) { size_t qblen; /* If we are going to read a large object from network * try to make it likely that it will start at c->querybuf * boundary so that we can optimize object creation * avoiding a large copy of data. */ sdsrange(c->querybuf,pos,-1); pos = 0; qblen = sdslen(c->querybuf); /* Hint the sds library about the amount of bytes this string is * going to contain. */ if (qblen < (size_t)ll+2) c->querybuf = sdsMakeRoomFor(c->querybuf,ll+2-qblen); } c->bulklen = ll; } /* Read bulk argument */ if (sdslen(c->querybuf)-pos < (unsigned)(c->bulklen+2)) { /* Not enough data (+2 == trailing \r\n) */ break; } else { /* Optimization: if the buffer contains JUST our bulk element * instead of creating a new object by *copying* the sds we * just use the current sds string. */ if (pos == 0 && c->bulklen >= PROTO_MBULK_BIG_ARG && (signed) sdslen(c->querybuf) == c->bulklen+2) { c->argv[c->argc++] = c->querybuf; sdsIncrLen(c->querybuf,-2); /* remove CRLF */ c->querybuf = sdsempty(); /* Assume that if we saw a fat argument we'll see another one * likely... */ c->querybuf = sdsMakeRoomFor(c->querybuf,c->bulklen+2); pos = 0; } else { c->argv[c->argc++] = sdsnewlen(c->querybuf+pos,c->bulklen); pos += c->bulklen+2; } c->bulklen = -1; c->multibulklen--; } } /* Trim to pos */ if (pos) sdsrange(c->querybuf,pos,-1); /* We're done when c->multibulk == 0 */ if (c->multibulklen == 0) return C_OK; /* Still not read to process the command */ return C_ERR; }
static int process_multibulk_buffer(sub_client *c) { char *newline = NULL; int pos = 0, ok; long long ll; if (c->multi_bulk_len == 0) { /* Multi bulk length cannot be read without a \r\n */ newline = strchr(c->read_buf, '\r'); if (newline == NULL) { if (sdslen(c->read_buf) > MAX_INLINE_READ) { srv_log(LOG_ERROR, "protocol error: too big mbulk string"); set_protocol_err(c, 0); } return SUBCLI_ERR; } /* Buffer should also contain \n */ if (newline-(c->read_buf) > ((signed)sdslen(c->read_buf)-2)) { return SUBCLI_ERR; } ok = string2ll(c->read_buf+1, newline-(c->read_buf+1), &ll); if (!ok || ll > SUB_READ_BUF_LEN) { srv_log(LOG_ERROR, "protocol error: invalid multibulk length"); set_protocol_err(c, pos); return SUBCLI_ERR; } pos = (newline - c->read_buf) + 2; if (ll <= 0) { sdsrange(c->read_buf, pos, -1); return SUBCLI_OK; } c->multi_bulk_len = ll; c->argv = malloc(sizeof(sds) * c->multi_bulk_len); } while (c->multi_bulk_len) { /* Read bulk length if unknown */ if (c->bulk_len == -1) { newline = strchr(c->read_buf + pos, '\r'); if (newline == NULL) { if (sdslen(c->read_buf) > MAX_INLINE_READ) { srv_log(LOG_ERROR, "protocol error: too big bulk count string"); set_protocol_err(c, 0); return SUBCLI_ERR; } break; } /* Buffer should also contain \n */ if (newline-(c->read_buf) > ((signed)sdslen(c->read_buf)-2)) { break; } if (c->read_buf[pos] != '$') { srv_log(LOG_ERROR, "Protocol error: expected '$', got '%c'", c->read_buf[pos]); set_protocol_err(c, pos); return SUBCLI_ERR; } ok = string2ll(c->read_buf+pos+1, newline-(c->read_buf+pos+1), &ll); if (!ok || ll < 0 || ll > MAX_BULK_LEN) { srv_log(LOG_ERROR, "Protocol error: invalid bulk length"); set_protocol_err(c, pos); return SUBCLI_ERR; } pos += newline - (c->read_buf + pos) + 2; c->bulk_len = ll; } /* Read bulk argument */ if (sdslen(c->read_buf) - pos < (unsigned)(c->bulk_len + 2)) { /* Not enough data (+2 == trailing \r\n) */ break; } else { /*c->argv[c->argc++] = create_string_obj(c->read_buf+pos, c->bulk_len);*/ c->argv[c->argc++] = sdsnewlen(c->read_buf+pos, c->bulk_len); pos += c->bulk_len + 2; } c->bulk_len = -1; c->multi_bulk_len--; } /* Trim to pos */ if (pos) sdsrange(c->read_buf, pos, -1); /* We're done when c->multibulk == 0 */ if (c->multi_bulk_len == 0) return SUBCLI_OK; /* Still not read to process the command */ return SUBCLI_ERR; }
int parse_redis_response (char *p, int len, int *size, redis_parse_cb_t * cb, void *ctx) { char *newline = NULL, *bp = NULL; int ok = 0; long long ll = 0; int ret = PARSE_CB_OK_CONTINUE; if (len == 0) { return -1; } /* Input should be null terminiated string */ assert (*(p + len) == '\0'); bp = p; while (ret == PARSE_CB_OK_CONTINUE && len > 0) { char *saved_p; char *dsp = NULL; // binary data start point char *dep = NULL; // binary data end point int is_null = 0; saved_p = p; switch (*p) { case '-': case '+': case ':': newline = strchr (p, '\n'); if (newline == NULL) { goto resp_need_more; } len -= newline + 1 - p; p = newline + 1; /* callback */ if (cb != NULL) { dsp = saved_p; dep = p - 2; // skip \r\n if (*saved_p == '-') { ret = cb->on_error (ctx, dsp, dep - dsp); } else if (*saved_p == '+') { ret = cb->on_status (ctx, dsp, dep - dsp); } else if (*saved_p == ':') { ok = string2ll (dsp + 1, dep - dsp - 1, &ll); if (!ok) { return -1; } ret = cb->on_integer (ctx, ll); } } break; case '$': newline = strchr (p, '\r'); if (newline == NULL) { goto resp_need_more; } ok = string2ll (p + 1, newline - p - 1, &ll); /* spec limit: 512M */ if (!ok || ll < -1 || ll > 512 * 1024 * 1024) { return -1; } if (ll == -1) { /* Null Bulk String */ if (newline + 2 - p > len) { goto resp_need_more; } len -= newline + 2 - p; p = newline + 2; is_null = 1; /* callback */ if (cb != NULL) { ret = cb->on_string (ctx, NULL, 0, is_null); } } else { /* Normal Case */ if (newline + 2 - p + ll + 2 > len) { goto resp_need_more; } len -= newline + 2 - p + ll + 2; p = newline + 2 + ll + 2; /* callback */ if (cb != NULL) { ret = cb->on_string (ctx, newline + 2, ll, is_null); } } break; case '*': newline = strchr (p, '\r'); if (newline == NULL || newline + 2 - p > len) { goto resp_need_more; } ok = string2ll (p + 1, newline - p - 1, &ll); if (ll == -1) { is_null = 1; ll = 0; /* Null Array */ } len -= newline + 2 - p; p = newline + 2; /* callback */ if (cb != NULL) { ret = cb->on_array (ctx, ll, is_null); } break; default: return -1; } } resp_need_more: *size = p - bp; return 0; }
static int parse_multi_line_message(Request* request, const char* data, const size_t data_len){ char *newline = NULL; int pos = 0, ok; long long ll; int partialdone = 0; if (request->parse_phase == RDS_PHASE_CONNECT){ if (request->multibulklen == 0) { newline = strchr(data,'\r'); if (newline == NULL) { // if (sdslen(c->querybuf) > REDIS_INLINE_MAX_SIZE) { // addReplyError(c,"Protocol error: too big mbulk count string"); // setProtocolError(c,0); // } // we will come back here, return -1; } ok = string2ll(data+1, newline-(data+1), &ll); if (!ok || ll > 1024*1024) { puts("couldnt find data length... "); return -2; } pos = (newline - data)+2; if (ll <= 0) { // TODO: handle *-1\r\n ? // c->querybuf = sdsrange(c->querybuf,pos,-1); return true; } request->cmd_list = PyList_New(ll); request->multibulklen = ll; request->arg_cnt = 0; request->parse_phase = RDS_PHASE_START; // now send the remainder to start line... request->lastpos = pos; } } while (request->multibulklen){ // since we found the start line, here we parse it... if (request->parse_phase == RDS_PHASE_START){ if (data[request->lastpos] == '$'){ // newline = strchr(data+request->lastpos,'\r'); if (!newline){ return -1; } ok = string2ll(data+request->lastpos+1, newline - (data+ request->lastpos+1),&ll); if (!ok || ll < 0 || ll > 512*1024*1024) { return -2; } // now parse data line... pos = (newline - data)+2; if (ll < 0) { // handle $-1\r\n ? // protocol error !!! // c->querybuf = sdsrange(c->querybuf,pos,-1); return -2; } // now send the remainder to start line... request->lastpos = pos; request->parse_phase = RDS_PHASE_DATA; request->bulklen = ll; } else { puts("ERR: protocol error"); return -2; } } // if (request->parse_phase == RDS_PHASE_DATA){ if ((int)(data_len - request->lastpos) < 0){ return -1; } // do we have enough data ??? if ( (int)(data_len - request->lastpos) < (int)(request->bulklen+2)) { /* Not enough data (+2 == trailing \r\n) */ return -1; break; } else { char *str2 = malloc(request->bulklen + 1); memcpy(str2, data + request->lastpos, request->bulklen); str2[request->bulklen] = '\0'; PyObject* str = PyString_FromStringAndSize(str2, request->bulklen); PyList_SetItem(request->cmd_list, request->arg_cnt++, str); // NOTE: as far as i understand, PyList_SetItem doesnt incref // http://stackoverflow.com/questions/3512414/does-this-pylist-appendlist-py-buildvalue-leak // Py_DECREF(str); <- TODO: why ? if i do this weird things happen free(str2); } request->lastpos = request->lastpos + request->bulklen + 2; request->parse_phase = RDS_PHASE_START; request->multibulklen--; } // if RDS_PHASE_DATA } // while bulklen if (request->multibulklen == 0){ return 1; } return -1; }
/* ----------------- */ static sds get_bitmap_from_argv (int argc, robj ** argv) { sds bitmap; int i; bitmap = sdsgrowzero (sdsempty (), ARC_KS_SIZE); for (i = 0; i < argc; i++) { int ok, n, j; long long ll, from, to; sds *tokens; sds from_to = (sds) argv[i]->ptr; /* There are two kinds of argument type. * 1. <slotNo> ex) 1024 * 2. <slotNo from>-<slotNo to> ex) 0-2047 */ tokens = sdssplitlen (from_to, sdslen (from_to), "-", 1, &n); if (tokens == NULL) { return NULL; } if (n == 1) { /* Type 1 <slotNo> */ ok = string2ll (tokens[0], sdslen (tokens[0]), &ll); if (!ok) { sdsfreesplitres (tokens, n); return NULL; } from = ll; to = ll; } else if (n == 2) { /* Type 2 <slotNo from>-<slotNo to> */ ok = string2ll (tokens[0], sdslen (tokens[0]), &ll); if (!ok) { sdsfreesplitres (tokens, n); return NULL; } from = ll; ok = string2ll (tokens[1], sdslen (tokens[1]), &ll); if (!ok) { sdsfreesplitres (tokens, n); return NULL; } to = ll; } else { /* not belong to Type 1 or Type 2 */ sdsfreesplitres (tokens, n); return NULL; } sdsfreesplitres (tokens, n); /* range check */ if (from < 0 || to >= ARC_KS_SIZE || from > to) { return NULL; } /* set bit */ for (j = from; j <= to; j++) { bitmapSetBit ((unsigned char *) bitmap, j); } } return bitmap; }