Fork of Smoothie to port to mbed non-LPC targets.
Fork of Smoothie by
Diff: libs/Network/uip/sftp/sftpd.cpp
- Revision:
- 2:1df0b61d3b5a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/Network/uip/sftp/sftpd.cpp Fri Feb 28 18:52:52 2014 -0800 @@ -0,0 +1,228 @@ +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + +#include "sftpd.h" +#include "string.h" +#include "stdlib.h" + +extern "C" { +#include "uip.h" +} + +#define ISO_nl 0x0a +#define ISO_cr 0x0d +#define ISO_sp 0x20 + +#define DEBUG_PRINTF(...) + +Sftpd::Sftpd() +{ + fd = NULL; + state = STATE_NORMAL; + outbuf = NULL; + filename= NULL; +} + +Sftpd::~Sftpd() +{ + if (fd != NULL) { + fclose(fd); + } +} + +int Sftpd::senddata() +{ + if (outbuf != NULL) { + DEBUG_PRINTF("sftp: senddata %s\n", outbuf); + strcpy((char *)uip_appdata, outbuf); + uip_send(uip_appdata, strlen(outbuf)); + } + return 0; +} + +int Sftpd::handle_command() +{ + PSOCK_BEGIN(&sin); + + do { + PSOCK_READTO(&sin, ISO_nl); + buf[PSOCK_DATALEN(&sin) - 1] = 0; + int len = PSOCK_DATALEN(&sin) - 1; + DEBUG_PRINTF("sftp: got command: %s, %d\n", buf, len); + + if (state == STATE_CONNECTED) { + if (strncmp(buf, "USER", 4) == 0) { + outbuf = "!user logged in\n"; + + } else if (strncmp(buf, "KILL", 4) == 0) { + if (len < 6) { + outbuf = "- incomplete KILL command\n"; + } else { + char *fn = &buf[5]; + int s = remove(fn); + if (s == 0) outbuf = "+ deleted\n"; + else outbuf = "- delete failed\n"; + } + + } else if (strncmp(buf, "DONE", 4) == 0) { + outbuf = "+ exit\n"; + state = STATE_CLOSE; + + } else if (strncmp(buf, "STOR", 4) == 0) { + if (len < 11) { + outbuf = "- incomplete STOR command\n"; + } else { + char *fn = &buf[9]; + if(this->filename != NULL) free(this->filename); + this->filename= strdup(fn); // REMOVE when bug fixed + // get { NEW|OLD|APP } + if (strncmp(&buf[5], "OLD", 3) == 0) { + DEBUG_PRINTF("sftp: Opening file: %s\n", fn); + fd = fopen(fn, "w"); + if (fd != NULL) { + outbuf = "+ new file\n"; + state = STATE_GET_LENGTH; + } else { + outbuf = "- failed\n"; + } + } else if (strncmp(&buf[5], "APP", 3) == 0) { + fd = fopen(fn, "a"); + if (fd != NULL) { + outbuf = "+ append file\n"; + state = STATE_GET_LENGTH; + } else { + outbuf = "- failed\n"; + } + } else { + outbuf = "- Only OLD|APP supported\n"; + } + } + + } else { + outbuf = "- Unknown command\n"; + } + + } else if (state == STATE_GET_LENGTH) { + if (len < 6 || strncmp(buf, "SIZE", 4) != 0) { + fclose(fd); + fd = NULL; + outbuf = "- Expected size\n"; + state = STATE_CONNECTED; + + } else { + filesize = atoi(&buf[5]); + if (filesize > 0) { + outbuf = "+ ok, waiting for file\n"; + state = STATE_DOWNLOAD; + } else { + fclose(fd); + fd = NULL; + outbuf = "- bad filesize\n"; + state = STATE_CONNECTED; + } + } + + } else { + DEBUG_PRINTF("WTF state: %d\n", state); + } + + } while(state == STATE_CONNECTED || state == STATE_GET_LENGTH); + + PSOCK_END(&sin); +} + +int Sftpd::handle_download() +{ + // Note this is not using PSOCK and it consumes all read data + char *readptr = (char *)uip_appdata; + unsigned int readlen = uip_datalen(); + DEBUG_PRINTF("sftp: starting download, expecting %d bytes, read %d\n", filesize, readlen); + + if (filesize > 0 && readlen > 0) { + if (readlen > filesize) readlen = filesize; + if (fwrite(readptr, 1, readlen, fd) != readlen) { + DEBUG_PRINTF("sftp: Error writing file\n"); + fclose(fd); + fd = NULL; + outbuf = "- Error saving file\n"; + state = STATE_CONNECTED; + return 0; + } + filesize -= readlen; + DEBUG_PRINTF("sftp: saved %d bytes %d left\n", readlen, filesize); + // HACK ALERT... to work around the fwrite/filesystem bug where writing large amounts of data corrupts the file + // we workaround by closing the file, the reopening for append until we are done + fclose(fd); + fd = fopen(this->filename, "a"); + } + if (filesize == 0) { + DEBUG_PRINTF("sftp: download complete\n"); + fclose(fd); + fd = NULL; + outbuf = "+ Saved file\n"; + state = STATE_CONNECTED; + return 0; + } + return 1; +} + +int Sftpd::acked() +{ + outbuf= NULL; + return 0; +} + + +void Sftpd::appcall(void) +{ + if (uip_connected()) { + // TODO check for other connections + PSOCK_INIT(&sin, buf, sizeof(buf)); + state = STATE_CONNECTED; + outbuf = "+Smoothie SFTP Service\n"; + } + + if (state == STATE_CLOSE) { + DEBUG_PRINTF("sftp: state close\n"); + state = STATE_NORMAL; + uip_close(); + return; + } + + if (uip_closed() || uip_aborted() || uip_timedout()) { + DEBUG_PRINTF("sftp: closed\n"); + if (fd != NULL) + fclose(fd); + fd = NULL; + state = STATE_NORMAL; + return; + } + + if (uip_acked()) { + DEBUG_PRINTF("sftp: acked\n"); + this->acked(); + } + + if (uip_newdata()) { + DEBUG_PRINTF("sftp: newdata\n"); + if (state == STATE_DOWNLOAD) { + if(handle_download() == 0) { + // we need to reset the input PSOCK again before using it after using the raw input buffer + PSOCK_INIT(&sin, buf, sizeof(buf)); + } + } else { + handle_command(); + } + } + + if (uip_rexmit() || uip_newdata() || uip_acked() || uip_connected() || uip_poll()) { + this->senddata(); + } + +} + +void Sftpd::init(void) +{ + +} + +