?? netcam.c
字號:
* * Read the next header record from the camera. * * Parameters * * netcam pointer to a netcam_context * * Returns: 0 for success, -1 if any error * */static int netcam_read_next_header(netcam_context_ptr netcam){ int retval; char *header; /* * return if not connected */ if (netcam->sock == -1) return -1; /* * We are expecting a header which *must* contain a mime-type of * image/jpeg, and *might* contain a Content-Length. * * If this is a "streaming" camera, the header *must* be preceded * by a "boundary" string. * */ netcam->caps.content_length = 0; /* * If this is a "streaming" camera, the stream header must be * preceded by a "boundary" string */ if (netcam->caps.streaming) { while (1) { retval = header_get(netcam, &header, HG_NONE); if (retval != HG_OK) { /* Header reported as not-OK, check to see if it's null */ if (strlen(header) == 0 ) { if (debug_level > CAMERA_INFO) motion_log(LOG_DEBUG, 0, "Error reading image header, streaming mode (1). Null header."); } else { /* Header is not null. Output it in case it's a new camera with unknown headers. */ if (debug_level > CAMERA_INFO) motion_log(LOG_ERR, 0, "Error reading image header, streaming mode (1). " "Unknown header '%s'", header ); } free(header); return -1; } retval = (strstr(header, netcam->boundary) == NULL); free(header); if (!retval) break; } } while (1) { retval = header_get(netcam, &header, HG_NONE); if (retval != HG_OK) { motion_log(LOG_ERR, 0, "Error reading image header (2)"); free(header); return -1; } if (*header == 0) break; if ((retval = netcam_check_content_type(header)) >= 0) { if (retval != 1) { motion_log(LOG_ERR, 0, "Header not JPEG"); free(header); return -1; } } if ((retval = (int) netcam_check_content_length(header)) > 0) { netcam->caps.content_length = 1; /* set flag */ netcam->receiving->content_length = (int) retval; } free(header); } if (debug_level > CAMERA_INFO) motion_log(-1, 0, "Found image header record"); free(header); return 0;}/** * netcam_read_first_header * * This routine attempts to read a header record from the netcam. If * successful, it analyses the header to determine whether the camera is * a "streaming" type. If it is, the routine looks for the Boundary-string; * if found, it positions just past the string so that the image header can * be read. It then reads the image header and continues processing that * header as well. * * If the camera does not appear to be a streaming type, it is assumed that the * header just read was the image header. It is processed to determine whether * a Content-length is present. * * After this processing, the routine returns to the caller. * * Parameters: * netcam Pointer to the netcam_context structure * * Returns: Content-type code if successful, -1 if not * */static int netcam_read_first_header(netcam_context_ptr netcam){ int retval = -2; /* "Unknown err" */ int ret; int firstflag = 1; int aliveflag = 0; /* If we have seen a Keep-Alive header from cam */ int closeflag = 0; /* If we have seen a Connection: close header from cam */ char *header; char *boundary; struct context *cnt = netcam->cnt; /* for conf debug_level */ /* Send the initial command to the camera */ if (send(netcam->sock, netcam->connect_request, strlen(netcam->connect_request), 0) < 0) { motion_log(LOG_ERR, 1, "Error sending 'connect' request"); return -1; } /* * We expect to get back an HTTP header from the camera. * Successive calls to header_get will return each line * of the header received. We will continue reading until * a blank line is received. * * As we process the header, we are looking for either of * header lines Content-type or Content-length. Content-type * is used to determine whether the camera is "streaming" or * "non-streaming", and Content-length will be used to determine * whether future reads of images will be controlled by the * length specified before the image, or by a boundary string. * * The Content-length will only be present "just before" an * image is sent (if it is present at all). That means that, if * this is a "streaming" camera, it will not be present in the * "first header", but will occur later (after a boundary-string). * For a non-streaming camera, however, there is no boundary-string, * and the first header is, in fact, the only header. In this case, * there may be a Content-length. * */ while (1) { /* 'Do forever' */ ret = header_get(netcam, &header, HG_NONE); if (debug_level > CAMERA_INFO) /* Changed criterion and moved up from below to catch headers that cause returns */ motion_log(LOG_DEBUG, 0, "Received first header ('%s')", header); if (ret != HG_OK) { if (debug_level > CAMERA_INFO) motion_log(LOG_ERR, 0, "Error reading first header (%s)", header); free(header); return -1; } if (firstflag) { if ((ret = http_result_code(header)) != 200) { if (debug_level > CAMERA_INFO) motion_log(-1, 0, "HTTP Result code %d", ret); free(header); if (netcam->connect_keepalive) { /* Cannot unset netcam->cnt->conf.netcam_http as it is assigned const */ /* But we do unset the netcam keepalive flag which was set in netcam_start */ /* This message is logged as Information as it would be useful to know */ /* if your netcam often returns bad HTTP result codes */ netcam->connect_keepalive = 0; motion_log(LOG_INFO, 0, "Removed netcam Keep-Alive flag" "due to apparent closed HTTP connection."); } return ret; } firstflag = 0; free(header); continue; } if (*header == 0) /* blank line received */ break; /* Check if this line is the content type */ if ((ret = netcam_check_content_type(header)) >= 0) { retval = ret; /* * We are expecting to find one of three types: * 'multipart/x-mixed-replace', 'multipart/mixed' * or 'image/jpeg'. The first two will be received * from a streaming camera, and the third from a * camera which provides a single frame only. */ switch (ret) { case 1: /* not streaming */ if (SETUP) { if (netcam->connect_keepalive) motion_log(LOG_DEBUG, 0, "Non-streaming camera (keep-alive set)"); else motion_log(LOG_DEBUG, 0, "Non-streaming camera (keep-alive not set)"); } netcam->caps.streaming = 0; break; case 2: /* streaming */ if (SETUP) motion_log(LOG_DEBUG, 0, "Streaming camera"); netcam->caps.streaming = 1; if ((boundary = strstr(header, "boundary="))) { /* * on error recovery this * may already be set * */ if (netcam->boundary) free(netcam->boundary); netcam->boundary = strdup(boundary + 9); /* * HTTP protocol apparently permits the boundary string * to be quoted (the Lumenera does this, which caused * trouble) so we need to get rid of any surrounding * quotes */ check_quote(netcam->boundary); netcam->boundary_length = strlen(netcam->boundary); if (SETUP) { motion_log(LOG_DEBUG, 0, "Boundary string [%s]", netcam->boundary); } } break; default:{ /* error */ motion_log(LOG_ERR, 0, "Unrecognized content type"); free(header); return -1; } } } else if ((ret = (int) netcam_check_content_length(header)) >= 0) { if (SETUP) motion_log(LOG_DEBUG, 0, "Content-length present"); netcam->caps.content_length = 1; /* set flag */ netcam->receiving->content_length = ret; } else if (netcam_check_keepalive(header) == TRUE) { /* Note that we have received a Keep-Alive header, and thus the socket can be left open */ aliveflag=TRUE; netcam->keepalive_thisconn = TRUE; /* This flag will not be set when a Streaming cam is in use, but that */ /* does not matter as the test below looks at Streaming state also. */ } else if (netcam_check_close(header) == TRUE) { /* Note that we have received a Connection: close header */ closeflag=TRUE; /* This flag is acted upon below */ if (debug_level > CAMERA_INFO) /* Changed criterion and moved up from below to catch headers that cause returns */ motion_log(LOG_DEBUG, 0, "Found Conn:close header ('%s')", header); } free(header); } free(header); if (!netcam->caps.streaming && netcam->connect_keepalive) { /* * If we are a non-streaming (ie. Jpeg) netcam and keepalive is configured */ if (aliveflag){ if (closeflag) { /* * If not a streaming cam, and keepalive is set, and the flag shows we * did not see a Keep-Alive field returned from netcam and a Close field. * Not quite sure what the correct course of action is here. In for testing. */ motion_log(LOG_INFO, 0, "Info: Both 'Connection: Keep-Alive' and 'Connection: close' " "header received. Motion continues unchanged."); }else{ /* aliveflag && !closeflag * * If not a streaming cam, and keepalive is set, and the flag shows we * just got a Keep-Alive field returned from netcam and no Close field. * No action, as this is the normal case. In debug we print a notification. */ if (debug_level > CAMERA_INFO) motion_log(LOG_INFO, 0, "Info: Received a Keep-Alive field in this set of headers."); } }else{ /* !aliveflag */ if (!closeflag) { /* * If not a streaming cam, and keepalive is set, and the flag shows we * did not see a Keep-Alive field returned from netcam nor a Close field. * Not quite sure what the correct course of action is here. In for testing. */ motion_log(LOG_INFO, 0, "Info: No 'Connection: Keep-Alive' nor 'Connection: close' " "header received. Motion continues unchanged."); }else{ /* !aliveflag & closeflag * If not a streaming cam, and keepalive is set, and the flag shows we * received a 'Connection: close' field returned from netcam. It is not likely * we will get a Keep-Alive and Close header together - this is picked up by * the test code above. * If we receive a Close header, then we want to cease keep-alive for this cam. * This situation will occur in 2 situations: * (a) in HTTP 1.1 when the client wants to stop the keep-alive * (and in this case it would be correct to close connection and then * make a new one, with keep-alive set again). * (b) in HTTP 1.0 with keepalive, when the client does not support it. * In this case we should not attempt to re-start Keep-Alive. * Due to that, we accept a Connection: close header in HTTP 1.0 & 1.1 modes * * To tell between the sitation where a camera has been in Keep-Alive mode and * is now finishing (and will want to be re-started in Keep-Alive) and the other * case when a cam does not support it, we have a flag which says if the netcam * has returned a Keep-Alive flag during this connection. If that's set, we * set ourselves up to re-connect with Keep-Alive after the socket is closed. * If it's not set, then we will not try again to use Keep-Alive. */ if (!netcam->keepalive_thisconn) { netcam->connect_keepalive = FALSE; /* No further attempts at keep-alive */ motion_log(LOG_INFO, 0, "Removed netcam Keep-Alive flag because 'Connection: close' " "header received. Netcam does not support Keep-Alive. Motion " "continues in non-Keep-Alive."); } else { netcam->keepalive_timeup = TRUE; /* We will close and re-open keep-alive */ motion_log(LOG_INFO, 0, "Keep-Alive has reached end of valid period. Motion will close " "netcam, then resume Keep-Alive with a new socket."); } } } } return retval;}/** * netcam_disconnect * * Disconnect from the network camera. * * Parameters: * * netcam pointer to netcam context * * Returns: Nothing * */static void netcam_disconnect(netcam_context_ptr netcam){ if (netcam->sock > 0) { if (close(netcam->sock) < 0) motion_log(LOG_ERR, 1, "netcam_disconnect"); netcam->sock = -1; }}/** * netcam_connect * * Attempt to open the network camera as a stream device. * Keep-alive is supported, ie. if netcam->connect_keepalive is TRUE, we * re-use netcam->sock unless it has value -1, meaning it is invalid. * * Parameters: * * netcam pointer to netcam_context structure * err_flag flag to suppress error printout (1 => suppress) * Note that errors which indicate something other than * a network connection problem are not suppressed. * * Returns: 0 for success, -1 for error * */static int netcam_connect(netcam_context_ptr netcam, int err_flag){ struct sockaddr_in server; /* for connect */ struct addrinfo *res; /* for getaddrinfo */ int ret; int saveflags; int back_err; int optval; socklen_t optlen=sizeof(optval); socklen_t len; fd_set fd_w; struct timeval selecttime; /* Assure any previous connection has been closed - IF we are not in keepalive */ if (!netcam->connect_keepalive) { if (debug_level > CAMERA_INFO ) motion_log(LOG_DEBUG, 0, "netcam_connect, disconnecting netcam since keep-alive not set." ); netcam_disconnect(netcam); /* create a new socket */ if ((netcam->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { motion_log(LOG_ERR, 1, "netcam_connect with no keepalive, attempt to create socket failed."); return -1; } if (debug_level > CAMERA_INFO ) motion_log(LOG_DEBUG, 0, "netcam_connect with no keepalive, new socket created fd %d", netcam->sock); } else { /* We are in keepalive mode, check for invalid socket */ if (netcam->sock == -1) { /* Must be first time, or closed, create a new socket */ if ((netcam->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { motion_log(LOG_ERR, 1, "netcam_connect with keepalive set, invalid socket." "This could be the first time. Creating a new one failed."); return -1; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -