?? netcam_ftp.c
字號:
/*** Much of the FTP code was inspired by the nanoftp.c module from* libxml2 (Copyright Daniel Veillard, 2003). The routines have been* modified to fit the needs of the Motion project.** Copyright 2005, William M. Brack* This software is distributed under the GNU Public license Version 2.* See also the file 'COPYING'.**/#include "motion.h" /* needs to come first, because _GNU_SOURCE_ set there */#include <ctype.h>//#include <errno.h>//#include <fcntl.h>#include <netdb.h>#include <regex.h>//#include <stdarg.h>//#include <stdlib.h>//#include <stdio.h>//#include <string.h>//#include <syslog.h>//#include <unistd.h>#include <sys/socket.h>//#include <sys/stat.h>//#include <sys/types.h>#include <netinet/in.h>#include "netcam_ftp.h"/*** ftp_new_context** Create a new FTP context structure** Parameters** None** Returns: Pointer to the newly-created structure, NULL if error**/ftp_context_pointer ftp_new_context(void){ ftp_context_pointer ret; /* note that mymalloc will exit on any problem */ ret = mymalloc(sizeof(ftp_context)); memset(ret, 0, sizeof(ftp_context)); ret->control_file_desc = -1; /* no control connection yet */ ret->data_file_desc = -1; /* no data connection yet */ return ret;}/*** ftp_free_context** Free the resources allocated for this context** Parameters** ctxt Pointer to the ftp_context structure** Returns: Nothing**/void ftp_free_context(ftp_context_pointer ctxt){ if (ctxt == NULL) return; if (ctxt->path != NULL) free(ctxt->path); if (ctxt->user) free(ctxt->user); if (ctxt->passwd) free(ctxt->passwd); if (ctxt->control_file_desc >= 0) close(ctxt->control_file_desc); free(ctxt);}/*** ftp_parse_response** Parses the answer from the server, extracting the numeric code.** Parameters:** buf the buffer containing the response* len the buffer length** Returns:* 0 for errors* +XXX for last line of response* -XXX for response to be continued*/static int ftp_parse_response(char *buf, int len) { int val = 0; if (len < 3) return(-1); if ((*buf >= '0') && (*buf <= '9')) val = val * 10 + (*buf - '0'); else return(0); buf++; if ((*buf >= '0') && (*buf <= '9')) val = val * 10 + (*buf - '0'); else return(0); buf++; if ((*buf >= '0') && (*buf <= '9')) val = val * 10 + (*buf - '0'); else return(0); buf++; if (*buf == '-') return(-val); return(val);}/*** ftp_get_more** Read more information from the FTP control connection** Parameters:** ctxt pointer to an FTP context** Returns the number of bytes read, < 0 indicates an error*/static int ftp_get_more(ftp_context_pointer ctxt) { int len; int size; /* Validate that our context structure is valid */ if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) return(-1); if ((ctxt->control_buffer_index < 0) || (ctxt->control_buffer_index > FTP_BUF_SIZE)) return(-1); if ((ctxt->control_buffer_used < 0) || (ctxt->control_buffer_used > FTP_BUF_SIZE)) return(-1); if (ctxt->control_buffer_index > ctxt->control_buffer_used) return(-1); /* * First pack the control buffer */ if (ctxt->control_buffer_index > 0) { memmove(&ctxt->control_buffer[0], &ctxt->control_buffer[ctxt->control_buffer_index], ctxt->control_buffer_used - ctxt->control_buffer_index); ctxt->control_buffer_used -= ctxt->control_buffer_index; ctxt->control_buffer_index = 0; } size = FTP_BUF_SIZE - ctxt->control_buffer_used; if (size == 0) { return(0); } /* * Read the amount left on the control connection */ if ((len = recv(ctxt->control_file_desc, &ctxt->control_buffer[ctxt->control_buffer_index], size, 0)) < 0) { motion_log(LOG_ERR, 1, "recv failed in ftp_get_more"); close(ctxt->control_file_desc); ctxt->control_file_desc = -1; return(-1); } ctxt->control_buffer_used += len; ctxt->control_buffer[ctxt->control_buffer_used] = 0; return(len);}/*** ftp_get_response** Read the response from the FTP server after a command.** Parameters** ctxt pointer to an FTP context** Returns the code number*/static int ftp_get_response(ftp_context_pointer ctxt) { char *ptr, *end; int len; int res = -1, cur = -1; if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) return(-1); get_more: /* * Assumes everything up to control_buffer[control_buffer_index] has been read * and analyzed. */ len = ftp_get_more(ctxt); if (len < 0) { return(-1); } if ((ctxt->control_buffer_used == 0) && (len == 0)) { return(-1); } ptr = &ctxt->control_buffer[ctxt->control_buffer_index]; end = &ctxt->control_buffer[ctxt->control_buffer_used]; while (ptr < end) { cur = ftp_parse_response(ptr, end - ptr); if (cur > 0) { /* * Successfully scanned the control code, skip * till the end of the line, but keep the index to be * able to analyze the result if needed. */ res = cur; ptr += 3; ctxt->control_buffer_answer = ptr - ctxt->control_buffer; while ((ptr < end) && (*ptr != '\n')) ptr++; if (*ptr == '\n') ptr++; if (*ptr == '\r') ptr++; break; } while ((ptr < end) && (*ptr != '\n')) ptr++; if (ptr >= end) { ctxt->control_buffer_index = ctxt->control_buffer_used; goto get_more; } if (*ptr != '\r') ptr++; } if (res < 0) goto get_more; ctxt->control_buffer_index = ptr - ctxt->control_buffer; return(res / 100);}/*** Send the user authentication*/static int ftp_send_user(ftp_context_pointer ctxt) { char buf[200]; int len; int res; if (ctxt->user == NULL) snprintf(buf, sizeof(buf), "USER anonymous\r\n"); else snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user); buf[sizeof(buf) - 1] = 0; len = strlen(buf); res = send(ctxt->control_file_desc, buf, len, 0); if (res < 0) { motion_log(LOG_ERR, 1, "send failed in ftp_send_user"); return(res); } return(0);}/*** Send the password authentication*/static int ftp_send_passwd(ftp_context_pointer ctxt) { char buf[200]; int len; int res; if (ctxt->passwd == NULL) snprintf(buf, sizeof(buf), "PASS anonymous@\r\n"); else snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd); buf[sizeof(buf) - 1] = 0; len = strlen(buf); res = send(ctxt->control_file_desc, buf, len, 0); if (res < 0) { motion_log(LOG_ERR, 1, "send failed in ftp_send_passwd"); return(res); } return(0);}/*** ftp_quit** Send a QUIT command to the server** Parameters:** ctxt pointer to an FTP context** Returns -1 in case of error, 0 otherwise*/static int ftp_quit(ftp_context_pointer ctxt) { char buf[200]; int len, res; if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) return(-1); snprintf(buf, sizeof(buf), "QUIT\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_quit"); return(res); } return(0);}/*** ftp_connect** Tries to open a control connection** Parameters:** ctxt an FTP context** Returns -1 in case of error, 0 otherwise*/int ftp_connect(netcam_context_ptr netcam) { ftp_context_pointer ctxt; struct hostent *hp; int port; int res; int addrlen = sizeof (struct sockaddr_in); if (netcam == NULL) return -1; ctxt = netcam->ftp; if (ctxt == NULL) return(-1); if (netcam->connect_host == NULL) return(-1); /* * do the blocking DNS query. */ port = netcam->connect_port; if (port == 0) port = 21; memset (&ctxt->ftp_address, 0, sizeof(ctxt->ftp_address)); hp = gethostbyname (netcam->connect_host); if (hp == NULL) { motion_log(LOG_ERR, 1, "gethostbyname failed in ftp_connect"); return (-1); } if ((unsigned int) hp->h_length > sizeof(((struct sockaddr_in *)&ctxt->ftp_address)->sin_addr)) { motion_log(LOG_ERR, 1, "gethostbyname address mismatch " "in ftp_connect"); return (-1); } /* * Prepare the socket */ ((struct sockaddr_in *)&ctxt->ftp_address)->sin_family = AF_INET; memcpy (&((struct sockaddr_in *)&ctxt->ftp_address)->sin_addr, hp->h_addr_list[0], hp->h_length); ((struct sockaddr_in *)&ctxt->ftp_address)->sin_port = (u_short)htons ((unsigned short)port); ctxt->control_file_desc = socket (AF_INET, SOCK_STREAM, 0); addrlen = sizeof (struct sockaddr_in); if (ctxt->control_file_desc < 0) { motion_log(LOG_ERR, 1, "socket failed"); return(-1); } /* * Do the connect. */ if (connect(ctxt->control_file_desc, (struct sockaddr *) &ctxt->ftp_address, addrlen) < 0) { motion_log(LOG_ERR, 1, "Failed to create a connection"); close(ctxt->control_file_desc); ctxt->control_file_desc = -1; return(-1); } /* * Wait for the HELLO from the server. */ res = ftp_get_response(ctxt); if (res != 2) { close(ctxt->control_file_desc); ctxt->control_file_desc = -1; return(-1); } /* * Do the authentication */ res = ftp_send_user(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: return(0); case 3:
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -