/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_dns_looker_ref_t tb_dns_looker_init(tb_char_t const* name) { // check tb_assert_and_check_return_val(name, tb_null); // must be not address tb_assert(!tb_ipaddr_ip_cstr_set(tb_null, name, TB_IPADDR_FAMILY_NONE)); // done tb_bool_t ok = tb_false; tb_dns_looker_t* looker = tb_null; do { // make looker looker = tb_malloc0_type(tb_dns_looker_t); tb_assert_and_check_return_val(looker, tb_null); // dump server // tb_dns_server_dump(); // get the dns server list looker->maxn = tb_dns_server_get(looker->list); tb_check_break(looker->maxn && looker->maxn <= tb_arrayn(looker->list)); // init name if (!tb_static_string_init(&looker->name, (tb_char_t*)looker->data, TB_DNS_NAME_MAXN)) break; tb_static_string_cstrcpy(&looker->name, name); // init rpkt if (!tb_static_buffer_init(&looker->rpkt, looker->data + TB_DNS_NAME_MAXN, TB_DNS_RPKT_MAXN)) break; // init family looker->family = TB_IPADDR_FAMILY_IPV4; // init sock looker->sock = tb_socket_init(TB_SOCKET_TYPE_UDP, looker->family); tb_assert_and_check_break(looker->sock); // init itor looker->itor = 1; // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it if (looker) tb_dns_looker_exit((tb_dns_looker_ref_t)looker); looker = tb_null; } // ok? return (tb_dns_looker_ref_t)looker; }
/* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_http_server_main(tb_int_t argc, tb_char_t** argv) { // done tb_socket_ref_t sock = tb_null; do { // init socket sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4); tb_assert_and_check_break(sock); // bind socket tb_ipaddr_t addr; tb_ipaddr_set(&addr, tb_null, TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4); if (!tb_socket_bind(sock, &addr)) break; // listen socket if (!tb_socket_listen(sock, 1000)) break; // init the root directory if (argv[1]) tb_strlcpy(g_rootdir, argv[1], sizeof(g_rootdir)); else tb_directory_current(g_rootdir, sizeof(g_rootdir)); // only data? if (!tb_file_info(g_rootdir, tb_null)) g_onlydata = tb_true; // trace tb_trace_i("%s: %s", g_onlydata? "data" : "rootdir", g_rootdir); #if TB_DEMO_CPU > 1 // start workers for multi-threads tb_size_t count = TB_DEMO_CPU - 1; while (count--) tb_thread_init(tb_null, tb_demo_coroutine_worker, sock, 0); #endif // start worker tb_demo_coroutine_worker(sock); } while (0); // exit socket if (sock) tb_socket_exit(sock); sock = tb_null; // ok return 0; }
tb_bool_t tb_aico_open_sock_from_type(tb_aico_ref_t aico, tb_size_t type) { // check tb_aico_impl_t* impl = (tb_aico_impl_t*)aico; tb_aicp_impl_t* aicp_impl = (tb_aicp_impl_t*)impl->aicp; tb_assert_and_check_return_val(impl && aicp_impl && aicp_impl->ptor && aicp_impl->ptor->addo, tb_false); // done tb_bool_t ok = tb_false; tb_socket_ref_t sock = tb_null; do { // closed? tb_assert_and_check_break(tb_atomic_get(&impl->state) == TB_STATE_CLOSED); tb_assert_and_check_break(!impl->type && !impl->handle); // init sock sock = tb_socket_init(type); tb_assert_and_check_break(sock); // bind type and handle impl->type = TB_AICO_TYPE_SOCK; impl->handle = (tb_handle_t)sock; // addo aico ok = aicp_impl->ptor->addo(aicp_impl->ptor, impl); tb_assert_and_check_break(ok); // opened tb_atomic_set(&impl->state, TB_STATE_OPENED); } while (0); // failed? if (!ok) { // exit it if (sock) tb_socket_exit(sock); sock = tb_null; } // ok? return ok; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_pull(tb_cpointer_t priv) { // done tb_socket_ref_t sock = tb_null; do { // init socket sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4); tb_assert_and_check_break(sock); // init address tb_ipaddr_t addr; tb_ipaddr_set(&addr, "127.0.0.1", TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4); // trace tb_trace_d("[%p]: connecting %{ipaddr} ..", sock, &addr); // connect socket tb_long_t ok; while (!(ok = tb_socket_connect(sock, &addr))) { // wait it if (tb_socket_wait(sock, TB_SOCKET_EVENT_CONN, TB_DEMO_TIMEOUT) <= 0) break; } // connect ok? tb_check_break(ok > 0); // trace tb_trace_d("[%p]: recving ..", sock); // recv data tb_byte_t data[8192]; tb_hize_t recv = 0; tb_long_t wait = 0; tb_hong_t time = tb_mclock(); while (1) { // read it tb_long_t real = tb_socket_recv(sock, data, sizeof(data)); // trace tb_trace_d("[%p]: recv: %ld, total: %lu", sock, real, recv + (real > 0? real : 0)); // has data? if (real > 0) { recv += real; wait = 0; } // no data? wait it else if (!real && !wait) { // wait it wait = tb_socket_wait(sock, TB_SOCKET_EVENT_RECV, TB_DEMO_TIMEOUT); tb_assert_and_check_break(wait >= 0); } // failed or end? else break; } // trace tb_trace_i("[%p]: recv %llu bytes %lld ms", sock, recv, tb_mclock() - time); } while (0); // exit socket if (sock) tb_socket_exit(sock); sock = tb_null; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_long_t tb_dns_looker_reqt(tb_dns_looker_t* looker) { // check tb_check_return_val(!(looker->step & TB_DNS_LOOKER_STEP_REQT), 1); // format it first if the request is null if (!tb_static_buffer_size(&looker->rpkt)) { // check size tb_assert_and_check_return_val(!looker->size, -1); // format query tb_static_stream_t stream; tb_byte_t rpkt[TB_DNS_RPKT_MAXN]; tb_size_t size = 0; tb_byte_t* p = tb_null; tb_static_stream_init(&stream, rpkt, TB_DNS_RPKT_MAXN); // identification number tb_static_stream_writ_u16_be(&stream, TB_DNS_HEADER_MAGIC); /* 0x2104: 0 0000 001 0000 0000 * * tb_uint16_t qr :1; // query/response flag * tb_uint16_t opcode :4; // purpose of message * tb_uint16_t aa :1; // authoritive answer * tb_uint16_t tc :1; // truncated message * tb_uint16_t rd :1; // recursion desired * tb_uint16_t ra :1; // recursion available * tb_uint16_t z :1; // its z! reserved * tb_uint16_t ad :1; // authenticated data * tb_uint16_t cd :1; // checking disabled * tb_uint16_t rcode :4; // response code * * this is a query * this is a standard query * not authoritive answer * not truncated * recursion desired * * recursion not available! hey we dont have it (lol) * */ #if 1 tb_static_stream_writ_u16_be(&stream, 0x0100); #else tb_static_stream_writ_u1(&stream, 0); // this is a query tb_static_stream_writ_ubits32(&stream, 0, 4); // this is a standard query tb_static_stream_writ_u1(&stream, 0); // not authoritive answer tb_static_stream_writ_u1(&stream, 0); // not truncated tb_static_stream_writ_u1(&stream, 1); // recursion desired tb_static_stream_writ_u1(&stream, 0); // recursion not available! hey we dont have it (lol) tb_static_stream_writ_u1(&stream, 0); tb_static_stream_writ_u1(&stream, 0); tb_static_stream_writ_u1(&stream, 0); tb_static_stream_writ_ubits32(&stream, 0, 4); #endif /* we have only one question * * tb_uint16_t question; // number of question entries * tb_uint16_t answer; // number of answer entries * tb_uint16_t authority; // number of authority entries * tb_uint16_t resource; // number of resource entries * */ tb_static_stream_writ_u16_be(&stream, 1); tb_static_stream_writ_u16_be(&stream, 0); tb_static_stream_writ_u16_be(&stream, 0); tb_static_stream_writ_u16_be(&stream, 0); // set questions, see as tb_dns_question_t // name + question1 + question2 + ... tb_static_stream_writ_u8(&stream, '.'); p = (tb_byte_t*)tb_static_stream_writ_cstr(&stream, tb_static_string_cstr(&looker->name)); // only one question now. tb_static_stream_writ_u16_be(&stream, 1); // we are requesting the ipv4 address tb_static_stream_writ_u16_be(&stream, 1); // it's internet (lol) // encode dns name if (!p || !tb_dns_encode_name((tb_char_t*)p - 1)) return -1; // size size = tb_static_stream_offset(&stream); tb_assert_and_check_return_val(size, -1); // copy tb_static_buffer_memncpy(&looker->rpkt, rpkt, size); } // data && size tb_byte_t const* data = tb_static_buffer_data(&looker->rpkt); tb_size_t size = tb_static_buffer_size(&looker->rpkt); // check tb_assert_and_check_return_val(data && size && looker->size < size, -1); // try get addr from the dns list tb_ipaddr_ref_t addr = tb_null; if (looker->maxn && looker->itor && looker->itor <= looker->maxn) addr = &looker->list[looker->itor - 1]; // check tb_assert_and_check_return_val(addr && !tb_ipaddr_is_empty(addr), -1); // family have been changed? reinit socket if (tb_ipaddr_family(addr) != looker->family) { // exit the previous socket if (looker->sock) tb_socket_exit(looker->sock); // init a new socket for the family looker->sock = tb_socket_init(TB_SOCKET_TYPE_UDP, tb_ipaddr_family(addr)); tb_assert_and_check_return_val(looker->sock, -1); // update the new family looker->family = (tb_uint8_t)tb_ipaddr_family(addr); } // need wait if no data looker->step &= ~TB_DNS_LOOKER_STEP_NEVT; // trace tb_trace_d("request: try %{ipaddr}", addr); // send request while (looker->size < size) { // writ data tb_long_t writ = tb_socket_usend(looker->sock, addr, data + looker->size, size - looker->size); tb_assert_and_check_return_val(writ >= 0, -1); // no data? if (!writ) { // abort? tb_check_return_val(!looker->size && !looker->tryn, -1); // tryn++ looker->tryn++; // continue return 0; } else looker->tryn = 0; // update size looker->size += writ; } // finish it looker->step |= TB_DNS_LOOKER_STEP_REQT; looker->tryn = 0; // reset rpkt looker->size = 0; tb_static_buffer_clear(&looker->rpkt); // ok tb_trace_d("request: ok"); return 1; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_mswsock_instance_init(tb_handle_t instance) { // check tb_mswsock_ref_t mswsock = (tb_mswsock_ref_t)instance; tb_assert_and_check_return_val(mswsock, tb_false); // done tb_socket_ref_t sock = tb_null; do { // init sock sock = tb_socket_init(TB_SOCKET_TYPE_TCP); tb_assert_and_check_break(sock); // init AcceptEx DWORD AcceptEx_real = 0; GUID AcceptEx_guid = TB_MSWSOCK_WSAID_ACCEPTEX; tb_ws2_32()->WSAIoctl( (SOCKET)sock - 1 , SIO_GET_EXTENSION_FUNCTION_POINTER , &AcceptEx_guid , sizeof(GUID) , &mswsock->AcceptEx , sizeof(tb_mswsock_AcceptEx_t) , &AcceptEx_real , tb_null , tb_null); // init ConnectEx DWORD ConnectEx_real = 0; GUID ConnectEx_guid = TB_MSWSOCK_WSAID_CONNECTEX; tb_ws2_32()->WSAIoctl( (SOCKET)sock - 1 , SIO_GET_EXTENSION_FUNCTION_POINTER , &ConnectEx_guid , sizeof(GUID) , &mswsock->ConnectEx , sizeof(tb_mswsock_ConnectEx_t) , &ConnectEx_real , tb_null , tb_null); // init DisconnectEx DWORD DisconnectEx_real = 0; GUID DisconnectEx_guid = TB_MSWSOCK_WSAID_DISCONNECTEX; tb_ws2_32()->WSAIoctl( (SOCKET)sock - 1 , SIO_GET_EXTENSION_FUNCTION_POINTER , &DisconnectEx_guid , sizeof(GUID) , &mswsock->DisconnectEx , sizeof(tb_mswsock_DisconnectEx_t) , &DisconnectEx_real , tb_null , tb_null); // init TransmitFile DWORD TransmitFile_real = 0; GUID TransmitFile_guid = TB_MSWSOCK_WSAID_TRANSMITFILE; tb_ws2_32()->WSAIoctl( (SOCKET)sock - 1 , SIO_GET_EXTENSION_FUNCTION_POINTER , &TransmitFile_guid , sizeof(GUID) , &mswsock->TransmitFile , sizeof(tb_mswsock_TransmitFile_t) , &TransmitFile_real , tb_null , tb_null); // init GetAcceptExSockaddrs DWORD GetAcceptExSockaddrs_real = 0; GUID GetAcceptExSockaddrs_guid = TB_MSWSOCK_WSAID_GETACCEPTEXSOCKADDRS; tb_ws2_32()->WSAIoctl( (SOCKET)sock - 1 , SIO_GET_EXTENSION_FUNCTION_POINTER , &GetAcceptExSockaddrs_guid , sizeof(GUID) , &mswsock->GetAcceptExSockaddrs , sizeof(tb_mswsock_GetAcceptExSockaddrs_t) , &GetAcceptExSockaddrs_real , tb_null , tb_null); } while (0); // exit sock if (sock) tb_socket_exit(sock); // ok return tb_true; }