tb_size_t tb_directory_temporary(tb_char_t* path, tb_size_t maxn) { // check tb_assert_and_check_return_val(path && maxn > 4, 0); // the temporary directory return tb_strlcpy(path, "/tmp", maxn); }
tb_char_t const* tb_addrinfo_name(tb_ipaddr_ref_t addr, tb_char_t* name, tb_size_t maxn) { // check tb_assert_and_check_return_val(addr && name && maxn, tb_null); #if defined(TB_CONFIG_POSIX_HAVE_GETNAMEINFO) // load socket address struct sockaddr_storage saddr; socklen_t saddrlen = (socklen_t)tb_sockaddr_load(&saddr, addr); tb_assert_and_check_return_val(saddrlen, tb_null); // get host name from address return !getnameinfo((struct sockaddr const*)&saddr, saddrlen, name, maxn, tb_null, 0, NI_NAMEREQD)? name : tb_null; #elif defined(TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME) // done struct hostent* hostaddr = tb_null; switch (tb_ipaddr_family(addr)) { case TB_IPADDR_FAMILY_IPV4: { // init ip address struct in_addr ipaddr = {0}; ipaddr.s_addr = tb_ipaddr_ip_is_any(addr)? INADDR_ANY : addr->u.ipv4.u32; // get host name from address hostaddr = gethostbyaddr((tb_char_t const*)&ipaddr, sizeof(ipaddr), AF_INET); } break; case TB_IPADDR_FAMILY_IPV6: { // init ip address struct in6_addr ipaddr; tb_memset(&ipaddr, 0, sizeof(ipaddr)); // save ipv6 if (tb_ipaddr_ip_is_any(addr)) ipaddr = in6addr_any; else tb_memcpy(ipaddr.s6_addr, addr->u.ipv6.addr.u8, sizeof(ipaddr.s6_addr)); // get host name from address hostaddr = gethostbyaddr((tb_char_t const*)&ipaddr, sizeof(ipaddr), AF_INET6); } break; default: break; } tb_check_return_val(hostaddr && hostaddr->h_name, tb_null); // save name tb_strlcpy(name, hostaddr->h_name, maxn); // ok? return name; #else tb_trace_noimpl(); return tb_null; #endif }
static tb_char_t const* tb_element_true_cstr(tb_element_ref_t element, tb_cpointer_t data, tb_char_t* cstr, tb_size_t maxn) { // check tb_assert_and_check_return_val(element && cstr && maxn, ""); // format string tb_strlcpy(cstr, "true", maxn - 1); cstr[maxn - 1] = '\0'; // ok? return (tb_char_t const*)cstr; }
static tb_void_t tb_test_strncpy(tb_char_t const* s2, tb_size_t size) { __tb_volatile__ tb_int_t n = 1000000; tb_char_t s1[4096]; tb_hong_t t = tb_mclock(); while (n--) { tb_strlcpy(s1, s2, size); } t = tb_mclock() - t; tb_printf("%lld ms, tb_test_strncpy(%s, %d) = %s\n", t, s2, size, s1); }
tb_size_t tb_directory_temp(tb_char_t* path, tb_size_t maxn) { // check tb_assert_and_check_return_val(path && maxn > 4, 0); // the temporary directory tb_strlcpy(path, "/tmp", maxn - 1); path[4] = '\0'; // ok return 4; }
static tb_void_t tb_element_str_repl(tb_element_ref_t element, tb_pointer_t buff, tb_cpointer_t data) { // check tb_assert_and_check_return(element && element->dupl && buff); #if 0 // free it if (element->free) element->free(element, buff); // dupl it element->dupl(element, buff, data); #else // replace it tb_pointer_t cstr = *((tb_pointer_t*)buff); if (cstr && data) { // attempt to replace it tb_char_t* p = (tb_char_t*)cstr; tb_char_t const* q = (tb_char_t const*)data; while (*p && *q) *p++ = *q++; // not enough space? if (!*p && *q) { // the left size tb_size_t left = tb_strlen(q); tb_assert_abort(left); // the copy size tb_size_t copy = p - (tb_char_t*)cstr; // grow size cstr = tb_ralloc(cstr, copy + left + 1); tb_assert_abort(cstr); // copy the left data tb_strlcpy((tb_char_t*)cstr + copy, q, left + 1); // update the cstr *((tb_pointer_t*)buff) = cstr; } // end else *p = '\0'; } // duplicate it else if (data) element->dupl(element, buff, data); // free it else if (element->free) element->free(element, buff); // clear it else *((tb_char_t const**)buff) = tb_null; #endif }
static tb_void_t tb_directory_walk_impl(tb_char_t const* path, tb_bool_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv) { // check tb_assert_and_check_return(path && func); // last tb_long_t last = tb_strlen(path) - 1; tb_assert_and_check_return(last >= 0); // init info tb_char_t temp[4096] = {0}; DIR* directory = tb_null; if ((directory = opendir(path))) { // walk struct dirent* item = tb_null; while ((item = readdir(directory))) { // check tb_assert_and_check_continue(item->d_name && item->d_reclen); // the item name tb_char_t name[1024] = {0}; tb_strlcpy(name, item->d_name, tb_min(item->d_reclen, 1023)); if (tb_strcmp(name, ".") && tb_strcmp(name, "..")) { // the temp path tb_long_t n = tb_snprintf(temp, 4095, "%s%s%s", path, path[last] == '/'? "" : "/", name); if (n >= 0) temp[n] = '\0'; // the file info tb_file_info_t info = {0}; if (tb_file_info(temp, &info)) { // do callback if (prefix) func(temp, &info, priv); // walk to the next directory if (info.type == TB_FILE_TYPE_DIRECTORY && recursion) tb_directory_walk_impl(temp, recursion, prefix, func, priv); // do callback if (!prefix) func(temp, &info, priv); } } } // exit directory closedir(directory); } }
tb_size_t tb_environment_get(tb_char_t const* name, tb_char_t* values, tb_size_t maxn) { // check tb_assert_and_check_return_val(name && values && maxn, 0); // init values tb_string_t valuestrs; if (!tb_string_init(&valuestrs)) return 0; // init environment tb_environment_ref_t environment = tb_environment_init(); if (environment) { // load variable if (tb_environment_load(environment, name)) { // make values tb_bool_t is_first = tb_true; tb_for_all_if (tb_char_t const*, value, environment, value) { // append separator if (!is_first) tb_string_chrcat(&valuestrs, TM_ENVIRONMENT_SEP); else is_first = tb_false; // append value tb_string_cstrcat(&valuestrs, value); } } // exit environment tb_environment_exit(environment); } // save result tb_size_t size = tb_string_size(&valuestrs); tb_char_t const* cstr = tb_string_cstr(&valuestrs); if (size && cstr) { // copy it size = tb_strlcpy(values, cstr, maxn); tb_assert(size < maxn); } // exit values tb_string_exit(&valuestrs); // ok? return size; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_path_translate(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const* path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // copy path tb_char_t data[TB_PATH_MAXN]; tb_strlcpy(data, path, sizeof(data)); // done path:translate() lua_pushstring(lua, tb_path_translate(data, 0, sizeof(data) - 1)? data : tb_null); // ok return 1; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_option_ref_t tb_option_init(tb_char_t const* name, tb_char_t const* help, tb_option_item_t const* opts) { // check tb_assert_and_check_return_val(name && opts, tb_null); // done tb_bool_t ok = tb_false; tb_option_impl_t* impl = tb_null; do { // make option impl = tb_malloc0_type(tb_option_impl_t); tb_assert_and_check_break(impl); // init option impl->opts = opts; impl->list = tb_oc_dictionary_init(TB_OC_DICTIONARY_SIZE_MICRO, tb_false); tb_assert_and_check_break(impl->list); // init name tb_strlcpy(impl->name, name, sizeof(impl->name)); // init help if (!tb_string_init(&impl->help)) break; if (help) tb_string_cstrcpy(&impl->help, help); // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it if (impl) tb_option_exit((tb_option_ref_t)impl); impl = tb_null; } // ok? return (tb_option_ref_t)impl; }
static tb_void_t tb_ifaddrs_interface_done_hwaddr(tb_list_ref_t interfaces, tb_hash_map_ref_t names, struct nlmsghdr* response) { // check tb_assert_and_check_return(interfaces && names && response); // the info struct ifaddrmsg* info = (struct ifaddrmsg *)NLMSG_DATA(response); // attempt to find the interface name tb_bool_t owner = tb_false; tb_char_t* name = (tb_char_t*)tb_hash_map_get(names, tb_u2p(info->ifa_index)); if (!name) { // get the interface name struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFLA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFLA_IFNAME: { // make name name = (tb_char_t*)tb_ralloc(name, rta_data_size + 1); tb_assert_and_check_break(name); // copy name tb_strlcpy(name, rta_data, rta_data_size + 1); // save name tb_hash_map_insert(names, tb_u2p(info->ifa_index), name); owner = tb_true; } break; default: break; } } } // check tb_check_return(name); // done struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFLA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, name); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFLA_ADDRESS: { // no hwaddr? if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR)) { // check tb_check_break(rta_data_size == sizeof(interface->hwaddr.u8)); // save flags interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; if (info->ifa_flags & IFF_LOOPBACK) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; // save hwaddr tb_memcpy(interface->hwaddr.u8, rta_data, sizeof(interface->hwaddr.u8)); // trace tb_trace_d("name: %s, hwaddr: %{hwaddr}", name, &interface->hwaddr); // new interface? save it if (interface == &interface_new) { // save interface name interface->name = tb_strdup(name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } } break; case IFLA_IFNAME: case IFLA_BROADCAST: case IFLA_STATS: break; default: break; } } // exit name if (name && owner) tb_free(name); name = tb_null; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_size_t tb_directory_temporary(tb_char_t* path, tb_size_t maxn) { // check tb_assert_and_check_return_val(path && maxn > 4, 0); // the jvm JavaVM* jvm = tb_android_jvm(); tb_assert_and_check_return_val(jvm, 0); // attempt to get jni environment first JNIEnv* jenv = tb_null; tb_bool_t jattached = tb_false; if ((*jvm)->GetEnv(jvm, (tb_pointer_t*)&jenv, JNI_VERSION_1_4) != JNI_OK) { // bind jni environment if ((*jvm)->AttachCurrentThread(jvm, &jenv, tb_null) != JNI_OK) return 0; // attach ok jattached = tb_true; } tb_assert_and_check_return_val(jenv, 0); // enter if ((*jenv)->PushLocalFrame(jenv, 10) < 0) return 0; // done tb_size_t size = 0; jboolean error = tb_false; do { // get the environment class jclass environment = (*jenv)->FindClass(jenv, "android/os/Environment"); tb_assert_and_check_break(!(error = (*jenv)->ExceptionCheck(jenv)) && environment); // get the getDownloadCacheDirectory func jmethodID getDownloadCacheDirectory_func = (*jenv)->GetStaticMethodID(jenv, environment, "getDownloadCacheDirectory", "()Ljava/io/File;"); tb_assert_and_check_break(getDownloadCacheDirectory_func); // get the download cache directory jobject directory = (*jenv)->CallStaticObjectMethod(jenv, environment, getDownloadCacheDirectory_func); tb_assert_and_check_break(!(error = (*jenv)->ExceptionCheck(jenv)) && directory); // get file class jclass file_class = (*jenv)->GetObjectClass(jenv, directory); tb_assert_and_check_break(!(error = (*jenv)->ExceptionCheck(jenv)) && file_class); // get the getPath func jmethodID getPath_func = (*jenv)->GetMethodID(jenv, file_class, "getPath", "()Ljava/lang/String;"); tb_assert_and_check_break(getPath_func); // get the directory path jstring path_jstr = (jstring)(*jenv)->CallObjectMethod(jenv, directory, getPath_func); tb_assert_and_check_break(!(error = (*jenv)->ExceptionCheck(jenv)) && path_jstr); // get the path string length size = (tb_size_t)(*jenv)->GetStringLength(jenv, path_jstr); tb_assert_and_check_break(size); // get the path string tb_char_t const* path_cstr = (*jenv)->GetStringUTFChars(jenv, path_jstr, tb_null); tb_assert_and_check_break(path_cstr); // trace tb_trace_d("temp: %s", path_cstr); // copy it tb_size_t need = tb_min(size + 1, maxn); tb_strlcpy(path, path_cstr, need); // exit the path string (*jenv)->ReleaseStringUTFChars(jenv, path_jstr, path_cstr); } while (0); // exception? clear it if (error) (*jenv)->ExceptionClear(jenv); // leave (*jenv)->PopLocalFrame(jenv, tb_null); // detach it? if (jattached) { // detach jni environment if ((*jvm)->DetachCurrentThread(jvm) == JNI_OK) jattached = tb_false; } // ok? return size; }
tb_char_t const* tb_path_relative_to(tb_char_t const* root, tb_char_t const* path, tb_char_t* data, tb_size_t maxn) { // check tb_assert_and_check_return_val(path && data && maxn, tb_null); // trace tb_trace_d("path: %s", path); // the root is the current and the path is absolute? return path directly if (!root && !tb_path_is_absolute(path)) { // copy it tb_strlcpy(data, path, maxn); // translate it return tb_path_translate(data, 0, maxn)? data : tb_null; } // get the absolute path tb_size_t path_size = 0; tb_char_t path_absolute[TB_PATH_MAXN]; tb_size_t path_maxn = sizeof(path_absolute); path = tb_path_absolute(path, path_absolute, path_maxn); path_size = tb_strlen(path); tb_assert_and_check_return_val(path && path_size && path_size < path_maxn, tb_null); // trace tb_trace_d("path_absolute: %s", path); // get the absolute root tb_size_t root_size = 0; tb_char_t root_absolute[TB_PATH_MAXN]; tb_size_t root_maxn = sizeof(root_absolute); if (root) { // get the absolute root root = tb_path_absolute(root, root_absolute, root_maxn); root_size = tb_strlen(root); } else { // get the current directory if (!(root_size = tb_directory_current(root_absolute, root_maxn))) return tb_null; // translate it if (!(root_size = tb_path_translate(root_absolute, root_size, root_maxn))) return tb_null; root = root_absolute; } tb_assert_and_check_return_val(root && root_size && root_size < root_maxn, tb_null); // trace tb_trace_d("root_absolute: %s", root); // same directory? return "." if (path_size == root_size && !tb_strncmp(path, root, root_size)) { // check tb_assert_and_check_return_val(maxn >= 2, "."); // return "." data[0] = '.'; data[1] = '\0'; return data; } // append separator if (path_size + 1 < path_maxn) { path_absolute[path_size++] = TB_PATH_SEPARATOR; path_absolute[path_size] = '\0'; } if (root_size + 1 < root_maxn) { root_absolute[root_size++] = TB_PATH_SEPARATOR; root_absolute[root_size] = '\0'; } // find the common leading directory tb_char_t const* p = path; tb_char_t const* q = root; tb_long_t last = -1; for (; *p && *q && *p == *q; q++, p++) { // save the last separator if (*p == TB_PATH_SEPARATOR) last = q - root; } // is different directory or outside the windows drive root? using the absolute path if (last <= 0 || (last == 2 && root[1] == ':')) { // the path size tb_size_t size = tb_min(path_size - 1, maxn); // copy it tb_strncpy(data, path, size); data[size] = '\0'; } // exists same root? else { // count the remaining levels in root tb_size_t count = 0; tb_char_t const* l = root + last + 1; for (; *l; l++) { if (*l == TB_PATH_SEPARATOR) count++; } // append "../" or "..\\" tb_char_t* d = data; tb_char_t* e = data + maxn; while (count--) { if (d + 3 < e) { d[0] = '.'; d[1] = '.'; d[2] = TB_PATH_SEPARATOR; d += 3; } } // append the left path l = path + last + 1; while (*l && d < e) *d++ = *l++; // remove the last separator if (d > data) d--; // end *d = '\0'; } // trace tb_trace_d("relative: %s", data); // ok? return data; }
tb_char_t const* tb_path_absolute_to(tb_char_t const* root, tb_char_t const* path, tb_char_t* data, tb_size_t maxn) { // check tb_assert_and_check_return_val(path && data && maxn, tb_null); // trace tb_trace_d("path: %s", path); // the path is absolute? if (tb_path_is_absolute(path)) { // copy it tb_strlcpy(data, path, maxn); // translate it return tb_path_translate(data, 0, maxn)? data : tb_null; } // get the root directory tb_size_t size = 0; if (root) { // copy it size = tb_strlcpy(data, root, maxn); tb_assert_and_check_return_val(size < maxn, tb_null); } else { // get the current directory if (!(size = tb_directory_current(data, maxn))) return tb_null; } // translate the root directory size = tb_path_translate(data, size, maxn); // trace tb_trace_d("root: %s, size: %lu", data, size); // is windows path? skip the drive prefix tb_char_t* absolute = data; if (size > 2 && tb_isalpha(absolute[0]) && absolute[1] == ':' && absolute[2] == TB_PATH_SEPARATOR) { // skip it absolute += 2; size -= 2; } // path => data tb_char_t const* p = path; tb_char_t const* t = p; tb_char_t* q = absolute + size; tb_char_t const* e = absolute + maxn - 1; while (1) { if (tb_path_is_separator(*p) || !*p) { // the item size tb_size_t n = p - t; // ..? remove item if (n == 2 && t[0] == '.' && t[1] == '.') { // find the last separator for (; q > absolute && *q != TB_PATH_SEPARATOR; q--) ; // strip it *q = '\0'; } // .? continue it else if (n == 1 && t[0] == '.') ; // append item else if (n && q + 1 + n < e) { *q++ = TB_PATH_SEPARATOR; tb_strncpy(q, t, n); q += n; } // empty item? remove repeat else if (!n) ; // too small? else { // trace tb_trace_e("the data path is too small for %s", path); return tb_null; } // break tb_check_break(*p); // next t = p + 1; } // next p++; } // end if (q > absolute) *q = '\0'; // root? else { *q++ = TB_PATH_SEPARATOR; *q = '\0'; } // trace tb_trace_d("absolute: %s", data); // ok? return data; }
static tb_void_t tb_ifaddrs_interface_done_ipaddr(tb_list_ref_t interfaces, tb_hash_map_ref_t names, struct nlmsghdr* response) { // check tb_assert_and_check_return(interfaces && names && response); // the info struct ifaddrmsg* info = (struct ifaddrmsg *)NLMSG_DATA(response); // must be not link tb_assert_and_check_return(info->ifa_family != AF_PACKET); // attempt to find the interface name tb_bool_t owner = tb_false; tb_char_t* name = (tb_char_t*)tb_hash_map_get(names, tb_u2p(info->ifa_index)); if (!name) { // get the interface name struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFA_LABEL: { // make name name = (tb_char_t*)tb_ralloc(name, rta_data_size + 1); tb_assert_and_check_break(name); // copy name tb_strlcpy(name, rta_data, rta_data_size + 1); // save name tb_hash_map_insert(names, tb_u2p(info->ifa_index), name); owner = tb_true; } break; default: break; } } } // check tb_check_return(name); // done struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, name); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // done tb_pointer_t rta_data = RTA_DATA(rta); switch(rta->rta_type) { case IFA_LOCAL: case IFA_ADDRESS: { // make ipaddr tb_ipaddr_t ipaddr; if (!tb_ifaddrs_netlink_ipaddr_save(&ipaddr, info->ifa_family, info->ifa_index, rta_data)) break; // save flags if ((info->ifa_flags & IFF_LOOPBACK) || tb_ipaddr_ip_is_loopback(&ipaddr)) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; // save ipaddr switch (tb_ipaddr_family(&ipaddr)) { case TB_IPADDR_FAMILY_IPV4: { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; interface->ipaddr4 = ipaddr.u.ipv4; } break; case TB_IPADDR_FAMILY_IPV6: { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; interface->ipaddr6 = ipaddr.u.ipv6; } break; default: break; } // trace tb_trace_d("name: %s, ipaddr: %{ipaddr}", name, &ipaddr); // new interface? save it if (tb_ipaddr_family(&ipaddr) && interface == &interface_new) { // save interface name interface->name = tb_strdup(name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } break; case IFA_LABEL: case IFA_BROADCAST: break; default: break; } } // exit name if (name && owner) tb_free(name); name = tb_null; }
tb_bool_t tb_aicp_dns_done(tb_aicp_dns_ref_t dns, tb_char_t const* host, tb_long_t timeout, tb_aicp_dns_done_func_t func, tb_cpointer_t priv) { // check tb_aicp_dns_impl_t* impl = (tb_aicp_dns_impl_t*)dns; tb_assert_and_check_return_val(impl && func && host && host[0], tb_false); // trace tb_trace_d("done: aico: %p, host: %s: ..", impl->aico, host); // init func impl->done.func = func; impl->done.priv = priv; // save host tb_strlcpy(impl->host, host, sizeof(impl->host)); // only address? ok tb_ipaddr_t addr = {0}; if (tb_ipaddr_ip_cstr_set(&addr, impl->host, TB_IPADDR_FAMILY_NONE)) { impl->done.func(dns, impl->host, &addr, impl->done.priv); return tb_true; } // try to lookup it from cache first if (tb_dns_cache_get(impl->host, &addr)) { impl->done.func(dns, impl->host, &addr, impl->done.priv); return tb_true; } // init server list if (!impl->size) impl->size = tb_dns_server_get(impl->list); tb_check_return_val(impl->size, tb_false); // get the server tb_ipaddr_ref_t server = &impl->list[impl->indx = 0]; tb_assert_and_check_return_val(!tb_ipaddr_is_empty(server), tb_false); // init reqt tb_size_t size = tb_aicp_dns_reqt_init(impl); tb_assert_and_check_return_val(size, tb_false); // init it first if no aico if (!impl->aico) { // init aico impl->aico = tb_aico_init(impl->aicp); tb_assert_and_check_return_val(impl->aico, tb_false); // open aico if (!tb_aico_open_sock_from_type(impl->aico, TB_SOCKET_TYPE_UDP, tb_ipaddr_family(server))) return tb_false; // init timeout tb_aico_timeout_set(impl->aico, TB_AICO_TIMEOUT_SEND, timeout); tb_aico_timeout_set(impl->aico, TB_AICO_TIMEOUT_RECV, timeout); } // post reqt return tb_aico_usend(impl->aico, server, impl->data, size, tb_aicp_dns_reqt_func, (tb_pointer_t)impl); }
static tb_bool_t tb_demo_spider_init(tb_demo_spider_t* spider, tb_int_t argc, tb_char_t** argv) { // check tb_assert_and_check_return_val(spider && argc && argv, tb_false); // done tb_bool_t ok = tb_false; do { #ifdef TB_CONFIG_MODULE_HAVE_OBJECT // init option spider->option = tb_option_init("spider", "the spider demo", g_options); tb_assert_and_check_break(spider->option); // done option if (!tb_option_done(spider->option, argc - 1, &argv[1])) break; // check tb_assert_and_check_break(tb_option_find(spider->option, "home")); // init home if (!tb_url_init(&spider->home)) break; tb_url_set(&spider->home, tb_option_item_cstr(spider->option, "home")); tb_trace_d("home: %s", tb_url_get(&spider->home)); // init only home? if (tb_option_find(spider->option, "only")) spider->home_only = tb_option_item_bool(spider->option, "only"); // init root tb_char_t const* root = tb_option_item_cstr(spider->option, "directory"); // init user agent spider->user_agent = tb_option_item_cstr(spider->option, "agent"); // init timeout if (tb_option_find(spider->option, "timeout")) spider->timeout = tb_option_item_sint32(spider->option, "timeout"); // init limited rate if (tb_option_find(spider->option, "rate")) spider->limited_rate = tb_option_item_uint32(spider->option, "rate"); #else // check tb_assert_and_check_break(argv[1]); // init home if (!tb_url_init(&spider->home)) break; spider->home = argv[1]? argv[1] : tb_null; tb_trace_d("home: %s", tb_url_get(&spider->home)); // init root tb_char_t const* root = argv[2]; #endif // the home host tb_char_t const* host = tb_url_host_get(&spider->home); tb_assert_and_check_break(host); // init home domain tb_char_t const* domain = tb_strchr(host, '.'); if (domain) { tb_strlcpy(spider->home_domain, domain, sizeof(spider->home_domain) - 1); spider->home_domain[sizeof(spider->home_domain) - 1] = '\0'; } // using the default root if (root) tb_strlcpy(spider->root, root, sizeof(spider->root) - 1); else { // the temporary root tb_directory_temp(spider->root, sizeof(spider->root) - 1); // append spider tb_strcat(spider->root, "/spider"); } tb_trace_d("root: %s", spider->root); // using the default user agent if (!spider->user_agent) spider->user_agent = TB_DEMO_SPIDER_USER_AGENT; // using the default timeout if (!spider->timeout) spider->timeout = TB_DEMO_SPIDER_TASK_TIMEOUT; // using the default rate if (!spider->limited_rate) spider->limited_rate = TB_DEMO_SPIDER_TASK_RATE; // strip root tail: '/' or '\\' tb_size_t size = tb_strlen(spider->root); if (size && (spider->root[size - 1] == '/' || spider->root[size - 1] == '\\')) spider->root[size - 1] = '\0'; // init state spider->state = TB_STATE_OK; // init lock if (!tb_spinlock_init(&spider->lock)) break; // init pool spider->pool = tb_fixed_pool_init(tb_null, TB_DEMO_SPIDER_TASK_MAXN >> 2, sizeof(tb_demo_spider_task_t), tb_null, tb_null, tb_null); tb_assert_and_check_break(spider->pool); // init filter spider->filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_001, 3, TB_DEMO_SPIDER_FILTER_MAXN, tb_item_func_str(tb_true)); tb_assert_and_check_break(spider->filter); // register lock profiler #ifdef TB_LOCK_PROFILER_ENABLE tb_lock_profiler_register(tb_lock_profiler(), (tb_pointer_t)&spider->lock, "spider"); #endif // ok ok = tb_true; } while (0); // failed? help it #ifdef TB_CONFIG_MODULE_HAVE_OBJECT if (!ok && spider->option) tb_option_help(spider->option); #endif // ok? return ok; }
static tb_bool_t tb_demo_spider_task_done(tb_demo_spider_t* spider, tb_char_t const* iurl, tb_bool_t* full) { // check tb_assert_and_check_return_val(spider && iurl, tb_false); // killed? tb_check_return_val(TB_STATE_OK == tb_atomic_get(&spider->state), tb_false); // only for home? if (spider->home_only && !tb_stristr(iurl, spider->home_domain)) { // trace tb_trace_d("task: done: %s: skip", iurl); return tb_true; } // enter tb_spinlock_enter(&spider->lock); // done tb_bool_t ok = tb_false; tb_size_t size = 0; tb_demo_spider_task_t* task = tb_null; tb_bool_t repeat = tb_false; do { // check tb_assert_and_check_break(spider->filter && spider->pool); // the task count size = tb_fixed_pool_size(spider->pool); // make the output url if (!tb_demo_spider_make_ourl(spider, iurl, spider->ourl, sizeof(spider->ourl) - 1)) break; // have been done already? if (!tb_bloom_filter_set(spider->filter, spider->ourl)) { // trace tb_trace_d("task: size: %lu, done: %s: repeat", size, iurl); // ok ok = tb_true; repeat = tb_true; break; } // trace tb_trace_d("task: size: %lu, done: %s: ..", size, iurl); // full? tb_check_break(size < TB_DEMO_SPIDER_TASK_MAXN); // make task task = (tb_demo_spider_task_t*)tb_fixed_pool_malloc0(spider->pool); tb_assert_and_check_break(task); // init task task->spider = spider; tb_strlcpy(task->iurl, iurl, sizeof(task->iurl) - 1); tb_strlcpy(task->ourl, spider->ourl, sizeof(task->ourl) - 1); // ok ok = tb_true; } while (0); // leave tb_spinlock_leave(&spider->lock); // ok? if (ok && !repeat) { // done ok = tb_false; do { // check tb_assert_and_check_break(task); // killed? tb_check_break(TB_STATE_OK == tb_atomic_get(&spider->state)); // repeat? if (tb_file_info(task->ourl, tb_null)) { // trace tb_trace_d("task: size: %lu, done: %s: repeat", size, iurl); // ok ok = tb_true; repeat = tb_true; break; } // done task ok = tb_transfer_pool_done(tb_transfer_pool(), task->iurl, task->ourl, 0, spider->limited_rate, tb_demo_spider_task_save, tb_demo_spider_task_ctrl, task); tb_assert_and_check_break(ok); } while (0); } // repeat or failed? if (repeat || !ok) { // exit task if (task) tb_demo_spider_task_exit(task); task = tb_null; // failed? if (!full && !ok) { // trace tb_trace_e("task: size: %lu, done: %s: post failed", size, iurl); } // save full if (full) *full = size < TB_DEMO_SPIDER_TASK_MAXN? tb_false : tb_true; } // ok? return ok; }