void SinkBase::cb_data(mblk_t *m) { uint32_t st = mblk_get_timestamp_info(m); mblk_t *fm = dupmsg(m); mblk_meta_copy(m, fm); MSQueue *queue = post_handle(fm); // 此处 dupmsg(m) 将不会导致 m 被释放 bool first = true; unsigned char *obuf = 0; size_t olen = 0; int index = 0; size_t off = 0; bool key = false; while (mblk_t *om = ms_queue_get(queue)) { int dlen = size_for(index, om); obuf = (unsigned char*)realloc(obuf, off + dlen); save_for(index, om, obuf + off); if (index == 0) key = is_key(index, om); index++; off += dlen; // 处理时间戳回绕 if (first_frame_) { first_frame_ = false; } else { uint32_t delta = st - last_stamp_; // 检查,是否乱序,乱序包直接扔掉! if (delta > 0x80000000) { fprintf(stderr, "??? maybe timestamp confusioned!, curr=%u, last=%u\n", st, last_stamp_); return; } next_stamp_ += delta / payload_freq(); } last_stamp_ = st; freemsg(om); } if (cb_data_ && obuf) { cb_data_(opaque_, next_stamp_, obuf, off, key); } if (obuf) free(obuf); }
int HttpParserImpl::parse(const char* data, uint32_t len) { if(HTTP_READ_DONE == read_state_ || HTTP_READ_ERROR == read_state_) { KUMA_WARNTRACE("HttpParser::parse, invalid state="<<read_state_); return 0; } if(HTTP_READ_BODY == read_state_ && !is_chunked_ && !has_content_length_) {// return directly, read untill EOF total_bytes_read_ += len; if(cb_data_) cb_data_(data, len); return len; } const char* pos = data; const char* end = data + len; ParseState parse_state = parseHttp(pos, end); int parsed_len = (int)(pos - data); if(PARSE_STATE_DESTROY == parse_state) { return parsed_len; } if(PARSE_STATE_ERROR == parse_state && cb_event_) { cb_event_(HTTP_ERROR); } return parsed_len; }
void WebSocketImpl::onWsData(uint8_t* data, uint32_t len) { if(cb_data_) cb_data_(data, len); }
HttpParserImpl::ParseState HttpParserImpl::parseChunk(const char*& cur_pos, const char* end) { const char* p_line = nullptr; const char* p_end = nullptr; bool b_line = false; while (cur_pos < end) { switch (chunk_state_) { case CHUNK_READ_SIZE: { b_line = getLine(cur_pos, end, p_line, p_end); if(!b_line) {// need more data, save remain data. if(saveData(cur_pos, end) != KUMA_ERROR_NOERR) { return PARSE_STATE_ERROR; } cur_pos = end; return PARSE_STATE_CONTINUE; } std::string str; if(!str_buf_.empty()) { str.swap(str_buf_); clearBuffer(); } str.append(p_line, p_end); // need not parse chunk extension chunk_size_ = (uint32_t)strtol(str.c_str(), NULL, 16); KUMA_INFOTRACE("HttpParser::parseChunk, chunk_size="<<chunk_size_); if(0 == chunk_size_) {// chunk completed chunk_state_ = CHUNK_READ_TRAILER; } else { chunk_bytes_read_ = 0; chunk_state_ = CHUNK_READ_DATA; } break; } case CHUNK_READ_DATA: { uint32_t cur_len = uint32_t(end - cur_pos); if(chunk_size_ - chunk_bytes_read_ <= cur_len) {// data enough const char* notify_data = cur_pos; uint32_t notify_len = chunk_size_ - chunk_bytes_read_; total_bytes_read_ += notify_len; chunk_bytes_read_ = chunk_size_ = 0; // reset chunk_state_ = CHUNK_READ_DATA_CR; cur_pos += notify_len; bool destroyed = false; destroy_flag_ptr_ = &destroyed; if(cb_data_) cb_data_(notify_data, notify_len); if(destroyed) { return PARSE_STATE_DESTROY; } destroy_flag_ptr_ = nullptr; } else {// need more data const char* notify_data = cur_pos; total_bytes_read_ += cur_len; chunk_bytes_read_ += cur_len; cur_pos += cur_len; if(cb_data_) cb_data_(notify_data, cur_len); return PARSE_STATE_CONTINUE; } break; } case CHUNK_READ_DATA_CR: { if(*cur_pos != CR) { KUMA_ERRTRACE("HttpParser::parseChunk, can not find data CR"); read_state_ = HTTP_READ_ERROR; return PARSE_STATE_ERROR; } ++cur_pos; chunk_state_ = CHUNK_READ_DATA_LF; break; } case CHUNK_READ_DATA_LF: { if(*cur_pos != LF) { KUMA_ERRTRACE("HttpParser::parseChunk, can not find data LF"); read_state_ = HTTP_READ_ERROR; return PARSE_STATE_ERROR; } ++cur_pos; chunk_state_ = CHUNK_READ_SIZE; break; } case CHUNK_READ_TRAILER: { b_line = getLine(cur_pos, end, p_line, p_end); if(b_line) { if(p_line == p_end && bufferEmpty()) { // blank line, http completed read_state_ = HTTP_READ_DONE; onComplete(); return PARSE_STATE_DONE; } clearBuffer(); // discard trailer } else { // need more data if(saveData(cur_pos, end) != KUMA_ERROR_NOERR) { return PARSE_STATE_ERROR; } cur_pos = end; // all data was consumed return PARSE_STATE_CONTINUE; } break; } } } return HTTP_READ_DONE == read_state_?PARSE_STATE_DONE:PARSE_STATE_CONTINUE; }
HttpParserImpl::ParseState HttpParserImpl::parseHttp(const char*& cur_pos, const char* end) { const char* line = nullptr; const char* line_end = nullptr; bool b_line = false; if(HTTP_READ_LINE == read_state_) {// try to get status line while ((b_line = getLine(cur_pos, end, line, line_end)) && line == line_end && str_buf_.empty()) ; if(b_line && (line != line_end || !str_buf_.empty())) { if(!parseStartLine(line, line_end)) { read_state_ = HTTP_READ_ERROR; return PARSE_STATE_ERROR; } read_state_ = HTTP_READ_HEAD; } else { // need more data if(saveData(cur_pos, end) != KUMA_ERROR_NOERR) { return PARSE_STATE_ERROR; } cur_pos = end; // all data was consumed return PARSE_STATE_CONTINUE; } } if(HTTP_READ_HEAD == read_state_) { while ((b_line = getLine(cur_pos, end, line, line_end))) { if(line == line_end && bufferEmpty()) {// blank line, header completed onHeaderComplete(); if(paused_) { return PARSE_STATE_CONTINUE; } if(hasBody() && !upgrade_) { read_state_ = HTTP_READ_BODY; } else { read_state_ = HTTP_READ_DONE; onComplete(); return PARSE_STATE_DONE; } break; } parseHeaderLine(line, line_end); } if(HTTP_READ_HEAD == read_state_) {// need more data if(saveData(cur_pos, end) != KUMA_ERROR_NOERR) { return PARSE_STATE_ERROR; } cur_pos = end; // all data was consumed return PARSE_STATE_CONTINUE; } } if(HTTP_READ_BODY == read_state_ && cur_pos < end) {// try to get body if(is_chunked_) { return parseChunk(cur_pos, end); } else { uint32_t cur_len = uint32_t(end - cur_pos); if(has_content_length_ && (content_length_ - total_bytes_read_) <= cur_len) {// data enough const char* notify_data = cur_pos; uint32_t notify_len = content_length_ - total_bytes_read_; cur_pos += notify_len; total_bytes_read_ = content_length_; read_state_ = HTTP_READ_DONE; KUMA_ASSERT(!destroy_flag_ptr_); bool destroyed = false; destroy_flag_ptr_ = &destroyed; if(cb_data_) cb_data_(notify_data, notify_len); if(destroyed) { return PARSE_STATE_DESTROY; } destroy_flag_ptr_ = nullptr; onComplete(); return PARSE_STATE_DONE; } else {// need more data, or read untill EOF const char* notify_data = cur_pos; total_bytes_read_ += cur_len; cur_pos = end; if(cb_data_) cb_data_(notify_data, cur_len); return PARSE_STATE_CONTINUE; } } } return HTTP_READ_DONE == read_state_?PARSE_STATE_DONE:PARSE_STATE_CONTINUE; }