コード例 #1
0
ファイル: TCPServer.cpp プロジェクト: wukehu/rtsp
void TCPServer::stop()
{
	//1.停止工作线程
	if (m_nServerThreadId != 0)
		exitThread(&m_nServerThreadId, &m_bThreadRunFlag);
	m_bThreadRunFlag = false;

	//2.关闭监听
	m_objListenTCPTransfer->close();
	delete m_objListenTCPTransfer;
	m_objListenTCPTransfer = NULL;

	//3.销毁epoll文件描述符
	::CLOSESOCKET(m_nEpollFd);

	//4.清理连接对象列表
	std::list<TCPLinkReceiver*>::iterator it = m_objTCPLinkReceiverList.begin();
	for (; it != m_objTCPLinkReceiverList.end(); ++it)
	{
		TCPLinkReceiver* pobjTCPLinkReceiver = *it;
		if (NULL != pobjTCPLinkReceiver)
			delete pobjTCPLinkReceiver;
	}
	m_objTCPLinkReceiverList.clear();
}
コード例 #2
0
ファイル: OperationQueue.cpp プロジェクト: adroitly/boom
    void OperationQueue::Impl::workerThread()
    {
        for (;;)
        {
            Record::Ptr item;
            {
                LockGuard lock(_inputMutex);
                item = getFirstUndoInputRecord();
                if (!item)
                {
                    exitThread(ThreadInfo::thisThreadId());
                    return;
                }

                item->state = Record::State::Doing;

                if (item->isCancel)
                {
                    popupInputRecord(item->Id);
                    continue;
                }
            }

            item->operation->action();

            {
                LockGuard lock(_inputMutex);
                if (!item->isCancel && item->callback != nullptr)
                {
                    s_addItem(_outputs, item, _outputMutex);
                }
                popupInputRecord(item->Id);
            }
        }
    }
コード例 #3
0
int xWorkingThread::stop()
{
	if(m_pRunner == NULL)
		return 1;
	exitThread(true);
	return 0;
}
コード例 #4
0
ファイル: pa4c.c プロジェクト: rhlin/unix-homework-CSE120-PA4
void Main ()
{
    int i, me;
    void printMyThread();

    initThreads ();

    me = getThread ();
    for(i=1; i<MAXTHREADS; i++)
        spawnThread(printMyThread,0);

    for (i = 0; i < NUMYIELDS; i++) {
        Printf("0 T%d\n",me);
        yieldThread(1);
    }

    exitThread ();
}
コード例 #5
0
void DemuxThread::stopPlay()
{
	fprintf("stop demux thread\n");
	if(m_videoDecoder != NULL)
	{
		m_videoDecoder->exitThread();
		bool ret = m_videoDecoder->wait();
		if(!ret)
		{
			fprintf(stderr, "force to stop video thread\n");
		    m_videoDecoder->setThreadStatus(THREAD_STOP);
			m_videoDecoder->quit();		
		}
	}
	exitThread();	
	bool ret = wait();
	if(!ret)
	{
		fprintf("force to stop video thread\n");
		quit();
	}
	releaseVideoInfo();
}	
コード例 #6
0
ファイル: proxy.c プロジェクト: alainrk/uniprefetchproxy
/* Thread per sessione di connessione */
static void *Session (void *p) {

	int clifd;												/* Socket Client-Proxy */
	int servfd;												/* Socket Proxy-Server */
	int ris;													/* Utili */
	struct Request req;								/* Conterrà le informazioni per forward e prefetch */
	struct Response resp;							/* Conterrà info per invio file cache, struttura richiesta da prepareResponse ecc */
	char cache_filename[MAXLENPATH];
	char error_response[16];
	char buffer[MAXLENRESP];
	int buffer_len;
	struct sockaddr_in Local, Serv; 	/* Per connessione con il server */

	/* Client socket Timeout */
	struct timeval timercli;
	timercli.tv_sec = INACTIVITY_TIMEOUT_SECONDS;
	timercli.tv_usec = 0;

	/* Estrazione informazioni parametro thread */
	clifd = ((struct param*)p)->fd;
	free(p);
	p = NULL;

	/* Controllo sul numero dei thread */
	pthread_mutex_lock(&mutex_num);
	if(numthread < MAXNUMTHREADWORKING)
		numthread++;
	pthread_mutex_unlock(&mutex_num);
	if(numthread >= MAXNUMTHREADWORKING) {
		close(clifd);
		exitThread();
		return(NULL);
	}

#ifdef DEBUG
printf("Thread: %ld. Client FD passato: %d\n", pthread_self(), clifd);
fflush(stdout);
#endif

	/* Imposto il timeout per questo socket client */
	setsockopt(clifd, SOL_SOCKET, SO_RCVTIMEO, &timercli, sizeof(struct timeval));
	setsockopt(clifd, SOL_SOCKET, SO_SNDTIMEO, &timercli, sizeof(struct timeval));

	/* Inizializzo struttura per richiesta */
	initRequest(&req);

	/* 
		Prelevo la richiesta ed estraggo le informazioni.
		Se a buon fine l'avrò tutta in req->buf, mentre il resto sarà estratto e messo negli altri campi di req.
	*/
	ris = getRequest(clifd,&req);

	switch(ris) {

		case -3: /* Client ha chiuso la connessione */

#ifdef DEBUG
printf("Thread: %ld. Client ha chiuso connessione. \nBuffer: %s\n", pthread_self(), req.buf);
fflush(stdout);
#endif

			close(clifd);
			exitThread();
			return(NULL);
		break;

		case -2: /* Errore in lettura, chiudo thread e connessione */

#ifdef DEBUG
printf("Thread: %ld. Errore in lettura client request. \nBuffer: %s\n", pthread_self(), req.buf);
fflush(stdout);
#endif

			close(clifd);
			exitThread();
			return(NULL);
		break;

		case -1: /* Lettura richiesta terminata, formato richiesta sbagliato */
			strcpy(error_response, "403\n\n");
			mysend(clifd, error_response, strlen(error_response));

#ifdef DEBUG
printf("Thread: %ld. Lettura req terminata, formato richiesta sbagliato. \nBuffer: %s\n", pthread_self(), req.buf);
fflush(stdout);
#endif

			close(clifd);
			exitThread();
			return(NULL);
		break;

		case 1: /* Lettura richiesta OK -> proseguo */

#ifdef DEBUG
printf("Thread: %ld. Lettura req OK. \nBuffer: %s\n", pthread_self(), req.buf);
fflush(stdout);
#endif

		break;
		
		default: /* Errore sconosciuto */
			strcpy(error_response, "402\n\n");
			mysend(clifd, error_response, strlen(error_response));

#ifdef DEBUG
printf("Thread: %ld. Errore sconosciuto. \nBuffer: %s\n", pthread_self(), req.buf);
fflush(stdout);
#endif

			close(clifd);
			exitThread();
			return(NULL);
		break;

	}	/* Switch */

	/* Ora ho nella struttura Request tutte le informazioni che mi servono */

	/* Tentativi connessione server */
	int servconn_chance = SERVER_CHANCE;

	/* 
		Ogni qualvolta ritento una connessione con il server per errori, 
		ricontrollo di avere il file in cache, qualche altro thread 
		potrebbe averlo	salvato nel frattempo.
	*/
	while (1) {

#ifdef DEBUG
printf("Controllo su thread: %ld. While session().\n", pthread_self());
fflush(stdout);
#endif

		/* Se ha fatto una richiesta GET e ho il file in cache */
		if ((req.reqType == GET) && (get_cache_name(&(req.inaddr), req.port, req.path, cache_filename))) {

			/* Cerco di preparare la risposta da mandare (Anche con RANGE), l'eventuale contenuto del file è nel buffer di resp */
			ris = prepareGetResponse(&req, &resp, cache_filename);

#ifdef DEBUG
printf("Thread: %ld. La req è GET e ho il file in cache. \nFile: %s\n", pthread_self(), resp.buf);
fflush(stdout);
#endif

			switch(ris) {

				case 1:
					ris = mysend(clifd, resp.buf, resp.lenresp);	/* caso OK ------> MANDO AL CLIENT IL FILE CHE ERA IN CACHE e chiudo */

					if (ris == -1) {
						printf ("Error on cached file response send.\n");
						fflush(stdout);
					}
					if (ris == -2) {
						printf ("Time out on cached file response send.\n");
						fflush(stdout);
					}
					if (ris == 0) {
						printf ("Client closed connection before sending cached file.\n");
						fflush(stdout);
					}
					else {
						printf ("Cached file sent to client.\n");
						fflush(stdout);
					}
					close(clifd);
					exitThread();
					return(NULL);
				break;

				case -3: /* file not found (expired nel frattempo) ---> faccio la richiesta */

#ifdef DEBUG
printf("Thread: %ld. Avevo il file ma è expired. \n", pthread_self());
fflush(stdout);
#endif

				break;

				case -4: /* interval not found -----> lo notifico */
					strcpy(error_response, "405\n\n");
					mysend(clifd, error_response, strlen(error_response));

#ifdef DEBUG
printf("Thread: %ld. Avevo il file ma il RANGE è sbagliato. \n", pthread_self());
fflush(stdout);
#endif

					close(clifd);
					exitThread();
					return(NULL);
				break;

				case -5: /* unknown error */
				default:
					strcpy(error_response, "402\n\n");
					mysend(clifd, error_response, strlen(error_response));

#ifdef DEBUG
printf("Thread: %ld. Avevo il file ma dopo la prepareResponse errore sconosciuto.\n", pthread_self());
fflush(stdout);
#endif

					close(clifd);
					exitThread();
					return(NULL);
				break;
			}
		} /* Fine GET e ho il file in cache */
	
	/* Non ho file in cache oppure richiesta INF -> Forward richiesta al server e poi discrimino in base a GET (prefetch) e INF (solo forward risposta) */

		servfd = socket(AF_INET, SOCK_STREAM, 0);
		if (servfd < 0) {
			printf("Thread: %ld. Chiamata a socket() per serverfd fallita. Errore: %d \"%s\"\n", pthread_self(), errno,strerror(errno));
			fflush(stdout);
			close(clifd);
			exitThread();
			return(NULL);
		}

		/* Server socket Timeout */
		struct timeval timerserv;
		timerserv.tv_sec = INACTIVITY_TIMEOUT_SECONDS;
		timerserv.tv_usec = 0;

		if ((SetsockoptReuseAddr(servfd) == 0) ||
				(setsockopt(servfd, SOL_SOCKET, SO_RCVTIMEO, &timerserv, sizeof(struct timeval)) != 0) ||
				(setsockopt(servfd, SOL_SOCKET, SO_SNDTIMEO, &timerserv, sizeof(struct timeval)) != 0)) {
			printf("Thread: %ld. Error on a setsockopt for server socket\n", pthread_self());
			fflush(stdout);

			close(servfd);
			close(clifd);
			exitThread();
			return(NULL);
		}

		/* Binding */
		memset(&Local, 0, sizeof(Local));
		Local.sin_family = AF_INET;
		Local.sin_addr.s_addr = INADDR_ANY;
		Local.sin_port = htons(0);

		ris = bind(servfd, (struct sockaddr *)&Local, sizeof(Local));
		if (ris < 0) {
			printf("Thread: %ld. Chiamata a bind() per serverfd fallita. Errore: %d \"%s\"\n", pthread_self(), errno,strerror(errno));
			fflush(stdout);
			close(servfd);
			exitThread();
			return(NULL);
		}

		/* Compilo campi server */
		memset(&Serv, 0, sizeof(Serv));
		Serv.sin_family = AF_INET;
		Serv.sin_addr.s_addr = req.inaddr.s_addr;
		Serv.sin_port = htons(req.port);

#ifdef DEBUG
printf ("Thread: %ld, %d° tentativo connessione con server. FD: %d\n", pthread_self(), (SERVER_CHANCE-servconn_chance+1), servfd);
fflush(stdout);
#endif

		int repeat;
		repeat = 0;	
		while (1) {

#ifdef DEBUG
printf("Controllo su thread: %ld. While connect session.\n", pthread_self());
fflush(stdout);
#endif

			ris = connect (servfd, (struct sockaddr *)&Serv, sizeof(Serv));
			if (ris < 0) {
				if ((errno == EINTR) || (errno == EINPROGRESS)) ; /* Ritento */
				if (errno == EISCONN) {
					printf("Thread: %ld, Chiamata a connect() per serverfd fallita. FD: %d. Errore: %d \"%s\"\n", pthread_self(), servfd, errno,strerror(errno));
					fflush(stdout);
					repeat = 0;
					break;
				}
				else {
					printf("Thread: %ld, Chiamata a connect() per serverfd fallita. FD: %d. Errore: %d \"%s\"\n", pthread_self(), servfd, errno,strerror(errno));
					fflush(stdout);
					if (servconn_chance > 0) servconn_chance--; /* Ritento */
					else {
						printf("Thread: %ld, Chiamata a connect() per serverfd fallita. FD: %d. Errore: %d \"%s\"\n", pthread_self(), servfd, errno,strerror(errno));
						fflush(stdout);
						close(servfd);
						exitThread();
						return(NULL);
					}
					/* Ritento nuovo socket */
					repeat = 1;
					break;
				}	/* Errore non recuperabile */
			} /* Error on connect */
			else {
				/* OK */
				repeat = 0;
				break;
			}
		}	/* Connect while */

		/* Se è il caso torno indietro */
		if (repeat) continue;

		/* Forwardo la richiesta, qualunque essa sia (inf/get) */

#ifdef DEBUG
printf("Thread: %ld. Forward richiesta del client al server.\n Req: %s\n", pthread_self(), req.buf);
fflush(stdout);
#endif

		ris = mysend(servfd, req.buf, strlen(req.buf));
		if (ris < 0) {

#ifdef DEBUG
printf("Thread: %ld. Errore su forward req.\n", pthread_self());
fflush(stdout);
#endif

			if (servconn_chance > 0) {
				servconn_chance--;
				close(servfd);
				continue;	/* Chiudo questa connessione e ritento */
			}
			else {
				close(clifd);
				close(servfd);
				exitThread();
				return(NULL);
			}
		}

		/* Aspetto la risposta del server */
		ris = myread(servfd, buffer, MAXLENRESP);
		if (ris <= 0) {

#ifdef DEBUG
printf("Thread: %ld. Errore in risposta server a forward req del client.\nErrore: %d \"%s\"\n", pthread_self(), errno,strerror(errno));
fflush(stdout);
#endif

			if (servconn_chance > 0) {
				servconn_chance--;
				close(servfd);
				continue;	/* Chiudo questa connessione e ritento */
			}
			else {
				close(clifd);
				close(servfd);
				exitThread();
				return(NULL);
			}
		}

#ifdef DEBUG
printf("Thread: %ld. OK arrivo risposta dal server per forward al client.\n Resp: %s\n", pthread_self(), buffer);
fflush(stdout);
#endif

		/* Concludo chiusura con server */
		close(servfd);

		/* Terminatore */
		buffer[ris] = '\0';
		buffer_len = ris;

		/* Controllo errori 40X nel qual caso forwardo e chiudo */
		if ((!(strncmp(buffer,"402\n\n",5))) ||
				(!(strncmp(buffer,"403\n\n",5))) ||
				(!(strncmp(buffer,"404\n\n",5))) ||
				(!(strncmp(buffer,"405\n\n",5)))) {

#ifdef DEBUG
printf("Thread: %ld. Server ha inviato un errore 40X, faccio forward al Client", pthread_self());
fflush(stdout);
#endif

			ris = mysend(clifd, buffer, buffer_len);
			close(clifd);
			exitThread();
			return(NULL);
		}

		/* Se la richiesta era INF faccio un parsing per INF e invio a client */
		if (req.reqType == INF) {
			/* Corretto */
			if (parseINF(buffer, buffer_len) == 0){
				ris = mysend(clifd, buffer, buffer_len);
				if (ris < 0) /* Errore irreparabile col client */

#ifdef DEBUG
printf("Thread: %ld. Errore in risposta a Client (dopo arrivo dal server).\n Errore: %d \"%s\"\n", pthread_self(), errno,strerror(errno));
fflush(stdout);
#endif

				close(clifd);
				exitThread();
				return(NULL);
			}
			/* Errato */
			else
				continue; /* Ritento */
		}

		/* Se la richiesta era GET per RANGE faccio il parsing per RANGE e poi invio il file */
		if (req.is_range) {
			/* Corretto */
			if (parseRANGE(buffer, buffer_len) == 0) ; /* Vado comunque a fare il parsing per fare prefetch sugli URL che trovo */
			/* Errato */
			else
				continue; /* Ritento */
		}

		int expire;
		char cachename[MAXLENPATH];
		struct timeval tod;

		/* Se invece la richiesta era GET per file completo prima faccio parsing per GET completo.
			 Se corretto salvo il file (così è a disposizione di altri thread) e poi invio a client */
		if (!(req.is_range)) {

#ifdef DEBUG
printf("Thread: %ld. Prelevo nome per caching.\n", pthread_self());
fflush(stdout);
#endif

			/* Prelevo nome univoco */
			my_tempname(cachename);

#ifdef DEBUG
printf("Thread: %ld. Salvo file caching.\n", pthread_self());
fflush(stdout);
#endif


			/* SE CORRETTO E COMPLETO salvo file appena scaricato in cache e prelevo expire */
			expire = buffer_data_to_file (cachename, buffer, buffer_len);

			/* Non completo / Corrotto */
			if (expire < 0) {

#ifdef DEBUG
printf("Thread: %ld. Il file arrivato è corrotto.\nEcco il file:\n", pthread_self());
fflush(stdout);
#endif

				write(1, buffer, MAXLENRESP);
				fflush(stdout);
				continue; /* Ritento da capo connessione con server e richiesta */
			}

			else {
				/* Prendo tempo attuale da sommare al tempo di expire del file appena ricevuto */
				gettimeofday(&tod, NULL);

				/* Gestione cache, aggiunta file */
				add_file_cache(&(req.inaddr), req.port, req.path, (tod.tv_sec + expire), cachename);
			}
		}
		

		/* Ora ho nel buffer ciò che devo inviare a Client e in ogni caso faccio lo stesso tipo di invio */
		ris = mysend(clifd, buffer, buffer_len);
		if (ris < 0) {	/* Errore irreparabile col client */

#ifdef DEBUG
printf("Thread: %ld. Errore in risposta a Client (dopo arrivo dal server).\n Errore: %d \"%s\"\n", pthread_self(), errno,strerror(errno));
fflush(stdout);
#endif

			close(clifd);
			exitThread();
			return(NULL);
		}

#ifdef DEBUG
printf("Thread: %ld. OK risposta dopo arrivo file del Server verso Client.\n Resp: %s\n", pthread_self(), buffer);
fflush(stdout);
#endif

		/* In ogni caso ho finito col client */
		close(clifd);

		/* Inizializzo qui, ma viene modificato nel parsing per scorrere il buffer con la risposta */
		int lenparsed = 0;
		struct Request *p_prefetch_req;
		char tmpname[MAXLENPATH];

#ifdef DEBUG
printf("Thread: %ld. Fase prefetching.\n", pthread_self());
fflush(stdout);
#endif

		while(1) {

#ifdef DEBUG
printf("Controllo su thread: %ld. While parse session().\n", pthread_self());
fflush(stdout);
#endif

			/* Struttura Request per fare richiesta al server, già passabile come parametro a thread */
			p_prefetch_req = (struct Request *) malloc (sizeof(struct Request));

			if (p_prefetch_req == NULL){

#ifdef DEBUG
printf("Thread: %ld. Errore in allocazione p_prefetch_req.\n", pthread_self());
fflush(stdout);
#endif

				exitThread();
				return(NULL);
			}
			/* Chiamo il parsing saltando almeno il minimo numero di byte che possono esserci prima dei dati.
				 NB: USO CAMPO "buf[]" della struttura Request per l'URL!! 
				 NB2: Chiedo sia REF che IDX;REF per 1° e 2° livello
			*/

#ifdef DEBUG
printf("Thread: %ld. Fase parsing del buffer.\n", pthread_self());
fflush(stdout);
#endif

			ris = parse((buffer+MIN_BYTE_BEFORE_DATA), &lenparsed, (buffer_len-MIN_BYTE_BEFORE_DATA), p_prefetch_req, FIRST_SECOND_LEVEL_PREFETCHING);

			/* Parsing finito, per errori o fine buffer */
			if(ris <= 0) {
				exitThread();
				return(NULL);
			}

			else if(ris == 1) {

#ifdef DEBUG
printf("Thread: %ld. OK parsing, URL estratto: %s.\n", pthread_self(), p_prefetch_req->buf);
fflush(stdout);
#endif

				/* Thread che fanno prefetch su REF - IDX+REF */
				pthread_attr_t attr;
				pthread_attr_init(&attr);
				pthread_t threadID;

				pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

				/* Se ho già il file passo al prossimo URL */
				if(get_cache_name(&(p_prefetch_req->inaddr), p_prefetch_req->port, p_prefetch_req->path, tmpname)) {
					free(p_prefetch_req);
					p_prefetch_req = NULL;
					continue;
				}

				/* Altrimenti setto il campo reqType della struttura Request che uso come parametro al thread, impostandolo per 
					il prefetching di primo e secondo livello.. */
				p_prefetch_req->reqType = FIRST_SECOND_LEVEL_PREFETCHING;

				/* .. e faccio partire il thread relativo alla sessione di prefetching per URL specificato in p_prefetch_req->buf[] */
				ris = pthread_create(&threadID, &attr, get_and_cache, (void *)p_prefetch_req);
				if(ris != 0) {
					printf("Thread: %ld. Chiamata a pthread_create() fallita.\n Errore: %d \"%s\"\n", pthread_self(), errno,strerror(errno));
					fflush(stdout);
					continue;
				}

			}

		} /* while del parsing */

	} /* While socket/binding */

} /* Session ****************/
コード例 #7
0
ファイル: ComThread.cpp プロジェクト: genua/anoubis
void *
ComThread::Entry(void)
{
	struct pollfd	 fds[2];
	ComTask		*current = NULL;
	Notification	*notify;
	ConnectResult	 connectResult;

	connectResult = connect();

	switch (connectResult) {
	case Success:
		break;
	case Failure:
		sendComEvent(JobCtrl::ERR_CONNECT);
		return (0);
	case VersionMismatch:
		sendComEvent(JobCtrl::ERR_VERSION_PROT);
		return (0);
	case AuthNoKey:
		sendComEvent(JobCtrl::ERR_NO_KEY);
		return (0);
	case AuthWrongKeyId:
		sendComEvent(JobCtrl::ERR_KEYID);
		return (0);
	case AuthInvalidKey:
		sendComEvent(JobCtrl::ERR_INV_KEY);
		return (0);
	case AuthInvalidCert:
		sendComEvent(JobCtrl::ERR_INV_CERT);
		return (0);
	case AuthSysFail:
		sendComEvent(JobCtrl::ERR_AUTH_SYS_FAIL);
		return(0);
	}

	fds[0].fd = comPipe_[0];
	fds[0].events = POLLIN;
	fds[1].fd = channel_->fd;
	fds[1].events = POLLIN;

	while (1) {
		/*
		 * Step 1: Clear the notification pipe. We do this first
		 *         to ensure that other events that come in along
		 *         the way will cause the poll below to return
		 *         immediately.
		 */
		while(1) {
			int ret;
			char buf[100];

			ret = read(comPipe_[0], buf, sizeof(buf));
			if (ret <= 0)
				break;
		}
		/* Step 2: Send any pending escalation answers. */
		while((notify = answerQueue_->pop()) != 0) {
			anoubis_token_t		 token;
			bool			 allowed;
			EscalationNotify	*escalation;

			escalation = dynamic_cast<EscalationNotify *>(notify);
			if (escalation) {
				allowed = escalation->getAnswer()->wasAllowed();
				token = escalation->getToken();
				anoubis_client_notifyreply(client_, token,
				    allowed ? 0 : EPERM, 0);
			}
			if (notify->needFree())
				delete notify;
		}
		/* Step 3: If no task is running, try to start a new one. */
		if (current == NULL) {
			Task	*task = getNextTask(Task::TYPE_COM);

			current = dynamic_cast<ComTask *>(task);
			if (current && !current->shallAbort()) {
				current->setClient(client_);
				current->exec();
			}
		}
		/*
		 * Step 4: If the current task is done, handle this.
		 *         This also handles errors in current->exec()
		 *         and performs the next stpes of the task if the
		 *         task is not yet done.
		 */
		if (current && (current->shallAbort() || current->done())) {
			TaskEvent	event(current, wxID_ANY);

			/* Task is no longer a COM task. Reschedule. */
			if (current->getType() != Task::TYPE_COM) {
				JobCtrl::instance()->addTask(current);
				current = NULL;
				continue;
			}
			if (current->shallAbort())
				current->setTaskResultAbort();
			sendEvent(event);
			/* Restart in case there are more tasks on the list. */
			current = NULL;
			continue;
		}
		/*
		 * Step 5: At this point we have an active task that is
		 *         waiting for data from the network and all
		 *         pending answer requests have been handled.
		 *         We poll until either new Jobs or answers
		 *         become ready or a message from the daemon arrives.
		 */
		if (!isConnected() || exitThread())
			break;
		fds[0].revents = 0;
		fds[1].revents = 0;
		if (poll(fds, 2, 60000) <= 0) {
			continue;
		}
		/*
		 * Step 6: Process a message from the Daemon if there is
		 *         one. Then start over.
		 */
		if (fds[1].revents) {
			if (!readMessage())
				break;
		}
	}

	/* Thread is short before exit, disconnect again */
	disconnect();

	return (0);
}