引言

  之前的文章已经描述wifidog大概的一个工作流程,这里我们具体说说wifidog是怎么把一个新用户重定向到认证服务器中的,它又是怎么对一个已认证的用户实行放行操作的。我们已经知道wifidog在启动时会删除iptables中mangle、nat、filter表中的所有规则,并在这三个表中添加wifidog自己的规则,其规则简单来说就是将网关80端口重定向到指定端口(默认为2060),禁止非认证用户连接外网(除认证服务器外)。当有新用户连接路由器上网时,wifidog会通过监听2060端口获取新用户的http报文,通过报文即可知道报文是否携带token进行认证,如果没有token,wifidog会返回一个重定向的http报文给新用户,用户则会跳转到认证服务器进行认证,当认证成功后,认真服务器又会对用户重定向到网关,并在重定向报文中添加关键路径"/wifidog/auth"和token,wifidog重新获取到用户的http报文,检测到包含关键路径"/wifidog/auth"后,会通过认证服务器验证token是否有效,有效则修改iptables放行此客户端。

main_loop

  此函数几乎相当于我们写程序的main函数,主要功能都是在这里面实现的,函数主要实现了主循环,并启动了三个线程,这三个线程的功能具体见wifidog源码分析 - wifidog原理,在此函数最后主循环中会等待用户连接,新用户只要通过浏览器打开非认证服务器网页时主循环就会监听到,监听到后会启动一个处理线程。其流程为

  • 设置程序启动时间
  • 获取网关信息
  • 绑定http端口(80重定向到了2060)
  • 设置关键路径和404错误的回调函数
  • 重新建立iptables规则
  • 启动客户端检测线程 (稍后文章分析)
  • 启动wdctrl交互线程 (稍后文章分析)
  • 认证服务器心跳检测线程 (稍后文章分析)
  • 循环等待用户http请求,为每个请求启动一个处理线程。(代码片段1.2 代码片段1.3 代码片段1.4

  代码片段1.1

  1. static void
  2. main_loop(void)
  3. {
  4. int result;
  5. pthread_t tid;
  6. s_config *config = config_get_config();
  7. request *r;
  8. void **params;
  9.  
  10. /* 设置启动时间 */
  11. if (!started_time) {
  12. debug(LOG_INFO, "Setting started_time");
  13. started_time = time(NULL);
  14. }
  15. else if (started_time < MINIMUM_STARTED_TIME) {
  16. debug(LOG_WARNING, "Detected possible clock skew - re-setting started_time");
  17. started_time = time(NULL);
  18. }
  19.  
  20. /* 获取网关IP,失败退出程序 */
  21. if (!config->gw_address) {
  22. debug(LOG_DEBUG, "Finding IP address of %s", config->gw_interface);
  23. if ((config->gw_address = get_iface_ip(config->gw_interface)) == NULL) {
  24. debug(LOG_ERR, "Could not get IP address information of %s, exiting...", config->gw_interface);
  25. exit();
  26. }
  27. debug(LOG_DEBUG, "%s = %s", config->gw_interface, config->gw_address);
  28. }
  29.  
  30. /* 获取网关ID,失败退出程序 */
  31. if (!config->gw_id) {
  32. debug(LOG_DEBUG, "Finding MAC address of %s", config->gw_interface);
  33. if ((config->gw_id = get_iface_mac(config->gw_interface)) == NULL) {
  34. debug(LOG_ERR, "Could not get MAC address information of %s, exiting...", config->gw_interface);
  35. exit();
  36. }
  37. debug(LOG_DEBUG, "%s = %s", config->gw_interface, config->gw_id);
  38. }
  39.  
  40. /* 初始化监听网关2060端口的socket */
  41. debug(LOG_NOTICE, "Creating web server on %s:%d", config->gw_address, config->gw_port);
  42.  
  43. if ((webserver = httpdCreate(config->gw_address, config->gw_port)) == NULL) {
  44. debug(LOG_ERR, "Could not create web server: %s", strerror(errno));
  45. exit();
  46. }
  47.  
  48. debug(LOG_DEBUG, "Assigning callbacks to web server");
  49. /* 设置关键路径及其回调函数,在代码片段1.2中会使用到 */
  50. httpdAddCContent(webserver, "/", "wifidog", , NULL, http_callback_wifidog);
  51. httpdAddCContent(webserver, "/wifidog", "", , NULL, http_callback_wifidog);
  52. httpdAddCContent(webserver, "/wifidog", "about", , NULL, http_callback_about);
  53. httpdAddCContent(webserver, "/wifidog", "status", , NULL, http_callback_status);
  54. httpdAddCContent(webserver, "/wifidog", "auth", , NULL, http_callback_auth);
  55. /* 设置404错误回调函数,在里面实现了重定向至认证服务器 */
  56. httpdAddC404Content(webserver, http_callback_404);
  57.  
  58. /* 清除iptables规则 */
  59. fw_destroy();
  60. /* 重新设置iptables规则 */
  61. if (!fw_init()) {
  62. debug(LOG_ERR, "FATAL: Failed to initialize firewall");
  63. exit();
  64. }
  65.  
  66. /* 客户端检测线程 */
  67. result = pthread_create(&tid_fw_counter, NULL, (void *)thread_client_timeout_check, NULL);
  68. if (result != ) {
  69. debug(LOG_ERR, "FATAL: Failed to create a new thread (fw_counter) - exiting");
  70. termination_handler();
  71. }
  72. pthread_detach(tid_fw_counter);
  73.  
  74. /* wdctrl交互线程 */
  75. result = pthread_create(&tid, NULL, (void *)thread_wdctl, (void *)safe_strdup(config->wdctl_sock));
  76. if (result != ) {
  77. debug(LOG_ERR, "FATAL: Failed to create a new thread (wdctl) - exiting");
  78. termination_handler();
  79. }
  80. pthread_detach(tid);
  81.  
  82. /* 认证服务器心跳检测线程 */
  83. result = pthread_create(&tid_ping, NULL, (void *)thread_ping, NULL);
  84. if (result != ) {
  85. debug(LOG_ERR, "FATAL: Failed to create a new thread (ping) - exiting");
  86. termination_handler();
  87. }
  88. pthread_detach(tid_ping);
  89.  
  90. debug(LOG_NOTICE, "Waiting for connections");
  91. while() {
  92. /* 监听2060端口等待用户http请求 */
  93. r = httpdGetConnection(webserver, NULL);
  94.  
  95. /* 错误处理 */
  96. if (webserver->lastError == -) {
  97. /* Interrupted system call */
  98. continue; /* restart loop */
  99. }
  100. else if (webserver->lastError < -) {
  101. debug(LOG_ERR, "FATAL: httpdGetConnection returned unexpected value %d, exiting.", webserver->lastError);
  102. termination_handler();
  103. }
  104. else if (r != NULL) {
  105. /* 用户http请求接收成功 */
  106. debug(LOG_INFO, "Received connection from %s, spawning worker thread", r->clientAddr);
  107. params = safe_malloc( * sizeof(void *));
  108. *params = webserver;
  109. *(params + ) = r;
  110.  
  111. /* 开启http请求处理线程 */
  112. result = pthread_create(&tid, NULL, (void *)thread_httpd, (void *)params);
  113. if (result != ) {
  114. debug(LOG_ERR, "FATAL: Failed to create a new thread (httpd) - exiting");
  115. termination_handler();
  116. }
  117. pthread_detach(tid);
  118. }
  119. else {
  120. ;
  121. }
  122. }
  123.  
  124. /* never reached */
  125. }

用户连接启动线程(void thread_httpd(void * args))

代码片段1.2

此段代码是当有新用户(未认证的用户 代码片段1.3,已在认证服务器上认证但没有在wifidog认证的用户 代码片段1.4)连接时创建的线程,其主要功能为

  • 获取用户浏览器发送过来的http报头
  • 分析http报头,分析是否包含关键路径
  • 不包含关键路径则调用404回调函数
  • 包含关键路径则执行关键路径回调函数(这里主要讲解"/wifidog/auth"路径)
  1. void
  2. thread_httpd(void *args)
  3. {
  4. void **params;
  5. httpd *webserver;
  6. request *r;
  7.  
  8. params = (void **)args;
  9. webserver = *params;
  10. r = *(params + );
  11. free(params);
  12.  
  13. /* 获取http报文 */
  14. if (httpdReadRequest(webserver, r) == ) {
  15. debug(LOG_DEBUG, "Processing request from %s", r->clientAddr);
  16. debug(LOG_DEBUG, "Calling httpdProcessRequest() for %s", r->clientAddr);
  17. /* 分析http报文 */
  18. httpdProcessRequest(webserver, r);
  19. debug(LOG_DEBUG, "Returned from httpdProcessRequest() for %s", r->clientAddr);
  20. }
  21. else {
  22. debug(LOG_DEBUG, "No valid request received from %s", r->clientAddr);
  23. }
  24. debug(LOG_DEBUG, "Closing connection with %s", r->clientAddr);
  25. httpdEndRequest(r);
  26. }
  27.  
  28. /* 被thread_httpd调用 */
  29. void httpdProcessRequest(httpd *server, request *r)
  30. {
  31. char dirName[HTTP_MAX_URL],
  32. entryName[HTTP_MAX_URL],
  33. *cp;
  34. httpDir *dir;
  35. httpContent *entry;
  36.  
  37. r->response.responseLength = ;
  38. strncpy(dirName, httpdRequestPath(r), HTTP_MAX_URL);
  39. dirName[HTTP_MAX_URL-]=;
  40. cp = rindex(dirName, '/');
  41. if (cp == NULL)
  42. {
  43. printf("Invalid request path '%s'\n",dirName);
  44. return;
  45. }
  46. strncpy(entryName, cp + , HTTP_MAX_URL);
  47. entryName[HTTP_MAX_URL-]=;
  48. if (cp != dirName)
  49. *cp = ;
  50. else
  51. *(cp+) = ;
  52.  
  53. /* 获取http报文中的关键路径,在main_loop中已经设置 */
  54. dir = _httpd_findContentDir(server, dirName, HTTP_FALSE);
  55. if (dir == NULL)
  56. {
  57. /* http报文中未包含关键路径,执行404回调函数(在404回调函数中新用户被重定向到认证服务器),见代码片段1.3 */
  58. _httpd_send404(server, r);
  59. _httpd_writeAccessLog(server, r);
  60. return;
  61. }
  62. /* 获取关键路径内容描述符 */
  63. entry = _httpd_findContentEntry(r, dir, entryName);
  64. if (entry == NULL)
  65. {
  66. _httpd_send404(server, r);
  67. _httpd_writeAccessLog(server, r);
  68. return;
  69. }
  70. if (entry->preload)
  71. {
  72. if ((entry->preload)(server) < )
  73. {
  74. _httpd_writeAccessLog(server, r);
  75. return;
  76. }
  77. }
  78. switch(entry->type)
  79. {
  80. case HTTP_C_FUNCT:
  81. case HTTP_C_WILDCARD:
  82. /* 如果是被认证服务器重定向到网关的用户,此处的关键路径为"/wifidog/auth",并执行回调函数 */
  83. (entry->function)(server, r);
  84. break;
  85.  
  86. case HTTP_STATIC:
  87. _httpd_sendStatic(server, r, entry->data);
  88. break;
  89.  
  90. case HTTP_FILE:
  91. _httpd_sendFile(server, r, entry->path);
  92. break;
  93.  
  94. case HTTP_WILDCARD:
  95. if (_httpd_sendDirectoryEntry(server, r, entry,
  96. entryName)<)
  97. {
  98. _httpd_send404(server, r);
  99. }
  100. break;
  101. }
  102. _httpd_writeAccessLog(server, r);
  103. }

代码片段1.3

此段代码表示wifidog是如何通过http 404回调函数实现客户端重定向了,实际上就是在404回调函数中封装了一个307状态的http报头,http的307状态在http协议中就是用于重定向的,封装完成后通过已经与客户端连接的socket返回给客户端。步骤流程为

  • 判断本机是否处于离线状态
  • 判断认证服务器是否在线
  • 封装http 307报文
  • 发送于目标客户端
  1. void
  2. http_callback_404(httpd *webserver, request *r)
  3. {
  4. char tmp_url[MAX_BUF],
  5. *url;
  6. s_config *config = config_get_config();
  7. t_auth_serv *auth_server = get_auth_server();
  8.  
  9. memset(tmp_url, , sizeof(tmp_url));
  10.  
  11. snprintf(tmp_url, (sizeof(tmp_url) - ), "http://%s%s%s%s",
  12. r->request.host,
  13. r->request.path,
  14. r->request.query[] ? "?" : "",
  15. r->request.query);
  16. url = httpdUrlEncode(tmp_url);
  17.  
  18. if (!is_online()) {
  19. /* 本机处于离线状态,此函数调用结果由认证服务器检测线程设置 */
  20. char * buf;
  21. safe_asprintf(&buf,
  22. "<p>We apologize, but it seems that the internet connection that powers this hotspot is temporarily unavailable.</p>"
  23. "<p>If at all possible, please notify the owners of this hotspot that the internet connection is out of service.</p>"
  24. "<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>"
  25. "<p>In a while please <a href='%s'>click here</a> to try your request again.</p>", tmp_url);
  26.  
  27. send_http_page(r, "Uh oh! Internet access unavailable!", buf);
  28. free(buf);
  29. debug(LOG_INFO, "Sent %s an apology since I am not online - no point sending them to auth server", r->clientAddr);
  30. }
  31. else if (!is_auth_online()) {
  32. /* 认证服务器处于离线状态 */
  33. char * buf;
  34. safe_asprintf(&buf,
  35. "<p>We apologize, but it seems that we are currently unable to re-direct you to the login screen.</p>"
  36. "<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>"
  37. "<p>In a couple of minutes please <a href='%s'>click here</a> to try your request again.</p>", tmp_url);
  38.  
  39. send_http_page(r, "Uh oh! Login screen unavailable!", buf);
  40. free(buf);
  41. debug(LOG_INFO, "Sent %s an apology since auth server not online - no point sending them to auth server", r->clientAddr);
  42. }
  43. else {
  44. /* 本机与认证服务器都在线,返回重定向包于客户端 */
  45. char *urlFragment;
  46. safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&url=%s",
  47. auth_server->authserv_login_script_path_fragment,
  48. config->gw_address,
  49. config->gw_port,
  50. config->gw_id,
  51. url);
  52. debug(LOG_INFO, "Captured %s requesting [%s] and re-directing them to login page", r->clientAddr, url);
  53. http_send_redirect_to_auth(r, urlFragment, "Redirect to login page"); /* 实际上此函数中通过socket返回一个307状态的http报头给客户端,里面包含有认证服务器地址 */
  54. free(urlFragment);
  55. }
  56. free(url);
  57. }

代码片段1.4

此段表明当客户端已经在认证服务器确认登陆,认证服务器将客户端重新重定向回网关,并在重定向包中包含关键路径"/wifidog/auth"和token,认证服务器所执行的操作。

  1. void
  2. http_callback_auth(httpd *webserver, request *r)
  3. {
  4. t_client *client;
  5. httpVar * token;
  6. char *mac;
  7. /* 判断http报文是否包含登出logout */
  8. httpVar *logout = httpdGetVariableByName(r, "logout");
  9. if ((token = httpdGetVariableByName(r, "token"))) {
  10. /* 获取http报文中的token */
  11. if (!(mac = arp_get(r->clientAddr))) {
  12. /* 获取客户端mac地址失败 */
  13. debug(LOG_ERR, "Failed to retrieve MAC address for ip %s", r->clientAddr);
  14. send_http_page(r, "WiFiDog Error", "Failed to retrieve your MAC address");
  15. } else {
  16. LOCK_CLIENT_LIST();
  17. /* 判断客户端是否存在于列表中 */
  18. if ((client = client_list_find(r->clientAddr, mac)) == NULL) {
  19. debug(LOG_DEBUG, "New client for %s", r->clientAddr);
  20. /* 将此客户端添加到客户端列表 */
  21. client_list_append(r->clientAddr, mac, token->value);
  22. } else if (logout) {
  23. /* http报文为登出 */
  24. t_authresponse authresponse;
  25. s_config *config = config_get_config();
  26. unsigned long long incoming = client->counters.incoming;
  27. unsigned long long outgoing = client->counters.outgoing;
  28. char *ip = safe_strdup(client->ip);
  29. char *urlFragment = NULL;
  30. t_auth_serv *auth_server = get_auth_server();
  31. /* 修改iptables禁止客户端访问外网 */
  32. fw_deny(client->ip, client->mac, client->fw_connection_state);
  33. /* 从客户端列表中删除此客户端 */
  34. client_list_delete(client);
  35. debug(LOG_DEBUG, "Got logout from %s", client->ip);
  36.  
  37. if (config->auth_servers != NULL) {
  38. UNLOCK_CLIENT_LIST();
  39. /* 发送登出认证包给认证服务器 */
  40. auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token->value,
  41. incoming, outgoing);
  42. LOCK_CLIENT_LIST();
  43.  
  44. /* 将客户端重定向到认证服务器 */
  45. debug(LOG_INFO, "Got manual logout from client ip %s, mac %s, token %s"
  46. "- redirecting them to logout message", client->ip, client->mac, client->token);
  47. safe_asprintf(&urlFragment, "%smessage=%s",
  48. auth_server->authserv_msg_script_path_fragment,
  49. GATEWAY_MESSAGE_ACCOUNT_LOGGED_OUT
  50. );
  51. http_send_redirect_to_auth(r, urlFragment, "Redirect to logout message");
  52. free(urlFragment);
  53. }
  54. free(ip);
  55. }
  56. else {
  57. debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip);
  58. }
  59. UNLOCK_CLIENT_LIST();
  60. if (!logout) {
  61. /* 通过认证服务器认证此客户端token */
  62. authenticate_client(r);
  63. }
  64. free(mac);
  65. }
  66. } else {
  67. send_http_page(r, "WiFiDog error", "Invalid token");
  68. }
  69. }
  70.  
  71. /* 此函数用于提交token到认证服务器进行认证 */
  72. void
  73. authenticate_client(request *r)
  74. {
  75. t_client *client;
  76. t_authresponse auth_response;
  77. char *mac,
  78. *token;
  79. char *urlFragment = NULL;
  80. s_config *config = NULL;
  81. t_auth_serv *auth_server = NULL;
  82.  
  83. LOCK_CLIENT_LIST();
  84.  
  85. client = client_list_find_by_ip(r->clientAddr);
  86. /* 判断此客户端是否在列表中 */
  87. if (client == NULL) {
  88. debug(LOG_ERR, "Could not find client for %s", r->clientAddr);
  89. UNLOCK_CLIENT_LIST();
  90. return;
  91. }
  92.  
  93. mac = safe_strdup(client->mac);
  94. token = safe_strdup(client->token);
  95.  
  96. UNLOCK_CLIENT_LIST();
  97.  
  98. /* 提交token、客户端ip、客户端mac至认证服务器 */
  99. auth_server_request(&auth_response, REQUEST_TYPE_LOGIN, r->clientAddr, mac, token, , );
  100.  
  101. LOCK_CLIENT_LIST();
  102.  
  103. /*再次判断客户端是否存在于列表中,保险起见,因为有可能在于认证服务器认证过程中,客户端检测线程把此客户端下线 */
  104. client = client_list_find(r->clientAddr, mac);
  105.  
  106. if (client == NULL) {
  107. debug(LOG_ERR, "Could not find client node for %s (%s)", r->clientAddr, mac);
  108. UNLOCK_CLIENT_LIST();
  109. free(token);
  110. free(mac);
  111. return;
  112. }
  113.  
  114. free(token);
  115. free(mac);
  116.  
  117. config = config_get_config();
  118. auth_server = get_auth_server();
  119.  
  120. /* 判断认证服务器认证结果 */
  121. switch(auth_response.authcode) {
  122.  
  123. case AUTH_ERROR:
  124. /* 认证错误 */
  125. debug(LOG_ERR, "Got %d from central server authenticating token %s from %s at %s", auth_response, client->token, client->ip, client->mac);
  126. send_http_page(r, "Error!", "Error: We did not get a valid answer from the central server");
  127. break;
  128.  
  129. case AUTH_DENIED:
  130. /* 认证服务器拒绝此客户端 */
  131. debug(LOG_INFO, "Got DENIED from central server authenticating token %s from %s at %s - redirecting them to denied message", client->token, client->ip, client->mac);
  132. safe_asprintf(&urlFragment, "%smessage=%s",
  133. auth_server->authserv_msg_script_path_fragment,
  134. GATEWAY_MESSAGE_DENIED
  135. );
  136. http_send_redirect_to_auth(r, urlFragment, "Redirect to denied message");
  137. free(urlFragment);
  138. break;
  139.  
  140. case AUTH_VALIDATION:
  141. /* 认证服务器处于等待此客户端电子邮件确认回执状态 */
  142. debug(LOG_INFO, "Got VALIDATION from central server authenticating token %s from %s at %s"
  143. "- adding to firewall and redirecting them to activate message", client->token,
  144. client->ip, client->mac);
  145. client->fw_connection_state = FW_MARK_PROBATION;
  146. fw_allow(client->ip, client->mac, FW_MARK_PROBATION);
  147. safe_asprintf(&urlFragment, "%smessage=%s",
  148. auth_server->authserv_msg_script_path_fragment,
  149. GATEWAY_MESSAGE_ACTIVATE_ACCOUNT
  150. );
  151. http_send_redirect_to_auth(r, urlFragment, "Redirect to activate message");
  152. free(urlFragment);
  153. break;
  154.  
  155. case AUTH_ALLOWED:
  156. /* 认证通过 */
  157. debug(LOG_INFO, "Got ALLOWED from central server authenticating token %s from %s at %s - "
  158. "adding to firewall and redirecting them to portal", client->token, client->ip, client->mac);
  159. client->fw_connection_state = FW_MARK_KNOWN;
  160. fw_allow(client->ip, client->mac, FW_MARK_KNOWN);
  161. served_this_session++;
  162. safe_asprintf(&urlFragment, "%sgw_id=%s",
  163. auth_server->authserv_portal_script_path_fragment,
  164. config->gw_id
  165. );
  166. http_send_redirect_to_auth(r, urlFragment, "Redirect to portal");
  167. free(urlFragment);
  168. break;
  169.  
  170. case AUTH_VALIDATION_FAILED:
  171. /* 电子邮件确认回执超时 */
  172. debug(LOG_INFO, "Got VALIDATION_FAILED from central server authenticating token %s from %s at %s "
  173. "- redirecting them to failed_validation message", client->token, client->ip, client->mac);
  174. safe_asprintf(&urlFragment, "%smessage=%s",
  175. auth_server->authserv_msg_script_path_fragment,
  176. GATEWAY_MESSAGE_ACCOUNT_VALIDATION_FAILED
  177. );
  178. http_send_redirect_to_auth(r, urlFragment, "Redirect to failed validation message");
  179. free(urlFragment);
  180. break;
  181.  
  182. default:
  183. debug(LOG_WARNING, "I don't know what the validation code %d means for token %s from %s at %s - sending error message", auth_response.authcode, client->token, client->ip, client->mac);
  184. send_http_page(r, "Internal Error", "We can not validate your request at this time");
  185. break;
  186.  
  187. }
  188.  
  189. UNLOCK_CLIENT_LIST();
  190. return;
  191. }

wifidog源码分析 - 用户连接过程的更多相关文章

  1. Dubbo 源码分析 - 服务调用过程

    注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...

  2. wifidog源码分析 - wifidog原理 tiger

    转:http://www.cnblogs.com/tolimit/p/4223644.html wifidog源码分析 - wifidog原理 wifidog是一个用于配合认证服务器实现无线网页认证功 ...

  3. SOFA 源码分析 —— 服务引用过程

    前言 在前面的 SOFA 源码分析 -- 服务发布过程 文章中,我们分析了 SOFA 的服务发布过程,一个完整的 RPC 除了发布服务,当然还需要引用服务. So,今天就一起来看看 SOFA 是如何引 ...

  4. MyBatis 源码分析 - 配置文件解析过程

    * 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...

  5. v79.01 鸿蒙内核源码分析(用户态锁篇) | 如何使用快锁Futex(上) | 百篇博客分析OpenHarmony源码

    百篇博客分析|本篇为:(用户态锁篇) | 如何使用快锁Futex(上) 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) ...

  6. 源码分析HotSpot GC过程(一)

    «上一篇:源码分析HotSpot GC过程(一)»下一篇:源码分析HotSpot GC过程(三):TenuredGeneration的GC过程 https://blogs.msdn.microsoft ...

  7. 源码分析HotSpot GC过程(三):TenuredGeneration的GC过程

    老年代TenuredGeneration所使用的垃圾回收算法是标记-压缩-清理算法.在回收阶段,将标记对象越过堆的空闲区移动到堆的另一端,所有被移动的对象的引用也会被更新指向新的位置.看起来像是把杂陈 ...

  8. 内核通信之Netlink源码分析-用户内核通信原理2

    2017-07-05 上文以一个简单的案例描述了通过Netlink进行用户.内核通信的流程,本节针对流程中的各个要点进行深入分析 sock的创建 sock管理结构 sendmsg源码分析  sock的 ...

  9. SOFA 源码分析 —— 服务发布过程

    前言 SOFA 包含了 RPC 框架,底层通信框架是 bolt ,基于 Netty 4,今天将通过 SOFA-RPC 源码中的例子,看看他是如何发布一个服务的. 示例代码 下面的代码在 com.ali ...

随机推荐

  1. Python input()

    在Python语言中,我们经常需要与用户实现交互,下面是一个小实例 # -*- coding:UTF-8 -*- #获取输入参数,并将输入的值存储到txt文件中 String1 = input(&qu ...

  2. String.split()方法你可能不知道的一面

    一.问题 java中String的split()是我们经常使用的方法,用来按照特定字符分割字符串,那么我们看以下一段代码: public void splitTest() { String str = ...

  3. supplicant

    概述 wpa_supplicant是wifi客户端(client)加密认证工具,和iwconfig不同,wpa_supplicant支持wep.wpa.wpa2等完整的加密认证,而iwconfig只能 ...

  4. iOS学习之UI自定义cell

    一.自定义Cell 为什么需要自定义cell:系统提供的cell满足不了复杂的样式,因此:自定义Cell和自定义视图一样,自己创建一种符合我们需求的Cell并使用这个Cell.如下图所示的这些Cell ...

  5. Client–server model

    Client–server model From Wikipedia, the free encyclopedia The client–server model of computing ] Oft ...

  6. 失败的数据库迁移UDB

    公司采用的是ucloud的云主机,数据库也是架设在云主机上.由于数据越来越多数据查询数据越来越慢,所以我决定往 UDB上迁移.当时考虑的理由如下: (1)云主机底层架设在虚拟机上IO性能有折损,而UD ...

  7. 如何在Quartus II中设置Virtual pin

    为了验证FPGA工程中的某个模块的功能和时序的正确性,常常需要对其单独进行验证,但是这些模块通常都与内部的众多信号相连(如系统总线,中断信号线等),往往一个模块的对外接口引脚会多达几百个,对其单独仿真 ...

  8. SQL Server2008 无法连接到 local

    以下这种情况: 第一步:检查是否选择的数据库引擎,然后实例名字是否正确,直接写的(local)或者打的"."号.换成电脑的计算机名字或者IP. 第二步:SQLserver配置远程连 ...

  9. C++中的链表节点用模板类和用普通类来实现的区别

    C++中的链表节点通常情况下类型都是一致的.因此我们可以用模板来实现. #include <iostream> using namespace std; template<typen ...

  10. “我爱淘”冲刺阶段Scrum站立会议4

    完成任务: 完成了搜索界面的Activity的编写. 计划任务: 实现数据库的链接,用户可以查到自己需要的书籍的信息. 遇到问题: 数据库的操作,实现查询功能: