listen=YES
#listen_ipv6=YES
anonymous_enable=YES
anon_root=/srv/ftp
local_enable=YES
write_enable=YES
local_umask=022
anon_upload_enable=YES
# anon_other_write_enable --> anonymous resume, delete, rename...function
anon_other_write_enable=YES
anon_mkdir_write_enable=YES
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd

ssl_enable=YES
allow_anon_ssl=YES
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
require_ssl_reuse=NO
rsa_cert_file=/etc/vsftpd.pem

#Filezilla 錯誤: GnuTLS error -12: A TLS fatal alert has been received.

ssl_ciphers=HIGH


#vsftpd.conf設定可以續傳

curl -uanonymous:aaa -T 0xdroid-eclair.tar.gz ftp://localhost/incoming/ --ftp-ssl --tlsv1 -k -v

測試的指令
先傳一半中斷, 再用-C的選項加入offset
會從offset的地方開始續傳
檔案也沒問題
anon_root=/srv/ftp  <--- 這個ftp root目錄, 我有chown 成 ftp.ftp
然後裡面要建個upload目錄
他不能直接傳檔在/srv/ftp這個目錄... = =
upload目錄權限 -> chown ftp.ftp, chmod 777
這樣就能vsftp續傳了


curl的範例程式如下



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pthread.h>

#include <curl/curl.h>
#include "h1n1_ftps.h"

#define PDEBUG(fmt, ...) fprintf(stderr, "[%s:%d] %s: " fmt "\n", __FILE__, __LINE__, __func__, ## __VA_ARGS__)
#define PDEBUGG(args...)

#ifdef DEBUG
#define ASSERT assert
#else
#define ASSERT(...)
#endif


//#define DEBUG
#define FTP_SSL

/* discard downloaded data */
static size_t discardfunc(void *ptr, size_t size, size_t nmemb, void *data)
{
(void)ptr;
(void)data;
/* we are not interested in the headers itself,
so we only return the size we would have saved ... */
return (size_t)(size * nmemb);
}

/* read local data for writing to ftp */
static size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
/* in real-world cases, this would probably get this data differently
as this fread() stuff is exactly what the library already would do
by default internally */
size_t ret = fread(ptr, size, nmemb, stream);
PDEBUGG("*** We read %d bytes from file", ret);
return ret;
}

static double get_filesize_from_ftp(CURL *curl)
{
double content_len = 0;
int r;
curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, discardfunc);

/*
* With NOBODY and NOHEADER, libcurl will issue a SIZE
* command, but the only way to retrieve the result is
* to parse the returned Content-Length header. Thus,
* getcontentlengthfunc(). We need discardfunc() above
* because HEADER will dump the headers to stdout
* without it.
*/
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
r = curl_easy_perform(curl);

if(CURLE_OK == r)
{
/* http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html */
r = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_len);
if((CURLE_OK == r) && (content_len > 0))
PDEBUG("filesize: %0.0f bytes", content_len);
}

curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
curl_easy_setopt(curl, CURLOPT_HEADER, 0);

return content_len;

}

/* parse headers for Content-Length */
size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
int r;
long len = 0;

/* _snscanf() is Win32 specific */
r = sscanf(ptr, "Content-Length: %ld\n", &len);

if (r) /* Microsoft: we don't read the specs */
*((long *) stream) = len;

return size * nmemb;
}

/* Avoid seeks inside the buffer data */
static int noop_seek_callback( void *instream, curl_off_t offset, int origin ){
/* Nothing to do */
//fseek(f, uploaded_len, SEEK_SET);
fseek(instream, offset, SEEK_SET);
PDEBUG("seek stram to %u\n", offset);
return 0;
}
static int upload_to_ftp(CURL *curl, const char *ftpurl, const char *localpath, int retry)
{
double uploaded_len = 0;
FILE *f;
CURLcode r = CURLE_GOT_NOTHING;
int c;

f = fopen(localpath, "rb");
if (f == NULL)
{
PDEBUG("No such file %s", localpath);
return -1;
}
curl_easy_setopt(curl, CURLOPT_URL, ftpurl);
for (c = 0; (r != CURLE_OK) && (c < retry); c++)
{
/* if the file exists in remote ftp server, get uploaded length */
uploaded_len = get_filesize_from_ftp(curl);
PDEBUGG("get len of remote file:%0.0f", uploaded_len);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, readfunc);
curl_easy_setopt(curl, CURLOPT_READDATA, f);
curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, noop_seek_callback );
curl_easy_setopt(curl, CURLOPT_SEEKDATA, f);
fseek(f, uploaded_len, SEEK_SET);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
//curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, uploaded_len);
curl_easy_setopt(curl, CURLOPT_APPEND, 1L);
r = curl_easy_perform(curl);
if(r == CURLE_UPLOAD_FAILED) // try overwrite method
{
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
curl_easy_setopt(curl, CURLOPT_APPEND, 0L);
fseek(f, 0, SEEK_SET);
r = curl_easy_perform(curl);
}
r = curl_easy_perform(curl);
}

fclose(f);

if (r == CURLE_OK)
{
PDEBUG("sending %s to %s is finish!!!", localpath, ftpurl);
return 1;
}
else
{
PDEBUG("%s", curl_easy_strerror(r));
sleep(3); // sleep more time
return 0;
}

}

static int ftpinfo_enqueue(struct ftpinfo *ftp, char *filename, char *remotepath, char *localpath)
{
pthread_mutex_lock(&ftp->ftp_mutex);
if(ftp->size == ftp->capacity)
{
PDEBUG("ftp upload queue is full");
pthread_mutex_unlock(&ftp->ftp_mutex);
return -1;
}
ftp->size++;
if(ftp->rear == ftp->capacity - 1)
{
ftp->rear = 0;
}
else
{
ftp->rear++;
}
strcpy(ftp->queue[ftp->rear]->filename, filename);
strcpy(ftp->queue[ftp->rear]->remotepath, remotepath);
strcpy(ftp->queue[ftp->rear]->localpath, localpath);

PDEBUG("%d %s", ftp->rear, ftp->queue[ftp->rear]->filename);
pthread_cond_signal(&ftp->ftp_cond);
pthread_mutex_unlock(&ftp->ftp_mutex);

return 0;
}

static struct ftpqueue *ftpinfo_dequeue(struct ftpinfo *ftp, struct ftpqueue* elem)
{
//PDEBUG("%d", ftp->size);
pthread_mutex_lock(&ftp->ftp_mutex);
if(ftp->size == 0)
{
PDEBUGG("ftp upload queue is empty");
PDEBUG("wait upload entry");
pthread_cond_wait(&ftp->ftp_cond, &ftp->ftp_mutex);
PDEBUGG("new upload entry");
// pthread_mutex_unlock(&ftp->ftp_mutex);
// return NULL;
}
ftp->size--;
if(ftp->front == ftp->capacity - 1)
{
ftp->front = 0;
}
else
{
ftp->front++;
}
strcpy(elem->filename, ftp->queue[ftp->front]->filename);
strcpy(elem->remotepath, ftp->queue[ftp->front]->remotepath);
strcpy(elem->localpath, ftp->queue[ftp->front]->localpath);
pthread_mutex_unlock(&ftp->ftp_mutex);
return elem;
}

void *ftp_handler(struct ftpinfo *ftp)
{
char ftpurl[128];
char localurl[128];

PDEBUG("enter handler");
while(ftp->status != FTP_STOP)
{
struct ftpqueue elem, *q;
q = ftpinfo_dequeue(ftp, &elem);
if(q != NULL)
{
pthread_mutex_lock(&ftp->ftp_mutex);
sprintf(ftpurl, "ftp://%s/%s/%s", ftp->ipaddr, q->remotepath, q->filename);
sprintf(localurl, "%s/%s", q->localpath, q->filename);
pthread_mutex_unlock(&ftp->ftp_mutex);
PDEBUG("copy %s to %s", localurl, ftpurl);

//upload success->remove files, upload fail->add back to queue & retry
if(upload_to_ftp(ftp->curl, ftpurl, localurl, ftp->retry))
{
//remove record files
char cmd[128];
//if(strstr("/mnt/sd/record", localurl)|| strstr("/mnt/sd/full_record", localurl))
sprintf(cmd, "rm -f %s", localurl);
system(cmd);
}
else
{
//if upload fail, enqueue to list and retry again
ftpinfo_enqueue(ftp, q->filename, q->remotepath, q->localpath);
}

PDEBUGG("queue size:%d", ftp->size);
}
}
return NULL;
}

void ftp_scan_dir(struct ftpinfo *ftp, char *remotepath, char *localpath)
{
DIR *dir;
struct dirent *ptr;
dir = opendir(localpath);
while((ptr = readdir(dir)) != NULL)
{
struct stat buf;
char name[256];
sprintf(name,"%s/%s",localpath, ptr->d_name);
stat(name,&buf);
if(S_ISREG(buf.st_mode))
{
ftpinfo_enqueue(ftp, ptr->d_name, remotepath, localpath);
}
}
closedir(dir);
}

static CURL *ftp_curl_init(CURL *curl, char *username, char *password, int timeout)
{
curl = NULL;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();

#ifdef DEBUG
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
#endif
#ifdef FTP_SSL
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_SSL);
#endif
curl_easy_setopt(curl, CURLOPT_USERNAME, username);
curl_easy_setopt(curl, CURLOPT_PASSWORD, password);
curl_easy_setopt(curl, CURLOPT_FTPPORT, "-"); /* disable passive mode */
curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1);

if(timeout)
{
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, timeout);
}

return curl;
}

struct ftpinfo *ftp_backup_service_init(char *ip, char *port, char *username, char *password, int timeout, int retry, int queuesize)
{
ASSERT(ftp != NULL);
ASSERT(ip != NULL && strlen(ip) != 0);
ASSERT(port != NULL && strlen(port) != 0);
ASSERT(username != NULL && strlen(username) != 0);
ASSERT(password != NULL);
ASSERT(timeout >=0 && retry >= 0);

int i = 0;
struct ftpinfo *ftp;
ftp = (struct ftpinfo *)malloc(sizeof(struct ftpinfo));
strcpy(ftp->ipaddr, ip);
strcpy(ftp->port, port);
strcpy(ftp->username, username);
strcpy(ftp->password, password);
ftp->timeout = timeout;
ftp->retry = retry;

ftp->capacity = queuesize;
ftp->front = 0;
ftp->rear = 0;
ftp->size = 0;
ftp->queue = (struct ftpqueue **)malloc(MAX_QUEUE * sizeof(struct ftpqueue *));
for(i = 0; i < queuesize; i++)
ftp->queue[i] = (struct ftpqueue *)malloc(sizeof(struct ftpqueue));

ftp->curl = ftp_curl_init(ftp->curl, username, password, timeout);

pthread_mutex_init(&ftp->ftp_mutex, NULL);
pthread_cond_init(&ftp->ftp_cond, NULL);
return ftp;
}

int ftp_modify_info(struct ftpinfo *ftp, char *ip, char *port, char *username, char *password, int timeout, int retry)
{
ASSERT(ftp);
pthread_mutex_lock(&ftp->ftp_mutex);
if(ip != NULL)
strcpy(ftp->ipaddr, ip);

if(port != NULL)
strcpy(ftp->port, port);

if(username != NULL)
strcpy(ftp->username, username);

if(password != NULL)
strcpy(ftp->password, password);

if(timeout >=0)
ftp->timeout = timeout;

if(retry >=0)
ftp->retry = retry;

curl_easy_cleanup(ftp->curl);
ftp->curl = ftp_curl_init(ftp->curl, username, password, timeout);
pthread_mutex_unlock(&ftp->ftp_mutex);

return 0;
}

int ftp_backup_service_destroy(struct ftpinfo *ftp)
{
int i = 0;
ftp->status = FTP_STOP;
pthread_join(ftp->ftp_thread, NULL);

for(i = 0; i < ftp->capacity; i++)
free(ftp->queue[i]);

free(ftp->queue);
pthread_mutex_destroy(&ftp->ftp_mutex);
pthread_cond_destroy(&ftp->ftp_cond);

curl_easy_cleanup(ftp->curl);
curl_global_cleanup();

return 0;
}

int ftp_add_list(struct ftpinfo *ftp, char *filelist, char *remotepath, char *localpath)
{
char *flist;
char *localfile, *saveptr;
flist = strdup(filelist);
if(!flist)
return -1;
localfile = strtok_r(flist, "\n", &saveptr);
do{
ftpinfo_enqueue(ftp, localfile, remotepath, localpath);
} while((localfile = strtok_r(NULL, "\n", &saveptr)) != NULL);
free(flist);
return 0;

}

void ftp_upload_file(struct ftpinfo *ftp, char *remotepath, char *localpath, char *filename)
{
char ftpurl[128];
char localurl[128];
sprintf(ftpurl, "ftp://%s%s%s", ftp->ipaddr, remotepath, filename);
sprintf(localurl, "%s/%s", localpath, filename);
PDEBUG("ftpurl:%s", ftpurl);
upload_to_ftp(ftp->curl, ftpurl, localurl, ftp->retry);
}

#ifdef TEST_AP
int main(void)
{
struct ftpinfo *ftp;
char filelist[1024]={"test_ftp\ntest_ftp2"};
char remotepath[128]={"upload"};
char localpath[128]={""};

ftp = ftp_backup_service_init("192.169.1.107", "21", "anonymous", "?", 3, 3, MAX_QUEUE);
//ftp = ftp_backup_service_init("192.169.1.107", "21", "personlin", "?", 3, 3, MAX_QUEUE);
// ftp = ftp_backup_service_init("10.110.1.17", "21", "personlin", "121436233", 3, 3, MAX_QUEUE);
ftp_scan_dir(ftp, remotepath, "/mnt/sd/record");
ftp_scan_dir(ftp, remotepath, "/mnt/sd/full_record");

/* scan /mnt/sd/record && /mnt/sd/full_record */


pthread_create(&ftp->ftp_thread, NULL, ftp_handler, ftp);
//pthread_detach(ftp->ftp_thread);
//sleep(1);

ftp_add_list(ftp, filelist, remotepath, localpath);
//ftp_upload_file(ftp, remotepath, localpath, filelist);

while(1)
{
getchar();
ftp_scan_dir(ftp, remotepath, "/mnt/sd/record");
}

ftp_backup_service_destroy(ftp);
return 0;
}
#endif

arrow
arrow
    全站熱搜

    Person 發表在 痞客邦 留言(0) 人氣()