Exemplo n.º 1
0
bool UDTPPeer::remove_thread()
{
    if(get_thread_count()  <= 0) return false;

    UDTPThreadFlow *removeFlowThread = front_flow_thread();
    UDTPThreadProcess *removeProcessThread = front_process_thread();

    removeFlowThread->kill();

    removeProcessThread->kill();
    sem_post(&_semProcessChunkThread); /*Have to post one!*/

    close(removeFlowThread->flow_socket()); /****FIND A WAY TO CLOSE BUT KEEP WHATEVER IS REMAINING INSIDE!*/

    removeFlowThread = NULL;
    removeProcessThread = NULL;


    std::cout << "PEER " << get_unique_id() << " has removed a flow and process thread!"  << std::endl;
    decrement_thread_count();
    pop_thread();
    return true;
}
Exemplo n.º 2
0
int daemon_listen(DRIVER_CTX *DTX) {
    struct sockaddr_in local_addr, remote_addr;
    THREAD_CTX *TTX = NULL;
    fd_set master, read_fds;
    pthread_attr_t attr;
    struct timeval tv;
    int fdmax, yes = 1;
    int domain = 0;		/* listening on domain socket? */
    int listener;			/* listener fd */
    int i;
    int port = 24, queue = 32;	/* default port and queue size */

    signal(SIGPIPE, SIG_IGN);
    signal(SIGINT,  process_signal);
    signal(SIGTERM, process_signal);
    signal(SIGHUP,  process_signal);

    if (_ds_read_attribute(agent_config, "ServerPort"))
        port = atoi(_ds_read_attribute(agent_config, "ServerPort"));

    if (_ds_read_attribute(agent_config, "ServerQueueSize"))
        queue = atoi(_ds_read_attribute(agent_config, "ServerQueueSize"));

    if (_ds_read_attribute(agent_config, "ServerDomainSocketPath"))
        domain = 1;

    /* initialize */

    FD_ZERO(&master);
    FD_ZERO(&read_fds);

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    /* Bind (domain socket) */

    if (domain) {
        struct sockaddr_un saun;
        char *address = _ds_read_attribute(agent_config, "ServerDomainSocketPath");
        mode_t mask;
        int len;

        mask = umask (000);

        listener = socket(AF_UNIX, SOCK_STREAM, 0);
        if (listener == -1) {
            LOG(LOG_CRIT, ERR_DAEMON_SOCKET, strerror(errno));
            umask (mask);
            return(EFAILURE);
        }

        memset(&saun, 0, sizeof(struct sockaddr_un));
        saun.sun_family = AF_UNIX;
        strcpy(saun.sun_path, address);

        unlink(address);
        len = sizeof(saun.sun_family) + strlen(saun.sun_path) + 1;

        LOGDEBUG(INFO_DAEMON_DOMAINSOCK, address);

        if (bind(listener, (struct sockaddr *) &saun, len)<0) {
            close(listener);
            LOG(LOG_CRIT, INFO_DAEMON_DOMAINSOCK, address, strerror(errno));
            umask (mask);
            return EFAILURE;
        }

        umask (mask);

        /* Bind to a TCP socket */

    } else {
        listener = socket(AF_INET, SOCK_STREAM, 0);
        if (listener == -1) {
            LOG(LOG_CRIT, ERR_DAEMON_SOCKET, strerror(errno));
            return(EFAILURE);
        }

        if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
            close(listener);
            LOG(LOG_CRIT, ERR_DAEMON_SOCKOPT, "SO_REUSEADDR", strerror(errno));
            return(EFAILURE);
        }

        memset(&local_addr, 0, sizeof(struct sockaddr_in));
        local_addr.sin_family = AF_INET;
        local_addr.sin_port = htons(port);
        if (_ds_read_attribute(agent_config, "ServerHost")) {
            char *host = _ds_read_attribute(agent_config, "ServerHost");
            local_addr.sin_addr.s_addr = inet_addr(host);
            LOGDEBUG(INFO_DAEMON_BIND, host, port);
        } else {
            local_addr.sin_addr.s_addr = INADDR_ANY;
            LOGDEBUG(INFO_DAEMON_BIND, "*", port);
        }

        if (bind(listener, (struct sockaddr *)&local_addr,
                 sizeof(struct sockaddr)) == -1)
        {
            close(listener);
            LOG(LOG_CRIT, ERR_DAEMON_BIND, port, strerror(errno));
            return(EFAILURE);
        }
    }

    /* Listen */

    if (listen(listener, queue) == -1) {
        close(listener);
        LOG(LOG_CRIT, ERR_DAEMON_LISTEN, strerror(errno));
        return(EFAILURE);
    }

    FD_SET(listener, &master);
    fdmax = listener;

    /* Process new connections (until death or reload) */

    for(;;) {
        read_fds = master;
        tv.tv_sec = 2;
        tv.tv_usec = 0;

        if (__daemon_run == 0) {
            close(listener);

            if (_ds_read_attribute(agent_config, "ServerDomainSocketPath"))
                unlink (_ds_read_attribute(agent_config, "ServerDomainSocketPath"));

            return 0;
        }

        if (select(fdmax+1, &read_fds, NULL, NULL, &tv)>0) {

            /* Process read-ready connections */

            for(i=0; i<=fdmax; i++) {
                if (FD_ISSET(i, &read_fds)) {

                    /* Accept new connections */

                    if (i == listener) {
                        int newfd;
                        int addrlen = sizeof(remote_addr);

                        if ((newfd = accept(listener,
                                            (struct sockaddr *)&remote_addr,
                                            (socklen_t *) &addrlen)) == -1)
                        {
                            LOG(LOG_WARNING, ERR_DAEMON_ACCEPT, strerror(errno));
                            continue;
#ifdef DEBUG
                        } else if (!domain) {
                            char buff[32];
                            LOGDEBUG("connection id %d from %s.", newfd,
#ifdef HAVE_INET_NTOA_R_2
                                     inet_ntoa_r(remote_addr.sin_addr, buff)
#else
                                     inet_ntoa_r(remote_addr.sin_addr, buff, sizeof(buff))
#endif
                                    );
#endif
                        }
                        fcntl(newfd, F_SETFL, O_RDWR);
                        setsockopt(newfd,SOL_SOCKET,TCP_NODELAY,&yes,sizeof(int));

                        /*
                         * Since processing time varies, each new connection gets its own
                         * thread, so we create a new thread context and send it on its way
                         *
                         */

                        TTX = calloc(1, sizeof(THREAD_CTX));
                        if (TTX == NULL) {
                            LOG(LOG_CRIT, ERR_MEM_ALLOC);
                            close(newfd);
                            continue;
                        } else {
                            TTX->sockfd = newfd;
                            TTX->DTX = DTX;
                            memcpy(&TTX->remote_addr, &remote_addr, sizeof(remote_addr));

                            increment_thread_count();
                            if (pthread_create(&TTX->thread,
                                               &attr, process_connection, (void *) TTX))
                            {
                                decrement_thread_count();
                                LOG(LOG_CRIT, ERR_DAEMON_THREAD, strerror(errno));
                                close(TTX->sockfd);
                                free(TTX);
                                continue;
                            }
                        }
                    } /* if i == listener */
                } /* if FD_SET else */
            } /* for(i.. */
        }  /* if (select)... */
    } /* for(;;) */

    /* Shutdown - we should never get here, but who knows */

    close(listener);
    pthread_attr_destroy(&attr);
    return 0;
}
Exemplo n.º 3
0
void *process_connection(void *ptr) {
    char *server_ident = _ds_read_attribute(agent_config, "ServerIdent");
    THREAD_CTX *TTX = (THREAD_CTX *) ptr;
    AGENT_CTX *ATX = NULL;
    char *input, *cmdline = NULL, *token, *ptrptr;
    buffer *message = NULL;
    char *parms=NULL, *p=NULL;
    int i, locked = -1, invalid = 0;
    int server_mode = SSM_DSPAM;
    char *argv[64];
    char buf[1024];
    int tries = 0;
    int argc = 0;
    FILE *fd = 0;

    if (_ds_read_attribute(agent_config, "ServerMode") &&
            !strcasecmp(_ds_read_attribute(agent_config, "ServerMode"), "standard"))
    {
        server_mode = SSM_STANDARD;
    }

    if (_ds_read_attribute(agent_config, "ServerMode") &&
            !strcasecmp(_ds_read_attribute(agent_config, "ServerMode"), "auto"))
    {
        server_mode = SSM_AUTO;
    }

    /* Initialize a file descriptor hook for dspam to use as stdout */

    fd = fdopen(TTX->sockfd, "w");
    if (!fd) {
        close(TTX->sockfd);
        goto CLOSE;
    }
    setbuf(fd, NULL);

    TTX->packet_buffer = buffer_create(NULL);
    if (TTX->packet_buffer == NULL)
        goto CLOSE;

    /*
     *  Send greeting banner
     *  in auto mode, we want to look like a regular LMTP server so we don't
     *  cause any compatibility problems. in dspam mode, we can change this.
     */

    snprintf(buf, sizeof(buf), "%d DSPAM %sLMTP %s %s",
             LMTP_GREETING,
             (server_mode == SSM_DSPAM) ? "D" : "",
             VERSION,
             (server_mode == SSM_DSPAM) ? "Authentication Required" : "Ready");
    if (send_socket(TTX, buf)<=0)
        goto CLOSE;

    TTX->authenticated = 0;

    /* LHLO */

    input = daemon_expect(TTX, "LHLO");
    if (input == NULL)
        goto CLOSE;
    if (server_mode == SSM_AUTO && input[4]) {
        char buff[128];

        /*
         *  Auto-detect the server mode based on whether or not the ident is
         *  assigned a password in dspam.conf
         */

        snprintf(buff, sizeof(buff), "ServerPass.%s", input + 5);
        chomp(buff);
        if (_ds_read_attribute(agent_config, buff))
            server_mode = SSM_DSPAM;
        else
            server_mode = SSM_STANDARD;
    }
    free(input);

    /* Advertise extensions */

    if (daemon_extension(TTX, (server_ident) ? server_ident :
                         "localhost.localdomain")<=0)
        goto CLOSE;

    if (daemon_extension(TTX, "PIPELINING")<=0)
        goto CLOSE;

    if (daemon_extension(TTX, "ENHANCEDSTATUSCODES")<=0)
        goto CLOSE;

    if (server_mode == SSM_DSPAM)
        if (daemon_extension(TTX, "DSPAMPROCESSMODE")<=0)
            goto CLOSE;

    if (daemon_extension(TTX, "8BITMIME")<=0)
        goto CLOSE;

    if (daemon_reply(TTX, LMTP_OK, "", "SIZE")<=0)
        goto CLOSE;

    /* Main protocol loop */

    while(1) {
        char processmode[256];
        parms = NULL;

        /* Configure a new agent context for each pass */

        ATX = calloc(1, sizeof(AGENT_CTX));
        if (ATX == NULL) {
            LOG(LOG_CRIT, ERR_MEM_ALLOC);
            daemon_reply(TTX, LMTP_TEMP_FAIL, "4.3.0", ERR_MEM_ALLOC);
            goto CLOSE;
        }

        if (initialize_atx(ATX)) {
            LOG(LOG_ERR, ERR_AGENT_INIT_ATX);
            daemon_reply(TTX, LMTP_BAD_CMD, "5.3.0", ERR_AGENT_INIT_ATX);
            goto CLOSE;
        }

        /* MAIL FROM (and authentication, if SSM_DSPAM) */

        processmode[0] = 0;
        while(!TTX->authenticated) {
            input = daemon_expect(TTX, "MAIL FROM");

            if (RSET(input))
                goto RSET;

            if (input == NULL)
                goto CLOSE;
            else {
                char *pass, *ident;
                chomp(input);

                if (server_mode == SSM_STANDARD) {
                    TTX->authenticated = 1;

                    ATX->mailfrom[0] = 0;
                    _ds_extract_address(ATX->mailfrom, input, sizeof(ATX->mailfrom));

                    if (daemon_reply(TTX, LMTP_OK, "2.1.0", "OK")<=0) {
                        free(input);
                        goto CLOSE;
                    }
                } else {
                    char id[256];
                    pass = ident = NULL;
                    id[0] = 0;
                    if (!_ds_extract_address(id, input, sizeof(id))) {
                        pass = strtok_r(id, "@", &ptrptr);
                        ident = strtok_r(NULL, "@", &ptrptr);
                    }

                    if (pass && ident) {
                        char *serverpass;
                        char *ptr, *ptr2, *ptr3;

                        snprintf(buf, sizeof(buf), "ServerPass.%s", ident);
                        serverpass = _ds_read_attribute(agent_config, buf);

                        snprintf(buf, sizeof(buf), "ServerPass.%s", ident);
                        if (serverpass && !strcmp(pass, serverpass)) {
                            TTX->authenticated = 1;

                            /* Parse PROCESSMODE service tag */

                            ptr = strstr(input, "DSPAMPROCESSMODE=\"");
                            if (ptr) {
                                char *mode;
                                int i;
                                ptr2 = strchr(ptr, '"')+1;
                                mode = ptr2;
                                while((ptr3 = strstr(ptr2, "\\\"")))
                                    ptr2 = ptr3+2;
                                ptr3 = strchr(ptr2+2, '"');
                                if (ptr3)
                                    ptr3[0] = 0;
                                strlcpy(processmode, mode, sizeof(processmode));

                                ptr = processmode;
                                for(i=0; ptr[i]; i++) {
                                    if (ptr[i] == '\\' && ptr[i+1] == '"') {
                                        strcpy(ptr+i, ptr+i+1);
                                    }
                                }
                                LOGDEBUG("process mode: '%s'", processmode);
                            }

                            if (daemon_reply(TTX, LMTP_OK, "2.1.0", "OK")<=0) {
                                free(input);
                                goto CLOSE;
                            }
                        }
                    }
                }

                free(input);
                if (!TTX->authenticated) {
                    LOGDEBUG("fd %d authentication failure.", TTX->sockfd);

                    if (daemon_reply(TTX, LMTP_AUTH_ERROR, "5.1.0",
                                     "Authentication Required")<=0)
                    {
                        free(input);
                        goto CLOSE;
                    }

                    tries++;
                    if (tries>=3) {
                        struct timeval tv;
                        tv.tv_sec = 5;
                        tv.tv_usec = 0;
                        select(0, NULL, NULL, NULL, &tv);
                        goto CLOSE;
                    }
                }
            }
        }

        /* MAIL FROM response */

        snprintf(buf, sizeof(buf), "%d OK", LMTP_OK);

        argc = 1;
        argv[0] = "dspam";
        argv[1] = 0;

        /* Load open-LMTP configuration parameters */

        if (server_mode == SSM_STANDARD) {
            parms = _ds_read_attribute(agent_config, "ServerParameters");
            if (parms) {
                p = strdup(parms);
                if (p) {
                    token = strtok_r(p, " ", &ptrptr);
                    while(token != NULL && argc<63) {
                        argv[argc] = token;
                        argc++;
                        argv[argc] = 0;
                        token = strtok_r(NULL, " ", &ptrptr);
                    }
                }
            }
        }

        /* RCPT TO */

        while(ATX->users->items == 0 || invalid) {
            free(cmdline);
            cmdline = daemon_getline(TTX, 300);

            while(cmdline &&
                    (!strncasecmp(cmdline, "RCPT TO:", 8) ||
                     !strncasecmp(cmdline, "RSET", 4)))
            {
                char username[256];
                char *at = NULL;

                if (!strncasecmp(cmdline, "RSET", 4)) {
                    snprintf(buf, sizeof(buf), "%d OK", LMTP_OK);
                    if (send_socket(TTX, buf)<=0)
                        goto CLOSE;
                    goto RSET;
                }

                if (_ds_extract_address(username, cmdline, sizeof(username)) ||
                        username[0] == 0 || username[0] == '-' || username[0] == '@')
                {
                    if ((server_mode == SSM_DSPAM) || (server_mode == SSM_STANDARD && _ds_validate_address(username) == 0)) {
                        daemon_reply(TTX, LMTP_BAD_CMD, "5.1.2", ERR_LMTP_BAD_RCPT);
                        goto GETCMD;
                    }
                }

                if (_ds_match_attribute(agent_config, "Broken", "case"))
                    lc(username, username);

                /* Chop of @.* from the recipient */
                if (_ds_match_attribute(agent_config, "StripRcptDomain", "on")) {
                    at = strchr(username, '@');
                    if (at != NULL)
                        *at = '\0';
                }

                if (server_mode == SSM_DSPAM) {
                    nt_add(ATX->users, username);
                }
                else {
                    if (!parms || !strstr(parms, "--user "))
                        nt_add(ATX->users, username);

                    if (!ATX->recipients) {
                        ATX->recipients = nt_create(NT_CHAR);
                        if (ATX->recipients == NULL) {
                            LOG(LOG_CRIT, ERR_MEM_ALLOC);
                            goto CLOSE;
                        }
                    }
                    if (at != NULL)
                        *at = '@'; /* always add complete address (user@domain) to recipient list */
                    nt_add(ATX->recipients, username);
                }

                if (daemon_reply(TTX, LMTP_OK, "2.1.5", "OK")<=0)
                    goto CLOSE;

GETCMD:
                free(cmdline);
                cmdline = daemon_getline(TTX, 300);
            }

            if (cmdline == NULL)
                goto CLOSE;

            if (!strncasecmp(cmdline, "RSET", 4)) {
                snprintf(buf, sizeof(buf), "%d OK", LMTP_OK);
                if (send_socket(TTX, buf)<=0)
                    goto CLOSE;
                goto RSET;
            }

            if (!strncasecmp(cmdline, "quit", 4)) {
                daemon_reply(TTX, LMTP_OK, "2.0.0", "OK");
                goto CLOSE;
            }

            /* Parse DSPAMPROCESSMODE input and set up process arguments */

            if (server_mode == SSM_DSPAM && processmode[0] != 0) {
                token = strtok_r(processmode, " ", &ptrptr);
                while(token != NULL && argc<63) {
                    argv[argc] = token;
                    argc++;
                    argv[argc] = 0;
                    token = strtok_r(NULL, " ", &ptrptr);
                }
            }

            invalid = 0;
            if (process_arguments(ATX, argc, argv) || apply_defaults(ATX))
            {
                LOG(LOG_ERR, ERR_AGENT_INIT_ATX);
                daemon_reply(TTX, LMTP_NO_RCPT, "5.1.0", ERR_AGENT_INIT_ATX);
                invalid = 1;
            } else if (ATX->users->items == 0) {
                daemon_reply(TTX, LMTP_NO_RCPT, "5.1.1", ERR_AGENT_USER_UNDEFINED);
            }
        }

        ATX->sockfd = fd;
        ATX->sockfd_output = 0;

        /* Something's terribly misconfigured */

        if (check_configuration(ATX)) {
            LOG(LOG_ERR, ERR_AGENT_MISCONFIGURED);
            daemon_reply(TTX, LMTP_BAD_CMD, "5.3.5", ERR_AGENT_MISCONFIGURED);
            goto CLOSE;
        }

        /* DATA */

        if (cmdline != NULL) {
            if (strncasecmp(cmdline, "DATA", 4)) {
                if (daemon_reply(TTX, LMTP_BAD_CMD, "5.0.0", "Need DATA Here")<0)
                    goto CLOSE;
                input = daemon_expect(TTX, "DATA");
                if (input == NULL)
                    goto CLOSE;
                if (RSET(input))
                    goto RSET;
            }
        }

        if (daemon_reply(TTX, LMTP_DATA, "", INFO_LMTP_DATA)<=0)
            goto CLOSE;

        /*
         *  Read in the message from a DATA. I personally like to just hang up on
         *  a client stupid enough to pass in a NULL message for DATA, but you're
         *  welcome to do whatever you want.
         */

        message = read_sock(TTX, ATX);
        if (message == NULL || message->data == NULL || message->used == 0) {
            daemon_reply(TTX, LMTP_FAILURE, "5.2.0", ERR_LMTP_MSG_NULL);
            goto CLOSE;
        }

        /*
         *  Lock a database handle. We currently use the modulus of the socket
         *  id against the number of database connections in the cache. This
         *  seems to work rather well, as we would need to lock up the entire
         *  cache to wrap back around. And if we do wrap back around, that means
         *  we're busy enough to justify spinning on the current lock (vs. seeking
         *  out a free handle, which there likely are none).
         */

        i = (TTX->sockfd % TTX->DTX->connection_cache);
        LOGDEBUG("using database handle id %d", i);
        if (TTX->DTX->flags & DRF_RWLOCK) {
            if (ATX->operating_mode == DSM_CLASSIFY ||
                    ATX->training_mode == DST_NOTRAIN   ||
                    (ATX->training_mode == DST_TOE && ATX->classification == DSR_NONE))
            {
                pthread_rwlock_rdlock(&TTX->DTX->connections[i]->rwlock);
            } else {
                pthread_rwlock_wrlock(&TTX->DTX->connections[i]->rwlock);
            }
        } else {
            pthread_mutex_lock(&TTX->DTX->connections[i]->lock);
        }
        LOGDEBUG("handle locked");
        ATX->dbh = TTX->DTX->connections[i]->dbh;
        locked = i;

        /* Process the message by tying back into the agent functions */

        ATX->results = nt_create(NT_PTR);
        if (ATX->results == NULL) {
            LOG(LOG_CRIT, ERR_MEM_ALLOC);
            goto CLOSE;
        }
        process_users(ATX, message);

        /*
         *  Unlock the database handle as soon as we're done. We also need to
         *  refresh our handle index with a new handle if for some reason we
         *  had to re-establish a dewedged connection.
         */

        if (TTX->DTX->connections[locked]->dbh != ATX->dbh)
            TTX->DTX->connections[locked]->dbh = ATX->dbh;

        if (TTX->DTX->flags & DRF_RWLOCK) {
            pthread_rwlock_unlock(&TTX->DTX->connections[locked]->rwlock);
        } else {
            pthread_mutex_unlock(&TTX->DTX->connections[locked]->lock);
        }
        locked = -1;

        /* Send a terminating '.' if --stdout in 'dspam' mode */

        if (ATX->sockfd_output) {
            if (send_socket(TTX, ".")<=0)
                goto CLOSE;

            /* Otherwise, produce standard delivery results */

        } else {
            struct nt_node *node_nt, *node_res = NULL;
            struct nt_c c_nt;
            if (ATX->recipients)
                node_nt = c_nt_first(ATX->recipients, &c_nt);
            else
                node_nt = c_nt_first(ATX->users, &c_nt);

            if (ATX->results)
                node_res = ATX->results->first;

            while(node_res && node_nt != NULL) {
                agent_result_t result = (agent_result_t) node_res->ptr;

                if (result != NULL && result->exitcode == ERC_SUCCESS)
                {
                    if (server_mode == SSM_DSPAM) {
                        snprintf(buf, sizeof(buf),
                                 "%d 2.6.0 <%s> Message accepted for delivery: %s",
                                 LMTP_OK, (char *) node_nt->ptr,
                                 (result->classification == DSR_ISSPAM) ? "SPAM" : "INNOCENT");
                    } else {
                        snprintf(buf, sizeof(buf),
                                 "%d 2.6.0 <%s> Message accepted for delivery",
                                 LMTP_OK, (char *) node_nt->ptr);
                    }
                }
                else
                {
                    if (result != NULL && result->exitcode == ERC_PERMANENT_DELIVERY) {
                        snprintf(buf, sizeof(buf), "%d 5.3.0 <%s> %s",
                                 LMTP_FAILURE, (char *) node_nt->ptr,
                                 (result->text[0]) ? result->text : "Permanent error occured");
                    } else {
                        if (result != NULL && result->text[0]) {
                            snprintf(buf, sizeof(buf),
                                     "%d 4.3.0 <%s> %s",
                                     LMTP_TEMP_FAIL, (char *) node_nt->ptr, result->text);
                        } else {
                            snprintf(buf, sizeof(buf),
                                     "%d 4.3.0 <%s> Error occured during %s",
                                     LMTP_TEMP_FAIL, (char *) node_nt->ptr,
                                     (result != NULL && result->exitcode == ERC_DELIVERY) ? "delivery" : "processing");
                        }
                    }
                }

                if (send_socket(TTX, buf)<=0)
                    goto CLOSE;
                if (ATX->recipients)
                    node_nt = c_nt_next(ATX->recipients, &c_nt);
                else
                    node_nt = c_nt_next(ATX->users, &c_nt);
                if (node_res)
                    node_res = node_res->next;
            }
        }

        /* Cleanup and get ready for another message */

RSET:
        fflush(fd);

        buffer_destroy(message);
        message = NULL;
        if (ATX != NULL) {
            nt_destroy(ATX->users);
            nt_destroy(ATX->recipients);
            nt_destroy(ATX->results);
            free(ATX);
            ATX = NULL;
            free(cmdline);
            cmdline = NULL;
            TTX->authenticated = 0;
            /* argc = 0; */
        }

        free(p);
        p = NULL;

    } /* while(1) */

    /* Close connection and return */

CLOSE:
    if (locked>=0)
        pthread_mutex_unlock(&TTX->DTX->connections[locked]->lock);
    if (fd)
        fclose(fd);
    buffer_destroy(TTX->packet_buffer);
    if (message)
        buffer_destroy(message);
    if (ATX != NULL) {
        nt_destroy(ATX->users);
        nt_destroy(ATX->recipients);
        nt_destroy(ATX->results);
    }
    free(ATX);
    free(cmdline);
    free(TTX);
    decrement_thread_count();
    pthread_exit(0);
    return 0;
}