⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 printd.c

📁 unix环境高级编程第二版配套源代码 unix环境高级编程第二版配套源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		sprintf(name, "%s/%s/%ld", SPOOLDIR, DATADIR, jobid);		unlink(name);		pthread_exit((void *)1);	}	close(fd);	/*	 * Send response to client.	 */	res.retcode = 0;	res.jobid = htonl(jobid);	sprintf(res.msg, "request ID %ld", jobid);	writen(sockfd, &res, sizeof(struct printresp));	/*	 * Notify the printer thread, clean up, and exit.	 */	log_msg("adding job %ld to queue", jobid);	add_job(&req, jobid);	pthread_cleanup_pop(1);	return((void *)0);}/** Add a worker to the list of worker threads.** LOCKING: acquires and releases workerlock.*/voidadd_worker(pthread_t tid, int sockfd){	struct worker_thread	*wtp;	if ((wtp = malloc(sizeof(struct worker_thread))) == NULL) {		log_ret("add_worker: can't malloc");		pthread_exit((void *)1);	}	wtp->tid = tid;	wtp->sockfd = sockfd;	pthread_mutex_lock(&workerlock);	wtp->prev = NULL;	wtp->next = workers;	if (workers == NULL)		workers = wtp;	else		workers->prev = wtp;	pthread_mutex_unlock(&workerlock);}/* * Cancel (kill) all outstanding workers. * * LOCKING: acquires and releases workerlock. */voidkill_workers(void){	struct worker_thread	*wtp;	pthread_mutex_lock(&workerlock);	for (wtp = workers; wtp != NULL; wtp = wtp->next)		pthread_cancel(wtp->tid);	pthread_mutex_unlock(&workerlock);}/* * Cancellation routine for the worker thread. * * LOCKING: acquires and releases workerlock. */voidclient_cleanup(void *arg){	struct worker_thread	*wtp;	pthread_t				tid;	tid = (pthread_t)arg;	pthread_mutex_lock(&workerlock);	for (wtp = workers; wtp != NULL; wtp = wtp->next) {		if (wtp->tid == tid) {			if (wtp->next != NULL)				wtp->next->prev = wtp->prev;			if (wtp->prev != NULL)				wtp->prev->next = wtp->next;			else				workers = wtp->next;			break;		}	}	pthread_mutex_unlock(&workerlock);	if (wtp != NULL) {		close(wtp->sockfd);		free(wtp);	}}/* * Deal with signals. * * LOCKING: acquires and releases configlock. */void *signal_thread(void *arg){	int		err, signo;	for (;;) {		err = sigwait(&mask, &signo);		if (err != 0)			log_quit("sigwait failed: %s", strerror(err));		switch (signo) {		case SIGHUP:			/*			 * Schedule to re-read the configuration file.			 */			pthread_mutex_lock(&configlock);			reread = 1;			pthread_mutex_unlock(&configlock);			break;		case SIGTERM:			kill_workers();			log_msg("terminate with signal %s", strsignal(signo));			exit(0);		default:			kill_workers();			log_quit("unexpected signal %d", signo);		}	}}/* * Add an option to the IPP header. * * LOCKING: none. */char *add_option(char *cp, int tag, char *optname, char *optval){	int		n;	union {		int16_t s;		char c[2];	}		u;	*cp++ = tag;	n = strlen(optname);	u.s = htons(n);	*cp++ = u.c[0];	*cp++ = u.c[1];	strcpy(cp, optname);	cp += n;	n = strlen(optval);	u.s = htons(n);	*cp++ = u.c[0];	*cp++ = u.c[1];	strcpy(cp, optval);	return(cp + n);}/* * Single thread to communicate with the printer. * * LOCKING: acquires and releases joblock and configlock. */void *printer_thread(void *arg){	struct job		*jp;	int				hlen, ilen, sockfd, fd, nr, nw;	char			*icp, *hcp;	struct ipp_hdr	*hp;	struct stat		sbuf;	struct iovec	iov[2];	char			name[FILENMSZ];	char			hbuf[HBUFSZ];	char			ibuf[IBUFSZ];	char			buf[IOBUFSZ];	char			str[64];	for (;;) {		/*		 * Get a job to print.		 */		pthread_mutex_lock(&joblock);		while (jobhead == NULL) {			log_msg("printer_thread: waiting...");			pthread_cond_wait(&jobwait, &joblock);		}		remove_job(jp = jobhead);		log_msg("printer_thread: picked up job %ld", jp->jobid);		pthread_mutex_unlock(&joblock);		update_jobno();		/*		 * Check for a change in the config file.		 */		pthread_mutex_lock(&configlock);		if (reread) {			freeaddrinfo(printer);			printer = NULL;			printer_name = NULL;			reread = 0;			pthread_mutex_unlock(&configlock);			init_printer();		} else {			pthread_mutex_unlock(&configlock);		}		/*		 * Send job to printer.		 */		sprintf(name, "%s/%s/%ld", SPOOLDIR, DATADIR, jp->jobid);		if ((fd = open(name, O_RDONLY)) < 0) {			log_msg("job %ld canceled - can't open %s: %s",			  jp->jobid, name, strerror(errno));			free(jp);			continue;		}		if (fstat(fd, &sbuf) < 0) {			log_msg("job %ld canceled - can't fstat %s: %s",			  jp->jobid, name, strerror(errno));			free(jp);			close(fd);			continue;		}		if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {			log_msg("job %ld deferred - can't create socket: %s",			  jp->jobid, strerror(errno));			goto defer;		}		if (connect_retry(sockfd, printer->ai_addr,		  printer->ai_addrlen) < 0) {			log_msg("job %ld deferred - can't contact printer: %s",			  jp->jobid, strerror(errno));			goto defer;		}		/*		 * Set up the IPP header.		 */		icp = ibuf;		hp = (struct ipp_hdr *)icp;		hp->major_version = 1;		hp->minor_version = 1;		hp->operation = htons(OP_PRINT_JOB);		hp->request_id = htonl(jp->jobid);		icp += offsetof(struct ipp_hdr, attr_group);		*icp++ = TAG_OPERATION_ATTR;		icp = add_option(icp, TAG_CHARSET, "attributes-charset",		  "utf-8");		icp = add_option(icp, TAG_NATULANG,		  "attributes-natural-language", "en-us");		sprintf(str, "http://%s:%d", printer_name, IPP_PORT);		icp = add_option(icp, TAG_URI, "printer-uri", str);		icp = add_option(icp, TAG_NAMEWOLANG,		  "requesting-user-name", jp->req.usernm);		icp = add_option(icp, TAG_NAMEWOLANG, "job-name",		  jp->req.jobnm);		if (jp->req.flags & PR_TEXT) {			icp = add_option(icp, TAG_MIMETYPE, "document-format",			  "text/plain");		} else {			icp = add_option(icp, TAG_MIMETYPE, "document-format",			  "application/postscript");		}		*icp++ = TAG_END_OF_ATTR;		ilen = icp - ibuf;		/*		 * Set up the HTTP header.		 */		hcp = hbuf;		sprintf(hcp, "POST /%s/ipp HTTP/1.1\r\n", printer_name);		hcp += strlen(hcp);		sprintf(hcp, "Content-Length: %ld\r\n",		  (long)sbuf.st_size + ilen);		hcp += strlen(hcp);		strcpy(hcp, "Content-Type: application/ipp\r\n");		hcp += strlen(hcp);		sprintf(hcp, "Host: %s:%d\r\n", printer_name, IPP_PORT);		hcp += strlen(hcp);		*hcp++ = '\r';		*hcp++ = '\n';		hlen = hcp - hbuf;		/*		 * Write the headers first.  Then send the file.		 */		iov[0].iov_base = hbuf;		iov[0].iov_len = hlen;		iov[1].iov_base = ibuf;		iov[1].iov_len = ilen;		if ((nw = writev(sockfd, iov, 2)) != hlen + ilen) {			log_ret("can't write to printer");			goto defer;		}		while ((nr = read(fd, buf, IOBUFSZ)) > 0) {			if ((nw = write(sockfd, buf, nr)) != nr) {				if (nw < 0)				  log_ret("can't write to printer");				else				  log_msg("short write (%d/%d) to printer", nw, nr);				goto defer;			}		}		if (nr < 0) {			log_ret("can't read %s", name);			goto defer;		}		/*		 * Read the response from the printer.		 */		if (printer_status(sockfd, jp)) {			unlink(name);			sprintf(name, "%s/%s/%ld", SPOOLDIR, REQDIR, jp->jobid);			unlink(name);			free(jp);			jp = NULL;		}defer:		close(fd);		if (sockfd >= 0)			close(sockfd);		if (jp != NULL) {			replace_job(jp);			sleep(60);		}	}}/* * Read data from the printer, possibly increasing the buffer. * Returns offset of end of data in buffer or -1 on failure. * * LOCKING: none. */ssize_treadmore(int sockfd, char **bpp, int off, int *bszp){	ssize_t	nr;	char	*bp = *bpp;	int		bsz = *bszp;	if (off >= bsz) {		bsz += IOBUFSZ;		if ((bp = realloc(*bpp, bsz)) == NULL)			log_sys("readmore: can't allocate bigger read buffer");		*bszp = bsz;		*bpp = bp;	}	if ((nr = tread(sockfd, &bp[off], bsz-off, 1)) > 0)		return(off+nr);	else		return(-1);}/* * Read and parse the response from the printer.  Return 1 * if the request was successful, and 0 otherwise. * * LOCKING: none. */intprinter_status(int sockfd, struct job *jp){	int				i, success, code, len, found, bufsz;	long			jobid;	ssize_t			nr;	char			*statcode, *reason, *cp, *contentlen;	struct ipp_hdr	*hp;	char			*bp;	/*	 * Read the HTTP header followed by the IPP response header.	 * They can be returned in multiple read attempts.  Use the	 * Content-Length specifier to determine how much to read.	 */	success = 0;	bufsz = IOBUFSZ;	if ((bp = malloc(IOBUFSZ)) == NULL)		log_sys("printer_status: can't allocate read buffer");	while ((nr = tread(sockfd, bp, IOBUFSZ, 5)) > 0) {		/*		 * Find the status.  Response starts with "HTTP/x.y"		 * so we can skip the first 8 characters.		 */		cp = bp + 8;		while (isspace((int)*cp))			cp++;		statcode = cp;		while (isdigit((int)*cp))			cp++;		if (cp == statcode) { /* Bad format; log it and move on */			log_msg(bp);		} else {			*cp++ = '\0';			reason = cp;			while (*cp != '\r' && *cp != '\n')				cp++;			*cp = '\0';			code = atoi(statcode);			if (HTTP_INFO(code))				continue;			if (!HTTP_SUCCESS(code)) { /* probable error: log it */				bp[nr] = '\0';				log_msg("error: %s", reason);				break;			}			/*			 * The HTTP request was okay, but we still			 * need to check the IPP status.  First			 * search for the Content-Length specifier.			 */			i = cp - bp;			for (;;) {				while (*cp != 'C' && *cp != 'c' && i < nr) {					cp++;					i++;				}				if (i >= nr &&	/* get more header */				  ((nr = readmore(sockfd, &bp, i, &bufsz)) < 0))					goto out;				cp = &bp[i];				if (strncasecmp(cp, "Content-Length:", 15) == 0) {					cp += 15;					while (isspace((int)*cp))						cp++;					contentlen = cp;					while (isdigit((int)*cp))						cp++;					*cp++ = '\0';					i = cp - bp;					len = atoi(contentlen);					break;				} else {					cp++;					i++;				}			}			if (i >= nr &&	/* get more header */			  ((nr = readmore(sockfd, &bp, i, &bufsz)) < 0))				goto out;			cp = &bp[i];			found = 0;			while (!found) {  /* look for end of HTTP header */				while (i < nr - 2) {					if (*cp == '\n' && *(cp + 1) == '\r' &&					  *(cp + 2) == '\n') {						found = 1;						cp += 3;						i += 3;						break;					}					cp++;					i++;				}				if (i >= nr &&	/* get more header */				  ((nr = readmore(sockfd, &bp, i, &bufsz)) < 0))					goto out;				cp = &bp[i];			}			if (nr - i < len &&	/* get more header */			  ((nr = readmore(sockfd, &bp, i, &bufsz)) < 0))				goto out;			cp = &bp[i];			hp = (struct ipp_hdr *)cp;			i = ntohs(hp->status);			jobid = ntohl(hp->request_id);			if (jobid != jp->jobid) {				/*				 * Different jobs.  Ignore it.				 */				log_msg("jobid %ld status code %d", jobid, i);				break;			}			if (STATCLASS_OK(i))				success = 1;			break;		}	}out:	free(bp);	if (nr < 0) {		log_msg("jobid %ld: error reading printer response: %s",		  jobid, strerror(errno));	}	return(success);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -