?? netcam.c
字號:
} 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 + -