/* Helper function called by connect_auth_server() to do the actual work including recursion * DO NOT CALL DIRECTLY @param level recursion level indicator must be 0 when not called by _connect_auth_server() */ int _connect_auth_server(int level) { s_config *config = config_get_config(); t_auth_serv *auth_server = NULL; t_popular_server *popular_server = NULL; struct in_addr *h_addr; int num_servers = 0; char *hostname = NULL; char *ip; struct sockaddr_in their_addr; int sockfd; /* If there are no auth servers, error out, from scan-build warning. */ if (NULL == config->auth_servers) { return (-1); } /* XXX level starts out at 0 and gets incremented by every iterations. */ level++; /* * Let's calculate the number of servers we have */ for (auth_server = config->auth_servers; auth_server; auth_server = auth_server->next) { num_servers++; } debug(LOG_DEBUG, "Level %d: Calculated %d auth servers in list", level, num_servers); if (level > num_servers) { /* * We've called ourselves too many times * This means we've cycled through all the servers in the server list * at least once and none are accessible */ return (-1); } /* * Let's resolve the hostname of the top server to an IP address */ auth_server = config->auth_servers; hostname = auth_server->authserv_hostname; debug(LOG_DEBUG, "Level %d: Resolving auth server [%s]", level, hostname); h_addr = wd_gethostbyname(hostname); if (!h_addr) { /* * DNS resolving it failed */ debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] failed", level, hostname); for (popular_server = config->popular_servers; popular_server; popular_server = popular_server->next) { debug(LOG_DEBUG, "Level %d: Resolving popular server [%s]", level, popular_server->hostname); h_addr = wd_gethostbyname(popular_server->hostname); if (h_addr) { debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] succeeded = [%s]", level, popular_server->hostname, inet_ntoa(*h_addr)); break; } else { debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] failed", level, popular_server->hostname); } } /* * If we got any h_addr buffer for one of the popular servers, in other * words, if one of the popular servers resolved, we'll assume the DNS * works, otherwise we'll deal with net connection or DNS failure. */ if (h_addr) { free(h_addr); /* * Yes * * The auth server's DNS server is probably dead. Try the next auth server */ debug(LOG_DEBUG, "Level %d: Marking auth server [%s] as bad and trying next if possible", level, hostname); if (auth_server->last_ip) { free(auth_server->last_ip); auth_server->last_ip = NULL; } mark_auth_server_bad(auth_server); return _connect_auth_server(level); } else { /* * No * * It's probably safe to assume that the internet connection is malfunctioning * and nothing we can do will make it work */ mark_offline(); debug(LOG_DEBUG, "Level %d: Failed to resolve auth server and all popular servers. " "The internet connection is probably down", level); return (-1); } } else { /* * DNS resolving was successful */ mark_online(); ip = safe_malloc(HTTP_IP_ADDR_LEN); inet_ntop(AF_INET, h_addr, ip, HTTP_IP_ADDR_LEN); ip[HTTP_IP_ADDR_LEN-1] = '\0'; debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] succeeded = [%s]", level, hostname, ip); if (!auth_server->last_ip || strcmp(auth_server->last_ip, ip) != 0) { /* * But the IP address is different from the last one we knew * Update it */ debug(LOG_DEBUG, "Level %d: Updating last_ip IP of server [%s] to [%s]", level, hostname, ip); if (auth_server->last_ip) free(auth_server->last_ip); auth_server->last_ip = ip; /* Update firewall rules */ fw_clear_authservers(); fw_set_authservers(); } else { /* * IP is the same as last time */ free(ip); } /* * Connect to it */ int port = 0; #ifdef USE_CYASSL if (auth_server->authserv_use_ssl) { debug(LOG_DEBUG, "Level %d: Connecting to SSL auth server %s:%d", level, hostname, auth_server->authserv_ssl_port); port = htons(auth_server->authserv_ssl_port); } else { debug(LOG_DEBUG, "Level %d: Connecting to auth server %s:%d", level, hostname, auth_server->authserv_http_port); port = htons(auth_server->authserv_http_port); } #endif #ifndef USE_CYASSL debug(LOG_DEBUG, "Level %d: Connecting to auth server %s:%d", level, hostname, auth_server->authserv_http_port); port = htons(auth_server->authserv_http_port); #endif their_addr.sin_port = port; their_addr.sin_family = AF_INET; their_addr.sin_addr = *h_addr; memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero)); free(h_addr); if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { debug(LOG_ERR, "Level %d: Failed to create a new SOCK_STREAM socket: %s", strerror(errno)); return (-1); } if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) { /* * Failed to connect * Mark the server as bad and try the next one */ debug(LOG_DEBUG, "Level %d: Failed to connect to auth server %s:%d (%s). Marking it as bad and trying next if possible", level, hostname, ntohs(port), strerror(errno)); close(sockfd); mark_auth_server_bad(auth_server); return _connect_auth_server(level); /* Yay recursion! */ } else { /* * We have successfully connected */ debug(LOG_DEBUG, "Level %d: Successfully connected to auth server %s:%d", level, hostname, ntohs(port)); return sockfd; } } }
/* Helper function called by connect_auth_server() to do the actual work including recursion * DO NOT CALL DIRECTLY @param level recursion level indicator must be 0 when not called by _connect_auth_server() @param type connect type authserver or centralserver */ int _connect_auth_server(int level,int type) { s_config *config = config_get_config(); t_auth_serv *auth_server = NULL; struct in_addr *h_addr; int num_servers = 0; char * hostname = NULL; char * popular_servers[] = { "www.google.com", "www.yahoo.com", NULL }; char ** popularserver; char * ip; struct sockaddr_in their_addr; int sockfd; /* XXX level starts out at 0 and gets incremented by every iterations. */ level++; /* * Let's calculate the number of servers we have */ for (auth_server = config->auth_servers; auth_server; auth_server = auth_server->next) { num_servers++; } debug(LOG_DEBUG, "Level %d: Calculated %d auth servers in list", level, num_servers); if (level > num_servers) { /* * We've called ourselves too many times * This means we've cycled through all the servers in the server list * at least once and none are accessible */ return (-1); } /* * Let's resolve the hostname of the top server to an IP address */ int auth_i = 1; auth_server = config->auth_servers; while(auth_i < level) { auth_server = auth_server->next; ++auth_i; } if(type==0) hostname = auth_server->authserv_hostname; else hostname = auth_server->central_server; debug(LOG_DEBUG, "Level %d: Resolving auth server [%s]", level, hostname); h_addr = wd_gethostbyname(hostname); if (!h_addr) { /* * DNS resolving it failed * * Can we resolve any of the popular servers ? */ debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] failed", level, hostname); for (popularserver = popular_servers; *popularserver; popularserver++) { debug(LOG_DEBUG, "Level %d: Resolving popular server [%s]", level, *popularserver); h_addr = wd_gethostbyname(*popularserver); if (h_addr) { debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] succeeded = [%s]", level, *popularserver, inet_ntoa(*h_addr)); break; } else { debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] failed", level, *popularserver); } } /* * If we got any h_addr buffer for one of the popular servers, in other * words, if one of the popular servers resolved, we'll assume the DNS * works, otherwise we'll deal with net connection or DNS failure. */ if (h_addr) { free (h_addr); /* * Yes * * The auth server's DNS server is probably dead. Try the next auth server */ debug(LOG_DEBUG, "Level %d: Marking auth server [%s] as bad and trying next if possible", level, hostname); if (auth_server->last_ip) { free(auth_server->last_ip); auth_server->last_ip = NULL; } mark_auth_server_bad(auth_server); return _connect_auth_server(level,type); } else { /* * No * * It's probably safe to assume that the internet connection is malfunctioning * and nothing we can do will make it work */ mark_offline(); debug(LOG_DEBUG, "Level %d: Failed to resolve auth server and all popular servers. " "The internet connection is probably down", level); return(-1); } } else { /* * DNS resolving was successful */ ip = safe_strdup(inet_ntoa(*h_addr)); debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] succeeded = [%s]", level, hostname, ip); if (!auth_server->last_ip || strcmp(auth_server->last_ip, ip) != 0) { /* * But the IP address is different from the last one we knew * Update it */ debug(LOG_DEBUG, "Level %d: Updating last_ip IP of server [%s] to [%s]", level, hostname, ip); if (auth_server->last_ip) free(auth_server->last_ip); auth_server->last_ip = ip; /* Update firewall rules */ fw_clear_authservers(); fw_set_authservers(); } else { /* * IP is the same as last time */ free(ip); } /* * Connect to it */ debug(LOG_DEBUG, "Level %d: Connecting to auth server %s:%d", level, hostname, auth_server->authserv_http_port); their_addr.sin_family = AF_INET; their_addr.sin_port = htons(auth_server->authserv_http_port); their_addr.sin_addr = *h_addr; memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero)); free (h_addr); if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { debug(LOG_ERR, "Level %d: Failed to create a new SOCK_STREAM socket: %s", strerror(errno)); return(-1); } struct timeval auth_server_timeout; auth_server_timeout.tv_sec = 5; //设置5秒 auth_server_timeout.tv_usec = 0; setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &auth_server_timeout, sizeof(auth_server_timeout)); //connect time out if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) { /* * Failed to connect * Mark the server as bad and try the next one */ debug(LOG_DEBUG, "Level %d: Failed to connect to auth server %s:%d (%s). Marking it as bad and trying next if possible", level, hostname, auth_server->authserv_http_port, strerror(errno)); close(sockfd); mark_auth_server_bad(auth_server); return _connect_auth_server(level,type); /* Yay recursion! */ } else { /* * We have successfully connected */ debug(LOG_DEBUG, "Level %d: Successfully connected to auth server %s:%d", level, hostname, auth_server->authserv_http_port); auth_server->inuse = 1; return sockfd; } } }
int _connect_auth_server(int level) { s_config *config = config_get_config(); t_auth_serv *auth_server = NULL; struct in_addr *h_addr; int num_servers = 0; int retry = 0; char * hostname = NULL; char ** popularserver; char * ip; char history_ip[16]; struct sockaddr_in their_addr; int sockfd; FILE *fh; level++; for (auth_server = config->auth_servers; auth_server; auth_server = auth_server->next) { num_servers++; } debug(LOG_DEBUG, "Level %d: Calculated %d auth servers in list", level, num_servers); if (level > num_servers) { if ((fh = fopen(TMP_HISTORY_PATH, "r"))) { fscanf(fh, "%s", history_ip); fclose(fh); debug(LOG_INFO, "Connecting to history ip %s", history_ip); } if(config->auth_servers->authserv_hostname) { free(config->auth_servers->authserv_hostname); } config->auth_servers->authserv_hostname = safe_strdup(history_ip); //return (-1); } auth_server = config->auth_servers; hostname = auth_server->authserv_hostname; debug(LOG_DEBUG, "Level %d: Resolving auth server [%s]", level, hostname); h_addr = wd_gethostbyname(hostname); if (!h_addr) { for(retry = 0; retry <= 5 && !h_addr; retry++) { debug(LOG_ERR, "Level %d: try %d: Resolving auth server [%s] failes,wait 1 min try again", level, retry, hostname); sleep(60); h_addr = wd_gethostbyname(hostname); } } if (!h_addr) { /* * DNS resolving it failed * * Can we resolve any of the popular servers ? */ debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] failed", level, hostname); /* * Yes * * The auth server's DNS server is probably dead. Try the next auth server */ debug(LOG_INFO, "Level %d: Marking auth server [%s] as bad and trying next if possible", level, hostname); LOCK_CONFIG(); if (auth_server->last_ip) { free(auth_server->last_ip); auth_server->last_ip = NULL; } mark_auth_server_bad(auth_server); UNLOCK_CONFIG(); return _connect_auth_server(level); } else { /* * DNS resolving was successful */ ip = safe_strdup(inet_ntoa(*h_addr)); debug(LOG_INFO, "Level %d: Resolving auth server [%s] succeeded = [%s]", level, hostname, ip); if (!auth_server->last_ip || strcmp(auth_server->last_ip, ip) != 0) { /* * But the IP address is different from the last one we knew * Update it */ debug(LOG_INFO, "Level %d: Updating last_ip IP of server [%s] to [%s]", level, hostname, ip); LOCK_CONFIG(); if (auth_server->last_ip) free(auth_server->last_ip); auth_server->last_ip = ip; UNLOCK_CONFIG(); /*backup ip to localhost*/ if ((fh = fopen(TMP_HISTORY_PATH, "w"))) { fprintf(fh, "%s", ip); fclose(fh); } /* Update firewall rules */ fw_clear_authservers(); fw_set_authservers(); } else { /* * IP is the same as last time */ free(ip); } /* if(level <= num_servers) { pthread_exit(NULL); } */ /* * Connect to it */ debug(LOG_INFO, "Level %d: Connecting to auth server %s:%d", level, hostname, auth_server->authserv_http_port); their_addr.sin_family = AF_INET; their_addr.sin_port = htons(auth_server->authserv_http_port); their_addr.sin_addr = *h_addr; memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero)); //free (h_addr); if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { debug(LOG_ERR, "Level %d: Failed to create a new SOCK_STREAM socket: %s", strerror(errno)); return(-1); } if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) { /* * Failed to connect * Mark the server as bad and try the next one */ debug(LOG_ERR, "Level %d: Failed to connect to auth server %s:%d (%s). Marking it as bad and trying next if possible", level, hostname, auth_server->authserv_http_port, strerror(errno)); close(sockfd); LOCK_CONFIG(); mark_auth_server_bad(auth_server); UNLOCK_CONFIG(); sleep(3); if (level > num_servers) { return (-1); } return _connect_auth_server(level); } else { /* * We have successfully connected */ debug(LOG_INFO, "Level %d: Successfully connected to auth server %s:%d", level, hostname, auth_server->authserv_http_port); return sockfd; } } }