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

📄 netcam.c

📁 motion motion
💻 C
📖 第 1 页 / 共 5 页
字号:
			}			continue;		}		/*		 * FIXME		 * Need to check whether the image was received / decoded		 * satisfactorily		 */		/*		 * If non-streaming, want to synchronize our thread with the		 * motion main-loop.		 */		if (!netcam->caps.streaming) {			pthread_mutex_lock(&netcam->mutex);			/* before anything else, check for system shutdown */			if (netcam->finish) {				pthread_mutex_unlock(&netcam->mutex);				break;			}			/*			 * If our current loop has finished before the next			 * request from the motion main-loop, we do a			 * conditional wait (wait for signal).  On the other			 * hand, if the motion main-loop has already signalled			 * us, we just continue.  In either event, we clear			 * the start_capture flag set by the main loop.			 */			if (!netcam->start_capture)				pthread_cond_wait(&netcam->cap_cond, &netcam->mutex);			netcam->start_capture = 0;			pthread_mutex_unlock(&netcam->mutex);		}	/* the loop continues forever, or until motion shutdown */	}	/* our thread is finished - decrement motion's thread count */	pthread_mutex_lock(&global_lock);	threads_running--;	pthread_mutex_unlock(&global_lock);	/* log out a termination message */	motion_log(LOG_INFO, 0, "netcam camera handler: finish set, exiting");	/* setting netcam->thread_id to zero shows netcam_cleanup we're done */	netcam->thread_id = 0;	/* signal netcam_cleanup that we're all done */	pthread_mutex_lock(&netcam->mutex);	pthread_cond_signal(&netcam->exiting);	pthread_mutex_unlock(&netcam->mutex);	/* Goodbye..... */	pthread_exit(NULL);}static int netcam_setup_html(netcam_context_ptr netcam, struct url_t *url) {	struct context *cnt = netcam->cnt;	const char *ptr;                  /* working var */	char *userpass;                   /* temp pointer to config value */	char *encuserpass;                /* temp storage for encoded ver */	char *request_pass = NULL;        /* temp storage for base64 conv */	int ix;	/* First the http context structure */	netcam->response = (struct rbuf *) mymalloc(sizeof(struct rbuf));	memset(netcam->response, 0, sizeof(struct rbuf));	if (debug_level > CAMERA_INFO)		motion_log(LOG_INFO, 0, "netcam_setup_html: Netcam has flags: HTTP1.0: %s HTTP1.1: %s Keep-Alive %s.", 		                        netcam->connect_http_10 ? "1":"0", netcam->connect_http_11 ? "1":"0", 		                        netcam->connect_keepalive ? "ON":"OFF");	/*	 * The network camera may require a username and password.  If	 * so, the information can come from two different places in the	 * motion configuration file.  Either it can be present in	 * the netcam_userpass, or it can be present as a part of the URL	 * for the camera.  We assume the first of these has a higher	 * relevance.	 */	if (cnt->conf.netcam_userpass)		ptr = cnt->conf.netcam_userpass;	else		ptr = url->userpass;	/* base64_encode needs up to 3 additional chars */	if (ptr) {		userpass = mymalloc(strlen(ptr) + 3);		strcpy(userpass, ptr);	} else		userpass = NULL;	/*	 * Now we want to create the actual string which will be used to	 * connect to the camera.  It may or may not contain a username /	 * password.  We first compose a basic connect message, then check	 * if a Keep-Alive header is to be included (or just 'close'), then	 * whether a username / password is required and, if so, just	 * concatenate it with the request.	 *	 */	/* space for final \r\n plus string terminator */	ix = 3;	/* See if username / password is required */	if (userpass) {         /* if either of the above are non-NULL */		/* Allocate space for the base64-encoded string */		encuserpass = mymalloc(BASE64_LENGTH(strlen(userpass)) + 1);		/* Fill in the value */		base64_encode(userpass, encuserpass, strlen(userpass));		/* Now create the last part (authorization) of the request */		request_pass = mymalloc(strlen(connect_auth_req) +		                        strlen(encuserpass) + 1);		ix += sprintf(request_pass, connect_auth_req, encuserpass);		/* free the working variables */		free(encuserpass);	}	/*	 * We are now ready to set up the netcam's "connect request".  Most of	 * this comes from the (preset) string 'connect_req', but additional	 * characters are required if there is a proxy server, or if there is	 * a Keep-Alive connection rather than a close connection, or	 * a username / password for the camera.  The variable 'ix' currently	 * has the number of characters required for username/password (which	 * could be zero) and for the \r\n and string terminator.  We will also	 * always need space for the netcam path, and if a proxy is being used	 * we also need space for a preceding  'http://{hostname}' for the	 * netcam path.	 * Note: Keep-Alive (but not HTTP 1.1) is disabled if a proxy URL	 * is set, since HTTP 1.0 Keep-alive cannot be transferred through.	 */	if (cnt->conf.netcam_proxy) {		/*		 * Allocate space for a working string to contain the path.		 * The extra 4 is for "://" and string terminator.		 */		ptr = mymalloc(strlen(url->service) + strlen(url->host)		               + strlen(url->path) + 4);		sprintf((char *)ptr, "http://%s%s", url->host, url->path);	        netcam->connect_keepalive=0; /* Disable Keepalive if proxy */		if (debug_level > CAMERA_INFO)			motion_log(LOG_DEBUG, 0, "Removed netcam_keepalive flag due to proxy set." 			                         "Proxy is incompatible with Keep-Alive.");	} else {		/* if no proxy, set as netcam_url path */		ptr = url->path;		/*		 * after generating the connect message the string		 * will be freed, so we don't want netcam_url_free		 * to free it as well.		 */		url->path = NULL;	}	ix += strlen(ptr);       /* Now add the required number of characters for the close header        * or Keep-Alive header.  We test the flag which can be unset if	* there is a problem (rather than the flag in the conf structure	* which is read-only.	*/         if (netcam->connect_keepalive) {		ix += strlen(connect_req_keepalive);	} else {		ix += strlen(connect_req_close);	}	/* Point to either the HTTP 1.0 or 1.1 request header set     */	/* If the configuration is anything other than 1.1, use 1.0   */	/* as a default. This avoids a chance of being left with none */	if (netcam->connect_http_11==TRUE)		connect_req = connect_req_http11;	else		connect_req = connect_req_http10;	/*	 * Now that we know how much space we need, we can allocate space	 * for the connect-request string.	 */	netcam->connect_request = mymalloc(strlen(connect_req) + ix +	                          strlen(netcam->connect_host));	/* Now create the request string with an sprintf */	sprintf(netcam->connect_request, connect_req, ptr,	        netcam->connect_host);         if (netcam->connect_keepalive) { 		strcat(netcam->connect_request, connect_req_keepalive);	} else {		strcat(netcam->connect_request, connect_req_close);	}	if (userpass) {		strcat(netcam->connect_request, request_pass);		free(request_pass);		free(userpass);	}	/* put on the final CRLF onto the request */	strcat(netcam->connect_request, "\r\n");	free((void *)ptr);	netcam_url_free(url);         /* Cleanup the url data */	if (debug_level > CAMERA_INFO) {		motion_log(-1, 0, "Camera connect string is ''%s''", netcam->connect_request);		motion_log(-1, 0, "End of camera connect string.");	}	/*	 * Our basic initialisation has been completed.  Now we will attempt	 * to connect with the camera so that we can then get a "header"	 * in order to find out what kind of camera we are dealing with,	 * as well as what are the picture dimensions.  Note that for	 * this initial connection, any failure will cause an error	 * return from netcam_start (unlike later possible attempts at	 * re-connecting, if the network connection is later interrupted).	 */	for (ix = 0; ix < MAX_HEADER_RETRIES; ix++) {		/*		 * netcam_connect does an automatic netcam_close, so it's		 * safe to include it as part of this loop		 * (Not always true now Keep-Alive is implemented)		 */		if (debug_level > CAMERA_INFO)			motion_log(-1, 0, "netcam_setup_html: about to try to connect, time #%d", ix );		if (netcam_connect(netcam, 0) != 0) {			motion_log(LOG_ERR, 0,"Failed to open camera - check your config and that netcamera is online");			/* Fatal error on startup */			ix = MAX_HEADER_RETRIES;			break;;		}		if (netcam_read_first_header(netcam) >= 0)			break;		motion_log(LOG_ERR, 0, "Error reading first header - re-trying");	}	if (ix == MAX_HEADER_RETRIES) {		motion_log(LOG_ERR, 0, "Failed to read first camera header - giving up for now");		return -1;	}	/*	 * If this is a streaming camera, we need to position just	 * past the boundary string and read the image header	 */	if (netcam->caps.streaming) {		if (netcam_read_next_header(netcam) < 0) {			motion_log(LOG_ERR, 0,			           "Failed to read first stream header - giving up for now");			return -1;		}	}	if (debug_level > CAMERA_INFO)		motion_log(-1, 0, "netcam_setup_html: connected, going on to read image.", ix );	netcam->get_image = netcam_read_html_jpeg;	return 0;}static int netcam_setup_ftp(netcam_context_ptr netcam, struct url_t *url) {	struct context *cnt = netcam->cnt;	const char *ptr;	if ((netcam->ftp = ftp_new_context()) == NULL)		return -1;	/*	 * We copy the strings out of the url structure into the ftp_context	 * structure.  By setting url->{string} to NULL we effectively "take	 * ownership" of the string away from the URL (i.e. it won't be freed	 * when we cleanup the url structure later).	 */	netcam->ftp->path = url->path;	url->path = NULL;	if (cnt->conf.netcam_userpass != NULL)		ptr = cnt->conf.netcam_userpass;	else {		ptr = url->userpass;  /* don't set this one NULL, gets freed */	}	if (ptr != NULL) {		char *cptr;		if ((cptr = strchr(ptr, ':')) == NULL)			netcam->ftp->user = strdup(ptr);		else {			netcam->ftp->user = mymalloc((cptr - ptr));			memcpy(netcam->ftp->user,ptr,(cptr - ptr));			netcam->ftp->passwd = strdup(cptr + 1);		}	}	netcam_url_free(url);	/*	 * The ftp context should be all ready to attempt a connection with	 * the server, so we try ....	 */	if (ftp_connect(netcam) < 0) {		ftp_free_context(netcam->ftp);		return -1;	}	if (ftp_send_type(netcam->ftp, 'I') < 0) {		motion_log(LOG_ERR, 0, "Error sending TYPE I to ftp server");		return -1;	}	netcam->get_image = netcam_read_ftp_jpeg;	return 0;}/** * netcam_recv * *      This routine receives the next block from the netcam.  It takes care *      of the potential timeouts and interrupt which may occur because of *      the settings from setsockopt. * * Parameters: * *      netcam          Pointer to a netcam context *      buffptr         Pointer to the receive buffer *      buffsize        Length of the buffer * * Returns: *      If successful, the length of the message received, otherwise the *      error reply from the system call. * */ssize_t netcam_recv(netcam_context_ptr netcam, void *buffptr, size_t buffsize) {	ssize_t retval;	fd_set fd_r;	struct timeval selecttime;	FD_ZERO(&fd_r);	FD_SET(netcam->sock, &fd_r);	selecttime = netcam->timeout;	retval = select(FD_SETSIZE, &fd_r, NULL, NULL, &selecttime);	if (retval == 0) {             /* 0 means timeout */		return -1;	}	return recv(netcam->sock, buffptr, buffsize, 0);}/** * netcam_cleanup * *      This routine releases any allocated data within the netcam context, *      then frees the context itself.  Extreme care must be taken to assure *      that the multi-threading nature of the program is correctly *      handled. *      This function is also called from motion_init if first time connection *      fails and we start retrying until we get a valid first frame from the *      camera.  * * Parameters: * *      netcam           Pointer to a netcam context *      init_retry_flag  1 when the function is called because we are retrying *                         making the initial connection with a netcam and we know *                         we do not need to kill a netcam handler thread *                       0 in any other case. * * Returns:              Nothing. * */void netcam_cleanup(netcam_context_ptr netcam, int init_retry_flag){	struct timespec waittime;	if (!netcam)		return;	/*	 * This 'lock' is just a bit of "defensive" programming.  It should	 * only be necessary if the routine is being called from different	 * threads, but in our Motion design, it should only be called from	 * the motion main-loop.	 */	pthread_mutex_lock(&netcam->mutex);	if (netcam->cnt->netcam == NULL) {		return;	}	/*	 * We set the netcam_context pointer in the motion main-loop context	 * to be NULL, so that this routine won't be called a second time	 */	netcam->cnt->netcam = NULL;	/*	 * Next we set 'finish' in order to get the camera-handler thread	 * to stop.	 */	netcam->finish = 1;	/*	 * If the camera is non-streaming, the handler thread could be waiting	 * for a signal, so we send it one.  If it's actually waiting on the	 * condition, it won't actually start yet because we still have	 * netcam->mutex locked.	 */	if (!netcam

⌨️ 快捷键说明

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