static void send_file(struct ftpd_datastate *fsd, struct tcp_pcb *pcb) { if (!fsd->connected) return; if (fsd->vfs_file) { char buffer[2048]; int len; len = sfifo_space(&fsd->fifo); if (len == 0) { send_data(pcb, fsd); return; } if (len > 2048) len = 2048; len = vfs_read(buffer, 1, len, fsd->vfs_file); if (len == 0) { if (vfs_eof(fsd->vfs_file) == 0) return; vfs_close(fsd->vfs_file); fsd->vfs_file = NULL; return; } sfifo_write(&fsd->fifo, buffer, len); send_data(pcb, fsd); } else { struct ftpd_msgstate *fsm; struct tcp_pcb *msgpcb; if (sfifo_used(&fsd->fifo) > 0) { send_data(pcb, fsd); return; } fsm = fsd->msgfs; msgpcb = fsd->msgpcb; vfs_close(fsd->vfs_file); fsd->vfs_file = NULL; ftpd_dataclose(pcb, fsd); fsm->datapcb = NULL; fsm->datafs = NULL; fsm->state = FTPD_IDLE; send_msg(msgpcb, fsm, msg226); return; } }
static void ftpd_msgclose(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); if (fsm->datafs) ftpd_dataclose(fsm->datapcb, fsm->datafs); sfifo_close(&fsm->fifo); vfs_close(fsm->vfs); fsm->vfs = NULL; if (fsm->renamefrom) free(fsm->renamefrom); fsm->renamefrom = NULL; free(fsm); tcp_arg(pcb, NULL); tcp_close(pcb); }
static void ftpd_msgerr(void *arg, err_t err) { struct ftpd_msgstate *fsm = arg; dbg_printf("ftpd_msgerr: %s (%i)\n", lwip_strerr(err), err); if (fsm == NULL) return; if (fsm->datafs) ftpd_dataclose(fsm->datapcb, fsm->datafs); sfifo_close(&fsm->fifo); vfs_close(fsm->vfs); fsm->vfs = NULL; if (fsm->renamefrom) free(fsm->renamefrom); fsm->renamefrom = NULL; free(fsm); }
static err_t ftpd_datarecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { struct ftpd_datastate *fsd = arg; if (err == ERR_OK && p != NULL) { struct pbuf *q; u16_t tot_len = 0; for (q = p; q != NULL; q = q->next) { int len; len = vfs_write(q->payload, 1, q->len, fsd->vfs_file); tot_len += len; if (len != q->len) break; } /* Inform TCP that we have taken the data. */ tcp_recved(pcb, tot_len); pbuf_free(p); } if (err == ERR_OK && p == NULL) { struct ftpd_msgstate *fsm; struct tcp_pcb *msgpcb; fsm = fsd->msgfs; msgpcb = fsd->msgpcb; vfs_close(fsd->vfs_file); fsd->vfs_file = NULL; ftpd_dataclose(pcb, fsd); fsm->datapcb = NULL; fsm->datafs = NULL; fsm->state = FTPD_IDLE; send_msg(msgpcb, fsm, msg226); } return ERR_OK; }
static void cmd_pasv(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { static u16_t port = 4096; static u16_t start_port = 4096; struct tcp_pcb *temppcb; /* Allocate memory for the structure that holds the state of the connection. */ fsm->datafs = malloc(sizeof(struct ftpd_datastate)); if (fsm->datafs == NULL) { send_msg(pcb, fsm, msg451); return; } memset(fsm->datafs, 0, sizeof(struct ftpd_datastate)); fsm->datapcb = tcp_new(); if (!fsm->datapcb) { free(fsm->datafs); send_msg(pcb, fsm, msg451); return; } sfifo_init(&fsm->datafs->fifo, 2000); start_port = port; while (1) { err_t err; if(++port > 0x7fff) port = 4096; fsm->dataport = port; err = tcp_bind(fsm->datapcb, (ip_addr_t*)&pcb->local_ip, fsm->dataport); if (err == ERR_OK) break; if (start_port == port) err = ERR_CLSD; if (err == ERR_USE) { continue; } else { ftpd_dataclose(fsm->datapcb, fsm->datafs); fsm->datapcb = NULL; fsm->datafs = NULL; return; } } fsm->datafs->msgfs = fsm; temppcb = tcp_listen(fsm->datapcb); if (!temppcb) { ftpd_dataclose(fsm->datapcb, fsm->datafs); fsm->datapcb = NULL; fsm->datafs = NULL; return; } fsm->datapcb = temppcb; fsm->passive = 1; fsm->datafs->connected = 0; fsm->datafs->msgpcb = pcb; /* Tell TCP that this is the structure we wish to be passed for our callbacks. */ tcp_arg(fsm->datapcb, fsm->datafs); tcp_accept(fsm->datapcb, ftpd_dataaccept); send_msg(pcb, fsm, msg227, ip4_addr1(ip_2_ip4(&pcb->local_ip)), ip4_addr2(ip_2_ip4(&pcb->local_ip)), ip4_addr3(ip_2_ip4(&pcb->local_ip)), ip4_addr4(ip_2_ip4(&pcb->local_ip)), (fsm->dataport >> 8) & 0xff, (fsm->dataport) & 0xff); }
static void send_next_directory(struct ftpd_datastate *fsd, struct tcp_pcb *pcb, int shortlist) { char buffer[1024]; int len; while (1) { if (fsd->vfs_dirent == NULL) fsd->vfs_dirent = vfs_readdir(fsd->vfs_dir); if (fsd->vfs_dirent) { if (shortlist) { len = sprintf(buffer, "%s\r\n", fsd->vfs_dirent->name); if (sfifo_space(&fsd->fifo) < len) { send_data(pcb, fsd); return; } sfifo_write(&fsd->fifo, buffer, len); fsd->vfs_dirent = NULL; } else { vfs_stat_t st; time_t current_time; int current_year; struct tm *s_time; time(¤t_time); s_time = gmtime(¤t_time); current_year = s_time->tm_year; vfs_stat(fsd->msgfs->vfs, fsd->vfs_dirent->name, &st); s_time = gmtime(&st.st_mtime); if (s_time->tm_year == current_year) len = sprintf(buffer, "-rw-rw-rw- 1 user ftp %11ld %s %02i %02i:%02i %s\r\n", st.st_size, month_table[s_time->tm_mon], s_time->tm_mday, s_time->tm_hour, s_time->tm_min, fsd->vfs_dirent->name); else len = sprintf(buffer, "-rw-rw-rw- 1 user ftp %11ld %s %02i %5i %s\r\n", st.st_size, month_table[s_time->tm_mon], s_time->tm_mday, s_time->tm_year + 1900, fsd->vfs_dirent->name); if (VFS_ISDIR(st.st_mode)) buffer[0] = 'd'; if (sfifo_space(&fsd->fifo) < len) { send_data(pcb, fsd); return; } sfifo_write(&fsd->fifo, buffer, len); fsd->vfs_dirent = NULL; } } else { struct ftpd_msgstate *fsm; struct tcp_pcb *msgpcb; if (sfifo_used(&fsd->fifo) > 0) { send_data(pcb, fsd); return; } fsm = fsd->msgfs; msgpcb = fsd->msgpcb; vfs_closedir(fsd->vfs_dir); fsd->vfs_dir = NULL; ftpd_dataclose(pcb, fsd); fsm->datapcb = NULL; fsm->datafs = NULL; fsm->state = FTPD_IDLE; send_msg(msgpcb, fsm, msg226); return; } } }