📄 netcam_ftp.c
字号:
break; case 1: case 4: case 5: case -1: default: close(ctxt->control_file_desc); ctxt->control_file_desc = -1; return(-1); } res = ftp_send_passwd(ctxt); if (res < 0) { close(ctxt->control_file_desc); ctxt->control_file_desc = -1; return(-1); } res = ftp_get_response(ctxt); switch (res) { case 2: break; case 3: motion_log(LOG_ERR, 0, "FTP server asking for ACCT on anonymous"); case 1: case 4: case 5: case -1: default: close(ctxt->control_file_desc); ctxt->control_file_desc = -1; ctxt->control_file_desc = -1; return(-1); } return(0);}/*** ftp_get_connection** Try to open a data connection to the server.** Parameters:** ctxt pointer to an FTP context** Returns -1 in case of error, 0 otherwise*/static int ftp_get_connection(ftp_context_pointer ctxt) { char buf[200], *cur; int len, i; int res; int on; unsigned char ad[6], *adp, *portp; unsigned int temp[6]; struct sockaddr_in data_address; unsigned int data_address_length; if (ctxt == NULL) return(-1); /* set up a socket for our data address */ if (ctxt->data_file_desc != -1) close(ctxt->data_file_desc); memset (&data_address, 0, sizeof(data_address)); ctxt->data_file_desc = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ctxt->data_file_desc < 0) { motion_log(LOG_ERR, 1, "socket failed"); return (-1); } on = 1; if (setsockopt(ctxt->data_file_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { motion_log(LOG_ERR, 1, "setting socket option SO_REUSEADDR"); return -1; } ((struct sockaddr_in *)&data_address)->sin_family = AF_INET; data_address_length = sizeof (struct sockaddr_in); if (ctxt->passive) { /* send PASV command over control channel */ snprintf (buf, sizeof(buf), "PASV\r\n"); len = strlen (buf); res = send(ctxt->control_file_desc, buf, len, 0); if (res < 0) { motion_log(LOG_ERR, 1, "send failed in ftp_get_connection"); close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return(res); } /* check server's answer */ res = ftp_get_response(ctxt); if (res != 2) { if (res == 5) { close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return(-1); } else { /* * retry with an active connection */ close(ctxt->data_file_desc); ctxt->data_file_desc = -1; ctxt->passive = 0; } } /* parse the IP address and port supplied by the server */ cur = &ctxt->control_buffer[ctxt->control_buffer_answer]; while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++; if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5]) != 6) { motion_log(LOG_ERR, 0, "Invalid answer to PASV"); if (ctxt->data_file_desc != -1) { close (ctxt->data_file_desc); ctxt->data_file_desc = -1; } return (-1); } for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff) ; memcpy (&((struct sockaddr_in *)&data_address)->sin_addr, &ad[0], 4); memcpy (&((struct sockaddr_in *)&data_address)->sin_port, &ad[4], 2); /* Now try to connect to the data port */ if (connect(ctxt->data_file_desc, (struct sockaddr *) &data_address, data_address_length) < 0) { motion_log(LOG_ERR, 1, "Failed to create a data connection"); close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return (-1); } } else { /* * We want to bind to a port to receive the data. To do this, * we need the address of our host. One easy way to get it is * to get the info from the control connection that we have * with the remote server */ getsockname(ctxt->control_file_desc, (struct sockaddr *)&data_address, &data_address_length); ((struct sockaddr_in *)&data_address)->sin_port = 0; /* bind to the socket - should give us a unique port */ if (bind(ctxt->data_file_desc, (struct sockaddr *) &data_address, data_address_length) < 0) { motion_log(LOG_ERR, 1, "bind failed"); close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return (-1); } /* we get the port number by reading back in the sockaddr */ getsockname(ctxt->data_file_desc, (struct sockaddr *)&data_address, &data_address_length); /* set up a 'listen' on the port to get the server's connection */ if (listen(ctxt->data_file_desc, 1) < 0) { motion_log(LOG_ERR, 1, "listen failed"); close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return (-1); } /* now generate the PORT command */ adp = (unsigned char *) &((struct sockaddr_in *)&data_address)->sin_addr; portp = (unsigned char *) &((struct sockaddr_in *)&data_address)->sin_port; snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n", adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff, portp[0] & 0xff, portp[1] & 0xff); buf[sizeof(buf) - 1] = 0; len = strlen(buf); /* send the PORT command to the server */ res = send(ctxt->control_file_desc, buf, len, 0); if (res < 0) { motion_log(LOG_ERR, 1, "send failed in ftp_get_connection"); close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return(res); } res = ftp_get_response(ctxt); if (res != 2) { close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return(-1); } } return(ctxt->data_file_desc);}/*** ftp_close_connection** Close the data connection from the server** Parameters:** ctxt Pointer to an FTP context** Returns -1 in case of error, 0 otherwise*/static int ftp_close_connection(ftp_context_pointer ctxt) { int res; fd_set rfd, efd; struct timeval tv; if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) return(-1); close(ctxt->data_file_desc); ctxt->data_file_desc = -1; /* Check for data on the control channel */ tv.tv_sec = 15; tv.tv_usec = 0; FD_ZERO(&rfd); FD_SET(ctxt->control_file_desc, &rfd); FD_ZERO(&efd); FD_SET(ctxt->control_file_desc, &efd); res = select(ctxt->control_file_desc + 1, &rfd, NULL, &efd, &tv); if (res < 0) { close(ctxt->control_file_desc); ctxt->control_file_desc = -1; return(-1); } if (res == 0) { /* timeout */ close(ctxt->control_file_desc); ctxt->control_file_desc = -1; } else { /* read the response */ res = ftp_get_response(ctxt); if (res != 2) { /* should be positive completion (2) */ close(ctxt->control_file_desc); ctxt->control_file_desc = -1; return(-1); } } return(0);}/*** ftp_get_socket** Initiate fetch of the given file from the server.** Parameters:** ctxt an FTP context** Returns the socket for the data connection, or <0 in case of error*/int ftp_get_socket(ftp_context_pointer ctxt) { char buf[300]; int res, len; int acfd; if ((ctxt == NULL) || (ctxt->path == NULL)) return(-1); /* Set up the data connection */ ctxt->data_file_desc = ftp_get_connection(ctxt); if (ctxt->data_file_desc == -1) return(-1); /* generate a "retrieve" command for the file */ snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path); buf[sizeof(buf) - 1] = 0; len = strlen(buf); /* send it to the server */ res = send(ctxt->control_file_desc, buf, len, 0); if (res < 0) { motion_log(LOG_ERR, 1, "send failed in ftp_get_socket"); close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return(res); } /* check the answer */ res = ftp_get_response(ctxt); if (res != 1) { close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return(-res); } /* * if not a passive connection, need to do an accept to get the * connection from the server */ if (!ctxt->passive) { struct sockaddr_in data_address; unsigned int data_address_length = sizeof(struct sockaddr_in); if ((acfd = accept(ctxt->data_file_desc, (struct sockaddr *)&data_address, &data_address_length)) < 0) { motion_log(LOG_ERR, 1, "accept in ftp_get_socket"); close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return -1; } close(ctxt->data_file_desc); ctxt->data_file_desc = acfd; } return(ctxt->data_file_desc);}/*** ftp_send_type** Send a TYPE (either 'I' or 'A') command to the server** Parameters** ctxt pointer to the ftp_context* type ascii character ('I' or 'A')** Returns 0 for success, negative error code for failure**/int ftp_send_type(ftp_context_pointer ctxt, char type) { char buf[100], utype; int len, res; utype = toupper(type); /* Assure transfer will be in "image" mode */ snprintf(buf, sizeof(buf), "TYPE I\r\n"); len = strlen(buf); res = send(ctxt->control_file_desc, buf, len, 0); if (res < 0) { motion_log(LOG_ERR, 1, "send failed in ftp_get_socket"); close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return(res); } res = ftp_get_response(ctxt); if (res != 2) { close(ctxt->data_file_desc); ctxt->data_file_desc = -1; return(-res); } return 0;}/*** ftp_read** This function tries to read len bytes from the existing FTP* connection and saves them in dest. This is a blocking call.** Parameters:* ctxt the FTP context* dest a buffer* len the buffer length** Returns: the number of bytes read.* 0 is an indication of an end of connection.* -1 indicates a parameter error.*/int ftp_read(ftp_context_pointer ctxt, void *dest, int len) { if (ctxt == NULL) return(-1); if (ctxt->data_file_desc < 0) return(0); if (dest == NULL) return(-1); if (len <= 0) return(0); len = recv(ctxt->data_file_desc, dest, len, 0); if (len <= 0) { if (len < 0) motion_log(LOG_ERR, 1, "recv failed in ftp_read"); ftp_close_connection(ctxt); } return(len);}/*** ftp_close** Close the connection and both control and transport** Parameters:** ctxt Pointer to an FTP context** Returns -1 in case of error, 0 otherwise*/int ftp_close(ftp_context_pointer ctxt) { if (ctxt == NULL) return(-1); if (ctxt->data_file_desc >= 0) { close(ctxt->data_file_desc); ctxt->data_file_desc = -1; } if (ctxt->control_file_desc >= 0) { ftp_quit(ctxt); close(ctxt->control_file_desc); ctxt->control_file_desc = -1; } ftp_free_context(ctxt); return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -