[IOMultiplexerV2] coding style fixes
[NextIRCd.git] / src / IOHandler / IODNSEngine_default.c
index b9f37641fe7f5e571ee58ecf4c6686dfe54e3d78..b8189272c7b8c7ed838f1fbb082dfdbb996f5f9d 100644 (file)
 
 
 #ifdef IODNS_USE_THREADS
-static pthread_t iodns_thread;
-static int iodns_thread_running = 1;
+#define IODNS_MAX_THREAD 10
+#define IODNS_INC_THREAD_BY_LOAD 5 /* add another thread when there are more than IODNS_INC_THREAD_BY_LOAD querys per thread */
+static pthread_t *iodns_thread[IODNS_MAX_THREAD];
+static int iodns_threads_wanted = 1;
+static int iodns_threads_running = 0;
 
 static pthread_cond_t iodns_cond;
 static pthread_mutex_t iodns_sync, iodns_sync2;
@@ -50,8 +53,13 @@ static void iodns_process_queries();
 #ifdef IODNS_USE_THREADS
 static void *dnsengine_worker_main(void *arg) {
        struct _IODNSQuery *query;
-       while(iodns_thread_running) {
+       while(1) {
                IOSYNCHRONIZE(iodns_sync);
+               if(iodns_threads_wanted < iodns_threads_running) {
+                       iodns_threads_running--;
+                       break;
+               }
+               
                for(query = iodnsquery_first; query; query = query->next) {
                        if((query->flags & IODNSFLAG_RUNNING))
                                break;
@@ -60,11 +68,38 @@ static void *dnsengine_worker_main(void *arg) {
                if(!query)
                        pthread_cond_wait(&iodns_cond, &iodns_sync2);
                
-               if(iodns_thread_running)
-                       iodns_process_queries();
+               if(iodns_threads_wanted < iodns_threads_running) {
+                       iodns_threads_running--;
+                       break;
+               }
+               
+               iodns_process_queries();
        }
        return NULL;
 }
+
+static int dnsengine_default_start_worker() {
+       if(iodns_threads_wanted >= IODNS_MAX_THREAD-1)
+               return 0;
+       int i;
+       for(i = 0; i < IODNS_MAX_THREAD; i++) {
+               if(!iodns_thread[i]) 
+                       break;
+       }
+       if(i >= IODNS_MAX_THREAD)
+               return 0;
+       iodns_thread[i] = malloc(sizeof(**iodns_thread));
+       if(!iodns_thread[i])
+               return 0;
+       iodns_threads_wanted++;
+       if(pthread_create(iodns_thread[i], NULL, dnsengine_worker_main, NULL)) {
+               iodns_threads_wanted--;
+               iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
+               return 0;
+       }
+       iodns_threads_running++;
+       return 1;
+}
 #endif
 
 static int dnsengine_default_init() {
@@ -74,123 +109,164 @@ static int dnsengine_default_init() {
        IOTHREAD_MUTEX_INIT(iodns_sync);
        IOTHREAD_MUTEX_INIT(iodns_sync2);
        
-       iodns_thread_running = 1;
-       
-       int thread_err;
-       thread_err = pthread_create(&iodns_thread, NULL, dnsengine_worker_main, NULL);
-       if(thread_err) {
-               iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
+       if(!dnsengine_default_start_worker()) {
                iodns_loop_blocking = 1;
-               iodns_thread_running = 0;
+               iodns_threads_running = 0;
        }
        #else
        iodns_loop_blocking = 1;
        #endif
-    return 1;
+       return 1;
 }
 
 static void dnsengine_default_stop() {
        #ifdef IODNS_USE_THREADS
+       int i;
        if(iodns_thread_running) {
-               iodns_thread_running = 0;
+               iodns_threads_wanted = 0;
                IOSYNCHRONIZE(iodns_sync2);
-               pthread_cond_signal(&iodns_cond);
+               pthread_cond_broadcast(&iodns_cond);
                IODESYNCHRONIZE(iodns_sync2);
-               pthread_join(iodns_thread, NULL);
+               for(i = 0; i < IODNS_MAX_THREAD; i++) {
+                       if(iodns_thread[i]) {
+                               pthread_join(*iodns_thread[i], NULL);
+                               free(iodns_thread[i]);
+                               iodns_thread[i] = NULL;
+                       }
+               }
        }
        #endif
 }
 
 static void dnsengine_default_add(struct _IODNSQuery *iodns) {
-    #ifdef IODNS_USE_THREADS
+       #ifdef IODNS_USE_THREADS
        if(iodns_thread_running) {
                IOSYNCHRONIZE(iodns_sync2);
                pthread_cond_signal(&iodns_cond);
                IODESYNCHRONIZE(iodns_sync2);
+               
+               int querycount = 0;
+               for(iodns = iodnsquery_first; iodns; iodns = iodns->next) {
+                       if(!(iodns->flags & IODNSFLAG_RUNNING))
+                               continue;
+                       if((iodns->flags & IODNSFLAG_PROCESSING))
+                               continue;
+                       querycount++;
+               }
+               if(querycount / iodns_threads_wanted > IODNS_INC_THREAD_BY_LOAD) {
+                       dnsengine_default_start_worker();
+               }
        }
        #endif
 }
 
 static void dnsengine_default_remove(struct _IODNSQuery *iodns) {
-    /* unused */
+       /* unused */
 }
 
 static void dnsengine_default_loop() {
-    if(iodns_loop_blocking)
+       if(iodns_loop_blocking)
                iodns_process_queries();
 }
 
 static void iodns_process_queries() {
        enum IODNSEventType querystate;
-    struct addrinfo hints, *res, *allres;
-    struct _IODNSQuery *iodns, *next_iodns;
-    struct IODNSResult *dnsresult;
+       struct addrinfo hints, *res, *allres;
+       struct _IODNSQuery *iodns, *next_iodns;
+       struct IODNSResult *dnsresult;
+       int ret;
        iodns_process_queries_start:
        IOSYNCHRONIZE(iodns_sync);
-    for(iodns = iodnsquery_first; iodns; iodns = next_iodns) {
-        next_iodns = iodns->next;
+       for(iodns = iodnsquery_first; iodns; iodns = next_iodns) {
+               next_iodns = iodns->next;
                
                if(!(iodns->flags & IODNSFLAG_RUNNING))
                        continue;
                if((iodns->flags & IODNSFLAG_PROCESSING))
                        continue;
+               iodns->flags |= IODNSFLAG_PROCESSING;
                
                IODESYNCHRONIZE(iodns_sync);
                
-        querystate = IODNSEVENT_FAILED;
-        
-        if((iodns->type & IODNS_FORWARD)) {
-            memset (&hints, 0, sizeof (hints));
-            hints.ai_family = PF_UNSPEC;
-            hints.ai_socktype = SOCK_STREAM;
-            hints.ai_flags |= AI_CANONNAME;
-                       int ret;
-            if (!(ret = getaddrinfo(iodns->request.host, NULL, &hints, &allres))) {
+               querystate = IODNSEVENT_FAILED;
+               
+               if((iodns->type & IODNS_FORWARD)) {
+                       memset (&hints, 0, sizeof (hints));
+                       hints.ai_family = PF_UNSPEC;
+                       hints.ai_socktype = SOCK_STREAM;
+                       hints.ai_flags |= AI_CANONNAME;
+                       if (!(ret = getaddrinfo(iodns->request.host, NULL, &hints, &allres))) {
                                res = allres;
-                while (res) {
-                    switch (res->ai_family) {
-                    case AF_INET:
-                        if((iodns->type & IODNS_RECORD_A)) {
-                            dnsresult = malloc(sizeof(*dnsresult));
-                            dnsresult->type = IODNS_RECORD_A;
-                            dnsresult->result.addr.addresslen = res->ai_addrlen;
-                            dnsresult->result.addr.address = malloc(dnsresult->result.addr.addresslen);
-                            memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
-                            dnsresult->next = iodns->result;
-                            iodns->result = dnsresult;
-                            
-                            char str[INET_ADDRSTRLEN];
+                               while (res) {
+                                       switch (res->ai_family) {
+                                       case AF_INET:
+                                               if((iodns->type & IODNS_RECORD_A)) {
+                                                       dnsresult = malloc(sizeof(*dnsresult));
+                                                       dnsresult->type = IODNS_RECORD_A;
+                                                       dnsresult->result.addr.addresslen = res->ai_addrlen;
+                                                       dnsresult->result.addr.address = calloc(dnsresult->result.addr.addresslen, 1);
+                                                       dnsresult->result.addr.address->sa_family = AF_INET;
+                                                       memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
+                                                       dnsresult->next = iodns->result;
+                                                       iodns->result = dnsresult;
+                                                       
+                                                       char str[INET_ADDRSTRLEN];
                                                        inet_ntop( AF_INET, &((struct sockaddr_in *)dnsresult->result.addr.address)->sin_addr, str, INET_ADDRSTRLEN );
-                            iolog_trigger(IOLOG_DEBUG, "Resolved %s to (A): %s", iodns->request.host, str);
-                            
-                            querystate = IODNSEVENT_SUCCESS;
-                        }
-                        break;
-                    case AF_INET6:
-                        if((iodns->type & IODNS_RECORD_AAAA)) {
-                            dnsresult = malloc(sizeof(*dnsresult));
-                            dnsresult->type = IODNS_RECORD_AAAA;
-                            dnsresult->result.addr.addresslen = res->ai_addrlen;
-                            dnsresult->result.addr.address = calloc(dnsresult->result.addr.addresslen, 1);
-                            memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
-                            dnsresult->next = iodns->result;
-                            iodns->result = dnsresult;
-                            
-                            char str[INET6_ADDRSTRLEN];
+                                                       iolog_trigger(IOLOG_DEBUG, "Resolved %s to (A): %s", iodns->request.host, str);
+                                                       
+                                                       querystate = IODNSEVENT_SUCCESS;
+                                               }
+                                               break;
+                                       case AF_INET6:
+                                               if((iodns->type & IODNS_RECORD_AAAA)) {
+                                                       dnsresult = malloc(sizeof(*dnsresult));
+                                                       dnsresult->type = IODNS_RECORD_AAAA;
+                                                       dnsresult->result.addr.addresslen = res->ai_addrlen;
+                                                       dnsresult->result.addr.address = calloc(dnsresult->result.addr.addresslen, 1);
+                                                       dnsresult->result.addr.address->sa_family = AF_INET6;
+                                                       memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
+                                                       dnsresult->next = iodns->result;
+                                                       iodns->result = dnsresult;
+                                                       
+                                                       char str[INET6_ADDRSTRLEN];
                                                        inet_ntop( AF_INET6, &((struct sockaddr_in6 *)dnsresult->result.addr.address)->sin6_addr, str, INET6_ADDRSTRLEN );
-                            iolog_trigger(IOLOG_DEBUG, "Resolved %s to (AAAA): %s", iodns->request.host, str);
-                            
-                            querystate = IODNSEVENT_SUCCESS;
-                        }
-                        break;
-                    }
-                    res = res->ai_next;
-                }
-                freeaddrinfo(allres);
-            } else {
+                                                       iolog_trigger(IOLOG_DEBUG, "Resolved %s to (AAAA): %s", iodns->request.host, str);
+                                                       
+                                                       querystate = IODNSEVENT_SUCCESS;
+                                               }
+                                               break;
+                                       }
+                                       res = res->ai_next;
+                               }
+                               freeaddrinfo(allres);
+                       } else {
                                iolog_trigger(IOLOG_WARNING, "getaddrinfo returned error code: %d", ret);
                        }
-        }
+               } else if((iodns->type & IODNS_REVERSE)) {
+                       char hostname[NI_MAXHOST];
+                       if(!(ret = getnameinfo(iodns->request.addr.address, iodns->request.addr.addresslen, hostname, sizeof(hostname), NULL, 0, 0))) {
+                               dnsresult = malloc(sizeof(*dnsresult));
+                               dnsresult->type = IODNS_RECORD_PTR;
+                               dnsresult->result.host = strdup(hostname);
+                               dnsresult->next = iodns->result;
+                               iodns->result = dnsresult;
+                               
+                               if(iodns->request.addr.address->sa_family == AF_INET) {
+                                       char str[INET_ADDRSTRLEN];
+                                       inet_ntop(AF_INET, &((struct sockaddr_in *)iodns->request.addr.address)->sin_addr, str, INET_ADDRSTRLEN);
+                                       iolog_trigger(IOLOG_DEBUG, "Resolved %s to (PTR): %s", str, hostname);
+                               } else {
+                                       char str[INET6_ADDRSTRLEN];
+                                       inet_ntop(AF_INET6, &((struct sockaddr_in6 *)iodns->request.addr.address)->sin6_addr, str, INET6_ADDRSTRLEN);
+                                       iolog_trigger(IOLOG_DEBUG, "Resolved %s to (PTR): %s", str, hostname);
+                               }
+                               
+                               querystate = IODNSEVENT_SUCCESS;
+                       } else {
+                               iolog_trigger(IOLOG_WARNING, "getnameinfo returned error code: %d", ret);
+                       }
+                       
+               }
                IOSYNCHRONIZE(iodns_sync);
                if(!(iodns->flags & IODNSFLAG_RUNNING)) {
                        iodns_free_result(iodns->result);
@@ -202,14 +278,15 @@ static void iodns_process_queries() {
                IODESYNCHRONIZE(iodns_sync);
                iodns_event_callback(iodns, querystate);
                goto iodns_process_queries_start;
-    }
+       }
 }
 
 struct IODNSEngine dnsengine_default = {
-    .name = "default",
-    .init = dnsengine_default_init,
+       .name = "default",
+       .init = dnsengine_default_init,
        .stop = dnsengine_default_stop,
-    .add = dnsengine_default_add,
-    .remove = dnsengine_default_remove,
-    .loop = dnsengine_default_loop,
+       .add = dnsengine_default_add,
+       .remove = dnsengine_default_remove,
+       .loop = dnsengine_default_loop,
+       .socket_callback = NULL,
 };