diff --git a/src/dns.c b/src/dns.c index a8d468cf4..c1f3beef5 100644 --- a/src/dns.c +++ b/src/dns.c @@ -486,6 +486,7 @@ static void dns_check_dns_response(struct dns_resolution *res) /* Remove any associated server */ for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) { + SPIN_LOCK(SERVER_LOCK, &srv->lock); if (srv->srvrq == srvrq && srv->svc_port == item->port && item->data_len == srv->hostname_dn_len && !memcmp(srv->hostname_dn, item->target, item->data_len)) { @@ -497,6 +498,7 @@ static void dns_check_dns_response(struct dns_resolution *res) srv->hostname_dn_len = 0; dns_unlink_resolution(srv->dns_requester); } + SPIN_UNLOCK(SERVER_LOCK, &srv->lock); } } @@ -516,6 +518,7 @@ static void dns_check_dns_response(struct dns_resolution *res) /* Check if a server already uses that hostname */ for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) { + SPIN_LOCK(SERVER_LOCK, &srv->lock); if (srv->srvrq == srvrq && srv->svc_port == item->port && item->data_len == srv->hostname_dn_len && !memcmp(srv->hostname_dn, item->target, item->data_len)) { @@ -525,16 +528,20 @@ static void dns_check_dns_response(struct dns_resolution *res) snprintf(weight, sizeof(weight), "%d", item->weight); server_parse_weight_change_request(srv, weight); } + SPIN_UNLOCK(SERVER_LOCK, &srv->lock); break; } + SPIN_UNLOCK(SERVER_LOCK, &srv->lock); } if (srv) continue; /* If not, try to find a server with undefined hostname */ for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) { + SPIN_LOCK(SERVER_LOCK, &srv->lock); if (srv->srvrq == srvrq && !srv->hostname_dn) break; + SPIN_UNLOCK(SERVER_LOCK, &srv->lock); } /* And update this server, if found */ if (srv) { @@ -556,6 +563,7 @@ static void dns_check_dns_response(struct dns_resolution *res) srv->check.port = item->port; snprintf(weight, sizeof(weight), "%d", item->weight); server_parse_weight_change_request(srv, weight); + SPIN_UNLOCK(SERVER_LOCK, &srv->lock); } } } @@ -1337,6 +1345,7 @@ int dns_link_resolution(void *requester, int requester_type) goto err; if (srv) { + SPIN_LOCK(SERVER_LOCK, &srv->lock); if (srv->dns_requester == NULL) { if ((req = calloc(1, sizeof(*req))) == NULL) goto err; @@ -1345,6 +1354,7 @@ int dns_link_resolution(void *requester, int requester_type) } else req = srv->dns_requester; + SPIN_UNLOCK(SERVER_LOCK, &srv->lock); } else if (srvrq) { if (srvrq->dns_requester == NULL) { diff --git a/src/server.c b/src/server.c index 37f90d8c9..555d6da19 100644 --- a/src/server.c +++ b/src/server.c @@ -3712,8 +3712,14 @@ struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char if (!srv) return NULL; + SPIN_LOCK(SERVER_LOCK, &srv->lock); + be = srv->proxy; for (tmpsrv = be->srv; tmpsrv; tmpsrv = tmpsrv->next) { + /* we found the current server is the same, ignore it */ + if (srv == tmpsrv) + continue; + /* We want to compare the IP in the record with the IP of the servers in the * same backend, only if: * * DNS resolution is enabled on the server @@ -3721,15 +3727,20 @@ struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char * one used for the server found in the backend * * the server found in the backend is not our current server */ + SPIN_LOCK(SERVER_LOCK, &tmpsrv->lock); if ((tmpsrv->hostname_dn == NULL) || (srv->hostname_dn_len != tmpsrv->hostname_dn_len) || (strcmp(srv->hostname_dn, tmpsrv->hostname_dn) != 0) || - (srv->puid == tmpsrv->puid)) + (srv->puid == tmpsrv->puid)) { + SPIN_UNLOCK(SERVER_LOCK, &tmpsrv->lock); continue; + } /* If the server has been taken down, don't consider it */ - if (tmpsrv->next_admin & SRV_ADMF_RMAINT) + if (tmpsrv->next_admin & SRV_ADMF_RMAINT) { + SPIN_UNLOCK(SERVER_LOCK, &tmpsrv->lock); continue; + } /* At this point, we have 2 different servers using the same DNS hostname * for their respective resolution. @@ -3739,10 +3750,15 @@ struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char memcmp(ip, &((struct sockaddr_in *)&tmpsrv->addr)->sin_addr, 4) == 0) || (tmpsrv->addr.ss_family == AF_INET6 && memcmp(ip, &((struct sockaddr_in6 *)&tmpsrv->addr)->sin6_addr, 16) == 0))) { + SPIN_UNLOCK(SERVER_LOCK, &tmpsrv->lock); + SPIN_UNLOCK(SERVER_LOCK, &srv->lock); return tmpsrv; } + SPIN_UNLOCK(SERVER_LOCK, &tmpsrv->lock); } + SPIN_UNLOCK(SERVER_LOCK, &srv->lock); + return NULL; }