tb_object_ref_t tb_object_data(tb_object_ref_t object, tb_size_t format) { // check tb_assert_and_check_return_val(object, tb_null); // done tb_object_ref_t odata = tb_null; tb_size_t maxn = 4096; tb_byte_t* data = tb_null; do { // make data data = data? (tb_byte_t*)tb_ralloc(data, maxn) : tb_malloc_bytes(maxn); tb_assert_and_check_break(data); // writ object to data tb_long_t size = tb_object_writ_to_data(object, data, maxn, format); // ok? make the data object if (size >= 0) odata = tb_object_data_init_from_data(data, size); // failed? grow it else maxn <<= 1; } while (!odata); // exit data if (data) tb_free(data); data = tb_null; // ok? return odata; }
tb_byte_t* tb_queue_buffer_push_init(tb_queue_buffer_ref_t buffer, tb_size_t* size) { // check tb_assert_and_check_return_val(buffer && buffer->maxn, tb_null); // no data? if (!buffer->data) { // make data buffer->data = tb_malloc_bytes(buffer->maxn); tb_assert_and_check_return_val(buffer->data, tb_null); // init buffer->head = buffer->data; buffer->size = 0; } tb_assert_and_check_return_val(buffer->data && buffer->head, tb_null); // full? tb_size_t left = buffer->maxn - buffer->size; tb_check_return_val(left, tb_null); // move data to head first, make sure there is enough write space if (buffer->head != buffer->data) { if (buffer->size) tb_memmov(buffer->data, buffer->head, buffer->size); buffer->head = buffer->data; } // save size if (size) *size = left; // ok return buffer->head + buffer->size; }
/* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_asio_aicpc_main(tb_int_t argc, tb_char_t** argv) { // check tb_assert_and_check_return_val(argv[1], 0); // init tb_aicp_ref_t aicp = tb_null; tb_demo_context_t context = {0}; do { // init aicp aicp = tb_aicp_init(2); tb_assert_and_check_break(aicp); // init data context.data = tb_malloc_bytes(TB_DEMO_SOCK_RECV_MAXN); tb_assert_and_check_break(context.data); // init sock aico context.sock = tb_aico_init(aicp); tb_assert_and_check_break(context.sock); // init addr tb_ipaddr_t addr; if (!tb_ipaddr_set(&addr, "127.0.0.1", 9090, TB_IPADDR_FAMILY_NONE)) break; // open sock aico if (!tb_aico_open_sock_from_type(context.sock, TB_SOCKET_TYPE_TCP, tb_ipaddr_family(&addr))) break; // init file aico context.file = tb_aico_init(aicp); tb_assert_and_check_break(context.file); // open file aico if (!tb_aico_open_file_from_path(context.file, argv[1], TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_BINARY | TB_FILE_MODE_TRUNC)) break; // init conn timeout tb_aico_timeout_set(context.sock, TB_AICO_TIMEOUT_CONN, 10000); // post conn tb_trace_i("conn: .."); if (!tb_aico_conn(context.sock, &addr, tb_demo_sock_conn_func, &context)) break; // loop aicp tb_aicp_loop(aicp); // trace if (tb_mclock() > context.base) tb_trace_i("size: %llu, sped: %llu KB/s", context.size, context.size / (tb_mclock() - context.base)); } while (0); // trace tb_trace_i("end"); // exit aicp if (aicp) tb_aicp_exit(aicp); return 0; }
tb_long_t tb_queue_buffer_writ(tb_queue_buffer_ref_t buffer, tb_byte_t const* data, tb_size_t size) { // check tb_assert_and_check_return_val(buffer && data && buffer->maxn, -1); // no data? if (!buffer->data) { // make data buffer->data = tb_malloc_bytes(buffer->maxn); tb_assert_and_check_return_val(buffer->data, -1); // init it buffer->head = buffer->data; buffer->size = 0; } tb_assert_and_check_return_val(buffer->data && buffer->head, -1); // full? tb_size_t left = buffer->maxn - buffer->size; tb_check_return_val(left, 0); // attempt to write data in tail directly if the tail space is enough tb_byte_t* tail = buffer->head + buffer->size; if (buffer->data + buffer->maxn >= tail + size) { tb_memcpy(tail, data, size); buffer->size += size; return (tb_long_t)size; } // move data to head if (buffer->head != buffer->data) { if (buffer->size) tb_memmov(buffer->data, buffer->head, buffer->size); buffer->head = buffer->data; } // write data tb_size_t writ = left > size? size : left; tb_memcpy(buffer->data + buffer->size, data, writ); buffer->size += writ; // ok return writ; }
static tb_object_ref_t tb_object_bplist_reader_func_array(tb_object_bplist_reader_t* reader, tb_size_t type, tb_size_t size, tb_size_t item_size) { // check tb_assert_and_check_return_val(reader && reader->stream, tb_null); // init tb_object_ref_t object = tb_null; // size is too large? if (size == 0x0f) { // read size tb_long_t val = tb_object_bplist_reader_func_size(reader, item_size); tb_assert_and_check_return_val(val >= 0, tb_null); size = (tb_size_t)val; } // init array object = tb_object_array_init(size? size : 16, tb_false); tb_assert_and_check_return_val(object, tb_null); // init items data if (size) { tb_byte_t* data = tb_malloc_bytes(sizeof(tb_uint32_t) + (size * item_size)); if (data) { if (tb_stream_bread(reader->stream, data + sizeof(tb_uint32_t), size * item_size)) { tb_bits_set_u32_ne(data, (tb_uint32_t)size); // FIXME: not using the user private data tb_object_setp(object, data); } else tb_free(data); } } // ok? return object; }
static tb_object_ref_t tb_object_bplist_reader_func_dictionary(tb_object_bplist_reader_t* reader, tb_size_t type, tb_size_t size, tb_size_t item_size) { // check tb_assert_and_check_return_val(reader && reader->stream, tb_null); // init tb_object_ref_t object = tb_null; // size is too large? if (size == 0x0f) { // read size tb_long_t val = tb_object_bplist_reader_func_size(reader, item_size); tb_assert_and_check_return_val(val >= 0, tb_null); size = (tb_size_t)val; } // init dictionary object = tb_object_dictionary_init(TB_OBJECT_DICTIONARY_SIZE_MICRO, tb_false); tb_assert_and_check_return_val(object, tb_null); // init items data if (size) { item_size <<= 1; tb_byte_t* data = tb_malloc_bytes(sizeof(tb_uint32_t) + (size * item_size)); if (data) { if (tb_stream_bread(reader->stream, data + sizeof(tb_uint32_t), size * item_size)) { tb_bits_set_u32_ne(data, (tb_uint32_t)size); tb_object_setp(object, data); } else tb_free(data); } } // ok? return object; }
tb_long_t tb_queue_buffer_writ(tb_queue_buffer_t* buffer, tb_byte_t const* data, tb_size_t size) { // check tb_assert_and_check_return_val(buffer && data && buffer->maxn, -1); // no data? if (!buffer->data) { // make data buffer->data = tb_malloc_bytes(buffer->maxn); tb_assert_and_check_return_val(buffer->data, -1); // init it buffer->head = buffer->data; buffer->size = 0; } tb_assert_and_check_return_val(buffer->data && buffer->head, -1); // no left? tb_size_t left = buffer->maxn - buffer->size; tb_check_return_val(left, 0); // move data to head if (buffer->head != buffer->data) { if (buffer->size) tb_memmov(buffer->data, buffer->head, buffer->size); buffer->head = buffer->data; } // writ data tb_size_t writ = left > size? size : left; tb_memcpy(buffer->data + buffer->size, data, writ); buffer->size += writ; // ok return writ; }
static tb_object_ref_t tb_object_bplist_reader_func_data(tb_object_bplist_reader_t* reader, tb_size_t type, tb_size_t size, tb_size_t item_size) { // check tb_assert_and_check_return_val(reader && reader->stream, tb_null); // init tb_byte_t* data = tb_null; tb_object_ref_t object = tb_null; // size is too large? if (size == 0x0f) { // read size tb_long_t val = tb_object_bplist_reader_func_size(reader, item_size); tb_assert_and_check_return_val(val >= 0, tb_null); size = (tb_size_t)val; } // no empty? if (size) { // make data data = tb_malloc_bytes(size); tb_assert_and_check_return_val(data, tb_null); // read data if (tb_stream_bread(reader->stream, data, size)) object = tb_object_data_init_from_data(data, size); } else object = tb_object_data_init_from_data(tb_null, 0); // exit if (data) tb_free(data); // ok? return object; }
tb_char_t const* tb_regex_replace(tb_regex_ref_t self, tb_char_t const* cstr, tb_size_t size, tb_size_t start, tb_char_t const* replace_cstr, tb_size_t replace_size, tb_size_t* plength) { // check tb_regex_t* regex = (tb_regex_t*)self; tb_assert_and_check_return_val(regex && regex->code && cstr && replace_cstr, tb_null); // done tb_char_t const* result = tb_null; do { // clear length first if (plength) *plength = 0; // end? tb_check_break(start < size); // init options #ifdef __tb_debug__ tb_uint32_t options = 0; #else tb_uint32_t options = PCRE2_NO_UTF_CHECK; #endif if (regex->mode & TB_REGEX_MODE_GLOBAL) options |= PCRE2_SUBSTITUTE_GLOBAL; // init buffer if (!regex->buffer_data) { regex->buffer_maxn = tb_max(size + replace_size + 64, 256); regex->buffer_data = (PCRE2_UCHAR*)tb_malloc_bytes(regex->buffer_maxn); } tb_assert_and_check_break(regex->buffer_data); // done tb_long_t ok = -1; PCRE2_SIZE length = 0; while (1) { // replace it length = (PCRE2_SIZE)regex->buffer_maxn; ok = pcre2_substitute(regex->code, (PCRE2_SPTR)cstr, (PCRE2_SIZE)size, (PCRE2_SIZE)start, options, tb_null, tb_null, (PCRE2_SPTR)replace_cstr, (PCRE2_SIZE)replace_size, regex->buffer_data, &length); // no space? if (ok == PCRE2_ERROR_NOMEMORY) { // grow buffer regex->buffer_maxn <<= 1; regex->buffer_data = (PCRE2_UCHAR*)tb_ralloc_bytes(regex->buffer_data, regex->buffer_maxn); tb_assert_and_check_break(regex->buffer_data); } // failed else if (ok < 0) { #if defined(__tb_debug__) && !defined(TB_CONFIG_OS_WINDOWS) // get error info PCRE2_UCHAR info[256]; pcre2_get_error_message(ok, info, sizeof(info)); // trace tb_trace_d("replace failed at offset %lu: error: %ld, %s\n", start, ok, info); #endif // end break; } else break; } // check tb_check_break(ok > 0); tb_assert_and_check_break(length < regex->buffer_maxn); // end regex->buffer_data[length] = '\0'; // trace tb_trace_d(" replace: [%lu]: %s", length, regex->buffer_data); // save length if (plength) *plength = (tb_size_t)length; // ok result = (tb_char_t const*)regex->buffer_data; } while (0); // ok? return result; }
/* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_asio_aiopd_main(tb_int_t argc, tb_char_t** argv) { // check tb_assert_and_check_return_val(argv[1], 0); // done tb_socket_ref_t sock = tb_null; tb_aiop_ref_t aiop = tb_null; do { // init sock sock = tb_socket_init(TB_SOCKET_TYPE_TCP); tb_assert_and_check_break(sock); // init aiop aiop = tb_aiop_init(16); tb_assert_and_check_break(aiop); // bind if (!tb_socket_bind(sock, tb_null, 9090)) break; // listen sock if (!tb_socket_listen(sock, 20)) break; // addo sock if (!tb_aiop_addo(aiop, sock, TB_AIOE_CODE_ACPT, tb_null)) break; // accept tb_aioe_t list[16]; while (1) { // wait tb_long_t objn = tb_aiop_wait(aiop, list, 16, -1); tb_assert_and_check_break(objn >= 0); // walk list tb_size_t i = 0; for (i = 0; i < objn; i++) { // the aioo tb_aioo_ref_t aioo = list[i].aioo; // check tb_assert_and_check_break(aioo && tb_aioo_sock(aioo)); // acpt? if (list[i].code & TB_AIOE_CODE_ACPT) { // done acpt tb_bool_t ok = tb_false; tb_demo_context_t* context = tb_null; do { // make context context = tb_malloc0_type(tb_demo_context_t); tb_assert_and_check_break(context); // init sock context->sock = tb_socket_accept(tb_aioo_sock(aioo), tb_null, tb_null); tb_assert_and_check_break(context->sock); // init file context->file = tb_file_init(argv[1], TB_FILE_MODE_RO); tb_assert_and_check_break(context->file); // init data context->data = tb_malloc_bytes(TB_DEMO_FILE_READ_MAXN); tb_assert_and_check_break(context->data); // addo sock context->aioo = tb_aiop_addo(aiop, context->sock, TB_AIOE_CODE_SEND, context); tb_assert_and_check_break(context->aioo); // trace tb_trace_i("acpt[%p]: ok", context->sock); // init left context->left = tb_file_size(context->file); // done read tb_long_t real = tb_file_read(context->file, context->data, tb_min((tb_size_t)context->left, TB_DEMO_FILE_READ_MAXN)); tb_assert_and_check_break(real > 0); // save size context->left -= real; // trace // tb_trace_i("read[%p]: real: %ld", context->file, real); // done send context->send = real; real = tb_socket_send(context->sock, context->data + context->real, context->send - context->real); if (real >= 0) { // save real context->real += real; // trace // tb_trace_i("send[%p]: real: %ld", context->sock, real); } else { // trace tb_trace_i("send[%p]: closed", context->sock); break; } // ok ok = tb_true; } while (0); // failed or closed? if (!ok) { // exit context tb_demo_context_exit(aiop, context); break; } } // writ? else if (list[i].code & TB_AIOE_CODE_SEND) { // the context tb_demo_context_t* context = (tb_demo_context_t*)list[i].priv; tb_assert_and_check_break(context); // continue to send it if not finished if (context->real < context->send) { // done send tb_long_t real = tb_socket_send(tb_aioo_sock(aioo), context->data + context->real, context->send - context->real); if (real > 0) { // save real context->real += real; // trace // tb_trace_i("send[%p]: real: %ld", tb_aioo_sock(aioo), real); } else { // trace tb_trace_i("send[%p]: closed", tb_aioo_sock(aioo)); // exit context tb_demo_context_exit(aiop, context); break; } } // finished? read file else if (context->left) { // init context->real = 0; context->send = 0; // done read tb_size_t tryn = 1; tb_long_t real = 0; while (!(real = tb_file_read(context->file, context->data, tb_min((tb_size_t)context->left, TB_DEMO_FILE_READ_MAXN))) && tryn--); if (real > 0) { // save left context->left -= real; // trace // tb_trace_i("read[%p]: real: %ld", context->file, real); // done send context->send = real; real = tb_socket_send(tb_aioo_sock(aioo), context->data, context->send); if (real >= 0) { // save real context->real += real; // trace // tb_trace_i("send[%p]: real: %ld", tb_aioo_sock(aioo), real); } else { // trace tb_trace_i("send[%p]: closed", tb_aioo_sock(aioo)); // exit context tb_demo_context_exit(aiop, context); break; } } else { // trace tb_trace_i("read[%p]: closed", tb_aioo_sock(aioo)); // exit context tb_demo_context_exit(aiop, context); break; } } else { // trace tb_trace_i("read[%p]: closed", tb_aioo_sock(aioo)); // exit context tb_demo_context_exit(aiop, context); break; } } // error? else { tb_trace_i("aioe[%p]: unknown code: %lu", tb_aioo_sock(aioo), list[i].code); break; } } } } while (0); // trace tb_trace_i("end"); // exit socket if (sock) tb_socket_exit(sock); // exit aiop if (aiop) tb_aiop_exit(aiop); // end return 0; }
tb_byte_t* tb_buffer_resize(tb_buffer_t* buffer, tb_size_t size) { // check tb_assert_and_check_return_val(buffer && size, tb_null); // done tb_bool_t ok = tb_false; tb_byte_t* buff_data = buffer->data; tb_size_t buff_size = buffer->size; tb_size_t buff_maxn = buffer->maxn; do { // check tb_assert_and_check_break(buff_data); // using static buffer? if (buff_data == buffer->buff) { // grow? if (size > buff_maxn) { // grow maxn buff_maxn = tb_align8(size + TB_BUFFER_GROW_SIZE); tb_assert_and_check_break(size <= buff_maxn); // grow data buff_data = tb_malloc_bytes(buff_maxn); tb_assert_and_check_break(buff_data); // copy data tb_memcpy(buff_data, buffer->buff, buff_size); } // update the size buff_size = size; } else { // grow? if (size > buff_maxn) { // grow maxn buff_maxn = tb_align8(size + TB_BUFFER_GROW_SIZE); tb_assert_and_check_break(size <= buff_maxn); // grow data buff_data = (tb_byte_t*)tb_ralloc(buff_data, buff_maxn); tb_assert_and_check_break(buff_data); } #if 0 // decrease to the static buffer else if (size <= sizeof(buffer->buff)) { // update the maxn buff_maxn = sizeof(buffer->buff); // copy data tb_memcpy(buffer->buff, buff_data, size); // free data tb_free(buff_data); // using the static buffer buff_data = buffer->buff; } #endif // update the size buff_size = size; } // update the buffer buffer->data = buff_data; buffer->size = buff_size; buffer->maxn = buff_maxn; // ok ok = tb_true; } while (0); // trace if (!ok) tb_trace_e("resize buffer failed: %lu => %lu", buff_size, size); // ok return ok? (tb_byte_t*)buffer->data : tb_null; }
static tb_bool_t tb_demo_sock_acpt_func(tb_aice_ref_t aice) { // check tb_assert_and_check_return_val(aice && aice->code == TB_AICE_CODE_ACPT, tb_false); // the file path tb_char_t const* path = (tb_char_t const*)aice->priv; tb_assert_and_check_return_val(path, tb_false); // the aicp tb_aicp_ref_t aicp = tb_aico_aicp(aice->aico); tb_assert_and_check_return_val(aicp, tb_false); // acpt ok? if (aice->state == TB_STATE_OK) { // trace tb_trace_i("acpt[%p]: %p", aice->aico, aice->u.acpt.aico); // done tb_bool_t ok = tb_false; tb_demo_context_t* context = tb_null; do { // make context context = tb_malloc0_type(tb_demo_context_t); tb_assert_and_check_break(context); #ifdef TB_DEMO_MODE_SENDF // init file context->file = tb_file_init(path, TB_FILE_MODE_RO | TB_FILE_MODE_ASIO); tb_assert_and_check_break(context->file); // init sock aico context->aico[0] = aice->u.acpt.aico; tb_assert_and_check_break(context->aico[0]); // post sendf from file if (!tb_aico_sendf(context->aico[0], context->file, 0ULL, tb_file_size(context->file), tb_demo_sock_sendf_func, context)) break; #else // init data context->data = tb_malloc_bytes(TB_DEMO_FILE_READ_MAXN); tb_assert_and_check_break(context->file && context->data); // init sock aico context->aico[0] = aice->u.acpt.aico; tb_assert_and_check_break(context->aico[0]); // init file aico context->aico[1] = tb_aico_init(aicp); tb_assert_and_check_break(context->aico[1]); // open file aico if (!tb_aico_open_file_from_path(context->aico[1], path, TB_FILE_MODE_RO)) break; // post read from file if (!tb_aico_read(context->aico[1], context->size, context->data, TB_DEMO_FILE_READ_MAXN, tb_demo_file_read_func, context)) break; #endif // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit context if (context) tb_demo_context_exit(context); } } // failed? else { // exit loop tb_trace_i("acpt[%p]: state: %s", aice->aico, tb_state_cstr(aice->state)); // clos aico if (aice->aico) tb_aico_clos(aice->aico, tb_demo_aico_clos, tb_null); } // ok return tb_true; }