From 0e482b02daf41d6b4a13077ee0a4c1e10f37b0a5 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Fri, 7 Jul 2023 21:49:39 +0200 Subject: [PATCH] [fsp] fsp protocol support non-forking version based on fsplib Maybe under DOS it makes sense. It works worse than with fsplib. You can only download one file at a time. --- config2.h.in | 3 + meson.build | 1 + meson_options.txt | 1 + src/protocol/fsp/fsp.c | 1 - src/protocol/fsp/fsp.h | 3 +- src/protocol/fsp/fsp2.c | 1179 ++++++++++++++++++++++++++++++++++ src/protocol/fsp/fsplib.h | 152 +++++ src/protocol/fsp/lock.c | 284 ++++++++ src/protocol/fsp/lock.h | 47 ++ src/protocol/fsp/meson.build | 8 +- src/protocol/meson.build | 2 +- src/protocol/protocol.cpp | 2 +- 12 files changed, 1677 insertions(+), 6 deletions(-) create mode 100644 src/protocol/fsp/fsp2.c create mode 100644 src/protocol/fsp/fsplib.h create mode 100644 src/protocol/fsp/lock.c create mode 100644 src/protocol/fsp/lock.h diff --git a/config2.h.in b/config2.h.in index c9a39453..8cbb4749 100644 --- a/config2.h.in +++ b/config2.h.in @@ -85,6 +85,9 @@ /* Define if you want: FSP protocol support */ #mesondefine CONFIG_FSP +/* Define if you want: FSP protocol support without fork calls */ +#mesondefine CONFIG_FSP2 + /* Define if you want: FTP protocol support */ #mesondefine CONFIG_FTP diff --git a/meson.build b/meson.build index 7626de61..e0b34434 100644 --- a/meson.build +++ b/meson.build @@ -41,6 +41,7 @@ conf_data.set('CONFIG_CGI', get_option('cgi')) conf_data.set('CONFIG_DGI', get_option('dgi')) conf_data.set('CONFIG_FINGER', get_option('finger')) conf_data.set('CONFIG_FSP', get_option('fsp')) +conf_data.set('CONFIG_FSP2', get_option('fsp2')) conf_data.set('CONFIG_FTP', get_option('ftp')) conf_data.set('CONFIG_GOPHER', get_option('gopher')) conf_data.set('CONFIG_NNTP', get_option('nntp')) diff --git a/meson_options.txt b/meson_options.txt index 56e4da93..1f238cb7 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -15,6 +15,7 @@ option('uri-rewrite', type: 'boolean', value: true, description: 'URI rewrite su option('cgi', type: 'boolean', value: false, description: 'local CGI support') option('finger', type: 'boolean', value: false, description: 'finger protocol support') option('fsp', type: 'boolean', value: false, description: 'FSP protocol support') +option('fsp2', type: 'boolean', value: false, description: 'FSP protocol support without fsplib and fork calls') option('ftp', type: 'boolean', value: true, description: 'ftp protocol support') option('gopher', type: 'boolean', value: false, description: 'gopher protocol support') option('nntp', type: 'boolean', value: false, description: 'nntp protocol support') diff --git a/src/protocol/fsp/fsp.c b/src/protocol/fsp/fsp.c index f363879f..2a4263b7 100644 --- a/src/protocol/fsp/fsp.c +++ b/src/protocol/fsp/fsp.c @@ -62,7 +62,6 @@ struct module fsp_protocol_module = struct_module( /* done: */ NULL ); - /* Because functions of fsplib block waiting for a response from the * server, and ELinks wants non-blocking operations so that other * connections and the user interface keep working, this FSP protocol diff --git a/src/protocol/fsp/fsp.h b/src/protocol/fsp/fsp.h index 35acf494..53d2eaf3 100644 --- a/src/protocol/fsp/fsp.h +++ b/src/protocol/fsp/fsp.h @@ -1,4 +1,3 @@ - #ifndef EL__PROTOCOL_FSP_FSP_H #define EL__PROTOCOL_FSP_FSP_H @@ -11,7 +10,7 @@ extern "C" { extern struct module fsp_protocol_module; -#ifdef CONFIG_FSP +#if defined(CONFIG_FSP) || defined(CONFIG_FSP2) extern protocol_handler_T fsp_protocol_handler; #else #define fsp_protocol_handler NULL diff --git a/src/protocol/fsp/fsp2.c b/src/protocol/fsp/fsp2.c new file mode 100644 index 00000000..8e77ce74 --- /dev/null +++ b/src/protocol/fsp/fsp2.c @@ -0,0 +1,1179 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* +This file is part of fsplib - FSP protocol stack implemented in C +language. See http://fsp.sourceforge.net for more information. + +Copyright (c) 2003-2005 by Radim HSN Kolar (hsn@sendmail.cz) + +You may copy or modify this file in any manner you wish, provided +that this notice is always included, and that you hold the author +harmless for any loss or damage resulting from the installation or +use of this software. + + This is a free software. Be creative. + Let me know of any bugs and suggestions. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#include "elinks.h" + +#include "intl/libintl.h" +#include "main/select.h" +#include "main/timer.h" +#include "network/connection.h" +#include "protocol/auth/auth.h" +#include "protocol/common.h" +#include "protocol/fsp/fsplib.h" +#include "protocol/fsp/lock.h" +#include "protocol/uri.h" +#include "util/conv.h" + +static void fsp_stat_continue(void *data); + +typedef void (*return_handler_T)(void *data); + +struct fsp_connection_info { + FSP_SESSION *ses; + FSP_PKT in, out; + FSP_FILE *f; + FSP_DIR *dir; + char *path; + return_handler_T return_func; + struct stat sb; + timer_id_T send_timer; + int ret; + + char buf[FSP_MAXPACKET]; + struct timeval start[8],stop; + unsigned int retry,dupes; + int w_delay; /* how long to wait on next packet */ + int f_delay; /* how long to wait after first send */ + int l_delay; /* last delay */ + unsigned int t_delay; /* time from first send */ + int blocksize; + int pos; +}; + +struct module fsp_protocol_module = struct_module( + /* name: */ N_("FSP"), + /* options: */ NULL, + /* hooks: */ NULL, + /* submodules: */ NULL, + /* data: */ NULL, + /* init: */ NULL, + /* done: */ NULL +); + +/* ************ Internal functions **************** */ + +/* builds filename in packet output buffer, appends password if needed */ +static int +buildfilename(const FSP_SESSION *s, FSP_PKT *out, const char *dirname) +{ + int len; + + len = strlen(dirname); + + if (len >= FSP_SPACE - 1) { + errno = ENAMETOOLONG; + return -1; + } + /* copy name + \0 */ + memcpy(out->buf, dirname, len + 1); + out->len = len; + + if (s->password) { + out->buf[len]='\n'; + out->len++; + len = strlen(s->password); + + if (out->len + len >= FSP_SPACE - 1) { + errno = ENAMETOOLONG; + return -1; + } + memcpy(out->buf + out->len, s->password, len + 1); + out->len += len; + } + /* add terminating \0 */ + out->len++; + + return 0; +} + +/* ************ Packet encoding / decoding *************** */ + +/* write binary representation of FSP packet p into *space. */ +/* returns number of bytes used or zero on error */ +/* Space must be long enough to hold created packet. */ +/* Maximum created packet size is FSP_MAXPACKET */ + +static size_t +fsp_pkt_write(const FSP_PKT *p, void *space) +{ + size_t used; + unsigned char *ptr; + int checksum; + size_t i; + + if (p->xlen + p->len > FSP_SPACE) { + /* not enough space */ + errno = EMSGSIZE; + return 0; + } + ptr = space; + /* pack header */ + ptr[FSP_OFFSET_CMD] = p->cmd; + ptr[FSP_OFFSET_SUM] = 0; + *(uint16_t *)(ptr + FSP_OFFSET_KEY) = htons(p->key); + *(uint16_t *)(ptr + FSP_OFFSET_SEQ) = htons(p->seq); + *(uint16_t *)(ptr + FSP_OFFSET_LEN) = htons(p->len); + *(uint32_t *)(ptr + FSP_OFFSET_POS) = htonl(p->pos); + used = FSP_HSIZE; + /* copy data block */ + memcpy(ptr + FSP_HSIZE, p->buf, p->len); + used += p->len; + /* copy extra data block */ + memcpy(ptr + used, p->buf + p->len, p->xlen); + used += p->xlen; + /* compute checksum */ + checksum = 0; + for(i = 0; i < used; i++) { + checksum += ptr[i]; + } + checksum +=used; + ptr[FSP_OFFSET_SUM] = checksum + (checksum >> 8); + + return used; +} + +/* read binary representation of FSP packet received from network into p */ +/* return zero on success */ +static int +fsp_pkt_read(FSP_PKT *p, const void *space, size_t recv_len) +{ + int mysum; + size_t i; + const unsigned char *ptr; + + if (recv_len < FSP_HSIZE) { + /* too short */ + errno = ERANGE; + return -1; + } + + if (recv_len > FSP_MAXPACKET) { + /* too long */ + errno = EMSGSIZE; + return -1; + } + ptr = space; + /* check sum */ + mysum = -ptr[FSP_OFFSET_SUM]; + + for(i = 0; i < recv_len; i++) { + mysum+=ptr[i]; + } + mysum = (mysum + (mysum >> 8)) & 0xff; + + if (mysum != ptr[FSP_OFFSET_SUM]) { + /* checksum failed */ +#ifdef MAINTAINER_MODE + fprintf(stderr, "mysum: %x, got %x\n", mysum, ptr[FSP_OFFSET_SUM]); +#endif + errno = EIO; + return -1; + } + + /* unpack header */ + p->cmd = ptr[FSP_OFFSET_CMD]; + p->sum = mysum; + p->key = ntohs(*(const uint16_t *)(ptr + FSP_OFFSET_KEY)); + p->seq = ntohs(*(const uint16_t *)(ptr + FSP_OFFSET_SEQ)); + p->len = ntohs(*(const uint16_t *)(ptr + FSP_OFFSET_LEN)); + p->pos = ntohl(*(const uint32_t *)(ptr + FSP_OFFSET_POS)); + + if (p->len > recv_len) { + /* bad length field, should not never happen */ + errno = EMSGSIZE; + return -1; + } + p->xlen = recv_len - p->len - FSP_HSIZE; + /* now copy data */ + memcpy(p->buf, ptr + FSP_HSIZE, recv_len - FSP_HSIZE); + + return 0; +} + + +static void fsp_transaction_send_loop(void *data); + +static void +try_fsp_transaction(void *data) +{ + struct connection *conn = (struct connection *)data; + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + FSP_SESSION *s = fsp->ses; + + //FD_ZERO(&mask); + /* get the next key */ + + fsp->out.key = client_get_key((FSP_LOCK *)s->lock); + fsp->retry = random() & 0xfff8; + + if (s->seq == fsp->retry) { + s->seq ^= 0x1080; + } else { + s->seq = fsp->retry; + } + fsp->dupes = fsp->retry = 0; + fsp->t_delay = 0; + /* compute initial delay here */ + /* we are using hardcoded value for now */ + fsp->f_delay = 1340; + fsp->l_delay = 0; + + fsp_transaction_send_loop(conn); +} + +static void fsp_transaction_continue(void *data); + +static void +fsp_transaction_send_loop(void *data) +{ + struct connection *conn = (struct connection *)data; + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + + FSP_SESSION *s = fsp->ses; + size_t l; + + if (fsp->t_delay >= s->timeout) { + client_set_key((FSP_LOCK *)s->lock, fsp->out.key); + errno = ETIMEDOUT; + fsp->ret = -1; + + if (fsp->return_func) { + fsp->return_func(conn); + } + return; + } + /* make a packet */ + fsp->out.key = client_get_key((FSP_LOCK *)s->lock); + fsp->out.seq = (s->seq) | (fsp->retry & 0x7); + l = fsp_pkt_write(&fsp->out, &fsp->buf); + + /* We should compute next delay wait time here */ + gettimeofday(&fsp->start[fsp->retry & 0x7], NULL); + + if (fsp->retry == 0) { + fsp->w_delay = fsp->f_delay; + } else { + fsp->w_delay = fsp->l_delay * 3 / 2; + } + fsp->l_delay = fsp->w_delay; + + /* send packet */ + if (send(s->fd, fsp->buf, l, 0) < 0) { +#if 1 + fprintf(stderr, "Send failed.\n"); +#endif + if (errno == EBADF || errno == ENOTSOCK) { + client_set_key((FSP_LOCK *)s->lock, fsp->out.key); + errno = EBADF; + + if (fsp->return_func) { + fsp->return_func(conn); + } + return; + } + fsp->retry--; + fsp->t_delay += 1000; + install_timer(&fsp->send_timer, 1000, fsp_transaction_send_loop, conn); + return; + } + /* keep delay value within sane limits */ + if (fsp->w_delay > (int)s->maxdelay) { + fsp->w_delay = s->maxdelay; + } else if (fsp->w_delay < 1000) { + fsp->w_delay = 1000; + } + fsp->t_delay += fsp->w_delay; + + install_timer(&fsp->send_timer, fsp->w_delay, fsp_transaction_send_loop, conn); + set_handlers(s->fd, fsp_transaction_continue, NULL, NULL, conn); +} + +static void +fsp_transaction_continue(void *data) +{ + struct connection *conn = (struct connection *)data; + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + + FSP_SESSION *s = fsp->ses; + ssize_t r; + + kill_timer(&fsp->send_timer); + + if (fsp->w_delay <= 0) { + fsp->retry++; + register_bottom_half(fsp_transaction_send_loop, conn); + return; + } + /* convert w_delay to timeval */ + fsp->stop.tv_sec = fsp->w_delay / 1000; + fsp->stop.tv_usec = (fsp->w_delay % 1000) * 1000; + r = recv(s->fd, fsp->buf, FSP_MAXPACKET, 0); + + if (r < 0) { + /* serious recv error */ + client_set_key((FSP_LOCK *)s->lock, fsp->out.key); + + fsp->ret = -1; + if (fsp->return_func) { + fsp->return_func(conn); + } + return; + } + gettimeofday(&fsp->stop, NULL); + fsp->w_delay -= 1000 * (fsp->stop.tv_sec - fsp->start[fsp->retry & 0x7].tv_sec); + fsp->w_delay -= (fsp->stop.tv_usec - fsp->start[fsp->retry & 0x7].tv_usec) / 1000; + + /* process received packet */ + if (fsp_pkt_read(&fsp->in, fsp->buf, r) < 0) { + set_handlers(s->fd, fsp_transaction_continue, NULL, NULL, conn); + /* unpack failed */ + return; + } + + /* check sequence number */ + if ((fsp->in.seq & 0xfff8) != s->seq) { + /* duplicate */ + fsp->dupes++; + set_handlers(s->fd, fsp_transaction_continue, NULL, NULL, conn); + return; + } + + /* check command code */ + if ((fsp->in.cmd != fsp->out.cmd) && (fsp->in.cmd != FSP_CC_ERR)) { + fsp->dupes++; + set_handlers(s->fd, fsp_transaction_continue, NULL, NULL, conn); + return; + } + + /* check correct filepos */ + if ((fsp->in.pos != fsp->out.pos) && ( fsp->in.cmd == FSP_CC_GET_DIR || + fsp->out.cmd == FSP_CC_GET_FILE || fsp->out.cmd == FSP_CC_UP_LOAD || + fsp->out.cmd == FSP_CC_GRAB_FILE || fsp->out.cmd == FSP_CC_INFO) ) { + fsp->dupes++; + set_handlers(s->fd, fsp_transaction_continue, NULL, NULL, conn); + return; + } + + /* now we have a correct packet */ + /* compute rtt delay */ + fsp->w_delay = 1000 * (fsp->stop.tv_sec - fsp->start[fsp->retry & 0x7].tv_sec); + fsp->w_delay += (fsp->stop.tv_usec - fsp->start[fsp->retry & 0x7].tv_usec) / 1000; + /* update last stats */ + s->last_rtt = fsp->w_delay; + s->last_delay = fsp->f_delay; + s->last_dupes = fsp->dupes; + s->last_resends = fsp->retry; + /* update cumul. stats */ + s->dupes += fsp->dupes; + s->resends += fsp->retry; + s->trips++; + s->rtts += fsp->w_delay; + /* grab a next key */ + client_set_key((FSP_LOCK *)s->lock, fsp->in.key); + errno = 0; + fsp->ret = 0; + + if (fsp->return_func) { + fsp->return_func(conn); + } +} + +/* ******************* Session management functions ************ */ + +/* initializes a session */ +static FSP_SESSION * +fsp_open_session(const char *host, unsigned short port, const char *password) +{ + FSP_SESSION *s; + int fd; + struct addrinfo hints,*res; + char port_s[6]; + struct sockaddr_in *addrin; + FSP_LOCK *lock; + + memset(&hints, 0, sizeof (hints)); + /* fspd do not supports inet6 */ + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_DGRAM; + + if (port == 0) { + strcpy(port_s, "fsp"); + } else { + sprintf(port_s,"%hu", port); + } + + if ((fd = getaddrinfo(host, port_s, &hints, &res)) != 0) { + + if (fd != EAI_SYSTEM) { + /* We need to set errno ourself */ + switch (fd) { + case EAI_SOCKTYPE: + case EAI_SERVICE: + case EAI_FAMILY: + errno = EOPNOTSUPP; + break; + case EAI_AGAIN: + errno = EAGAIN; + break; + case EAI_FAIL: + errno = ECONNRESET; + break; + case EAI_BADFLAGS: + errno = EINVAL; + break; + case EAI_MEMORY: + errno = ENOMEM; + break; + default: + errno = EFAULT; + } + } + return NULL; /* host not found */ + } + + /* create socket */ + fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + + if (fd < 0) { + return NULL; + } + /* connect socket */ + if (connect(fd, res->ai_addr, res->ai_addrlen)) { + close(fd); + return NULL; + } + /* allocate memory */ + s = calloc(1, sizeof(FSP_SESSION)); + + if (!s) { + close(fd); + errno = ENOMEM; + return NULL; + } + lock = malloc(sizeof(FSP_LOCK)); + + if (!lock) { + close(fd); + free(s); + errno = ENOMEM; + return NULL; + } + s->lock = lock; + /* init locking subsystem */ + addrin = (struct sockaddr_in *)res->ai_addr; + + if (client_init_key((FSP_LOCK *)s->lock, addrin->sin_addr.s_addr, ntohs(addrin->sin_port))) { + free(s); + close(fd); + free(lock); + return NULL; + } + s->fd = fd; + s->timeout = 300000; /* 5 minutes */ + s->maxdelay = 60000; /* 1 minute */ + s->seq = random() & 0xfff8; + + if (password) { + s->password = strdup(password); + } + + return s; +} + +static void bye_bye(void *data); + +/* closes a session */ +static void +try_fsp_close_session(struct connection *conn) +{ + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + + if (!fsp->ses || fsp->ses->fd == -1) { + return; + } + fsp->return_func = bye_bye; + fsp->out.cmd = FSP_CC_BYE; + fsp->out.len = fsp->out.xlen = 0; + fsp->out.pos = 0; + fsp->ses->timeout = 7000; + + try_fsp_transaction(conn); + clear_handlers(fsp->ses->fd); + bye_bye(conn); +} + +static void +bye_bye(void *data) +{ + struct connection *conn = (struct connection *)data; + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + FSP_SESSION *s = fsp->ses; + + kill_timer(&fsp->send_timer); + close(s->fd); + if (s->password) free(s->password); + client_destroy_key((FSP_LOCK *)s->lock); + free(s->lock); + memset(s, 0, sizeof(FSP_SESSION)); + s->fd = -1; + free(s); + + fsp->return_func = NULL; +} + +/* *************** Directory listing functions *************** */ + +/* native FSP directory reader */ +static int +fsp_readdir_native(FSP_DIR *dir, FSP_RDENTRY *entry, FSP_RDENTRY **result) +{ + unsigned char ftype; + int namelen; + + if (dir == NULL || entry == NULL || result == NULL) { + return -EINVAL; + } + + if (dir->dirpos < 0 || dir->dirpos % 4) { + return -ESPIPE; + } + + while(1) { + if (dir->dirpos >= (int)dir->datasize) { + /* end of the directory */ + *result = NULL; + return 0; + } + + if (dir->blocksize - (dir->dirpos % dir->blocksize) < 9) { + ftype = FSP_RDTYPE_SKIP; + } else { + /* get the file type */ + ftype = dir->data[dir->dirpos + 8]; + } + + if (ftype == FSP_RDTYPE_END) { + dir->dirpos = dir->datasize; + continue; + } + + if (ftype == FSP_RDTYPE_SKIP) { + /* skip to next directory block */ + dir->dirpos = (dir->dirpos / dir->blocksize + 1) * dir->blocksize; +#ifdef MAINTAINER_MODE + fprintf(stderr, "new block dirpos: %d\n", dir->dirpos); +#endif + continue; + } + /* extract binary data */ + entry->lastmod = ntohl(*(const uint32_t *)(dir->data + dir->dirpos)); + entry->size = ntohl(*(const uint32_t *)(dir->data + dir->dirpos + 4)); + entry->type = ftype; + /* skip file date and file size */ + dir->dirpos += 9; + /* read file name */ + entry->name[255] = '\0'; + strncpy(entry->name, (char *)(dir->data + dir->dirpos), 255); + /* check for ASCIIZ encoded filename */ + if (memchr(dir->data + dir->dirpos, 0, dir->datasize - dir->dirpos) != NULL) { + namelen = strlen((char *) dir->data+dir->dirpos); + } else { + /* \0 terminator not found at end of filename */ + *result = NULL; + return 0; + } + /* skip over file name */ + dir->dirpos += namelen + 1; + /* set entry namelen field */ + if (namelen > 255) { + entry->namlen = 255; + } else { + entry->namlen = namelen; + } + /* set record length */ + entry->reclen = 10 + namelen; + + /* pad to 4 byte boundary */ + while (dir->dirpos & 0x3) { + dir->dirpos++; + entry->reclen++; + } + /* and return it */ + *result = entry; + + return 0; + } +} + +static int +fsp_closedir(FSP_DIR *dirp) +{ + if (dirp == NULL) { + return -1; + } + + if (dirp->dirname) { + free(dirp->dirname); + } + free(dirp->data); + free(dirp); + + return 0; +} + +/* ***************** File input/output functions ********* */ +static FSP_FILE * +fsp_fopen(struct connection *conn, const char *path, const char *modeflags) +{ + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + FSP_SESSION *session = fsp->ses; + FSP_FILE *f; + + if (session == NULL || path == NULL || modeflags == NULL) { + errno = EINVAL; + return NULL; + } + + f = calloc(1, sizeof(FSP_FILE)); + + if (f == NULL) { + return NULL; + } + + /* check and parse flags */ + switch (*modeflags++) { + case 'r': + break; +// case 'w': +// f->writing = 1; +// break; + case 'a': + /* not supported */ + free(f); + errno = ENOTSUP; + return NULL; + default: + free(f); + errno = EINVAL; + return NULL; + } + + if (*modeflags == '+' || ( *modeflags == 'b' && modeflags[1] == '+')) { + free(f); + errno = ENOTSUP; + return NULL; + } + + /* build request packet */ + if (0 && f->writing) { + f->out.cmd = FSP_CC_UP_LOAD; + } else { + if (buildfilename(session, &fsp->out, path)) { + free(f); + return NULL; + } + f->bufpos = FSP_SPACE; + fsp->out.cmd = FSP_CC_GET_FILE; + } + fsp->out.xlen = 0; + /* setup control variables */ + f->s = session; + f->name = strdup(path); + + if (f->name == NULL) { + free(f); + errno = ENOMEM; + return NULL; + } + + return f; +} + +static int +fsp_fclose(FSP_FILE *file) +{ + int rc; + + rc = 0; + errno = 0; + free(file->name); + free(file); + + return rc; +} + + +static void +try_fsp_stat(struct connection *conn, const char *path) +{ + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + + if (buildfilename(fsp->ses, &fsp->out, path)) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + fsp->path = strdup(path); + + if (!fsp->path) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + + memset(&fsp->sb, 0xAA, sizeof(fsp->sb)); + + fsp->out.cmd = FSP_CC_STAT; + fsp->out.xlen = 0; + fsp->out.pos = 0; + fsp->return_func = fsp_stat_continue; + + try_fsp_transaction(conn); +} + +static void try_fsp_read_file(void *data); +static void try_fsp_opendir(void *data); + +static void +fsp_stat_continue(void *data) +{ + struct connection *conn = (struct connection *)data; + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + unsigned char ftype; + + if (fsp->ret) { + if (errno) { + abort_connection(conn, connection_state_for_errno(errno)); + } else { + abort_connection(conn, connection_state(S_FSP_OPEN_SESSION_UNKN)); + } + return; + } + + if (fsp->in.cmd == FSP_CC_ERR) { + errno = ENOTSUP; + abort_connection(conn, connection_state_for_errno(errno)); + return; + } + /* parse results */ + ftype = fsp->in.buf[8]; + + if (ftype == 0) { + errno = ENOENT; + abort_connection(conn, connection_state_for_errno(errno)); + return; + } + fsp->sb.st_uid = fsp->sb.st_gid = 0; + fsp->sb.st_mtime = fsp->sb.st_ctime = fsp->sb.st_atime = ntohl(*(const uint32_t *)(fsp->in.buf)); + fsp->sb.st_size = ntohl(*(const uint32_t *)(fsp->in.buf + 4)); + fsp->sb.st_blocks = (fsp->sb.st_size + 511) / 512; + + if (ftype == FSP_RDTYPE_DIR) { + fsp->sb.st_mode = S_IFDIR | 0755; + fsp->sb.st_nlink = 2; + } else { + fsp->sb.st_mode = S_IFREG | 0644; + fsp->sb.st_nlink = 1; + } + errno = 0; + +#if SIZEOF_OFF_T >= 8 + if (fsp->sb.st_size < 0 || fsp->sb.st_size > 0xFFFFFFFF) { + /* Probably a _FILE_OFFSET_BITS mismatch as + * described above. Try to detect which half + * of st_size is the real size. This may + * depend on the endianness of the processor + * and on the padding in struct stat. */ + if ((fsp->sb.st_size & 0xFFFFFFFF00000000ULL) == 0xAAAAAAAA00000000ULL) { + fsp->sb.st_size = fsp->sb.st_size & 0xFFFFFFFF; + } else if ((fsp->sb.st_size & 0xFFFFFFFF) == 0xAAAAAAAA) { + fsp->sb.st_size = (fsp->sb.st_size >> 32) & 0xFFFFFFFF; + } else { + /* Can't figure it out. */ + fsp->sb.st_size = 1; + } + } +#endif + + if (S_ISDIR(fsp->sb.st_mode)) { + if (buildfilename(fsp->ses, &fsp->out, fsp->path)) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + fsp->pos = 0; + fsp->blocksize = 0; + fsp->dir = NULL; + fsp->out.cmd = FSP_CC_GET_DIR; + fsp->out.xlen = 0; + fsp->out.pos = 0; + fsp->return_func = try_fsp_opendir; + try_fsp_transaction(conn); + } else { + FSP_FILE *file = fsp_fopen(conn, fsp->path, "r"); + + if (!file) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + conn->est_length = fsp->sb.st_size; + fsp->f = file; + fsp->out.pos = conn->from; + fsp->return_func = try_fsp_read_file; + try_fsp_transaction(conn); + } +} + +static void +display_entry(struct connection *conn, const FSP_RDENTRY *fentry, const char dircolor[]) +{ + struct string string; + + /* fentry->name is a fixed-size array and is followed by other + * members; thus, if the name reported by the server does not + * fit in the array, fsplib must either truncate or reject it. + * If fsplib truncates the name, it does not document whether + * fentry->namlen is the original length or the truncated + * length. ELinks therefore ignores fentry->namlen and + * instead measures the length on its own. */ + const size_t namelen = strlen(fentry->name); + + if (!init_string(&string)) return; + add_format_to_string(&string, "%10d", fentry->size); + add_to_string(&string, "\tname, namelen, 0); + if (fentry->type == FSP_RDTYPE_DIR) { + add_to_string(&string, "/\">"); + if (*dircolor) { + add_to_string(&string, ""); + } + add_html_to_string(&string, fentry->name, namelen); + if (*dircolor) { + add_to_string(&string, ""); + } + } else { + add_to_string(&string, "\">"); + add_html_to_string(&string, fentry->name, namelen); + } + add_to_string(&string, "\n"); + add_fragment(conn->cached, conn->from, string.source, string.length); + conn->from += string.length; + done_string(&string); +} + +static int +compare(const void *av, const void *bv) +{ + const FSP_RDENTRY *a = (const FSP_RDENTRY *)av, *b = (const FSP_RDENTRY *)bv; + int res = ((b->type == FSP_RDTYPE_DIR) - (a->type == FSP_RDTYPE_DIR)); + + if (res) + return res; + return strcmp(a->name, b->name); +} + +static void +sort_and_display_entries(struct connection *conn, FSP_DIR *dir, const char dircolor[]) +{ + /* fsp_readdir_native in fsplib 0.9 and earlier requires + * the third parameter to point to a non-null pointer + * even though it does not dereference that pointer + * and overwrites it with another one anyway. + * http://sourceforge.net/tracker/index.php?func=detail&aid=1875210&group_id=93841&atid=605738 + * Work around the bug by using non-null &tmp. + * Nothing will actually read or write tmp. */ + FSP_RDENTRY fentry, tmp, *table = NULL; + FSP_RDENTRY *fresult = &tmp; + int size = 0; + int i; + + while (!fsp_readdir_native(dir, &fentry, &fresult)) { + FSP_RDENTRY *new_table; + + if (!fresult) break; + if (!strcmp(fentry.name, ".")) + continue; + new_table = (FSP_RDENTRY *)mem_realloc(table, (size + 1) * sizeof(*table)); + if (!new_table) + continue; + table = new_table; + copy_struct(&table[size], &fentry); + size++; + } + /* If size==0, then table==NULL. According to ISO/IEC 9899:1999 + * 7.20.5p1, the NULL must not be given to qsort. */ + if (size > 0) + qsort(table, size, sizeof(*table), compare); + + for (i = 0; i < size; i++) { + display_entry(conn, &table[i], dircolor); + } +} + +static void +show_fsp_directory(struct connection *conn) +{ + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + struct string buf; + + fsp->dir->inuse = 1; + fsp->dir->blocksize = fsp->blocksize; + fsp->dir->dirname = strdup(fsp->path); + fsp->dir->datasize = fsp->pos; + + errno = 0; + char *data = get_uri_string(conn->uri, URI_DATA); + char dircolor[8] = ""; + + if (!conn->cached) conn->cached = get_cache_entry(conn->uri); + if (!conn->cached) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + + if (!data) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + decode_uri(data); + + if (!is_in_state(init_directory_listing(&buf, conn->uri), S_OK)) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + + add_fragment(conn->cached, conn->from, buf.source, buf.length); + conn->from += buf.length; + done_string(&buf); + + if (get_opt_bool("document.browse.links.color_dirs", NULL)) { + color_to_string(get_opt_color("document.colors.dirs", NULL), + dircolor); + } + + sort_and_display_entries(conn, fsp->dir, dircolor); +// fsp_closedir(dir); + add_fragment(conn->cached, conn->from, "
", strlen("
")); + conn->from += strlen("
"); +// fsp_close_session(ses); + mem_free_set(&conn->cached->content_type, stracpy("text/html")); + abort_connection(conn, connection_state(S_OK)); + + mem_free(data); +} + +static void +try_fsp_opendir(void *data) +{ + struct connection *conn = (struct connection *)data; + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + unsigned char *tmp; + + if (fsp->ret) { + if (errno) { + abort_connection(conn, connection_state_for_errno(errno)); + } else { + abort_connection(conn, connection_state(S_FSP_OPEN_SESSION_UNKN)); + } + return; + } + + if (fsp->in.cmd == FSP_CC_ERR) { + errno = EIO; + abort_connection(conn, connection_state_for_errno(errno)); + return; + } + + if (!fsp->in.len) { + show_fsp_directory(conn); + return; + } + + if (fsp->blocksize == 0) { + fsp->blocksize = fsp->in.len; + } + + if (fsp->dir == NULL) { + fsp->dir = calloc(1, sizeof(FSP_DIR)); + + if (!fsp->dir) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + } + tmp = realloc(fsp->dir->data, fsp->pos + fsp->in.len); + + if (tmp == NULL) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + fsp->dir->data = tmp; + memcpy(fsp->dir->data + fsp->pos, fsp->in.buf, fsp->in.len); + fsp->pos += fsp->in.len; + + if (fsp->in.len < fsp->blocksize) { + show_fsp_directory(conn); + return; + } + fsp->out.pos = fsp->pos; + register_bottom_half(try_fsp_transaction, conn); +} + +static void +try_fsp_read_file(void *data) +{ + struct connection *conn = (struct connection *)data; + struct fsp_connection_info *fsp = (struct fsp_connection_info *)conn->info; + + if (fsp->ret) { + if (errno) { + abort_connection(conn, connection_state_for_errno(errno)); + } else { + abort_connection(conn, connection_state(S_FSP_OPEN_SESSION_UNKN)); + } + return; + } + + if (fsp->in.cmd == FSP_CC_ERR) { + errno = EIO; + abort_connection(conn, connection_state_for_errno(errno)); + return; + } + + if (!conn->cached) conn->cached = get_cache_entry(conn->uri); + if (!conn->cached) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + + if (!fsp->in.len) { + abort_connection(conn, connection_state(S_OK)); + return; + } + + if (add_fragment(conn->cached, conn->from, (const char *)fsp->in.buf, fsp->in.len) == 1) { + conn->tries = 0; + } + conn->from += fsp->in.len; + conn->received += fsp->in.len; + fsp->out.pos = conn->from; + + register_bottom_half(try_fsp_transaction, conn); +} + +static void +done_fsp_connection(struct connection *conn) +{ + struct fsp_connection_info *fsp; + + if (!conn || !conn->info) { + return; + } + fsp = (struct fsp_connection_info *)conn->info; + + if (fsp->dir) { + fsp_closedir(fsp->dir); + } + + if (fsp->f) { + fsp_fclose(fsp->f); + } + + if (fsp->ses) { + try_fsp_close_session(conn); + } + + if (fsp->path) { + free(fsp->path); + } +} + +static void +do_fsp(struct connection *conn) +{ + FSP_SESSION *ses; + struct uri *uri = conn->uri; + struct auth_entry *auth; + char *host = get_uri_string(uri, URI_HOST); + char *data = get_uri_string(uri, URI_DATA); + unsigned short port = (unsigned short)get_uri_port(uri); + char *password = NULL; + struct fsp_connection_info *fsp = (struct fsp_connection_info *)mem_calloc(1, sizeof(*fsp)); + + if (!fsp) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + conn->info = fsp; + conn->done = done_fsp_connection; + + decode_uri(data); + if (uri->passwordlen) { + password = get_uri_string(uri, URI_PASSWORD); + } else { + auth = find_auth(uri); + if (auth) password = auth->password; + } + + /* fsp_open_session may not set errno if getaddrinfo fails + * https://sourceforge.net/tracker/index.php?func=detail&aid=2036798&group_id=93841&atid=605738 + * Try to detect this bug and use an ELinks-specific error + * code instead, so that we can display a message anyway. */ + errno = 0; + ses = fsp_open_session(host, port, password); + + if (!ses) { + if (errno) { + abort_connection(conn, connection_state_for_errno(errno)); + return; + } + else { + abort_connection(conn, connection_state(S_FSP_OPEN_SESSION_UNKN)); + return; + } + } + fsp->ses = ses; + set_connection_state(conn, connection_state(S_TRANS)); + try_fsp_stat(conn, data); +} + +void +fsp_protocol_handler(struct connection *conn) +{ + conn->from = 0; + conn->unrestartable = 1; + do_fsp(conn); +} diff --git a/src/protocol/fsp/fsplib.h b/src/protocol/fsp/fsplib.h new file mode 100644 index 00000000..4eaa3543 --- /dev/null +++ b/src/protocol/fsp/fsplib.h @@ -0,0 +1,152 @@ +#ifndef EL__PROTOCOL_FSP_FSPLIB_H +#define EL__PROTOCOL_FSP_FSPLIB_H + +#include +#include +#include +#include + +/* The FSP v2 protocol support library - public interface */ + +/* +This file is part of fsplib - FSP protocol stack implemented in C +language. See http://fsp.sourceforge.net for more information. + +Copyright (c) 2003-2005 by Radim HSN Kolar (hsn@sendmail.cz) + +You may copy or modify this file in any manner you wish, provided +that this notice is always included, and that you hold the author +harmless for any loss or damage resulting from the installation or +use of this software. + + This is a free software. Be creative. + Let me know of any bugs and suggestions. +*/ + +/* definition of FSP protocol v2 commands */ + +#define FSP_CC_VERSION 0x10 /* return server's version string. */ +#define FSP_CC_INFO 0x11 /* return server's extended info block */ +#define FSP_CC_ERR 0x40 /* error response from server. */ +#define FSP_CC_GET_DIR 0x41 /* get a directory listing. */ +#define FSP_CC_GET_FILE 0x42 /* get a file. */ +#define FSP_CC_UP_LOAD 0x43 /* open a file for writing. */ +#define FSP_CC_INSTALL 0x44 /* close a file opened for writing. */ +#define FSP_CC_DEL_FILE 0x45 /* delete a file. */ +#define FSP_CC_DEL_DIR 0x46 /* delete a directory. */ +#define FSP_CC_GET_PRO 0x47 /* get directory protection. */ +#define FSP_CC_SET_PRO 0x48 /* set directory protection. */ +#define FSP_CC_MAKE_DIR 0x49 /* create a directory. */ +#define FSP_CC_BYE 0x4A /* finish a session. */ +#define FSP_CC_GRAB_FILE 0x4B /* atomic get+delete a file. */ +#define FSP_CC_GRAB_DONE 0x4C /* atomic get+delete a file done. */ +#define FSP_CC_STAT 0x4D /* get information about file. */ +#define FSP_CC_RENAME 0x4E /* rename file or directory. */ +#define FSP_CC_CH_PASSWD 0x4F /* change password */ +#define FSP_CC_LIMIT 0x80 /* # > 0x7f for future cntrl blk ext. */ +#define FSP_CC_TEST 0x81 /* reserved for testing */ + +/* FSP v2 packet size */ +#define FSP_HSIZE 12 /* 12 bytes for v2 header */ +#define FSP_SPACE 1024 /* maximum payload. */ +#define FSP_MAXPACKET FSP_HSIZE+FSP_SPACE /* maximum packet size. */ + +/* byte offsets of fields in the FSP v2 header */ +#define FSP_OFFSET_CMD 0 +#define FSP_OFFSET_SUM 1 +#define FSP_OFFSET_KEY 2 +#define FSP_OFFSET_SEQ 4 +#define FSP_OFFSET_LEN 6 +#define FSP_OFFSET_POS 8 + +/* types of directory entry */ +#define FSP_RDTYPE_END 0x00 +#define FSP_RDTYPE_FILE 0x01 +#define FSP_RDTYPE_DIR 0x02 +#define FSP_RDTYPE_LINK 0x03 +#define FSP_RDTYPE_SKIP 0x2A + +/* definition of directory bitfield for directory information */ +/* directory information is just going to be a bitfield encoding + * of which protection bits are set/unset + */ + +#define FSP_PRO_BYTES 1 /* currently only 8 bits or less of info */ +#define FSP_DIR_OWNER 0x01 /* does caller own directory */ +#define FSP_DIR_DEL 0x02 /* can files be deleted from this dir */ +#define FSP_DIR_ADD 0x04 /* can files be added to this dir */ +#define FSP_DIR_MKDIR 0x08 /* can new subdirectories be created */ +#define FSP_DIR_GET 0x10 /* are files readable by non-owners? */ +#define FSP_DIR_README 0x20 /* does this dir contain an readme file? */ +#define FSP_DIR_LIST 0x40 /* public can list directory */ +#define FSP_DIR_RENAME 0x80 /* can files be renamed in this dir */ + +/* decoded FSP packet */ +typedef struct FSP_PKT { + unsigned char cmd; /* message code. */ + unsigned char sum; /* message checksum. */ + unsigned short key; /* message key. */ + unsigned short seq; /* message sequence number. */ + unsigned short len; /* number of bytes in buf 1. */ + unsigned int pos; /* location in the file. */ unsigned short xlen; /* number of bytes in buf 2 */ + + unsigned char buf[FSP_SPACE]; /* packet payload */ + } FSP_PKT; + +/* FSP host:port */ +typedef struct FSP_SESSION { + void * lock; /* key locking */ + unsigned int timeout; /* send timeout 1/1000s*/ + unsigned int maxdelay; /* maximum recv. delay */ + unsigned short seq; /* sequence number */ + unsigned int dupes; /* total pkt. dupes */ + unsigned int resends; /* total pkt. sends */ + unsigned int trips; /* total pkt trips */ + unsigned long rtts; /* cumul. rtt */ + unsigned int last_rtt; /* last rtt */ + unsigned int last_delay; /* last delay time */ + unsigned int last_dupes; /* last dupes */ + unsigned int last_resends;/* last resends */ + int fd; /* i/o descriptor */ + char *password; /* host acccess password */ + } FSP_SESSION; + +/* fsp directory handle */ +typedef struct FSP_DIR { + char *dirname; /* directory name */ + short inuse; /* in use counter */ + int dirpos; /* current directory pos. */ + unsigned short blocksize; /* size of directory block */ + unsigned char *data; /* raw directory data */ + unsigned int datasize; /* size of raw dir. data */ +} FSP_DIR; + +/* fsp directory entry */ +typedef struct FSP_RDENTRY { + char name[255 + 1]; /* entry name */ + unsigned short namlen; /* length */ + unsigned char type; /* field type */ + unsigned short reclen; /* directory record length */ + unsigned int size; + unsigned int lastmod; +} FSP_RDENTRY; + +/* fsp file handle */ +typedef struct FSP_FILE { + FSP_PKT in,out; /* io packets */ + FSP_SESSION *s; /* master session */ + char *name; /* filename for upload */ + unsigned char writing; /* opened for writing */ + unsigned char eof; /* EOF reached? */ + unsigned char err; /* i/o error? */ + int bufpos; /* position in buffer */ + unsigned int pos; /* position of next packet */ +} FSP_FILE; + + +typedef union dirent_workaround { + struct dirent dirent; + char fill[offsetof (struct dirent, d_name) + MAXNAMLEN + 1]; +} dirent_workaround; + +#endif diff --git a/src/protocol/fsp/lock.c b/src/protocol/fsp/lock.c new file mode 100644 index 00000000..0b8275cc --- /dev/null +++ b/src/protocol/fsp/lock.c @@ -0,0 +1,284 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "protocol/fsp/lock.h" + +/* ************ Locking functions ***************** */ +#ifndef FSP_NOLOCKING + +static char code_str[] = + "0123456789:_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void +make_key_string(FSP_LOCK *lock, unsigned long server_addr, unsigned long server_port) +{ + unsigned long v1, v2; + char *p; + + strcpy(lock->key_string, FSP_KEY_PREFIX); + + for (p = lock->key_string; *p; p++); + + v1 = server_addr; + v2 = server_port; + *p++ = code_str[v1 & 0x3f]; v1 >>= 6; + *p++ = code_str[v1 & 0x3f]; v1 >>= 6; + *p++ = code_str[v1 & 0x3f]; v1 >>= 6; + v1 = v1 | (v2 << (32-3*6)); + *p++ = code_str[v1 & 0x3f]; v1 >>= 6; + *p++ = code_str[v1 & 0x3f]; v1 >>= 6; + *p++ = code_str[v1 & 0x3f]; v1 >>= 6; + *p++ = code_str[v1 & 0x3f]; v1 >>= 6; + *p++ = code_str[v1 & 0x3f]; v1 >>= 6; + *p = 0; +} +#endif + +/********************************************************************/ +/******* For those systems that has SysV shared memory + semop ******/ +/********************************************************************/ +#ifdef FSP_USE_SHAREMEM_AND_SEMOP + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _SEM_SEMUN_UNDEFINED +union semun +{ + int val; + struct semid_ds *buf; + unsigned short int *array; + struct seminfo *__buf; +}; +#endif + +unsigned short +client_get_key(FSP_LOCK *lock) +{ + struct sembuf sem; + sem.sem_num = 0; + sem.sem_op = -1; + sem.sem_flg = SEM_UNDO; + + if (semop(lock->lock_sem,&sem,1) == -1) { + perror("semop lock"); + } + + return (*lock->share_key); +} + +void +client_set_key(FSP_LOCK *lock,unsigned short key) +{ + struct sembuf sem; + + sem.sem_num = 0; + sem.sem_op = 1; + sem.sem_flg = SEM_UNDO; + + *lock->share_key = key; + + if (semop(lock->lock_sem,&sem,1) == -1) { + perror("semop unlock"); + } +} + +int +client_init_key(FSP_LOCK *lock, unsigned long server_addr, unsigned short server_port) +{ + mode_t omask; + key_t lock_key; + int fd; + union semun su; + struct sembuf sem; + + make_key_string(lock, server_addr, server_port); + omask = umask(0); + fd = open(lock->key_string, O_RDWR|O_CREAT, 0666); + umask(omask); + close(fd); + + if ((lock_key = ftok(lock->key_string, 238)) == -1) { + perror("ftok"); + return -1; + } + + if ((lock->lock_shm = shmget(lock_key, 2 * sizeof(unsigned int), IPC_CREAT|0666)) == -1) { + perror("shmget"); + return -1; + } + + if (!(lock->share_key = (unsigned int *)shmat(lock->lock_shm, NULL, 0))) { + perror("shmat"); + return -1; + } + + if ((lock->lock_sem = semget(lock_key, 0, 0)) == -1) { + /* create a new semaphore and init it */ + if ((lock->lock_sem = semget(lock_key, 2, IPC_CREAT|0666)) == -1) { + perror("semget"); + return -1; + } + /* we need to init this semaphore */ + su.val = 1; + + if (semctl(lock->lock_sem, 0, SETVAL,su) == -1) { + perror("semctl setval"); + return -1; + } + } + /* increase in use counter */ + sem.sem_num = 1; + sem.sem_op = 1; + sem.sem_flg = SEM_UNDO; + + if (semop(lock->lock_sem, &sem, 1) == -1) { + perror("semop incuse"); + } + + return 0; +} + +void +client_destroy_key(FSP_LOCK *lock) +{ + int rc; + struct sembuf sem; + + if (shmdt(lock->share_key) < 0) { + perror("shmdt"); + return; + } + /* check if we are only one process holding lock */ + rc = semctl(lock->lock_sem, 1, GETVAL); + + if (rc == 1) { + /* safe to destroy */ + if ( + (semctl(lock->lock_sem,0,IPC_RMID) < 0) || + (shmctl(lock->lock_shm,IPC_RMID,NULL) < 0) || + (unlink(lock->key_string) < 0) ) { + rc = 0;/* ignore cleanup errors */ + } + } else if (rc > 1) { + /* we need to decrease sem. */ + sem.sem_num = 1; + sem.sem_op = -1; + sem.sem_flg = SEM_UNDO; + + if (semop(lock->lock_sem,&sem,1) == -1) { + perror("semop decuse"); + } + } +} +#endif + + +/********************************************************************/ +/******* For those who do not want to use locking *******************/ +/********************************************************************/ +#ifdef FSP_NOLOCKING + +unsigned short +client_get_key(FSP_LOCK *lock) +{ + return lock->share_key; +} + +void +client_set_key(FSP_LOCK *lock,unsigned short key) +{ + lock->share_key = key; +} + +int +client_init_key(FSP_LOCK *lock, unsigned long server_addr, unsigned short server_port) +{ + return 0; +} + +void +client_destroy_key(FSP_LOCK *lock) +{ + return; +} +#endif + +/********************************************************************/ +/******* For those systems that has lockf function call *************/ +/********************************************************************/ +#ifdef FSP_USE_LOCKF + +#include +#include +#include + +unsigned short +client_get_key(FSP_LOCK *lock) +{ + unsigned int okey; + + if (lockf(lock->lock_fd, F_LOCK, sizeof(okey)) < 0) { + perror("lockf"); + } + + if (read(lock->lock_fd, &okey, sizeof(okey)) < 0) { + perror("readlk"); + } + + if (lseek(lock->lock_fd, 0L, 0) < 0) { + perror("seek"); + } + + return(okey); +} + +void +client_set_key(FSP_LOCK *lock,unsigned short nkey) +{ + unsigned int key; + key = nkey; + + if (write(lock->lock_fd, &key, sizeof(key)) < 0) { + perror("write"); + } + + if (lseek(lock->lock_fd, 0L, 0) < 0) { + perror("seek"); + } + + if (lockf(lock->lock_fd, F_ULOCK, sizeof(key)) < 0) { + perror("unlockf"); + } +} + +int +client_init_key(FSP_LOCK *lock, unsigned long server_addr, unsigned short server_port) +{ + mode_t omask; + make_key_string(lock,server_addr, server_port); + omask = umask(0); + lock->lock_fd = open(lock->key_string, O_RDWR | O_CREAT, 0666); + (void)umask(omask); + + if (lock->lock_fd < 0) { + return -1; + } else { + return 0; + } +} + +void +client_destroy_key(FSP_LOCK *lock) +{ + (void)close(lock->lock_fd); +} +#endif diff --git a/src/protocol/fsp/lock.h b/src/protocol/fsp/lock.h new file mode 100644 index 00000000..589f1bc5 --- /dev/null +++ b/src/protocol/fsp/lock.h @@ -0,0 +1,47 @@ +#ifndef EL__PROTOCOL_FSP_LOCK_H +#define EL__PROTOCOL_FSP_LOCK_H 1 + +#define FSP_NOLOCKING 1 + +#ifndef FSP_NOLOCKING +/* define locking prefix if needed */ +# ifndef FSP_KEY_PREFIX +# define FSP_KEY_PREFIX "/tmp/.FSPL" +# endif +#endif + +#ifdef FSP_USE_SHAREMEM_AND_SEMOP + +typedef struct FSP_LOCK { + unsigned int *share_key; + int lock_shm; + int lock_sem; + char key_string[sizeof(FSP_KEY_PREFIX)+32]; +} FSP_LOCK; + +#elif defined(FSP_NOLOCKING) + +typedef struct FSP_LOCK { + unsigned short share_key; +} FSP_LOCK; + +#elif defined(FSP_USE_LOCKF) + +typedef struct FSP_LOCK { + int lock_fd; + char key_string[sizeof(FSP_KEY_PREFIX)+32]; +} FSP_LOCK; + +#else +#error "No locking type specified" +#endif + +/* prototypes */ + +unsigned short client_get_key (FSP_LOCK *lock); +void client_set_key (FSP_LOCK *lock,unsigned short key); +int client_init_key (FSP_LOCK *lock, + unsigned long server_addr, + unsigned short server_port); +void client_destroy_key(FSP_LOCK *lock); +#endif diff --git a/src/protocol/fsp/meson.build b/src/protocol/fsp/meson.build index d9c60d9f..eb557586 100644 --- a/src/protocol/fsp/meson.build +++ b/src/protocol/fsp/meson.build @@ -1 +1,7 @@ -srcs += files('fsp.c') +if conf_data.get('CONFIG_FSP2') + srcs += files('fsp2.c', 'lock.c') +endif + +if conf_data.get('CONFIG_FSP') + srcs += files('fsp.c') +endif diff --git a/src/protocol/meson.build b/src/protocol/meson.build index 82692c4f..7d89dcd8 100644 --- a/src/protocol/meson.build +++ b/src/protocol/meson.build @@ -7,7 +7,7 @@ endif if conf_data.get('CONFIG_FINGER') subdir('finger') endif -if conf_data.get('CONFIG_FSP') +if conf_data.get('CONFIG_FSP') or conf_data.get('CONFIG_FSP2') subdir('fsp') endif if conf_data.get('CONFIG_FTP') diff --git a/src/protocol/protocol.cpp b/src/protocol/protocol.cpp index ed5b6cd7..67355f03 100644 --- a/src/protocol/protocol.cpp +++ b/src/protocol/protocol.cpp @@ -313,7 +313,7 @@ static struct module *protocol_submodules[] = { #ifdef CONFIG_FINGER &finger_protocol_module, #endif -#ifdef CONFIG_FSP +#if defined(CONFIG_FSP) || defined(CONFIG_FSP2) &fsp_protocol_module, #endif #ifdef CONFIG_FTP