initial import
This commit is contained in:
commit
1092c73986
|
@ -0,0 +1 @@
|
||||||
|
.pio
|
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the usual convention is to give header files names that end with `.h'.
|
||||||
|
It is most portable to use only letters, digits, dashes, and underscores in
|
||||||
|
header file names, and at most one dot.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
enum ConnFlag
|
||||||
|
{
|
||||||
|
FLAG_DISCONNECT_ON_EXIT=1,
|
||||||
|
FLAG_PETSCII=2,
|
||||||
|
FLAG_TELNET=4,
|
||||||
|
FLAG_ECHO=8,
|
||||||
|
FLAG_XONXOFF=16,
|
||||||
|
FLAG_SECURE=32,
|
||||||
|
FLAG_RTSCTS=64
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConnSettings
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boolean petscii = false;
|
||||||
|
boolean telnet = false;
|
||||||
|
boolean echo = false;
|
||||||
|
boolean xonxoff = false;
|
||||||
|
boolean rtscts = false;
|
||||||
|
boolean secure = false;
|
||||||
|
|
||||||
|
ConnSettings(int flagBitmap);
|
||||||
|
ConnSettings(const char *dmodifiers);
|
||||||
|
ConnSettings(String modifiers);
|
||||||
|
int getBitmap();
|
||||||
|
int getBitmap(FlowControlType forceCheck);
|
||||||
|
void setFlag(ConnFlag flagMask, boolean newVal);
|
||||||
|
String getFlagString();
|
||||||
|
|
||||||
|
static void IPtoStr(IPAddress *ip, String &str);
|
||||||
|
static IPAddress *parseIP(const char *ipStr);
|
||||||
|
};
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum LogOutputState
|
||||||
|
{
|
||||||
|
LOS_NADA=0,
|
||||||
|
LOS_SocketIn=1,
|
||||||
|
LOS_SocketOut=2,
|
||||||
|
LOS_SerialIn=3,
|
||||||
|
LOS_SerialOut=4
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned long expectedSerialTime = 1000;
|
||||||
|
|
||||||
|
static boolean logFileOpen = false;
|
||||||
|
static bool logFileDebug= false;
|
||||||
|
static File logFile;
|
||||||
|
|
||||||
|
static void logSerialOut(const uint8_t c);
|
||||||
|
static void logSocketOut(const uint8_t c);
|
||||||
|
static void logSerialIn(const uint8_t c);
|
||||||
|
static void logSocketIn(const uint8_t c);
|
||||||
|
static void logPrint(const char* msg);
|
||||||
|
static void logPrintln(const char* msg);
|
||||||
|
static void logPrintf(const char* format, ...);
|
||||||
|
static void logPrintfln(const char* format, ...);
|
||||||
|
static char *TOHEX(const char *s, char *hex, const size_t len);
|
||||||
|
static char *TOHEX(long a);
|
||||||
|
static char *TOHEX(int a);
|
||||||
|
static char *TOHEX(unsigned int a);
|
||||||
|
static char *TOHEX(unsigned long a);
|
||||||
|
static char *tohex(uint8_t a);
|
||||||
|
static char *TOHEX(uint8_t a);
|
||||||
|
static uint8_t FROMHEX(uint8_t a1, uint8_t a2);
|
||||||
|
static char *FROMHEX(const char *hex, char *s, const size_t len);
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
# include <WiFi.h>
|
||||||
|
# define ENC_TYPE_NONE WIFI_AUTH_OPEN
|
||||||
|
# include <HardwareSerial.h>
|
||||||
|
# include <SPIFFS.h>
|
||||||
|
# include <Update.h>
|
||||||
|
# include "SD.h"
|
||||||
|
# include "SPI.h"
|
||||||
|
# include "driver/uart.h"
|
||||||
|
static HardwareSerial HWSerial(UART_NUM_2);
|
||||||
|
#else
|
||||||
|
# include "ESP8266WiFi.h"
|
||||||
|
# define HWSerial Serial
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
char petToAsc(char c);
|
||||||
|
bool ascToPet(char *c, Stream *stream);
|
||||||
|
char ascToPetcii(char c);
|
||||||
|
bool handleAsciiIAC(char *c, Stream *stream);
|
||||||
|
|
||||||
|
static void setCharArray(char **target, const char *src)
|
||||||
|
{
|
||||||
|
if(src == NULL)
|
||||||
|
return;
|
||||||
|
if(*target != NULL)
|
||||||
|
free(*target);
|
||||||
|
*target = (char *)malloc(strlen(src)+1);
|
||||||
|
strcpy(*target,src);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freeCharArray(char **arr)
|
||||||
|
{
|
||||||
|
if(*arr == NULL)
|
||||||
|
return;
|
||||||
|
free(*arr);
|
||||||
|
*arr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int modifierCompare(const char *match1, const char *match2)
|
||||||
|
{
|
||||||
|
if(strlen(match1) != strlen(match2))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for(int i1=0;i1<strlen(match1);i1++)
|
||||||
|
{
|
||||||
|
char c1=tolower(match1[i1]);
|
||||||
|
bool found=false;
|
||||||
|
for(int i2=0;i2<strlen(match2);i2++)
|
||||||
|
{
|
||||||
|
char c2=tolower(match2[i2]);
|
||||||
|
found = found || (c1==c2);
|
||||||
|
}
|
||||||
|
if(!found)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
class PhoneBookEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unsigned long number;
|
||||||
|
const char *address;
|
||||||
|
const char *modifiers;
|
||||||
|
const char *notes;
|
||||||
|
PhoneBookEntry *next = null;
|
||||||
|
|
||||||
|
PhoneBookEntry(unsigned long phnum, const char *addr, const char *mod, const char *note);
|
||||||
|
~PhoneBookEntry();
|
||||||
|
|
||||||
|
static void loadPhonebook();
|
||||||
|
static void clearPhonebook();
|
||||||
|
static void savePhonebook();
|
||||||
|
static bool checkPhonebookEntry(String cmd);
|
||||||
|
static PhoneBookEntry *findPhonebookEntry(long number);
|
||||||
|
static PhoneBookEntry *findPhonebookEntry(String number);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
#ifndef ZIMODEM_PROTO_FTP
|
||||||
|
#define ZIMODEM_PROTO_FTP
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class FTPHost
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
char *hostIp = 0;
|
||||||
|
int port = 0;
|
||||||
|
bool doSSL = false;
|
||||||
|
char *username = 0;
|
||||||
|
char *pw = 0;
|
||||||
|
char *path = 0;
|
||||||
|
char *file = 0;
|
||||||
|
~FTPHost();
|
||||||
|
bool doGet(FS *fs, const char *localpath, const char *remotepath);
|
||||||
|
bool doPut(File &f, const char *remotepath);
|
||||||
|
bool doLS(ZSerial *serial, const char *remotepath);
|
||||||
|
bool parseUrl(uint8_t *vbuf, char **req);
|
||||||
|
void fixPath(const char *remotepath);
|
||||||
|
};
|
||||||
|
|
||||||
|
FTPHost *makeFTPHost(bool isUrl, FTPHost **host, uint8_t *buf, char **req);
|
||||||
|
bool parseFTPUrl(uint8_t *vbuf, char **hostIp, char **req, int *port, bool *doSSL, char **username, char **pw);
|
||||||
|
bool doFTPGet(FS *fs, const char *hostIp, int port, const char *localpath, const char *remotepath, const char *username, const char *pw, const bool doSSL);
|
||||||
|
bool doFTPPut(File &f, const char *hostIp, int port, const char *remotepath, const char *username, const char *pw, const bool doSSL);
|
||||||
|
bool doFTPLS(ZSerial *serial, const char *hostIp, int port, const char *remotepath, const char *username, const char *pw, const bool doSSL);
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,84 @@
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
#ifdef INCLUDE_HOSTCM
|
||||||
|
/* Converted from source reverse engineered from SP9000 roms by Rob Ferguson */
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
# define HCM_BUFSIZ 104
|
||||||
|
# define HCM_SENDBUF (208/2 - 6)
|
||||||
|
# define HCM_FNSIZ 32
|
||||||
|
# define HCM_MAXFN 16
|
||||||
|
|
||||||
|
typedef struct _HCMFile
|
||||||
|
{
|
||||||
|
char descriptor;
|
||||||
|
File f;
|
||||||
|
uint8_t mode;
|
||||||
|
uint8_t format;
|
||||||
|
uint8_t type;
|
||||||
|
int reclen;
|
||||||
|
char filename[HCM_FNSIZ+1];
|
||||||
|
struct _HCMFile *nxt;
|
||||||
|
} HCMFile;
|
||||||
|
|
||||||
|
class HostCM
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ZSerial hserial;
|
||||||
|
const struct _HCOpts
|
||||||
|
{
|
||||||
|
unsigned int speed = 15; //B9600
|
||||||
|
unsigned int parity = 0;// ?!
|
||||||
|
unsigned int stopb=0;
|
||||||
|
unsigned char lineend=0xd;
|
||||||
|
unsigned char prompt=0x11;
|
||||||
|
unsigned char response=0x13;
|
||||||
|
unsigned char ext=0;
|
||||||
|
} opt PROGMEM;
|
||||||
|
|
||||||
|
uint8_t outbuf[HCM_BUFSIZ];
|
||||||
|
int odex = 0;
|
||||||
|
|
||||||
|
uint8_t inbuf[HCM_BUFSIZ+1];
|
||||||
|
int idex = 0;
|
||||||
|
|
||||||
|
bool aborted = false;
|
||||||
|
unsigned long lastNonPlusTm = 0;
|
||||||
|
unsigned int plussesInARow = 0;
|
||||||
|
unsigned long plusTimeExpire = 0;
|
||||||
|
HCMFile files[HCM_MAXFN];
|
||||||
|
FS *hFS = &SD;
|
||||||
|
File openDirF = (File)0;
|
||||||
|
File renameF = (File)0;
|
||||||
|
|
||||||
|
char checksum(uint8_t *b, int n);
|
||||||
|
void checkDoPlusPlusPlus(const int c, const unsigned long tm);
|
||||||
|
bool checkPlusPlusPlusExpire(const unsigned long tm);
|
||||||
|
void sendNAK();
|
||||||
|
void sendACK();
|
||||||
|
void sendError(const char* format, ...);
|
||||||
|
bool closeAllFiles();
|
||||||
|
HCMFile *addNewFileEntry();
|
||||||
|
void delFileEntry(HCMFile *e);
|
||||||
|
HCMFile *getFileByDescriptor(char c);
|
||||||
|
int numOpenFiles();
|
||||||
|
|
||||||
|
void protoOpenFile();
|
||||||
|
void protoCloseFile();
|
||||||
|
void protoPutToFile();
|
||||||
|
void protoGetFileBytes();
|
||||||
|
void protoOpenDir();
|
||||||
|
void protoNextDirFile();
|
||||||
|
void protoCloseDir();
|
||||||
|
void protoSetRenameFile();
|
||||||
|
void protoFinRenameFile();
|
||||||
|
void protoEraseFile();
|
||||||
|
void protoSeekFile();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void receiveLoop();
|
||||||
|
bool isAborted();
|
||||||
|
HostCM(FS *fs);
|
||||||
|
~HostCM();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef ZIMODEM_PROTO_HTTP
|
||||||
|
#define ZIMODEM_PROTO_HTTP
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
bool parseWebUrl(uint8_t *vbuf, char **hostIp, char **req, int *port, bool *doSSL);
|
||||||
|
bool doWebGetBytes(const char *hostIp, int port, const char *req, const bool doSSL, uint8_t *buf, int *bufSize);
|
||||||
|
WiFiClient *doWebGetStream(const char *hostIp, int port, const char *req, bool doSSL, uint32_t *responseSize);
|
||||||
|
bool doWebGet(const char *hostIp, int port, FS *fs, const char *filename, const char *req, const bool doSSL);
|
||||||
|
#endif
|
|
@ -0,0 +1,155 @@
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
class KModem
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static const int MAXPACKSIZ = 94; /* Maximum packet size */
|
||||||
|
static const int MAXTRY = 20; /* Times to retry a packet */
|
||||||
|
static const int MYTIME = 10; /* (10) Seconds after which I should be timed out */
|
||||||
|
static const int MAXTIM = 60; /* (60) Maximum timeout interval */
|
||||||
|
static const int MINTIM = 2; /* (2) Minumum timeout interval */
|
||||||
|
static const char MYQUOTE ='#'; /* Quote character I will use */
|
||||||
|
static const int MYPAD = 0; /* Number of padding characters I will need */
|
||||||
|
static const int MYPCHAR = 0; /* Padding character I need (NULL) */
|
||||||
|
static const char MYEOL = '\n'; /* End-Of-Line character I need */
|
||||||
|
static const char SOH = 1; /* Start of header */
|
||||||
|
static const char CR = 13; /* ASCII Carriage Return */
|
||||||
|
static const char SP = 32; /* ASCII space */
|
||||||
|
static const char DEL = 127; /* Delete (rubout) */
|
||||||
|
static const char ESCCHR = '^'; /* Default escape character for CONNECT */
|
||||||
|
static const char NUL = '\0'; /* Null character */
|
||||||
|
static const char FALSE = 0;
|
||||||
|
static const char TRUE = -1;
|
||||||
|
|
||||||
|
int size=0, /* Size of present data */
|
||||||
|
rpsiz=0, /* Maximum receive packet size */
|
||||||
|
spsiz=0, /* Maximum send packet size */
|
||||||
|
pad=0, /* How much padding to send */
|
||||||
|
timint=0, /* Timeout for foreign host on sends */
|
||||||
|
n=0, /* Packet number */
|
||||||
|
numtry=0, /* Times this packet retried */
|
||||||
|
oldtry=0, /* Times previous packet retried */
|
||||||
|
image=1, /* -1 means 8-bit mode */
|
||||||
|
debug=99, /* indicates level of debugging output (0=none) */
|
||||||
|
filecount=0, /* Number of files left to send */
|
||||||
|
filenum=0,
|
||||||
|
mflg=0, /* Flag for MacKermit mode */
|
||||||
|
xflg=0; /* flag for xmit directory structure */
|
||||||
|
char state, /* Present state of the automaton */
|
||||||
|
padchar, /* Padding character to send */
|
||||||
|
eol, /* End-Of-Line character to send */
|
||||||
|
escchr, /* Connect command escape character */
|
||||||
|
quote, /* Quote character in incoming data */
|
||||||
|
*filnam, /* Current file name */
|
||||||
|
*filnamo, /* File name sent */
|
||||||
|
*ttyline, /* Pointer to tty line */
|
||||||
|
recpkt[MAXPACKSIZ], /* Receive packet buffer */
|
||||||
|
packet[MAXPACKSIZ], /* Packet buffer */
|
||||||
|
ldata[1024]; /* First line of data to send over connection */
|
||||||
|
String **filelist = 0;
|
||||||
|
int (*recvChar)(ZSerial *ser, int);
|
||||||
|
void (*sendChar)(ZSerial *ser, char);
|
||||||
|
bool (*dataHandler)(File *kfp, unsigned long number, char *buffer, int len);
|
||||||
|
|
||||||
|
void flushinput();
|
||||||
|
void rpar(char data[]);
|
||||||
|
void spar(char data[]);
|
||||||
|
int gnxtfl();
|
||||||
|
void bufemp(char buffer[], int len);
|
||||||
|
void prerrpkt(char *msg);
|
||||||
|
int bufill(char buffer[]);
|
||||||
|
int rpack(int *len, int *num, char *data);
|
||||||
|
int spack(char type, int num, int len, char *data);
|
||||||
|
char rdata();
|
||||||
|
char rinit();
|
||||||
|
char rfile();
|
||||||
|
char sfile();
|
||||||
|
char sinit();
|
||||||
|
char sdata();
|
||||||
|
char sbreak();
|
||||||
|
char seof();
|
||||||
|
|
||||||
|
bool kfpClosed = true;
|
||||||
|
String *errStr = 0;
|
||||||
|
public:
|
||||||
|
String rootpath = "";
|
||||||
|
FS *kfileSystem = &SD;
|
||||||
|
File kfp;
|
||||||
|
ZSerial kserial;
|
||||||
|
|
||||||
|
KModem(FlowControlType commandFlow,
|
||||||
|
int (*recvChar)(ZSerial *ser, int),
|
||||||
|
void (*sendChar)(ZSerial *ser, char),
|
||||||
|
bool (*dataHandler)(File *kfp, unsigned long, char*, int),
|
||||||
|
String &errors);
|
||||||
|
void setTransmitList(String **fileList, int numFiles);
|
||||||
|
bool receive();
|
||||||
|
bool transmit();
|
||||||
|
};
|
||||||
|
|
||||||
|
static int kReceiveSerial(ZSerial *ser, int del)
|
||||||
|
{
|
||||||
|
unsigned long end=millis() + (del * 1000L);
|
||||||
|
while(millis() < end)
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
if(ser->available() > 0)
|
||||||
|
{
|
||||||
|
int c=ser->read();
|
||||||
|
logSerialIn(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kSendSerial(ZSerial *ser, char c)
|
||||||
|
{
|
||||||
|
ser->write((uint8_t)c);
|
||||||
|
ser->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool kUDataHandler(File *kfp, unsigned long number, char *buf, int sz)
|
||||||
|
{
|
||||||
|
for(int i=0;i<sz;i++)
|
||||||
|
kfp->write((uint8_t)buf[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool kDDataHandler(File *kfp, unsigned long number, char *buf, int sz)
|
||||||
|
{
|
||||||
|
for(int i=0;i<sz;i++)
|
||||||
|
{
|
||||||
|
int c=kfp->read();
|
||||||
|
if(c<0)
|
||||||
|
{
|
||||||
|
if(i==0)
|
||||||
|
return false;
|
||||||
|
buf[i] = (char)26;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buf[i] = (char)c;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean kDownload(FlowControlType commandFlow, FS &fs, String **fileList, int fileCount, String &errors)
|
||||||
|
{
|
||||||
|
KModem kmo(commandFlow, kReceiveSerial, kSendSerial, kDDataHandler, errors);
|
||||||
|
kmo.kfileSystem = &fs;
|
||||||
|
kmo.setTransmitList(fileList,fileCount);
|
||||||
|
bool result = kmo.transmit();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean kUpload(FlowControlType commandFlow, FS &fs, String rootPath, String &errors)
|
||||||
|
{
|
||||||
|
KModem kmo(commandFlow, kReceiveSerial, kSendSerial, kUDataHandler, errors);
|
||||||
|
kmo.kfileSystem = &fs;
|
||||||
|
kmo.rootpath = rootPath;
|
||||||
|
bool result = kmo.receive();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef ZIMODEM_PROTO_PING
|
||||||
|
#define ZIMODEM_PROTO_PING
|
||||||
|
#ifdef INCLUDE_PING
|
||||||
|
/*
|
||||||
|
Copyright 2023-2023 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
int ping(char *host);
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
class XModem
|
||||||
|
{
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
Crc,
|
||||||
|
ChkSum
|
||||||
|
} transfer_t;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//holds readed byte (due to dataAvail())
|
||||||
|
int byte;
|
||||||
|
//expected block number
|
||||||
|
unsigned char blockNo;
|
||||||
|
//extended block number, send to dataHandler()
|
||||||
|
unsigned long blockNoExt;
|
||||||
|
//retry counter for NACK
|
||||||
|
int retries;
|
||||||
|
//buffer
|
||||||
|
char buffer[128];
|
||||||
|
//repeated block flag
|
||||||
|
bool repeatedBlock;
|
||||||
|
File *xfile = null;
|
||||||
|
ZSerial xserial;
|
||||||
|
|
||||||
|
int (*recvChar)(ZSerial *ser, int);
|
||||||
|
void (*sendChar)(ZSerial *ser, char);
|
||||||
|
bool (*dataHandler)(File *xfile, unsigned long number, char *buffer, int len);
|
||||||
|
unsigned short crc16_ccitt(char *buf, int size);
|
||||||
|
bool dataAvail(int delay);
|
||||||
|
int dataRead(int delay);
|
||||||
|
void dataWrite(char symbol);
|
||||||
|
bool receiveFrameNo(void);
|
||||||
|
bool receiveData(void);
|
||||||
|
bool checkCrc(void);
|
||||||
|
bool checkChkSum(void);
|
||||||
|
bool receiveFrames(transfer_t transfer);
|
||||||
|
bool sendNack(void);
|
||||||
|
void init(void);
|
||||||
|
|
||||||
|
bool transmitFrames(transfer_t);
|
||||||
|
unsigned char generateChkSum(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const unsigned char XMO_NACK = 21;
|
||||||
|
static const unsigned char XMO_ACK = 6;
|
||||||
|
|
||||||
|
static const unsigned char XMO_SOH = 1;
|
||||||
|
static const unsigned char XMO_EOT = 4;
|
||||||
|
static const unsigned char XMO_CAN = 0x18;
|
||||||
|
|
||||||
|
static const int receiveDelay=7000;
|
||||||
|
static const int rcvRetryLimit = 10;
|
||||||
|
|
||||||
|
|
||||||
|
XModem(File &f,
|
||||||
|
FlowControlType commandFlow,
|
||||||
|
int (*recvChar)(ZSerial *ser, int),
|
||||||
|
void (*sendChar)(ZSerial *ser, char),
|
||||||
|
bool (*dataHandler)(File *xfile, unsigned long, char*, int));
|
||||||
|
bool receive();
|
||||||
|
bool transmit();
|
||||||
|
};
|
||||||
|
|
||||||
|
static int xReceiveSerial(ZSerial *ser, int del)
|
||||||
|
{
|
||||||
|
unsigned long end=micros() + (del * 1000L);
|
||||||
|
while(micros() < end)
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
if(ser->available() > 0)
|
||||||
|
{
|
||||||
|
int c=ser->read();
|
||||||
|
logSerialIn(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xSendSerial(ZSerial *ser, char c)
|
||||||
|
{
|
||||||
|
ser->write((uint8_t)c);
|
||||||
|
ser->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xUDataHandler(File *xfile, unsigned long number, char *buf, int sz)
|
||||||
|
{
|
||||||
|
for(int i=0;i<sz;i++)
|
||||||
|
xfile->write((uint8_t)buf[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xDDataHandler(File *xfile, unsigned long number, char *buf, int sz)
|
||||||
|
{
|
||||||
|
for(int i=0;i<sz;i++)
|
||||||
|
{
|
||||||
|
int c=xfile->read();
|
||||||
|
if(c<0)
|
||||||
|
{
|
||||||
|
if(i==0)
|
||||||
|
return false;
|
||||||
|
buf[i] = (char)26;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buf[i] = (char)c;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean xDownload(FlowControlType commandFlow, File &f, String &errors)
|
||||||
|
{
|
||||||
|
XModem xmo(f,commandFlow, xReceiveSerial, xSendSerial, xDDataHandler);
|
||||||
|
bool result = xmo.transmit();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean xUpload(FlowControlType commandFlow, File &f, String &errors)
|
||||||
|
{
|
||||||
|
XModem xmo(f,commandFlow, xReceiveSerial, xSendSerial, xUDataHandler);
|
||||||
|
bool result = xmo.receive();
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,504 @@
|
||||||
|
/*
|
||||||
|
* zmodem.h
|
||||||
|
* zmodem constants
|
||||||
|
* (C) Mattheij Computer Service 1994
|
||||||
|
*
|
||||||
|
* Date: Thu, 19 Nov 2015 10:10:02 +0100
|
||||||
|
* From: Jacques Mattheij
|
||||||
|
* Subject: Re: zmodem license
|
||||||
|
* To: Stephen Hurd, Fernando Toledo
|
||||||
|
* CC: Rob Swindell
|
||||||
|
*
|
||||||
|
* Hello there to all of you,
|
||||||
|
*
|
||||||
|
* So, this email will then signify as the transfer of any and all rights I
|
||||||
|
* held up to this point with relation to the copyright of the zmodem
|
||||||
|
* package as released by me many years ago and all associated files to
|
||||||
|
* Stephen Hurd. Fernando Toledo and Rob Swindell are named as
|
||||||
|
* witnesses to this transfer.
|
||||||
|
*
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* best regards,
|
||||||
|
*
|
||||||
|
* Jacques Mattheij
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* $Id: zmodem.h,v 1.55 2018/02/01 08:20:19 deuce Exp $ */
|
||||||
|
|
||||||
|
#ifndef _ZMODEM_H
|
||||||
|
#define _ZMODEM_H
|
||||||
|
|
||||||
|
#define ZMODEM_FILE_SIZE_MAX 0xffffffff /* 32-bits, blame Chuck */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ascii constants
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BOOL bool
|
||||||
|
#define BYTE uint8_t
|
||||||
|
#define uchar uint8_t
|
||||||
|
#define MAX_PATH 253
|
||||||
|
#define NOINP -1 /* input buffer empty (incom only) */
|
||||||
|
#define LOG_EMERG 0 /* system is unusable */
|
||||||
|
#define LOG_ALERT 1 /* action must be taken immediately */
|
||||||
|
#define LOG_CRIT 2 /* critical conditions */
|
||||||
|
#define LOG_ERR 3 /* error conditions */
|
||||||
|
#define LOG_WARNING 4 /* warning conditions */
|
||||||
|
#define LOG_NOTICE 5 /* normal but significant condition */
|
||||||
|
#define LOG_INFO 6 /* informational */
|
||||||
|
#define LOG_DEBUG 7 /* debug-level messages */
|
||||||
|
|
||||||
|
#define ZMO_DLE 0x10
|
||||||
|
#define ZMO_XON 0x11
|
||||||
|
#define ZMO_XOFF 0x13
|
||||||
|
#define ZMO_CAN 0x18
|
||||||
|
|
||||||
|
#ifndef INT_TO_BOOL
|
||||||
|
#define INT_TO_BOOL(x) ((x)?ZTRUE:ZFALSE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ZFALSE 0
|
||||||
|
#define ZTRUE 1
|
||||||
|
|
||||||
|
#define TERMINATE(str) str[sizeof(str)-1]=0
|
||||||
|
|
||||||
|
/* This is a bound-safe version of strcpy basically - only works with fixed-length arrays */
|
||||||
|
#ifdef SAFECOPY_USES_SPRINTF
|
||||||
|
#define SAFECOPY(dst,src) sprintf(dst,"%.*s",(int)sizeof(dst)-1,src)
|
||||||
|
#else /* strncpy is faster */
|
||||||
|
#define SAFECOPY(dst,src) (strncpy(dst,src,sizeof(dst)), TERMINATE(dst))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* zmodem constants
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZBLOCKLEN 1024 /* "true" Zmodem max subpacket length */
|
||||||
|
|
||||||
|
#define ZMAXHLEN 0x10 /* maximum header information length */
|
||||||
|
#define ZMAXSPLEN 0x400 /* maximum subpacket length */
|
||||||
|
|
||||||
|
|
||||||
|
#define ZPAD 0x2a /* pad character; begins frames */
|
||||||
|
#define ZDLE 0x18 /* ctrl-x zmodem escape */
|
||||||
|
#define ZDLEE 0x58 /* escaped ZDLE */
|
||||||
|
|
||||||
|
#define ZBIN 0x41 /* binary frame indicator (CRC16) */
|
||||||
|
#define ZHEX 0x42 /* hex frame indicator */
|
||||||
|
#define ZBIN32 0x43 /* binary frame indicator (CRC32) */
|
||||||
|
#define ZBINR32 0x44 /* run length encoded binary frame (CRC32) */
|
||||||
|
|
||||||
|
#define ZVBIN 0x61 /* binary frame indicator (CRC16) */
|
||||||
|
#define ZVHEX 0x62 /* hex frame indicator */
|
||||||
|
#define ZVBIN32 0x63 /* binary frame indicator (CRC32) */
|
||||||
|
#define ZVBINR32 0x64 /* run length encoded binary frame (CRC32) */
|
||||||
|
|
||||||
|
#define ZRESC 0x7e /* run length encoding flag / escape character */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* zmodem frame types
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZRQINIT 0x00 /* request receive init (s->r) */
|
||||||
|
#define ZRINIT 0x01 /* receive init (r->s) */
|
||||||
|
#define ZSINIT 0x02 /* send init sequence (optional) (s->r) */
|
||||||
|
#define ZACK 0x03 /* ack to ZRQINIT ZRINIT or ZSINIT (s<->r) */
|
||||||
|
#define ZFILE 0x04 /* file name (s->r) */
|
||||||
|
#define ZSKIP 0x05 /* skip this file (r->s) */
|
||||||
|
#define ZNAK 0x06 /* last packet was corrupted (?) */
|
||||||
|
#define ZABORT 0x07 /* abort batch transfers (?) */
|
||||||
|
#define ZFIN 0x08 /* finish session (s<->r) */
|
||||||
|
#define ZRPOS 0x09 /* resume data transmission here (r->s) */
|
||||||
|
#define ZDATA 0x0a /* data packet(s) follow (s->r) */
|
||||||
|
#define ZEOF 0x0b /* end of file reached (s->r) */
|
||||||
|
#define ZFERR 0x0c /* fatal read or write error detected (?) */
|
||||||
|
#define ZCRC 0x0d /* request for file CRC and response (?) */
|
||||||
|
#define ZCHALLENGE 0x0e /* security challenge (r->s) */
|
||||||
|
#define ZCOMPL 0x0f /* request is complete (?) */
|
||||||
|
#define ZCAN 0x10 /* pseudo frame;
|
||||||
|
other end cancelled session with 5* CAN */
|
||||||
|
#define ZFREECNT 0x11 /* request free bytes on file system (s->r) */
|
||||||
|
#define ZCOMMAND 0x12 /* issue command (s->r) */
|
||||||
|
#define ZSTDERR 0x13 /* output data to stderr (??) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZDLE sequences
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZCRCE 0x68 /* CRC next, frame ends, header packet follows */
|
||||||
|
#define ZCRCG 0x69 /* CRC next, frame continues nonstop */
|
||||||
|
#define ZCRCQ 0x6a /* CRC next, frame continuous, ZACK expected */
|
||||||
|
#define ZCRCW 0x6b /* CRC next, frame ends, ZACK expected */
|
||||||
|
#define ZRUB0 0x6c /* translate to rubout 0x7f */
|
||||||
|
#define ZRUB1 0x6d /* translate to rubout 0xff */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* frame specific data.
|
||||||
|
* entries are prefixed with their location in the header array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Byte positions within header array
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FTYPE 0 /* frame type */
|
||||||
|
|
||||||
|
#define ZF0 4 /* First flags byte */
|
||||||
|
#define ZF1 3
|
||||||
|
#define ZF2 2
|
||||||
|
#define ZF3 1
|
||||||
|
|
||||||
|
#define ZP0 1 /* Low order 8 bits of position */
|
||||||
|
#define ZP1 2
|
||||||
|
#define ZP2 3
|
||||||
|
#define ZP3 4 /* High order 8 bits of file position */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZRINIT frame
|
||||||
|
* zmodem receiver capability flags
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZF0_CANFDX 0x01 /* Receiver can send and receive true full duplex */
|
||||||
|
#define ZF0_CANOVIO 0x02 /* receiver can receive data during disk I/O */
|
||||||
|
#define ZF0_CANBRK 0x04 /* receiver can send a break signal */
|
||||||
|
#define ZF0_CANCRY 0x08 /* Receiver can decrypt DONT USE */
|
||||||
|
#define ZF0_CANLZW 0x10 /* Receiver can uncompress DONT USE */
|
||||||
|
#define ZF0_CANFC32 0x20 /* Receiver can use 32 bit Frame Check */
|
||||||
|
#define ZF0_ESCCTL 0x40 /* Receiver expects ctl chars to be escaped */
|
||||||
|
#define ZF0_ESC8 0x80 /* Receiver expects 8th bit to be escaped */
|
||||||
|
|
||||||
|
#define ZF1_CANVHDR 0x01 /* Variable headers OK */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZSINIT frame
|
||||||
|
* zmodem sender capability
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZF0_TESCCTL 0x40 /* Transmitter expects ctl chars to be escaped */
|
||||||
|
#define ZF0_TESC8 0x80 /* Transmitter expects 8th bit to be escaped */
|
||||||
|
|
||||||
|
#define ZATTNLEN 0x20 /* Max length of attention string */
|
||||||
|
#define ALTCOFF ZF1 /* Offset to alternate canit string, 0 if not used */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZFILE frame
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conversion options one of these in ZF0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZF0_ZCBIN 1 /* Binary transfer - inhibit conversion */
|
||||||
|
#define ZF0_ZCNL 2 /* Convert NL to local end of line convention */
|
||||||
|
#define ZF0_ZCRESUM 3 /* Resume interrupted file transfer */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Management include options, one of these ored in ZF1
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZF1_ZMSKNOLOC 0x80 /* Skip file if not present at rx */
|
||||||
|
#define ZF1_ZMMASK 0x1f /* Mask for the choices below */
|
||||||
|
#define ZF1_ZMNEWL 1 /* Transfer if source newer or longer */
|
||||||
|
#define ZF1_ZMCRC 2 /* Transfer if different file CRC or length */
|
||||||
|
#define ZF1_ZMAPND 3 /* Append contents to existing file (if any) */
|
||||||
|
#define ZF1_ZMCLOB 4 /* Replace existing file */
|
||||||
|
#define ZF1_ZMNEW 5 /* Transfer if source newer */
|
||||||
|
#define ZF1_ZMDIFF 6 /* Transfer if dates or lengths different */
|
||||||
|
#define ZF1_ZMPROT 7 /* Protect destination file */
|
||||||
|
#define ZF1_ZMCHNG 8 /* Change filename if destination exists */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transport options, one of these in ZF2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZF2_ZTNOR 0 /* no compression */
|
||||||
|
#define ZF2_ZTLZW 1 /* Lempel-Ziv compression */
|
||||||
|
#define ZF2_ZTRLE 3 /* Run Length encoding */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended options for ZF3, bit encoded
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZF3_ZCANVHDR 0x01 /* Variable headers OK */
|
||||||
|
/* Receiver window size override */
|
||||||
|
#define ZF3_ZRWOVR 0x04 /* byte position for receive window override/256 */
|
||||||
|
#define ZF3_ZXSPARS 0x40 /* encoding for sparse file operations */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZCOMMAND frame
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZF0_ZCACK1 0x01 /* Acknowledge, then do command */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
BYTE rxd_header[ZMAXHLEN]; /* last received header */
|
||||||
|
int rxd_header_len; /* last received header size */
|
||||||
|
uint32_t rxd_header_pos; /* last received header position value */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* receiver capability flags
|
||||||
|
* extracted from the ZRINIT frame as received
|
||||||
|
*/
|
||||||
|
|
||||||
|
BOOL can_full_duplex;
|
||||||
|
BOOL can_overlap_io;
|
||||||
|
BOOL can_break;
|
||||||
|
BOOL can_fcs_32;
|
||||||
|
BOOL want_fcs_16;
|
||||||
|
BOOL escape_ctrl_chars;
|
||||||
|
BOOL escape_8th_bit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* file management options.
|
||||||
|
* only one should be on
|
||||||
|
*/
|
||||||
|
|
||||||
|
int management_newer;
|
||||||
|
int management_clobber;
|
||||||
|
int management_protect;
|
||||||
|
|
||||||
|
/* from zmtx.c */
|
||||||
|
|
||||||
|
BYTE tx_data_subpacket[8192];
|
||||||
|
BYTE rx_data_subpacket[8192]; /* zzap = 8192 */
|
||||||
|
|
||||||
|
char current_file_name[MAX_PATH+1];
|
||||||
|
int64_t current_file_size;
|
||||||
|
int64_t current_file_pos;
|
||||||
|
time_t current_file_time;
|
||||||
|
unsigned current_file_num;
|
||||||
|
unsigned total_files;
|
||||||
|
int64_t total_bytes;
|
||||||
|
unsigned files_remaining;
|
||||||
|
int64_t bytes_remaining;
|
||||||
|
int64_t transfer_start_pos;
|
||||||
|
time_t transfer_start_time;
|
||||||
|
|
||||||
|
int receive_32bit_data;
|
||||||
|
int use_crc16;
|
||||||
|
int32_t ack_file_pos; /* file position used in acknowledgement of correctly */
|
||||||
|
/* received data subpackets */
|
||||||
|
|
||||||
|
int last_sent;
|
||||||
|
|
||||||
|
int n_cans;
|
||||||
|
|
||||||
|
/* Stuff added by RRS */
|
||||||
|
|
||||||
|
/* Status */
|
||||||
|
BOOL cancelled;
|
||||||
|
BOOL local_abort;
|
||||||
|
BOOL file_skipped;
|
||||||
|
BOOL no_streaming;
|
||||||
|
BOOL frame_in_transit;
|
||||||
|
unsigned recv_bufsize; /* Receiver specified buffer size */
|
||||||
|
int32_t crc_request;
|
||||||
|
unsigned errors;
|
||||||
|
unsigned consecutive_errors;
|
||||||
|
|
||||||
|
/* Configuration */
|
||||||
|
BOOL escape_telnet_iac;
|
||||||
|
unsigned init_timeout;
|
||||||
|
unsigned send_timeout;
|
||||||
|
unsigned recv_timeout;
|
||||||
|
unsigned crc_timeout;
|
||||||
|
unsigned max_errors;
|
||||||
|
unsigned block_size;
|
||||||
|
unsigned max_block_size;
|
||||||
|
int64_t max_file_size; /* 0 = unlimited */
|
||||||
|
int *log_level;
|
||||||
|
/* error C2520: conversion from unsigned __int64 to double not implemented, use signed __int64 */
|
||||||
|
void* cbdata;
|
||||||
|
} zmodem_t;
|
||||||
|
|
||||||
|
class ZModem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ZModem(FS *zfs, void* cbdata);
|
||||||
|
~ZModem();
|
||||||
|
BOOL send_file( char* name, File* fp, BOOL request_init, time_t* start, uint64_t* bytes_sent);
|
||||||
|
int get_zfin();
|
||||||
|
int recv_init();
|
||||||
|
int lputs(void* unused, int level, const char* str);
|
||||||
|
int lprintf(int level, const char *fmt, ...);
|
||||||
|
int send_zabort();
|
||||||
|
int send_zfin();
|
||||||
|
int recv_files(const char* download_dir, uint64_t* bytes_received);
|
||||||
|
unsigned recv_file_data( File*, int64_t offset);
|
||||||
|
zmodem_t *zm=0;
|
||||||
|
ZSerial zserial;
|
||||||
|
FS *zfileSystem=0;
|
||||||
|
private:
|
||||||
|
char* ver(char *buf);
|
||||||
|
const char* source(void);
|
||||||
|
int rx();
|
||||||
|
int tx(BYTE ch);
|
||||||
|
int send_ack( int32_t pos);
|
||||||
|
int send_nak();
|
||||||
|
int send_zskip();
|
||||||
|
int send_zrinit();
|
||||||
|
int send_pos_header(int type, int32_t pos, BOOL hex);
|
||||||
|
int get_zrinit();
|
||||||
|
BOOL get_crc( int32_t length, uint32_t* crc);
|
||||||
|
void parse_zrinit();
|
||||||
|
void parse_zfile_subpacket();
|
||||||
|
int recv_file_frame(File* fp);
|
||||||
|
int recv_header_and_check();
|
||||||
|
int send_hex(uchar val);
|
||||||
|
int send_padded_zdle();
|
||||||
|
int send_hex_header(unsigned char * p);
|
||||||
|
int send_bin32_header(unsigned char * p);
|
||||||
|
int send_bin16_header(unsigned char * p);
|
||||||
|
int send_bin_header(unsigned char * p);
|
||||||
|
int send_data32(uchar subpkt_type, unsigned char * p, size_t l);
|
||||||
|
int send_data16(uchar subpkt_type,unsigned char * p, size_t l);
|
||||||
|
int send_data(uchar subpkt_type, unsigned char * p, size_t l);
|
||||||
|
int send_data_subpkt(uchar subpkt_type, unsigned char * p, size_t l);
|
||||||
|
int data_waiting(unsigned timeout);
|
||||||
|
void recv_purge();
|
||||||
|
void flush();
|
||||||
|
int send_raw(unsigned char ch);
|
||||||
|
int send_esc(unsigned char c);
|
||||||
|
int recv_data32(unsigned char * p, unsigned maxlen, unsigned* l);
|
||||||
|
int recv_data16(register unsigned char* p, unsigned maxlen, unsigned* l);
|
||||||
|
int recv_data(unsigned char* p, size_t maxlen, unsigned* l, BOOL ack);
|
||||||
|
BOOL recv_subpacket(BOOL ack);
|
||||||
|
int recv_nibble();
|
||||||
|
int recv_hex();
|
||||||
|
int recv_raw();
|
||||||
|
BOOL recv_bin16_header();
|
||||||
|
BOOL recv_hex_header();
|
||||||
|
BOOL recv_bin32_header();
|
||||||
|
int recv_header_raw(int errors);
|
||||||
|
int recv_header();
|
||||||
|
BOOL request_crc(int32_t length);
|
||||||
|
BOOL recv_crc(uint32_t* crc);
|
||||||
|
BOOL handle_zrpos(uint64_t* pos);
|
||||||
|
BOOL handle_zack();
|
||||||
|
BOOL is_connected();
|
||||||
|
BOOL is_cancelled();
|
||||||
|
int send_from(File* fp, uint64_t pos, uint64_t* sent);
|
||||||
|
int send_znak();
|
||||||
|
int send_zeof(uint32_t pos);
|
||||||
|
void progress(void* cbdata, int64_t current_pos);
|
||||||
|
int send_byte(void* unused, uchar ch, unsigned timeout);
|
||||||
|
int recv_byte(void* unused, unsigned timeout); /* seconds */
|
||||||
|
ulong frame_pos(int type);
|
||||||
|
char* getfname(const char* path);
|
||||||
|
};
|
||||||
|
|
||||||
|
static ZModem *initZSerial(FS &fs, FlowControlType commandFlow)
|
||||||
|
{
|
||||||
|
ZModem *modem = new ZModem(&SD, NULL);
|
||||||
|
modem->zserial.setFlowControlType(FCT_DISABLED);
|
||||||
|
if(commandFlow==FCT_RTSCTS)
|
||||||
|
modem->zserial.setFlowControlType(FCT_RTSCTS);
|
||||||
|
else
|
||||||
|
modem->zserial.setFlowControlType(FCT_NORMAL);
|
||||||
|
modem->zserial.setPetsciiMode(false);
|
||||||
|
modem->zserial.setXON(true);
|
||||||
|
return modem;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean zDownload(FlowControlType flow, FS &fs, String filePath, String &errors)
|
||||||
|
{
|
||||||
|
time_t starttime = 0;
|
||||||
|
uint64_t bytes_sent=0;
|
||||||
|
BOOL success=ZFALSE;
|
||||||
|
char filePathC[MAX_PATH];
|
||||||
|
File F;
|
||||||
|
|
||||||
|
ZModem *modem = initZSerial(fs, flow);
|
||||||
|
|
||||||
|
//static int send_files(char** fname, uint fnames)
|
||||||
|
F=modem->zfileSystem->open(filePath);
|
||||||
|
modem->zm->files_remaining = 1;
|
||||||
|
modem->zm->bytes_remaining = F.size();
|
||||||
|
strcpy(filePathC,filePath.c_str());
|
||||||
|
success=modem->send_file(filePathC, &F, ZTRUE, &starttime, &bytes_sent);
|
||||||
|
if(success)
|
||||||
|
modem->get_zfin();
|
||||||
|
F.close();
|
||||||
|
|
||||||
|
modem->zserial.flushAlways();
|
||||||
|
delete modem;
|
||||||
|
return (success==ZTRUE) && (modem->zm->cancelled==ZFALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean zUpload(FlowControlType flow, FS &fs, String dirPath, String &errors)
|
||||||
|
{
|
||||||
|
BOOL success=ZFALSE;
|
||||||
|
int i;
|
||||||
|
char str[MAX_PATH];
|
||||||
|
File fp;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
ZModem *modem = initZSerial(fs,flow);
|
||||||
|
|
||||||
|
//static int receive_files(char** fname_list, int fnames)
|
||||||
|
//TODO: loop might be necc around here, for multiple files?
|
||||||
|
i=modem->recv_init();
|
||||||
|
if(modem->zm->cancelled || (i<0))
|
||||||
|
{
|
||||||
|
delete modem;
|
||||||
|
return ZFALSE;
|
||||||
|
}
|
||||||
|
switch(i) {
|
||||||
|
case ZFILE:
|
||||||
|
//SAFECOPY(fname,zm.current_file_name);
|
||||||
|
//file_bytes = zm.current_file_size;
|
||||||
|
//ftime = zm.current_file_time;
|
||||||
|
//total_files = zm.files_remaining;
|
||||||
|
//total_bytes = zm.bytes_remaining;
|
||||||
|
break;
|
||||||
|
case ZFIN:
|
||||||
|
case ZCOMPL:
|
||||||
|
delete modem;
|
||||||
|
return ZTRUE; // was (!success)
|
||||||
|
default:
|
||||||
|
delete modem;
|
||||||
|
return ZFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(str,dirPath.c_str());
|
||||||
|
if(str[strlen(str)-1]!='/')
|
||||||
|
{
|
||||||
|
str[strlen(str)]='/';
|
||||||
|
str[strlen(str)+1]=0;
|
||||||
|
}
|
||||||
|
strcpy(str+strlen(str),modem->zm->current_file_name);
|
||||||
|
|
||||||
|
fp = modem->zfileSystem->open(str,FILE_WRITE);
|
||||||
|
if(!fp)
|
||||||
|
{
|
||||||
|
modem->lprintf(LOG_ERR,"Error %d creating %s",errno,str);
|
||||||
|
modem->send_zabort();
|
||||||
|
//zmodem_send_zskip(); //TODO: for when we move to multiple files
|
||||||
|
//continue;
|
||||||
|
delete modem;
|
||||||
|
return ZFALSE;
|
||||||
|
}
|
||||||
|
err=modem->recv_file_data(&fp,0);
|
||||||
|
|
||||||
|
if(err<=modem->zm->max_errors && !modem->zm->cancelled)
|
||||||
|
success=ZTRUE;
|
||||||
|
|
||||||
|
if(success)
|
||||||
|
modem->send_zfin();
|
||||||
|
|
||||||
|
fp.close();
|
||||||
|
if(modem->zm->local_abort)
|
||||||
|
{
|
||||||
|
modem->lprintf(LOG_ERR,"Locally aborted, sending cancel to remote");
|
||||||
|
modem->send_zabort();
|
||||||
|
delete modem;
|
||||||
|
return ZFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
modem->zserial.flushAlways();
|
||||||
|
delete modem;
|
||||||
|
return (success == ZTRUE);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
static const char *TimeZones[243][2] PROGMEM = { {"UTC","0"},
|
||||||
|
{"A","1"},{"CDT","10:30"},{"ACST","9:30"},{"ACT","-5"},
|
||||||
|
{"ACT","9:30/10:30"},{"ACWST","8:45"},{"ADT","3"},{"ADT","-3"},
|
||||||
|
{"AEDT","11"},{"AEST","10"},{"AET","11"},{"AFT","4:30"},
|
||||||
|
{"AKDT","-8"},{"AKST","-9"},{"ALMT","6"},{"AMST","-3"},{"AMST","5"},
|
||||||
|
{"AMT","-4"},{"AMT","4"},{"ANAST","12"},{"ANAT","12"},{"AQTT","5"},
|
||||||
|
{"ART","-3"},{"AST","2"},{"AST","-4"},{"AT","-4/-3"},{"AWDT","9"},
|
||||||
|
{"AWST","8"},{"AZOST","0"},{"AZOT","-1"},{"AZST","5"},{"AZT","4"},
|
||||||
|
{"AOE","-12"},{"B","2"},{"BNT","8"},{"BOT","-4"},{"BRST","-2"},
|
||||||
|
{"BRT","-3"},{"BST","6"},{"BST","11"},{"BST","1"},{"BTT","6"},
|
||||||
|
{"C","3"},{"CAST","8"},{"CAT","2"},{"CCT","6:30"},{"CDT","-5"},
|
||||||
|
{"CDT","-4"},{"CEST","2"},{"CET","1"},{"CHADT","13:45"},
|
||||||
|
{"CHAST","12:45"},{"CHOST","9"},{"CHOT","8"},{"CHUT","10"},
|
||||||
|
{"CIDST","-4"},{"CIST","-5"},{"CKT","-10"},{"CLST","-3"},
|
||||||
|
{"CLT","-4"},{"COT","-5"},{"CST","-6"},{"CST","8"},{"CST","-5"},
|
||||||
|
{"CT","-6/-5"},{"CVT","-1"},{"CXT","7"},{"ChST","10"},{"D","4"},
|
||||||
|
{"DAVT","7"},{"DDUT","10"},{"E","5"},{"EASST","-5"},{"EAST","-6"},
|
||||||
|
{"EAT","3"},{"ECT","-5"},{"EDT","-4"},{"EEST","3"},{"EET","2"},
|
||||||
|
{"EGST","0"},{"EGT","-1"},{"EST","-5"},{"ET","-5/-4"},{"F","6"},
|
||||||
|
{"FET","3"},{"FJST","13"},{"FJT","12"},{"FKST","-3"},{"FKT","-4"},
|
||||||
|
{"FNT","-2"},{"G","7"},{"GALT","-6"},{"GAMT","-9"},{"GET","4"},
|
||||||
|
{"GFT","-3"},{"GILT","12"},{"GMT","0"},{"GST","4"},{"GST","-2"},
|
||||||
|
{"GYT","-4"},{"H","8"},{"HADT","-9"},{"HAST","-10"},{"HKT","8"},
|
||||||
|
{"HOVST","8"},{"HOVT","7"},{"I","9"},{"ICT","7"},{"IDT","3"},
|
||||||
|
{"IOT","6"},{"IRDT","4:30"},{"IRKST","9"},{"IRKT","8"},
|
||||||
|
{"IRST","3:30"},{"IST","5:30"},{"IST","1"},{"IST","2"},{"JST","9"},
|
||||||
|
{"K","10"},{"KGT","6"},{"KOST","11"},{"KRAST","8"},{"KRAT","7"},
|
||||||
|
{"KST","9"},{"KUYT","4"},{"L","11"},{"LHDT","11"},{"LHST","10:30"},
|
||||||
|
{"LINT","14"},{"M","12"},{"MAGST","12"},{"MAGT","11"},{"MART","-9:30"},
|
||||||
|
{"MAWT","5"},{"MDT","-6"},{"MHT","12"},{"MMT","6:30"},{"MSD","4"},
|
||||||
|
{"MSK","3"},{"MST","-7"},{"MT","-7/-6"},{"MUT","4"},{"MVT","5"},
|
||||||
|
{"MYT","8"},{"N","-1"},{"NCT","11"},{"NDT","-2:30"},{"NFT","11"},
|
||||||
|
{"NOVST","7"},{"NOVT","6"},{"NPT","5:45"},{"NRT","12"},{"NST","-3:30"},
|
||||||
|
{"NUT","-11"},{"NZDT","13"},{"NZST","12"},{"O","-2"},{"OMSST","7"},
|
||||||
|
{"OMST","6"},{"ORAT","5"},{"P","-3"},{"PDT","-7"},{"PET","-5"},
|
||||||
|
{"PETST","12"},{"PETT","12"},{"PGT","10"},{"PHOT","13"},{"PHT","8"},
|
||||||
|
{"PKT","5"},{"PMDT","-2"},{"PMST","-3"},{"PONT","11"},{"PST","-8"},
|
||||||
|
{"PST","-8"},{"PT","-8/-7"},{"PWT","9"},{"PYST","-3"},{"PYT","-4"},
|
||||||
|
{"PYT","8:30"},{"Q","-4"},{"QYZT","6"},{"R","-5"},{"RET","4"},
|
||||||
|
{"ROTT","-3"},{"S","-6"},{"SAKT","11"},{"SAMT","4"},{"SAST","2"},
|
||||||
|
{"SBT","11"},{"SCT","4"},{"SGT","8"},{"SRET","11"},{"SRT","-3"},
|
||||||
|
{"SST","-11"},{"SYOT","3"},{"T","-7"},{"TAHT","-10"},{"TFT","5"},
|
||||||
|
{"TJT","5"},{"TKT","13"},{"TLT","9"},{"TMT","5"},{"TOST","14"},
|
||||||
|
{"TOT","13"},{"TRT","3"},{"TVT","12"},{"U","-8"},{"ULAST","9"},
|
||||||
|
{"ULAT","8"},{"UYST","-2"},{"UYT","-3"},{"UZT","5"},
|
||||||
|
{"V","-9"},{"VET","-4"},{"VLAST","11"},{"VLAT","10"},{"VOST","6"},
|
||||||
|
{"VUT","11"},{"W","-10"},{"WAKT","12"},{"WARST","-3"},{"WAST","2"},
|
||||||
|
{"WAT","1"},{"WEST","1"},{"WET","0"},{"WFT","12"},{"WGST","-2"},
|
||||||
|
{"WGT","-3"},{"WIB","7"},{"WIT","9"},{"WITA","8"},{"WST","14"},
|
||||||
|
{"WST","1"},{"WT","0"},{"X","-11"},{"Y","-12"},{"YAKST","10"},
|
||||||
|
{"YAKT","9"},{"YAPT","10"},{"YEKST","6"},{"YEKT","5"},{"Z","0"}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DateTimeClock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DateTimeClock(uint32_t epochSecs);
|
||||||
|
DateTimeClock();
|
||||||
|
DateTimeClock(int year, int month, int day, int hour, int min, int sec, int millis);
|
||||||
|
protected:
|
||||||
|
uint16_t year=0;
|
||||||
|
uint8_t month=0;
|
||||||
|
uint8_t day=0;
|
||||||
|
uint8_t hour=0;
|
||||||
|
uint8_t min=0;
|
||||||
|
uint8_t sec=0;
|
||||||
|
uint16_t milsec=0;
|
||||||
|
char str[55];
|
||||||
|
|
||||||
|
bool isLeapYear();
|
||||||
|
uint8_t getDaysInThisMonth();
|
||||||
|
public:
|
||||||
|
int getYear();
|
||||||
|
void setYear(int y);
|
||||||
|
void addYear(uint32_t y);
|
||||||
|
int getMonth();
|
||||||
|
void setMonth(int m);
|
||||||
|
void addMonth(uint32_t m);
|
||||||
|
int getDay();
|
||||||
|
void setDay(int d);
|
||||||
|
void addDay(uint32_t d);
|
||||||
|
int getHour();
|
||||||
|
void setHour(int h);
|
||||||
|
void addHour(uint32_t h);
|
||||||
|
int getMinute();
|
||||||
|
void setMinute(int mm);
|
||||||
|
void addMinute(uint32_t mm);
|
||||||
|
int getSecond();
|
||||||
|
void setSecond(int s);
|
||||||
|
void addSecond(uint32_t s);
|
||||||
|
int getMillis();;
|
||||||
|
void setMillis(int s);
|
||||||
|
void addMillis(uint64_t s);
|
||||||
|
|
||||||
|
void setByUnixEpoch(uint32_t unisex);
|
||||||
|
uint32_t getUnixEpoch();
|
||||||
|
|
||||||
|
int getDoWNumber();
|
||||||
|
const char *getDoW();
|
||||||
|
|
||||||
|
bool isInStandardTime();
|
||||||
|
bool isInDaylightSavingsTime();
|
||||||
|
|
||||||
|
void setTime(DateTimeClock &clock);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RealTimeClock : DateTimeClock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RealTimeClock(uint32_t epochSecs);
|
||||||
|
RealTimeClock();
|
||||||
|
RealTimeClock(int year, int month, int day, int hour, int min, int sec, int millis);
|
||||||
|
|
||||||
|
void tick();
|
||||||
|
|
||||||
|
bool isTimeSet();
|
||||||
|
|
||||||
|
bool reset();
|
||||||
|
|
||||||
|
int getTimeZoneCode();
|
||||||
|
void setTimeZoneCode(int val);
|
||||||
|
bool setTimeZone(String str);
|
||||||
|
|
||||||
|
String getFormat();
|
||||||
|
void setFormat(String fmt);
|
||||||
|
|
||||||
|
String getNtpServerHost();
|
||||||
|
void setNtpServerHost(String newHost);
|
||||||
|
|
||||||
|
bool isDisabled();
|
||||||
|
void setDisabled(bool tf);
|
||||||
|
|
||||||
|
void forceUpdate();
|
||||||
|
|
||||||
|
DateTimeClock &getCurrentTime();
|
||||||
|
String getCurrentTimeFormatted();
|
||||||
|
|
||||||
|
// should be private
|
||||||
|
private:
|
||||||
|
bool disabled = false;
|
||||||
|
DateTimeClock adjClock;
|
||||||
|
WiFiUDP udp;
|
||||||
|
bool udpStarted = false;
|
||||||
|
uint32_t lastMillis = 0;
|
||||||
|
uint32_t nextNTPMillis = 0;
|
||||||
|
int32_t ntpPeriodMillis = 60 * 1000; // every minute
|
||||||
|
int32_t ntpPeriodLongMillis = 5 * 60 * 60 * 1000; // every 5 hours
|
||||||
|
uint8_t tzCode = 0;
|
||||||
|
String format="%M/%d/%yyyy %h:%mm:%ss%aa %z";
|
||||||
|
String ntpServerName = "time.nist.gov";
|
||||||
|
|
||||||
|
void startUdp();
|
||||||
|
bool sendTimeRequest();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifndef ZHEADER_SEROUT_H
|
||||||
|
#define ZHEADER_SEROUT_H
|
||||||
|
|
||||||
|
#define DBG_BYT_CTR 20
|
||||||
|
|
||||||
|
#define SER_WRITE_BUFSIZE 4096
|
||||||
|
|
||||||
|
enum FlowControlType
|
||||||
|
{
|
||||||
|
FCT_RTSCTS=0,
|
||||||
|
FCT_NORMAL=1,
|
||||||
|
FCT_AUTOOFF=2,
|
||||||
|
FCT_MANUAL=3,
|
||||||
|
FCT_DISABLED=4,
|
||||||
|
FCT_INVALID=5
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool enableRtsCts = true;
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
# define SER_BUFSIZE 0x7F
|
||||||
|
#else
|
||||||
|
# define SER_BUFSIZE 128
|
||||||
|
#endif
|
||||||
|
static uint8_t TBUF[SER_WRITE_BUFSIZE];
|
||||||
|
static char FBUF[256];
|
||||||
|
static int TBUFhead=0;
|
||||||
|
static int TBUFtail=0;
|
||||||
|
static int serialDelayMs = 0;
|
||||||
|
|
||||||
|
static void serialDirectWrite(uint8_t c);
|
||||||
|
static void serialOutDeque();
|
||||||
|
static int serialOutBufferBytesRemaining();
|
||||||
|
static void clearSerialOutBuffer();
|
||||||
|
|
||||||
|
class ZSerial : public Stream
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool petsciiMode = false;
|
||||||
|
FlowControlType flowControlType=DEFAULT_FCT;
|
||||||
|
bool XON_STATE=true;
|
||||||
|
void enqueByte(uint8_t c);
|
||||||
|
public:
|
||||||
|
ZSerial();
|
||||||
|
void setPetsciiMode(bool petscii);
|
||||||
|
bool isPetsciiMode();
|
||||||
|
void setFlowControlType(FlowControlType type);
|
||||||
|
FlowControlType getFlowControlType();
|
||||||
|
void setXON(bool isXON);
|
||||||
|
bool isXON();
|
||||||
|
bool isSerialOut();
|
||||||
|
bool isSerialHalted();
|
||||||
|
bool isSerialCancelled();
|
||||||
|
bool isPacketOut();
|
||||||
|
int getConfigFlagBitmap();
|
||||||
|
|
||||||
|
void prints(String str);
|
||||||
|
void prints(const char *expr);
|
||||||
|
void printc(const char c);
|
||||||
|
void printc(uint8_t c);
|
||||||
|
virtual size_t write(uint8_t c);
|
||||||
|
size_t write(uint8_t *buf, int bufSz);
|
||||||
|
void printb(uint8_t c);
|
||||||
|
void printd(double f);
|
||||||
|
void printi(int i);
|
||||||
|
void printf(const char* format, ...);
|
||||||
|
void flush();
|
||||||
|
void flushAlways();
|
||||||
|
int availableForWrite();
|
||||||
|
char drainForXonXoff();
|
||||||
|
|
||||||
|
virtual int available();
|
||||||
|
virtual int read();
|
||||||
|
virtual int peek();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef _STRING_STREAM_H_INCLUDED_
|
||||||
|
#define _STRING_STREAM_H_INCLUDED_
|
||||||
|
|
||||||
|
class StringStream : public Stream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StringStream(const String &s)
|
||||||
|
{
|
||||||
|
str = s;
|
||||||
|
position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stream methods
|
||||||
|
virtual int available() { return str.length() - position; }
|
||||||
|
virtual int read() { return position < str.length() ? str[position++] : -1; }
|
||||||
|
virtual int peek() { return position < str.length() ? str[position] : -1; }
|
||||||
|
virtual void flush() { };
|
||||||
|
// Print methods
|
||||||
|
virtual size_t write(uint8_t c) { str += (char)c; return 1;};
|
||||||
|
|
||||||
|
private:
|
||||||
|
String str;
|
||||||
|
int length;
|
||||||
|
int position;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _STRING_STREAM_H_INCLUDED_
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PACKET_BUF_SIZE 256
|
||||||
|
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
# include <WiFiClientSecure.h>
|
||||||
|
#endif
|
||||||
|
#ifdef INCLUDE_SSH
|
||||||
|
# include "wifisshclient.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static WiFiClient *createWiFiClient(bool SSL)
|
||||||
|
{
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
if(SSL)
|
||||||
|
{
|
||||||
|
WiFiClientSecure *c = new WiFiClientSecure();
|
||||||
|
c->setInsecure();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#else
|
||||||
|
//WiFiClientSecure *c = new WiFiClientSecure();
|
||||||
|
//c->setInsecure();
|
||||||
|
#endif
|
||||||
|
return new WiFiClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Packet
|
||||||
|
{
|
||||||
|
uint8_t num = 0;
|
||||||
|
uint16_t len = 0;
|
||||||
|
uint8_t buf[PACKET_BUF_SIZE] = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
class WiFiClientNode : public Stream
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void finishConnectionLink();
|
||||||
|
int flushOverflowBuffer();
|
||||||
|
void fillUnderflowBuf();
|
||||||
|
WiFiClient client;
|
||||||
|
WiFiClient *clientPtr;
|
||||||
|
bool answered=true;
|
||||||
|
int ringsRemain=0;
|
||||||
|
unsigned long nextRingMillis = 0;
|
||||||
|
unsigned long nextDisconnect = 0;
|
||||||
|
void constructNode();
|
||||||
|
void constructNode(char *hostIp, int newport, int flagsBitmap, int ringDelay);
|
||||||
|
void constructNode(char *hostIp, int newport, char *username, char *password, int flagsBitmap, int ringDelay);
|
||||||
|
|
||||||
|
public:
|
||||||
|
int id=0;
|
||||||
|
char *host;
|
||||||
|
int port;
|
||||||
|
bool wasConnected=false;
|
||||||
|
bool serverClient=false;
|
||||||
|
int flagsBitmap = 0;
|
||||||
|
char *delimiters = NULL;
|
||||||
|
char *maskOuts = NULL;
|
||||||
|
char *stateMachine = NULL;
|
||||||
|
char *machineState = NULL;
|
||||||
|
String machineQue = "";
|
||||||
|
|
||||||
|
uint8_t nextPacketNum=1;
|
||||||
|
uint8_t blankPackets=0;
|
||||||
|
struct Packet lastPacket[3]; // 0 = current buf, 1&2 are back-cache bufs
|
||||||
|
//struct Packet underflowBuf; // underflows no longer handled this way
|
||||||
|
WiFiClientNode *next = null;
|
||||||
|
|
||||||
|
WiFiClientNode(char *hostIp, int newport, int flagsBitmap);
|
||||||
|
WiFiClientNode(char *hostIp, int newport, char *username, char *password, int flagsBitmap);
|
||||||
|
WiFiClientNode(WiFiClient newClient, int flagsBitmap, int ringDelay);
|
||||||
|
~WiFiClientNode();
|
||||||
|
bool isConnected();
|
||||||
|
|
||||||
|
FlowControlType getFlowControl();
|
||||||
|
bool isPETSCII();
|
||||||
|
bool isEcho();
|
||||||
|
bool isTelnet();
|
||||||
|
|
||||||
|
bool isAnswered();
|
||||||
|
void answer();
|
||||||
|
int ringsRemaining(int delta);
|
||||||
|
unsigned long nextRingTime(long delta);
|
||||||
|
void markForDisconnect();
|
||||||
|
bool isMarkedForDisconnect();
|
||||||
|
|
||||||
|
bool isDisconnectedOnStreamExit();
|
||||||
|
void setDisconnectOnStreamExit(bool tf);
|
||||||
|
|
||||||
|
void setNoDelay(bool tf);
|
||||||
|
|
||||||
|
size_t write(uint8_t c);
|
||||||
|
size_t write(const uint8_t *buf, size_t size);
|
||||||
|
void print(String s);
|
||||||
|
int read();
|
||||||
|
int peek();
|
||||||
|
void flush();
|
||||||
|
void flushAlways();
|
||||||
|
int available();
|
||||||
|
int read(uint8_t *buf, size_t size);
|
||||||
|
String readLine(unsigned int timeout);
|
||||||
|
|
||||||
|
static int getNumOpenWiFiConnections();
|
||||||
|
static void checkForAutoDisconnections();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int WiFiNextClientId = 0;
|
||||||
|
|
||||||
|
class WiFiServerSpec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int port;
|
||||||
|
int id;
|
||||||
|
int flagsBitmap = 0;
|
||||||
|
char *delimiters = NULL;
|
||||||
|
char *maskOuts = NULL;
|
||||||
|
char *stateMachine = NULL;
|
||||||
|
|
||||||
|
WiFiServerSpec();
|
||||||
|
WiFiServerSpec(WiFiServerSpec ©);
|
||||||
|
~WiFiServerSpec();
|
||||||
|
|
||||||
|
WiFiServerSpec& operator=(const WiFiServerSpec&);
|
||||||
|
};
|
||||||
|
|
||||||
|
class WiFiServerNode : public WiFiServerSpec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WiFiServer *server;
|
||||||
|
WiFiServerNode *next = null;
|
||||||
|
|
||||||
|
WiFiServerNode(int port, int flagsBitmap);
|
||||||
|
bool hasClient();
|
||||||
|
~WiFiServerNode();
|
||||||
|
|
||||||
|
static WiFiServerNode *FindServer(int port);
|
||||||
|
static void DestroyAllServers();
|
||||||
|
static bool ReadWiFiServer(File &f, WiFiServerSpec &node);
|
||||||
|
static void SaveWiFiServers();
|
||||||
|
static void RestoreWiFiServers();
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
#ifdef INCLUDE_SSH
|
||||||
|
/*
|
||||||
|
Copyright 2023-2023 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "IPAddress.h"
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include "src/libssh2/libssh2_config.h"
|
||||||
|
#include "src/libssh2/libssh2.h"
|
||||||
|
|
||||||
|
class WiFiSSHClient : public WiFiClient
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
String _username = "";
|
||||||
|
String _password = "";
|
||||||
|
libssh2_socket_t sock = null;
|
||||||
|
LIBSSH2_SESSION *session = null;
|
||||||
|
LIBSSH2_CHANNEL *channel = null;
|
||||||
|
static const size_t INTERNAL_BUF_SIZE = 1024;
|
||||||
|
size_t ibufSz = 0;
|
||||||
|
char ibuf[INTERNAL_BUF_SIZE];
|
||||||
|
|
||||||
|
bool finishLogin();
|
||||||
|
void closeSSH();
|
||||||
|
void intern_buffer_fill();
|
||||||
|
|
||||||
|
public:
|
||||||
|
WiFiSSHClient();
|
||||||
|
~WiFiSSHClient();
|
||||||
|
int connect(IPAddress ip, uint16_t port) override;
|
||||||
|
int connect(IPAddress ip, uint16_t port, int32_t timeout_ms) override;
|
||||||
|
int connect(const char *host, uint16_t port) override;
|
||||||
|
int connect(const char *host, uint16_t port, int32_t timeout_ms) override;
|
||||||
|
void setLogin(String username, String password);
|
||||||
|
int peek() override;
|
||||||
|
size_t write(uint8_t data) override;
|
||||||
|
size_t write(const uint8_t *buf, size_t size) override;
|
||||||
|
int available() override;
|
||||||
|
int read() override;
|
||||||
|
int read(uint8_t *buf, size_t size) override;
|
||||||
|
void flush() {}
|
||||||
|
void stop() override;
|
||||||
|
uint8_t connected() override;
|
||||||
|
int fd() const override;
|
||||||
|
|
||||||
|
operator bool()
|
||||||
|
{
|
||||||
|
return connected();
|
||||||
|
}
|
||||||
|
WiFiSSHClient &operator=(const WiFiSSHClient &other);
|
||||||
|
bool operator==(const bool value)
|
||||||
|
{
|
||||||
|
return bool() == value;
|
||||||
|
}
|
||||||
|
bool operator!=(const bool value)
|
||||||
|
{
|
||||||
|
return bool() != value;
|
||||||
|
}
|
||||||
|
bool operator==(const WiFiSSHClient &);
|
||||||
|
bool operator!=(const WiFiSSHClient &rhs)
|
||||||
|
{
|
||||||
|
return !this->operator==(rhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
class ZBrowser : public ZMode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
enum ZBrowseState
|
||||||
|
{
|
||||||
|
ZBROW_MAIN=0,
|
||||||
|
} currState;
|
||||||
|
|
||||||
|
ZSerial serial;
|
||||||
|
|
||||||
|
void switchBackToCommandMode();
|
||||||
|
String makePath(String addendum);
|
||||||
|
String fixPathNoSlash(String path);
|
||||||
|
String stripDir(String path);
|
||||||
|
String stripFilename(String path);
|
||||||
|
String stripArgs(String line, String &argLetters);
|
||||||
|
String cleanOneArg(String line);
|
||||||
|
String cleanFirstArg(String line);
|
||||||
|
String cleanRemainArg(String line);
|
||||||
|
bool isMask(String mask);
|
||||||
|
bool matches(String fname, String mask);
|
||||||
|
void makeFileList(String ***l, int *n, String p, String mask, bool recurse);
|
||||||
|
void deleteFile(String fname, String mask, bool recurse);
|
||||||
|
void showDirectory(String path, String mask, String prefix, bool recurse);
|
||||||
|
void copyFiles(String source, String mask, String target, bool recurse, bool overwrite);
|
||||||
|
|
||||||
|
FTPHost *ftpHost = 0;
|
||||||
|
bool showMenu;
|
||||||
|
bool savedEcho;
|
||||||
|
String path="/";
|
||||||
|
String EOLN;
|
||||||
|
char EOLNC[5];
|
||||||
|
unsigned long lastNumber;
|
||||||
|
String lastString;
|
||||||
|
|
||||||
|
public:
|
||||||
|
~ZBrowser();
|
||||||
|
void switchTo();
|
||||||
|
void serialIncoming();
|
||||||
|
void loop();
|
||||||
|
void init();
|
||||||
|
void doModeCommand(String &line);
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,202 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const int MAX_COMMAND_SIZE=256;
|
||||||
|
static const char *CONFIG_FILE_OLD = "/zconfig.txt";
|
||||||
|
static const char *CONFIG_FILE = "/zconfig_v2.txt";
|
||||||
|
#define ZI_STATE_MACHINE_LEN 7
|
||||||
|
#define DEFAULT_TERMTYPE "Zimodem"
|
||||||
|
#define DEFAULT_BUSYMSG "\r\nBUSY\r\n7\r\n"
|
||||||
|
|
||||||
|
static void parseHostInfo(uint8_t *vbuf, char **hostIp, int *port, char **username, char **password);
|
||||||
|
static bool validateHostInfo(uint8_t *vbuf);
|
||||||
|
|
||||||
|
enum ZResult
|
||||||
|
{
|
||||||
|
ZOK,
|
||||||
|
ZERROR,
|
||||||
|
ZCONNECT,
|
||||||
|
ZNOCARRIER,
|
||||||
|
ZNOANSWER,
|
||||||
|
ZIGNORE,
|
||||||
|
ZIGNORE_SPECIAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ConfigOptions
|
||||||
|
{
|
||||||
|
CFG_WIFISSI=0,
|
||||||
|
CFG_WIFIPW=1,
|
||||||
|
CFG_BAUDRATE=2,
|
||||||
|
CFG_EOLN=3,
|
||||||
|
CFG_FLOWCONTROL=4,
|
||||||
|
CFG_ECHO=5,
|
||||||
|
CFG_RESP_SUPP=6,
|
||||||
|
CFG_RESP_NUM=7,
|
||||||
|
CFG_RESP_LONG=8,
|
||||||
|
CFG_PETSCIIMODE=9,
|
||||||
|
CFG_DCDMODE=10,
|
||||||
|
CFG_UART=11,
|
||||||
|
CFG_CTSMODE=12,
|
||||||
|
CFG_RTSMODE=13,
|
||||||
|
CFG_DCDPIN=14,
|
||||||
|
CFG_CTSPIN=15,
|
||||||
|
CFG_RTSPIN=16,
|
||||||
|
CFG_S0_RINGS=17,
|
||||||
|
CFG_S41_STREAM=18,
|
||||||
|
CFG_S60_LISTEN=19,
|
||||||
|
CFG_RIMODE=20,
|
||||||
|
CFG_DTRMODE=21,
|
||||||
|
CFG_DSRMODE=22,
|
||||||
|
CFG_RIPIN=23,
|
||||||
|
CFG_DTRPIN=24,
|
||||||
|
CFG_DSRPIN=25,
|
||||||
|
CFG_TIMEZONE=26,
|
||||||
|
CFG_TIMEFMT=27,
|
||||||
|
CFG_TIMEURL=28,
|
||||||
|
CFG_HOSTNAME=29,
|
||||||
|
CFG_PRINTDELAYMS=30,
|
||||||
|
CFG_PRINTSPEC=31,
|
||||||
|
CFG_TERMTYPE=32,
|
||||||
|
CFG_STATIC_IP=33,
|
||||||
|
CFG_STATIC_DNS=34,
|
||||||
|
CFG_STATIC_GW=35,
|
||||||
|
CFG_STATIC_SN=36,
|
||||||
|
CFG_BUSYMSG=37,
|
||||||
|
CFG_S62_TELNET=38,
|
||||||
|
CFG_LAST=38
|
||||||
|
};
|
||||||
|
|
||||||
|
const ConfigOptions v2HexCfgs[] = { CFG_WIFISSI, CFG_WIFIPW, CFG_TIMEZONE, CFG_TIMEFMT, CFG_TIMEURL,
|
||||||
|
CFG_PRINTSPEC, CFG_BUSYMSG, CFG_HOSTNAME, CFG_TERMTYPE, (ConfigOptions)255 };
|
||||||
|
|
||||||
|
enum BinType
|
||||||
|
{
|
||||||
|
BTYPE_NORMAL=0,
|
||||||
|
BTYPE_HEX=1,
|
||||||
|
BTYPE_DEC=2,
|
||||||
|
BTYPE_NORMAL_NOCHK=3,
|
||||||
|
BTYPE_NORMAL_PLUS=4,
|
||||||
|
BTYPE_HEX_PLUS=5,
|
||||||
|
BTYPE_DEC_PLUS=6,
|
||||||
|
BTYPE_INVALID=7
|
||||||
|
};
|
||||||
|
|
||||||
|
class ZCommand : public ZMode
|
||||||
|
{
|
||||||
|
friend class WiFiClientNode;
|
||||||
|
friend class ZConfig;
|
||||||
|
friend class ZBrowser;
|
||||||
|
#ifdef INCLUDE_IRCC
|
||||||
|
friend class ZIRCMode;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
char CRLF[4];
|
||||||
|
char LFCR[4];
|
||||||
|
char LF[2];
|
||||||
|
char CR[2];
|
||||||
|
char BS=8;
|
||||||
|
char ringCounter = 1;
|
||||||
|
|
||||||
|
ZSerial serial;
|
||||||
|
bool packetXOn = true;
|
||||||
|
BinType binType = BTYPE_NORMAL;
|
||||||
|
uint8_t nbuf[MAX_COMMAND_SIZE];
|
||||||
|
char hbuf[MAX_COMMAND_SIZE];
|
||||||
|
int eon=0;
|
||||||
|
int lastServerClientId = 0;
|
||||||
|
WiFiClientNode *current = null;
|
||||||
|
bool autoStreamMode=false;
|
||||||
|
bool telnetSupport=true;
|
||||||
|
bool preserveListeners=false;
|
||||||
|
unsigned long lastNonPlusTimeMs = 0;
|
||||||
|
unsigned long currentExpiresTimeMs = 0;
|
||||||
|
char *tempDelimiters = NULL;
|
||||||
|
char *tempMaskOuts = NULL;
|
||||||
|
char *tempStateMachine = NULL;
|
||||||
|
char *delimiters = NULL;
|
||||||
|
char *maskOuts = NULL;
|
||||||
|
char *stateMachine = NULL;
|
||||||
|
char *machineState = NULL;
|
||||||
|
String machineQue = "";
|
||||||
|
String previousCommand = "";
|
||||||
|
WiFiClientNode *nextConn=null;
|
||||||
|
int lastPacketId = -1;
|
||||||
|
|
||||||
|
byte CRC8(const byte *data, byte len);
|
||||||
|
|
||||||
|
void showInitMessage();
|
||||||
|
bool readSerialStream();
|
||||||
|
void clearPlusProgress();
|
||||||
|
bool checkPlusEscape();
|
||||||
|
String getNextSerialCommand();
|
||||||
|
ZResult doSerialCommand();
|
||||||
|
void setConfigDefaults();
|
||||||
|
void parseConfigOptions(String configArguments[]);
|
||||||
|
void setOptionsFromSavedConfig(String configArguments[]);
|
||||||
|
void reSaveConfig();
|
||||||
|
void reSendLastPacket(WiFiClientNode *conn, uint8_t which);
|
||||||
|
void acceptNewConnection();
|
||||||
|
void headerOut(const int channel, const int num, const int sz, const int crc8);
|
||||||
|
void sendConnectionNotice(int nodeId);
|
||||||
|
void sendNextPacket();
|
||||||
|
void connectionArgs(WiFiClientNode *c);
|
||||||
|
void updateAutoAnswer();
|
||||||
|
uint8_t *doStateMachine(uint8_t *buf, uint16_t *bufLen, char **machineState, String *machineQue, char *stateMachine);
|
||||||
|
uint8_t *doMaskOuts(uint8_t *buf, uint16_t *bufLen, char *maskOuts);
|
||||||
|
ZResult doWebDump(Stream *in, int len, const bool cacheFlag);
|
||||||
|
ZResult doWebDump(const char *filename, const bool cache);
|
||||||
|
|
||||||
|
ZResult doResetCommand();
|
||||||
|
ZResult doNoListenCommand();
|
||||||
|
ZResult doBaudCommand(int vval, uint8_t *vbuf, int vlen);
|
||||||
|
ZResult doTransmitCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers, int *crc8);
|
||||||
|
ZResult doLastPacket(int vval, uint8_t *vbuf, int vlen, bool isNumber);
|
||||||
|
ZResult doConnectCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
|
||||||
|
ZResult doWiFiCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
|
||||||
|
ZResult doDialStreamCommand(unsigned long vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
|
||||||
|
ZResult doPhonebookCommand(unsigned long vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
|
||||||
|
ZResult doAnswerCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
|
||||||
|
ZResult doHangupCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber);
|
||||||
|
ZResult doEOLNCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber);
|
||||||
|
ZResult doInfoCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber);
|
||||||
|
ZResult doWebStream(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *filename, bool cache);
|
||||||
|
ZResult doUpdateFirmware(int vval, uint8_t *vbuf, int vlen, bool isNumber);
|
||||||
|
ZResult doTimeZoneSetupCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber);
|
||||||
|
|
||||||
|
public:
|
||||||
|
int packetSize = 127;
|
||||||
|
bool suppressResponses;
|
||||||
|
bool numericResponses;
|
||||||
|
bool longResponses;
|
||||||
|
boolean doEcho;
|
||||||
|
String EOLN;
|
||||||
|
char EC='+';
|
||||||
|
char ECS[32];
|
||||||
|
|
||||||
|
ZCommand();
|
||||||
|
void loadConfig();
|
||||||
|
|
||||||
|
FlowControlType getFlowControlType();
|
||||||
|
int getConfigFlagBitmap();
|
||||||
|
|
||||||
|
void sendOfficialResponse(ZResult res);
|
||||||
|
void serialIncoming();
|
||||||
|
void loop();
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ZConfig : public ZMode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
enum ZConfigMenu
|
||||||
|
{
|
||||||
|
ZCFGMENU_MAIN=0,
|
||||||
|
ZCFGMENU_NUM=1,
|
||||||
|
ZCFGMENU_ADDRESS=2,
|
||||||
|
ZCFGMENU_OPTIONS=3,
|
||||||
|
ZCFGMENU_WIMENU=4,
|
||||||
|
ZCFGMENU_WIFIPW=5,
|
||||||
|
ZCFGMENU_WICONFIRM=6,
|
||||||
|
ZCFGMENU_FLOW=7,
|
||||||
|
ZCFGMENU_BBSMENU=8,
|
||||||
|
ZCFGMENU_NEWPORT=9,
|
||||||
|
ZCFGMENU_NEWHOST=10,
|
||||||
|
ZCFGMENU_NOTES=11,
|
||||||
|
ZCFGMENU_NETMENU=12,
|
||||||
|
ZCFGMENU_SUBNET=13,
|
||||||
|
ZCFGMENU_NEWPRINT=14
|
||||||
|
} currState;
|
||||||
|
|
||||||
|
ZSerial serial; // storage for serial settings only
|
||||||
|
|
||||||
|
void switchBackToCommandMode();
|
||||||
|
void doModeCommand();
|
||||||
|
bool showMenu;
|
||||||
|
bool savedEcho;
|
||||||
|
String EOLN;
|
||||||
|
const char *EOLNC;
|
||||||
|
unsigned long lastNumber;
|
||||||
|
String lastAddress;
|
||||||
|
String lastOptions;
|
||||||
|
String lastNotes;
|
||||||
|
WiFiServerSpec serverSpec;
|
||||||
|
bool newListen;
|
||||||
|
bool useDHCP;
|
||||||
|
bool settingsChanged=false;
|
||||||
|
char netOpt = ' ';
|
||||||
|
int lastNumNetworks=0;
|
||||||
|
IPAddress lastIP;
|
||||||
|
IPAddress lastDNS;
|
||||||
|
IPAddress lastGW;
|
||||||
|
IPAddress lastSN;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void switchTo();
|
||||||
|
void serialIncoming();
|
||||||
|
void loop();
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
#ifdef INCLUDE_HOSTCM
|
||||||
|
#include "proto_hostcm.h"
|
||||||
|
|
||||||
|
class ZHostCMMode : public ZMode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void switchBackToCommandMode();
|
||||||
|
HostCM *proto = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void switchTo();
|
||||||
|
void serialIncoming();
|
||||||
|
void loop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* zircmode.h
|
||||||
|
*
|
||||||
|
* Created on: May 18, 2022
|
||||||
|
* Author: Bo Zimmerman
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef INCLUDE_IRCC
|
||||||
|
class ZIRCMode: public ZMode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ZSerial serial; // storage for serial settings only
|
||||||
|
bool showMenu;
|
||||||
|
bool savedEcho;
|
||||||
|
String EOLN;
|
||||||
|
const char *EOLNC;
|
||||||
|
WiFiClientNode *current = null;
|
||||||
|
unsigned long lastNumber;
|
||||||
|
unsigned long timeout=0;
|
||||||
|
String buf;
|
||||||
|
String nick;
|
||||||
|
String lastAddress;
|
||||||
|
String lastOptions;
|
||||||
|
String lastNotes;
|
||||||
|
String channelName;
|
||||||
|
bool joinReceived;
|
||||||
|
enum ZIRCMenu
|
||||||
|
{
|
||||||
|
ZIRCMENU_MAIN=0,
|
||||||
|
ZIRCMENU_NICK=1,
|
||||||
|
ZIRCMENU_ADDRESS=2,
|
||||||
|
ZIRCMENU_NUM=3,
|
||||||
|
ZIRCMENU_NOTES=4,
|
||||||
|
ZIRCMENU_OPTIONS=5,
|
||||||
|
ZIRCMENU_COMMAND=6
|
||||||
|
} currState;
|
||||||
|
enum ZIRCState
|
||||||
|
{
|
||||||
|
ZIRCSTATE_WAIT=0,
|
||||||
|
ZIRCSTATE_COMMAND=1
|
||||||
|
} ircState;
|
||||||
|
|
||||||
|
void switchBackToCommandMode();
|
||||||
|
void doIRCCommand();
|
||||||
|
void loopMenuMode();
|
||||||
|
void loopCommandMode();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void switchTo();
|
||||||
|
void serialIncoming();
|
||||||
|
void loop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* INCLUDE_IRCC */
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020-2020 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum PrintPayloadType
|
||||||
|
{
|
||||||
|
PETSCII,
|
||||||
|
ASCII,
|
||||||
|
RAW
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int DEFAULT_DELAY_MS = 5000;
|
||||||
|
|
||||||
|
class ZPrint : public ZMode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
WiFiClientNode *wifiSock = null;
|
||||||
|
File tfile;
|
||||||
|
Stream *outStream = null;
|
||||||
|
unsigned int timeoutDelayMs = DEFAULT_DELAY_MS;
|
||||||
|
char *lastPrinterSpec = 0;
|
||||||
|
unsigned long currentExpiresTimeMs = 0;
|
||||||
|
unsigned long nextFlushMs = 0;
|
||||||
|
PrintPayloadType payloadType = PETSCII;
|
||||||
|
unsigned long lastNonPlusTimeMs = 0;
|
||||||
|
int plussesInARow=0;
|
||||||
|
size_t pdex=0;
|
||||||
|
size_t coldex=0;
|
||||||
|
char pbuf[258];
|
||||||
|
ZSerial serial;
|
||||||
|
char lastLastC = 0;
|
||||||
|
char lastC = 0;
|
||||||
|
short jobNum = 0;
|
||||||
|
|
||||||
|
size_t writeStr(char *s);
|
||||||
|
size_t writeChunk(char *s, int len);
|
||||||
|
void switchBackToCommandMode(bool error);
|
||||||
|
ZResult finishSwitchTo(char *hostIp, char *req, int port, bool doSSL);
|
||||||
|
void announcePrintJob(const char *hostIp, const int port, const char *req);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ZResult switchTo(char *vbuf, int vlen, bool petscii);
|
||||||
|
ZResult switchToPostScript(char *prefix);
|
||||||
|
void setLastPrinterSpec(const char *spec);
|
||||||
|
bool testPrinterSpec(const char *vbuf, int vlen, bool petscii);
|
||||||
|
char *getLastPrinterSpec();
|
||||||
|
void setTimeoutDelayMs(int ms);
|
||||||
|
int getTimeoutDelayMs();
|
||||||
|
|
||||||
|
void serialIncoming();
|
||||||
|
void loop();
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* zslipmode.h
|
||||||
|
*
|
||||||
|
* Created on: May 17, 2022
|
||||||
|
* Author: Bo Zimmerman
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef INCLUDE_SLIP
|
||||||
|
extern "C" {
|
||||||
|
#include "lwip/raw.h"
|
||||||
|
#include "slipif.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZSerial sserial;
|
||||||
|
class ZSLIPMode: public ZMode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void switchBackToCommandMode();
|
||||||
|
String inPacket;
|
||||||
|
bool started=false;
|
||||||
|
bool escaped=false;
|
||||||
|
raw_pcb *_pcb = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const char SLIP_END = '\xc0';
|
||||||
|
static const char SLIP_ESC = '\xdb';
|
||||||
|
static const char SLIP_ESC_END = '\xdc';
|
||||||
|
static const char SLIP_ESC_ESC = '\xdd';
|
||||||
|
void switchTo();
|
||||||
|
void serialIncoming();
|
||||||
|
void loop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* INCLUDE_SLIP_ */
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZSTREAM_ESC_BUF_MAX 10
|
||||||
|
|
||||||
|
class ZStream : public ZMode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
WiFiClientNode *current = null;
|
||||||
|
unsigned long lastNonPlusTimeMs = 0;
|
||||||
|
unsigned long currentExpiresTimeMs = 0;
|
||||||
|
unsigned long nextFlushMs = 0;
|
||||||
|
int plussesInARow = 0;
|
||||||
|
ZSerial serial;
|
||||||
|
int lastDTR = 0;
|
||||||
|
uint8_t escBuf[ZSTREAM_ESC_BUF_MAX];
|
||||||
|
unsigned long nextAlarm = millis() + 5000;
|
||||||
|
|
||||||
|
void switchBackToCommandMode(bool logout);
|
||||||
|
void socketWrite(uint8_t c);
|
||||||
|
void socketWrite(uint8_t *buf, uint8_t len);
|
||||||
|
void baudDelay();
|
||||||
|
|
||||||
|
bool isPETSCII();
|
||||||
|
bool isEcho();
|
||||||
|
FlowControlType getFlowControl();
|
||||||
|
bool isTelnet();
|
||||||
|
bool isDisconnectedOnStreamExit();
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void switchTo(WiFiClientNode *conn);
|
||||||
|
|
||||||
|
void serialIncoming();
|
||||||
|
void loop();
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
|
@ -0,0 +1,114 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_AGENT_H
|
||||||
|
#define __LIBSSH2_AGENT_H
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009 by Daiki Ueno
|
||||||
|
* Copyright (C) 2010-2014 by Daniel Stenberg
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "session.h"
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* non-blocking mode on agent connection is not yet implemented, but
|
||||||
|
for future use. */
|
||||||
|
typedef enum {
|
||||||
|
agent_NB_state_init = 0,
|
||||||
|
agent_NB_state_request_created,
|
||||||
|
agent_NB_state_request_length_sent,
|
||||||
|
agent_NB_state_request_sent,
|
||||||
|
agent_NB_state_response_length_received,
|
||||||
|
agent_NB_state_response_received
|
||||||
|
} agent_nonblocking_states;
|
||||||
|
|
||||||
|
typedef struct agent_transaction_ctx {
|
||||||
|
unsigned char *request;
|
||||||
|
size_t request_len;
|
||||||
|
unsigned char *response;
|
||||||
|
size_t response_len;
|
||||||
|
agent_nonblocking_states state;
|
||||||
|
size_t send_recv_total;
|
||||||
|
} *agent_transaction_ctx_t;
|
||||||
|
|
||||||
|
typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent);
|
||||||
|
typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent,
|
||||||
|
agent_transaction_ctx_t transctx);
|
||||||
|
typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent);
|
||||||
|
|
||||||
|
struct agent_publickey {
|
||||||
|
struct list_node node;
|
||||||
|
|
||||||
|
/* this is the struct we expose externally */
|
||||||
|
struct libssh2_agent_publickey external;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct agent_ops {
|
||||||
|
agent_connect_func connect;
|
||||||
|
agent_transact_func transact;
|
||||||
|
agent_disconnect_func disconnect;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _LIBSSH2_AGENT
|
||||||
|
{
|
||||||
|
LIBSSH2_SESSION *session; /* the session this "belongs to" */
|
||||||
|
|
||||||
|
libssh2_socket_t fd;
|
||||||
|
|
||||||
|
struct agent_ops *ops;
|
||||||
|
|
||||||
|
struct agent_transaction_ctx transctx;
|
||||||
|
struct agent_publickey *identity;
|
||||||
|
struct list_head head; /* list of public keys */
|
||||||
|
|
||||||
|
char *identity_agent_path; /* Path to a custom identity agent socket */
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
OVERLAPPED overlapped;
|
||||||
|
HANDLE pipe;
|
||||||
|
BOOL pending_io;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
extern struct agent_ops agent_ops_openssh;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_AGENT_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,185 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* $OpenBSD: bcrypt_pbkdf.c,v 1.4 2013/07/29 00:55:53 tedu Exp $ */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Ted Unangst <tedu@openbsd.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HAVE_BCRYPT_PBKDF
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifdef HAVE_SYS_PARAM_H
|
||||||
|
#include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "blf.h"
|
||||||
|
|
||||||
|
#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pkcs #5 pbkdf2 implementation using the "bcrypt" hash
|
||||||
|
*
|
||||||
|
* The bcrypt hash function is derived from the bcrypt password hashing
|
||||||
|
* function with the following modifications:
|
||||||
|
* 1. The input password and salt are preprocessed with SHA512.
|
||||||
|
* 2. The output length is expanded to 256 bits.
|
||||||
|
* 3. Subsequently the magic string to be encrypted is lengthened and modified
|
||||||
|
* to "OxychromaticBlowfishSwatDynamite"
|
||||||
|
* 4. The hash function is defined to perform 64 rounds of initial state
|
||||||
|
* expansion. (More rounds are performed by iterating the hash.)
|
||||||
|
*
|
||||||
|
* Note that this implementation pulls the SHA512 operations into the caller
|
||||||
|
* as a performance optimization.
|
||||||
|
*
|
||||||
|
* One modification from official pbkdf2. Instead of outputting key material
|
||||||
|
* linearly, we mix it. pbkdf2 has a known weakness where if one uses it to
|
||||||
|
* generate (i.e.) 512 bits of key material for use as two 256 bit keys, an
|
||||||
|
* attacker can merely run once through the outer loop below, but the user
|
||||||
|
* always runs it twice. Shuffling output bytes requires computing the
|
||||||
|
* entirety of the key material to assemble any subkey. This is something a
|
||||||
|
* wise caller could do; we just do it for you.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BCRYPT_BLOCKS 8
|
||||||
|
#define BCRYPT_HASHSIZE (BCRYPT_BLOCKS * 4)
|
||||||
|
|
||||||
|
static void
|
||||||
|
bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out)
|
||||||
|
{
|
||||||
|
blf_ctx state;
|
||||||
|
uint8_t ciphertext[BCRYPT_HASHSIZE] = {
|
||||||
|
'O', 'x', 'y', 'c', 'h', 'r', 'o', 'm', 'a', 't', 'i', 'c',
|
||||||
|
'B', 'l', 'o', 'w', 'f', 'i', 's', 'h',
|
||||||
|
'S', 'w', 'a', 't',
|
||||||
|
'D', 'y', 'n', 'a', 'm', 'i', 't', 'e' };
|
||||||
|
uint32_t cdata[BCRYPT_BLOCKS];
|
||||||
|
int i;
|
||||||
|
uint16_t j;
|
||||||
|
uint16_t shalen = SHA512_DIGEST_LENGTH;
|
||||||
|
|
||||||
|
/* key expansion */
|
||||||
|
Blowfish_initstate(&state);
|
||||||
|
Blowfish_expandstate(&state, sha2salt, shalen, sha2pass, shalen);
|
||||||
|
for(i = 0; i < 64; i++) {
|
||||||
|
Blowfish_expand0state(&state, sha2salt, shalen);
|
||||||
|
Blowfish_expand0state(&state, sha2pass, shalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encryption */
|
||||||
|
j = 0;
|
||||||
|
for(i = 0; i < BCRYPT_BLOCKS; i++)
|
||||||
|
cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext),
|
||||||
|
&j);
|
||||||
|
for(i = 0; i < 64; i++)
|
||||||
|
blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
|
||||||
|
|
||||||
|
/* copy out */
|
||||||
|
for(i = 0; i < BCRYPT_BLOCKS; i++) {
|
||||||
|
out[4 * i + 3] = (cdata[i] >> 24) & 0xff;
|
||||||
|
out[4 * i + 2] = (cdata[i] >> 16) & 0xff;
|
||||||
|
out[4 * i + 1] = (cdata[i] >> 8) & 0xff;
|
||||||
|
out[4 * i + 0] = cdata[i] & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zap */
|
||||||
|
_libssh2_explicit_zero(ciphertext, sizeof(ciphertext));
|
||||||
|
_libssh2_explicit_zero(cdata, sizeof(cdata));
|
||||||
|
_libssh2_explicit_zero(&state, sizeof(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
|
||||||
|
size_t saltlen,
|
||||||
|
uint8_t *key, size_t keylen, unsigned int rounds)
|
||||||
|
{
|
||||||
|
uint8_t sha2pass[SHA512_DIGEST_LENGTH];
|
||||||
|
uint8_t sha2salt[SHA512_DIGEST_LENGTH];
|
||||||
|
uint8_t out[BCRYPT_HASHSIZE];
|
||||||
|
uint8_t tmpout[BCRYPT_HASHSIZE];
|
||||||
|
uint8_t *countsalt;
|
||||||
|
size_t i, j, amt, stride;
|
||||||
|
uint32_t count;
|
||||||
|
size_t origkeylen = keylen;
|
||||||
|
libssh2_sha512_ctx ctx;
|
||||||
|
|
||||||
|
/* nothing crazy */
|
||||||
|
if(rounds < 1)
|
||||||
|
return -1;
|
||||||
|
if(passlen == 0 || saltlen == 0 || keylen == 0 ||
|
||||||
|
keylen > sizeof(out) * sizeof(out) || saltlen > 1<<20)
|
||||||
|
return -1;
|
||||||
|
countsalt = calloc(1, saltlen + 4);
|
||||||
|
if(countsalt == NULL)
|
||||||
|
return -1;
|
||||||
|
stride = (keylen + sizeof(out) - 1) / sizeof(out);
|
||||||
|
amt = (keylen + stride - 1) / stride;
|
||||||
|
|
||||||
|
memcpy(countsalt, salt, saltlen);
|
||||||
|
|
||||||
|
/* collapse password */
|
||||||
|
(void)libssh2_sha512_init(&ctx);
|
||||||
|
libssh2_sha512_update(ctx, pass, passlen);
|
||||||
|
libssh2_sha512_final(ctx, sha2pass);
|
||||||
|
|
||||||
|
/* generate key, sizeof(out) at a time */
|
||||||
|
for(count = 1; keylen > 0; count++) {
|
||||||
|
countsalt[saltlen + 0] = (count >> 24) & 0xff;
|
||||||
|
countsalt[saltlen + 1] = (count >> 16) & 0xff;
|
||||||
|
countsalt[saltlen + 2] = (count >> 8) & 0xff;
|
||||||
|
countsalt[saltlen + 3] = count & 0xff;
|
||||||
|
|
||||||
|
/* first round, salt is salt */
|
||||||
|
(void)libssh2_sha512_init(&ctx);
|
||||||
|
libssh2_sha512_update(ctx, countsalt, saltlen + 4);
|
||||||
|
libssh2_sha512_final(ctx, sha2salt);
|
||||||
|
|
||||||
|
bcrypt_hash(sha2pass, sha2salt, tmpout);
|
||||||
|
memcpy(out, tmpout, sizeof(out));
|
||||||
|
|
||||||
|
for(i = 1; i < rounds; i++) {
|
||||||
|
/* subsequent rounds, salt is previous output */
|
||||||
|
(void)libssh2_sha512_init(&ctx);
|
||||||
|
libssh2_sha512_update(ctx, tmpout, sizeof(tmpout));
|
||||||
|
libssh2_sha512_final(ctx, sha2salt);
|
||||||
|
|
||||||
|
bcrypt_hash(sha2pass, sha2salt, tmpout);
|
||||||
|
for(j = 0; j < sizeof(out); j++)
|
||||||
|
out[j] ^= tmpout[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pbkdf2 deviation: output the key material non-linearly.
|
||||||
|
*/
|
||||||
|
amt = MINIMUM(amt, keylen);
|
||||||
|
for(i = 0; i < amt; i++) {
|
||||||
|
size_t dest = i * stride + (count - 1);
|
||||||
|
if(dest >= origkeylen) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
key[dest] = out[i];
|
||||||
|
}
|
||||||
|
keylen -= i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zap */
|
||||||
|
_libssh2_explicit_zero(out, sizeof(out));
|
||||||
|
free(countsalt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* HAVE_BCRYPT_PBKDF */
|
||||||
|
#endif
|
|
@ -0,0 +1,88 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_BLF_H
|
||||||
|
#define __LIBSSH2_BLF_H
|
||||||
|
/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */
|
||||||
|
/*
|
||||||
|
* Blowfish - a fast block cipher designed by Bruce Schneier
|
||||||
|
*
|
||||||
|
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H)
|
||||||
|
|
||||||
|
/* Schneier specifies a maximum key length of 56 bytes.
|
||||||
|
* This ensures that every key bit affects every cipher
|
||||||
|
* bit. However, the subkeys can hold up to 72 bytes.
|
||||||
|
* Warning: For normal blowfish encryption only 56 bytes
|
||||||
|
* of the key affect all cipherbits.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BLF_N 16 /* Number of Subkeys */
|
||||||
|
#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */
|
||||||
|
#define BLF_MAXUTILIZED ((BLF_N + 2)*4) /* 576 bits */
|
||||||
|
|
||||||
|
/* Blowfish context */
|
||||||
|
typedef struct BlowfishContext {
|
||||||
|
uint32_t S[4][256]; /* S-Boxes */
|
||||||
|
uint32_t P[BLF_N + 2]; /* Subkeys */
|
||||||
|
} blf_ctx;
|
||||||
|
|
||||||
|
/* Raw access to customized Blowfish
|
||||||
|
* blf_key is just:
|
||||||
|
* Blowfish_initstate( state )
|
||||||
|
* Blowfish_expand0state( state, key, keylen )
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Blowfish_encipher(blf_ctx *, uint32_t *, uint32_t *);
|
||||||
|
void Blowfish_decipher(blf_ctx *, uint32_t *, uint32_t *);
|
||||||
|
void Blowfish_initstate(blf_ctx *);
|
||||||
|
void Blowfish_expand0state(blf_ctx *, const uint8_t *, uint16_t);
|
||||||
|
void Blowfish_expandstate
|
||||||
|
(blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t);
|
||||||
|
|
||||||
|
/* Standard Blowfish */
|
||||||
|
|
||||||
|
void blf_key(blf_ctx *, const uint8_t *, uint16_t);
|
||||||
|
void blf_enc(blf_ctx *, uint32_t *, uint16_t);
|
||||||
|
void blf_dec(blf_ctx *, uint32_t *, uint16_t);
|
||||||
|
|
||||||
|
void blf_ecb_encrypt(blf_ctx *, uint8_t *, uint32_t);
|
||||||
|
void blf_ecb_decrypt(blf_ctx *, uint8_t *, uint32_t);
|
||||||
|
|
||||||
|
void blf_cbc_encrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t);
|
||||||
|
void blf_cbc_decrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t);
|
||||||
|
|
||||||
|
/* Converts uint8_t to uint32_t */
|
||||||
|
uint32_t Blowfish_stream2word(const uint8_t *, uint16_t, uint16_t *);
|
||||||
|
|
||||||
|
/* bcrypt with pbkd */
|
||||||
|
int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
|
||||||
|
size_t saltlen,
|
||||||
|
uint8_t *key, size_t keylen, unsigned int rounds);
|
||||||
|
|
||||||
|
#endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */
|
||||||
|
#endif /* __LIBSSH2_BLF_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,696 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* $OpenBSD: blowfish.c,v 1.18 2004/11/02 17:23:26 hshoexer Exp $ */
|
||||||
|
/*
|
||||||
|
* Blowfish block cipher for OpenBSD
|
||||||
|
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Implementation advice by David Mazieres <dm@lcs.mit.edu>.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is derived from section 14.3 and the given source
|
||||||
|
* in section V of Applied Cryptography, second edition.
|
||||||
|
* Blowfish is an unpatented fast block cipher designed by
|
||||||
|
* Bruce Schneier.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(HAVE_BCRYPT_PBKDF) && (!defined(HAVE_BLOWFISH_INITSTATE) || \
|
||||||
|
!defined(HAVE_BLOWFISH_EXPAND0STATE) || \
|
||||||
|
!defined(HAVE_BLF_ENC))
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <stdio.h> /* used for debugging */
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "libssh2.h"
|
||||||
|
#include "blf.h"
|
||||||
|
|
||||||
|
#undef inline
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define inline __inline
|
||||||
|
#else /* !__GNUC__ */
|
||||||
|
#define inline
|
||||||
|
#endif /* !__GNUC__ */
|
||||||
|
|
||||||
|
/* Function for Feistel Networks */
|
||||||
|
|
||||||
|
#define F(s, x) ((((s)[ (((x)>>24)&0xFF)] \
|
||||||
|
+ (s)[0x100 + (((x)>>16)&0xFF)]) \
|
||||||
|
^ (s)[0x200 + (((x)>> 8)&0xFF)]) \
|
||||||
|
+ (s)[0x300 + ( (x) &0xFF)])
|
||||||
|
|
||||||
|
#define BLFRND(s,p,i,j,n) (i ^= F(s,j) ^ (p)[n])
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_encipher(blf_ctx *c, uint32_t *xl, uint32_t *xr)
|
||||||
|
{
|
||||||
|
uint32_t Xl;
|
||||||
|
uint32_t Xr;
|
||||||
|
uint32_t *s = c->S[0];
|
||||||
|
uint32_t *p = c->P;
|
||||||
|
|
||||||
|
Xl = *xl;
|
||||||
|
Xr = *xr;
|
||||||
|
|
||||||
|
Xl ^= p[0];
|
||||||
|
BLFRND(s, p, Xr, Xl, 1); BLFRND(s, p, Xl, Xr, 2);
|
||||||
|
BLFRND(s, p, Xr, Xl, 3); BLFRND(s, p, Xl, Xr, 4);
|
||||||
|
BLFRND(s, p, Xr, Xl, 5); BLFRND(s, p, Xl, Xr, 6);
|
||||||
|
BLFRND(s, p, Xr, Xl, 7); BLFRND(s, p, Xl, Xr, 8);
|
||||||
|
BLFRND(s, p, Xr, Xl, 9); BLFRND(s, p, Xl, Xr, 10);
|
||||||
|
BLFRND(s, p, Xr, Xl, 11); BLFRND(s, p, Xl, Xr, 12);
|
||||||
|
BLFRND(s, p, Xr, Xl, 13); BLFRND(s, p, Xl, Xr, 14);
|
||||||
|
BLFRND(s, p, Xr, Xl, 15); BLFRND(s, p, Xl, Xr, 16);
|
||||||
|
|
||||||
|
*xl = Xr ^ p[17];
|
||||||
|
*xr = Xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_decipher(blf_ctx *c, uint32_t *xl, uint32_t *xr)
|
||||||
|
{
|
||||||
|
uint32_t Xl;
|
||||||
|
uint32_t Xr;
|
||||||
|
uint32_t *s = c->S[0];
|
||||||
|
uint32_t *p = c->P;
|
||||||
|
|
||||||
|
Xl = *xl;
|
||||||
|
Xr = *xr;
|
||||||
|
|
||||||
|
Xl ^= p[17];
|
||||||
|
BLFRND(s, p, Xr, Xl, 16); BLFRND(s, p, Xl, Xr, 15);
|
||||||
|
BLFRND(s, p, Xr, Xl, 14); BLFRND(s, p, Xl, Xr, 13);
|
||||||
|
BLFRND(s, p, Xr, Xl, 12); BLFRND(s, p, Xl, Xr, 11);
|
||||||
|
BLFRND(s, p, Xr, Xl, 10); BLFRND(s, p, Xl, Xr, 9);
|
||||||
|
BLFRND(s, p, Xr, Xl, 8); BLFRND(s, p, Xl, Xr, 7);
|
||||||
|
BLFRND(s, p, Xr, Xl, 6); BLFRND(s, p, Xl, Xr, 5);
|
||||||
|
BLFRND(s, p, Xr, Xl, 4); BLFRND(s, p, Xl, Xr, 3);
|
||||||
|
BLFRND(s, p, Xr, Xl, 2); BLFRND(s, p, Xl, Xr, 1);
|
||||||
|
|
||||||
|
*xl = Xr ^ p[0];
|
||||||
|
*xr = Xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_initstate(blf_ctx *c)
|
||||||
|
{
|
||||||
|
/* P-box and S-box tables initialized with digits of Pi */
|
||||||
|
|
||||||
|
static const blf_ctx initstate =
|
||||||
|
{ {
|
||||||
|
{
|
||||||
|
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
|
||||||
|
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
||||||
|
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||||
|
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
||||||
|
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
|
||||||
|
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||||
|
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
|
||||||
|
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
||||||
|
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||||
|
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
||||||
|
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
|
||||||
|
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||||
|
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
|
||||||
|
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
||||||
|
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||||
|
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
||||||
|
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
|
||||||
|
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||||
|
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
|
||||||
|
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
||||||
|
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||||
|
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
||||||
|
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
|
||||||
|
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||||
|
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
|
||||||
|
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||||
|
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||||
|
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
||||||
|
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
|
||||||
|
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||||
|
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
|
||||||
|
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
||||||
|
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||||
|
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
||||||
|
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
|
||||||
|
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||||
|
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
|
||||||
|
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
||||||
|
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||||
|
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
||||||
|
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
|
||||||
|
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||||
|
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
|
||||||
|
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
||||||
|
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||||
|
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
||||||
|
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
|
||||||
|
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||||
|
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
|
||||||
|
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
||||||
|
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||||
|
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||||
|
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
|
||||||
|
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||||
|
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
|
||||||
|
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
||||||
|
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||||
|
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
||||||
|
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
|
||||||
|
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||||
|
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
|
||||||
|
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
||||||
|
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||||
|
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a},
|
||||||
|
{
|
||||||
|
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
|
||||||
|
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
||||||
|
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||||
|
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
||||||
|
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
|
||||||
|
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||||
|
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
|
||||||
|
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
||||||
|
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||||
|
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
||||||
|
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
|
||||||
|
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||||
|
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
|
||||||
|
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
||||||
|
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||||
|
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
||||||
|
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
|
||||||
|
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||||
|
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
|
||||||
|
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
||||||
|
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||||
|
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
||||||
|
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
|
||||||
|
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||||
|
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
|
||||||
|
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||||
|
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||||
|
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
||||||
|
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
|
||||||
|
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||||
|
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
|
||||||
|
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
||||||
|
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||||
|
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
||||||
|
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
|
||||||
|
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||||
|
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
|
||||||
|
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
||||||
|
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||||
|
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
||||||
|
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
|
||||||
|
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||||
|
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
|
||||||
|
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
||||||
|
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||||
|
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
||||||
|
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
|
||||||
|
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||||
|
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
|
||||||
|
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
||||||
|
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||||
|
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||||
|
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
|
||||||
|
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||||
|
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
|
||||||
|
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
||||||
|
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||||
|
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
||||||
|
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
|
||||||
|
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||||
|
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
|
||||||
|
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
||||||
|
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||||
|
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7},
|
||||||
|
{
|
||||||
|
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
|
||||||
|
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
||||||
|
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||||
|
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
||||||
|
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
|
||||||
|
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||||
|
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
|
||||||
|
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
||||||
|
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||||
|
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
||||||
|
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
|
||||||
|
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||||
|
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
|
||||||
|
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
||||||
|
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||||
|
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
||||||
|
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
|
||||||
|
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||||
|
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
|
||||||
|
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
||||||
|
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||||
|
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
||||||
|
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
|
||||||
|
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||||
|
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
|
||||||
|
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||||
|
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||||
|
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
||||||
|
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
|
||||||
|
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||||
|
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
|
||||||
|
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
||||||
|
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||||
|
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
||||||
|
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
|
||||||
|
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||||
|
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
|
||||||
|
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
||||||
|
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||||
|
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
||||||
|
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
|
||||||
|
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||||
|
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
|
||||||
|
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
||||||
|
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||||
|
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
||||||
|
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
|
||||||
|
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||||
|
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
|
||||||
|
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
||||||
|
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||||
|
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||||
|
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
|
||||||
|
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||||
|
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
|
||||||
|
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
||||||
|
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||||
|
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
||||||
|
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
|
||||||
|
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||||
|
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
|
||||||
|
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
||||||
|
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||||
|
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0},
|
||||||
|
{
|
||||||
|
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
|
||||||
|
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
||||||
|
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||||
|
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
||||||
|
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
|
||||||
|
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||||
|
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
|
||||||
|
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
||||||
|
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||||
|
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
||||||
|
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
|
||||||
|
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||||
|
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
|
||||||
|
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
||||||
|
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||||
|
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
||||||
|
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
|
||||||
|
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||||
|
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
|
||||||
|
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
||||||
|
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||||
|
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
||||||
|
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
|
||||||
|
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||||
|
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
|
||||||
|
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||||
|
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||||
|
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
||||||
|
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
|
||||||
|
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||||
|
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
|
||||||
|
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
||||||
|
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||||
|
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
||||||
|
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
|
||||||
|
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||||
|
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
|
||||||
|
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
||||||
|
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||||
|
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
||||||
|
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
|
||||||
|
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||||
|
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
|
||||||
|
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
||||||
|
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||||
|
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
||||||
|
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
|
||||||
|
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||||
|
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
|
||||||
|
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
||||||
|
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||||
|
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||||
|
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
|
||||||
|
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||||
|
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
|
||||||
|
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
||||||
|
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||||
|
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
||||||
|
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
|
||||||
|
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||||
|
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
|
||||||
|
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
||||||
|
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||||
|
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||||
|
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||||
|
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||||
|
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||||
|
0x9216d5d9, 0x8979fb1b
|
||||||
|
} };
|
||||||
|
|
||||||
|
*c = initstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
Blowfish_stream2word(const uint8_t *data, uint16_t databytes,
|
||||||
|
uint16_t *current)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
uint16_t j;
|
||||||
|
uint32_t temp;
|
||||||
|
|
||||||
|
temp = 0x00000000;
|
||||||
|
j = *current;
|
||||||
|
|
||||||
|
for(i = 0; i < 4; i++, j++) {
|
||||||
|
if(j >= databytes)
|
||||||
|
j = 0;
|
||||||
|
temp = (temp << 8) | data[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
*current = j;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_expand0state(blf_ctx *c, const uint8_t *key, uint16_t keybytes)
|
||||||
|
{
|
||||||
|
uint16_t i;
|
||||||
|
uint16_t j;
|
||||||
|
uint16_t k;
|
||||||
|
uint32_t temp;
|
||||||
|
uint32_t datal;
|
||||||
|
uint32_t datar;
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for(i = 0; i < BLF_N + 2; i++) {
|
||||||
|
/* Extract 4 int8 to 1 int32 from keystream */
|
||||||
|
temp = Blowfish_stream2word(key, keybytes, &j);
|
||||||
|
c->P[i] = c->P[i] ^ temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
datal = 0x00000000;
|
||||||
|
datar = 0x00000000;
|
||||||
|
for(i = 0; i < BLF_N + 2; i += 2) {
|
||||||
|
Blowfish_encipher(c, &datal, &datar);
|
||||||
|
|
||||||
|
c->P[i] = datal;
|
||||||
|
c->P[i + 1] = datar;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
for(k = 0; k < 256; k += 2) {
|
||||||
|
Blowfish_encipher(c, &datal, &datar);
|
||||||
|
|
||||||
|
c->S[i][k] = datal;
|
||||||
|
c->S[i][k + 1] = datar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_expandstate(blf_ctx *c, const uint8_t *data, uint16_t databytes,
|
||||||
|
const uint8_t *key, uint16_t keybytes)
|
||||||
|
{
|
||||||
|
uint16_t i;
|
||||||
|
uint16_t j;
|
||||||
|
uint16_t k;
|
||||||
|
uint32_t temp;
|
||||||
|
uint32_t datal;
|
||||||
|
uint32_t datar;
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for(i = 0; i < BLF_N + 2; i++) {
|
||||||
|
/* Extract 4 int8 to 1 int32 from keystream */
|
||||||
|
temp = Blowfish_stream2word(key, keybytes, &j);
|
||||||
|
c->P[i] = c->P[i] ^ temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
datal = 0x00000000;
|
||||||
|
datar = 0x00000000;
|
||||||
|
for(i = 0; i < BLF_N + 2; i += 2) {
|
||||||
|
datal ^= Blowfish_stream2word(data, databytes, &j);
|
||||||
|
datar ^= Blowfish_stream2word(data, databytes, &j);
|
||||||
|
Blowfish_encipher(c, &datal, &datar);
|
||||||
|
|
||||||
|
c->P[i] = datal;
|
||||||
|
c->P[i + 1] = datar;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
for(k = 0; k < 256; k += 2) {
|
||||||
|
datal ^= Blowfish_stream2word(data, databytes, &j);
|
||||||
|
datar ^= Blowfish_stream2word(data, databytes, &j);
|
||||||
|
Blowfish_encipher(c, &datal, &datar);
|
||||||
|
|
||||||
|
c->S[i][k] = datal;
|
||||||
|
c->S[i][k + 1] = datar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_key(blf_ctx *c, const uint8_t *k, uint16_t len)
|
||||||
|
{
|
||||||
|
/* Initialize S-boxes and subkeys with Pi */
|
||||||
|
Blowfish_initstate(c);
|
||||||
|
|
||||||
|
/* Transform S-boxes and subkeys with key */
|
||||||
|
Blowfish_expand0state(c, k, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_enc(blf_ctx *c, uint32_t *data, uint16_t blocks)
|
||||||
|
{
|
||||||
|
uint32_t *d;
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
d = data;
|
||||||
|
for(i = 0; i < blocks; i++) {
|
||||||
|
Blowfish_encipher(c, d, d + 1);
|
||||||
|
d += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_dec(blf_ctx *c, uint32_t *data, uint16_t blocks)
|
||||||
|
{
|
||||||
|
uint32_t *d;
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
d = data;
|
||||||
|
for(i = 0; i < blocks; i++) {
|
||||||
|
Blowfish_decipher(c, d, d + 1);
|
||||||
|
d += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_ecb_encrypt(blf_ctx *c, uint8_t *data, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t l, r;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for(i = 0; i < len; i += 8) {
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_encipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
data += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_ecb_decrypt(blf_ctx *c, uint8_t *data, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t l, r;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for(i = 0; i < len; i += 8) {
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_decipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
data += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_cbc_encrypt(blf_ctx *c, uint8_t *iv, uint8_t *data, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t l, r;
|
||||||
|
uint32_t i, j;
|
||||||
|
|
||||||
|
for(i = 0; i < len; i += 8) {
|
||||||
|
for(j = 0; j < 8; j++)
|
||||||
|
data[j] ^= iv[j];
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_encipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
iv = data;
|
||||||
|
data += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_cbc_decrypt(blf_ctx *c, uint8_t *iva, uint8_t *data, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t l, r;
|
||||||
|
uint8_t *iv;
|
||||||
|
uint32_t i, j;
|
||||||
|
|
||||||
|
iv = data + len - 16;
|
||||||
|
data = data + len - 8;
|
||||||
|
for(i = len - 8; i >= 8; i -= 8) {
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_decipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
for(j = 0; j < 8; j++)
|
||||||
|
data[j] ^= iv[j];
|
||||||
|
iv -= 8;
|
||||||
|
data -= 8;
|
||||||
|
}
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_decipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
for(j = 0; j < 8; j++)
|
||||||
|
data[j] ^= iva[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
report(uint32_t data[], uint16_t len)
|
||||||
|
{
|
||||||
|
uint16_t i;
|
||||||
|
for(i = 0; i < len; i += 2)
|
||||||
|
printf("Block %0hd: %08lx %08lx.\n",
|
||||||
|
i / 2, data[i], data[i + 1]);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
blf_ctx c;
|
||||||
|
char key[] = "AAAAA";
|
||||||
|
char key2[] = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
uint32_t data[10];
|
||||||
|
uint32_t data2[] =
|
||||||
|
{0x424c4f57l, 0x46495348l};
|
||||||
|
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
/* First test */
|
||||||
|
for(i = 0; i < 10; i++)
|
||||||
|
data[i] = i;
|
||||||
|
|
||||||
|
blf_key(&c, (uint8_t *) key, 5);
|
||||||
|
blf_enc(&c, data, 5);
|
||||||
|
blf_dec(&c, data, 1);
|
||||||
|
blf_dec(&c, data + 2, 4);
|
||||||
|
printf("Should read as 0 - 9.\n");
|
||||||
|
report(data, 10);
|
||||||
|
|
||||||
|
/* Second test */
|
||||||
|
blf_key(&c, (uint8_t *) key2, strlen(key2));
|
||||||
|
blf_enc(&c, data2, 1);
|
||||||
|
printf("\nShould read as: 0x324ed0fe 0xf413a203.\n");
|
||||||
|
report(data2, 2);
|
||||||
|
blf_dec(&c, data2, 1);
|
||||||
|
report(data2, 2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(HAVE_BCRYPT_PBKDF) && \
|
||||||
|
(!defined(HAVE_BLOWFISH_INITSTATE) || \
|
||||||
|
!defined(HAVE_BLOWFISH_EXPAND0STATE) || \
|
||||||
|
'!defined(HAVE_BLF_ENC)) */
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,143 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_CHANNEL_H
|
||||||
|
#define __LIBSSH2_CHANNEL_H
|
||||||
|
/* Copyright (c) 2008-2010 by Daniel Stenberg
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_channel_receive_window_adjust
|
||||||
|
*
|
||||||
|
* Adjust the receive window for a channel by adjustment bytes. If the amount
|
||||||
|
* to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the
|
||||||
|
* adjustment amount will be queued for a later packet.
|
||||||
|
*
|
||||||
|
* Always non-blocking.
|
||||||
|
*/
|
||||||
|
int _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
|
||||||
|
uint32_t adjustment,
|
||||||
|
unsigned char force,
|
||||||
|
unsigned int *store);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_channel_flush
|
||||||
|
*
|
||||||
|
* Flush data from one (or all) stream
|
||||||
|
* Returns number of bytes flushed, or negative on failure
|
||||||
|
*/
|
||||||
|
int _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_channel_free
|
||||||
|
*
|
||||||
|
* Make sure a channel is closed, then remove the channel from the session
|
||||||
|
* and free its resource(s)
|
||||||
|
*
|
||||||
|
* Returns 0 on success, negative on failure
|
||||||
|
*/
|
||||||
|
int _libssh2_channel_free(LIBSSH2_CHANNEL *channel);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_channel_write
|
||||||
|
*
|
||||||
|
* Send data to a channel
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||||
|
const unsigned char *buf, size_t buflen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_channel_open
|
||||||
|
*
|
||||||
|
* Establish a generic session channel
|
||||||
|
*/
|
||||||
|
LIBSSH2_CHANNEL *
|
||||||
|
_libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
|
||||||
|
uint32_t channel_type_len,
|
||||||
|
uint32_t window_size,
|
||||||
|
uint32_t packet_size,
|
||||||
|
const unsigned char *message, size_t message_len);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_channel_process_startup
|
||||||
|
*
|
||||||
|
* Primitive for libssh2_channel_(shell|exec|subsystem)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
|
||||||
|
const char *request, size_t request_len,
|
||||||
|
const char *message, size_t message_len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_channel_read
|
||||||
|
*
|
||||||
|
* Read data from a channel
|
||||||
|
*
|
||||||
|
* It is important to not return 0 until the currently read channel is
|
||||||
|
* complete. If we read stuff from the wire but it was no payload data to fill
|
||||||
|
* in the buffer with, we MUST make sure to return PACKET_EAGAIN.
|
||||||
|
*/
|
||||||
|
ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||||
|
char *buf, size_t buflen);
|
||||||
|
|
||||||
|
uint32_t _libssh2_channel_nextid(LIBSSH2_SESSION * session);
|
||||||
|
|
||||||
|
LIBSSH2_CHANNEL *_libssh2_channel_locate(LIBSSH2_SESSION * session,
|
||||||
|
uint32_t channel_id);
|
||||||
|
|
||||||
|
size_t _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel,
|
||||||
|
int stream_id);
|
||||||
|
|
||||||
|
int _libssh2_channel_close(LIBSSH2_CHANNEL * channel);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_channel_forward_cancel
|
||||||
|
*
|
||||||
|
* Stop listening on a remote port and free the listener
|
||||||
|
* Toss out any pending (un-accept()ed) connections
|
||||||
|
*
|
||||||
|
* Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error
|
||||||
|
*/
|
||||||
|
int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_CHANNEL_H */
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,379 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2004-2007, 2019, Sara Golemon <sarag@libssh2.org>
|
||||||
|
* Copyright (c) 2010-2014, Daniel Stenberg <daniel@haxx.se>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#ifdef LIBSSH2_HAVE_ZLIB
|
||||||
|
#include <zlib.h>
|
||||||
|
#undef compress /* dodge name clash with ZLIB macro */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "comp.h"
|
||||||
|
|
||||||
|
/* ********
|
||||||
|
* none *
|
||||||
|
******** */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* comp_method_none_comp
|
||||||
|
*
|
||||||
|
* Minimalist compression: Absolutely none
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
comp_method_none_comp(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char *dest,
|
||||||
|
size_t *dest_len,
|
||||||
|
const unsigned char *src,
|
||||||
|
size_t src_len,
|
||||||
|
void **abstract)
|
||||||
|
{
|
||||||
|
(void) session;
|
||||||
|
(void) abstract;
|
||||||
|
(void) dest;
|
||||||
|
(void) dest_len;
|
||||||
|
(void) src;
|
||||||
|
(void) src_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* comp_method_none_decomp
|
||||||
|
*
|
||||||
|
* Minimalist decompression: Absolutely none
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
comp_method_none_decomp(LIBSSH2_SESSION * session,
|
||||||
|
unsigned char **dest,
|
||||||
|
size_t *dest_len,
|
||||||
|
size_t payload_limit,
|
||||||
|
const unsigned char *src,
|
||||||
|
size_t src_len, void **abstract)
|
||||||
|
{
|
||||||
|
(void) session;
|
||||||
|
(void) payload_limit;
|
||||||
|
(void) abstract;
|
||||||
|
*dest = (unsigned char *) src;
|
||||||
|
*dest_len = src_len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const LIBSSH2_COMP_METHOD comp_method_none = {
|
||||||
|
"none",
|
||||||
|
0, /* not really compressing */
|
||||||
|
0, /* isn't used in userauth, go figure */
|
||||||
|
NULL,
|
||||||
|
comp_method_none_comp,
|
||||||
|
comp_method_none_decomp,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef LIBSSH2_HAVE_ZLIB
|
||||||
|
/* ********
|
||||||
|
* zlib *
|
||||||
|
******** */
|
||||||
|
|
||||||
|
/* Memory management wrappers
|
||||||
|
* Yes, I realize we're doing a callback to a callback,
|
||||||
|
* Deal...
|
||||||
|
*/
|
||||||
|
|
||||||
|
static voidpf
|
||||||
|
comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
|
||||||
|
{
|
||||||
|
LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
|
||||||
|
|
||||||
|
return (voidpf) LIBSSH2_ALLOC(session, items * size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
comp_method_zlib_free(voidpf opaque, voidpf address)
|
||||||
|
{
|
||||||
|
LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
|
||||||
|
|
||||||
|
LIBSSH2_FREE(session, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* libssh2_comp_method_zlib_init
|
||||||
|
* All your bandwidth are belong to us (so save some)
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
comp_method_zlib_init(LIBSSH2_SESSION * session, int compr,
|
||||||
|
void **abstract)
|
||||||
|
{
|
||||||
|
z_stream *strm;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
strm = LIBSSH2_CALLOC(session, sizeof(z_stream));
|
||||||
|
if(!strm) {
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"zlib compression/decompression");
|
||||||
|
}
|
||||||
|
|
||||||
|
strm->opaque = (voidpf) session;
|
||||||
|
strm->zalloc = (alloc_func) comp_method_zlib_alloc;
|
||||||
|
strm->zfree = (free_func) comp_method_zlib_free;
|
||||||
|
if(compr) {
|
||||||
|
/* deflate */
|
||||||
|
status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* inflate */
|
||||||
|
status = inflateInit(strm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status != Z_OK) {
|
||||||
|
LIBSSH2_FREE(session, strm);
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||||
|
"unhandled zlib error %d", status);
|
||||||
|
return LIBSSH2_ERROR_COMPRESS;
|
||||||
|
}
|
||||||
|
*abstract = strm;
|
||||||
|
|
||||||
|
return LIBSSH2_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libssh2_comp_method_zlib_comp
|
||||||
|
*
|
||||||
|
* Compresses source to destination. Without allocation.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
comp_method_zlib_comp(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char *dest,
|
||||||
|
|
||||||
|
/* dest_len is a pointer to allow this function to
|
||||||
|
update it with the final actual size used */
|
||||||
|
size_t *dest_len,
|
||||||
|
const unsigned char *src,
|
||||||
|
size_t src_len,
|
||||||
|
void **abstract)
|
||||||
|
{
|
||||||
|
z_stream *strm = *abstract;
|
||||||
|
int out_maxlen = *dest_len;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
strm->next_in = (unsigned char *) src;
|
||||||
|
strm->avail_in = src_len;
|
||||||
|
strm->next_out = dest;
|
||||||
|
strm->avail_out = out_maxlen;
|
||||||
|
|
||||||
|
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||||
|
|
||||||
|
if((status == Z_OK) && (strm->avail_out > 0)) {
|
||||||
|
*dest_len = out_maxlen - strm->avail_out;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||||
|
"unhandled zlib compression error %d, avail_out",
|
||||||
|
status, strm->avail_out);
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compression failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libssh2_comp_method_zlib_decomp
|
||||||
|
*
|
||||||
|
* Decompresses source to destination. Allocates the output memory.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
comp_method_zlib_decomp(LIBSSH2_SESSION * session,
|
||||||
|
unsigned char **dest,
|
||||||
|
size_t *dest_len,
|
||||||
|
size_t payload_limit,
|
||||||
|
const unsigned char *src,
|
||||||
|
size_t src_len, void **abstract)
|
||||||
|
{
|
||||||
|
z_stream *strm = *abstract;
|
||||||
|
/* A short-term alloc of a full data chunk is better than a series of
|
||||||
|
reallocs */
|
||||||
|
char *out;
|
||||||
|
size_t out_maxlen = src_len;
|
||||||
|
|
||||||
|
if(src_len <= SIZE_MAX / 4)
|
||||||
|
out_maxlen = src_len * 4;
|
||||||
|
else
|
||||||
|
out_maxlen = payload_limit;
|
||||||
|
|
||||||
|
/* If strm is null, then we have not yet been initialized. */
|
||||||
|
if(strm == NULL)
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_COMPRESS,
|
||||||
|
"decompression uninitialized");;
|
||||||
|
|
||||||
|
/* In practice they never come smaller than this */
|
||||||
|
if(out_maxlen < 25)
|
||||||
|
out_maxlen = 25;
|
||||||
|
|
||||||
|
if(out_maxlen > payload_limit)
|
||||||
|
out_maxlen = payload_limit;
|
||||||
|
|
||||||
|
strm->next_in = (unsigned char *) src;
|
||||||
|
strm->avail_in = src_len;
|
||||||
|
strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
|
||||||
|
out = (char *) strm->next_out;
|
||||||
|
strm->avail_out = out_maxlen;
|
||||||
|
if(!strm->next_out)
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate decompression buffer");
|
||||||
|
|
||||||
|
/* Loop until it's all inflated or hit error */
|
||||||
|
for(;;) {
|
||||||
|
int status;
|
||||||
|
size_t out_ofs;
|
||||||
|
char *newout;
|
||||||
|
|
||||||
|
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||||
|
|
||||||
|
if(status == Z_OK) {
|
||||||
|
if(strm->avail_out > 0)
|
||||||
|
/* status is OK and the output buffer has not been exhausted
|
||||||
|
so we're done */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(status == Z_BUF_ERROR) {
|
||||||
|
/* the input data has been exhausted so we are done */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* error state */
|
||||||
|
LIBSSH2_FREE(session, out);
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||||
|
"unhandled zlib error %d", status);
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||||
|
"decompression failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(out_maxlen > payload_limit || out_maxlen > SIZE_MAX / 2) {
|
||||||
|
LIBSSH2_FREE(session, out);
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||||
|
"Excessive growth in decompression phase");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here we need to grow the output buffer and try again */
|
||||||
|
out_ofs = out_maxlen - strm->avail_out;
|
||||||
|
out_maxlen *= 2;
|
||||||
|
newout = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||||
|
if(!newout) {
|
||||||
|
LIBSSH2_FREE(session, out);
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to expand decompression buffer");
|
||||||
|
}
|
||||||
|
out = newout;
|
||||||
|
strm->next_out = (unsigned char *) out + out_ofs;
|
||||||
|
strm->avail_out = out_maxlen - out_ofs;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest = (unsigned char *) out;
|
||||||
|
*dest_len = out_maxlen - strm->avail_out;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* libssh2_comp_method_zlib_dtor
|
||||||
|
* All done, no more compression for you
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compr, void **abstract)
|
||||||
|
{
|
||||||
|
z_stream *strm = *abstract;
|
||||||
|
|
||||||
|
if(strm) {
|
||||||
|
if(compr)
|
||||||
|
deflateEnd(strm);
|
||||||
|
else
|
||||||
|
inflateEnd(strm);
|
||||||
|
LIBSSH2_FREE(session, strm);
|
||||||
|
}
|
||||||
|
|
||||||
|
*abstract = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const LIBSSH2_COMP_METHOD comp_method_zlib = {
|
||||||
|
"zlib",
|
||||||
|
1, /* yes, this compresses */
|
||||||
|
1, /* do compression during userauth */
|
||||||
|
comp_method_zlib_init,
|
||||||
|
comp_method_zlib_comp,
|
||||||
|
comp_method_zlib_decomp,
|
||||||
|
comp_method_zlib_dtor,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const LIBSSH2_COMP_METHOD comp_method_zlib_openssh = {
|
||||||
|
"zlib@openssh.com",
|
||||||
|
1, /* yes, this compresses */
|
||||||
|
0, /* don't use compression during userauth */
|
||||||
|
comp_method_zlib_init,
|
||||||
|
comp_method_zlib_comp,
|
||||||
|
comp_method_zlib_decomp,
|
||||||
|
comp_method_zlib_dtor,
|
||||||
|
};
|
||||||
|
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||||
|
|
||||||
|
/* If compression is enabled by the API, then this array is used which then
|
||||||
|
may allow compression if zlib is available at build time */
|
||||||
|
static const LIBSSH2_COMP_METHOD *comp_methods[] = {
|
||||||
|
#ifdef LIBSSH2_HAVE_ZLIB
|
||||||
|
&comp_method_zlib,
|
||||||
|
&comp_method_zlib_openssh,
|
||||||
|
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||||
|
&comp_method_none,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
/* If compression is disabled by the API, then this array is used */
|
||||||
|
static const LIBSSH2_COMP_METHOD *no_comp_methods[] = {
|
||||||
|
&comp_method_none,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
const LIBSSH2_COMP_METHOD **
|
||||||
|
_libssh2_comp_methods(LIBSSH2_SESSION *session)
|
||||||
|
{
|
||||||
|
if(session->flag.compress)
|
||||||
|
return comp_methods;
|
||||||
|
else
|
||||||
|
return no_comp_methods;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,46 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_COMP_H
|
||||||
|
#define __LIBSSH2_COMP_H
|
||||||
|
/* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
|
||||||
|
const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(LIBSSH2_SESSION *session);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_COMP_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,353 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2009, 2010 Simon Josefsson <simon@josefsson.org>
|
||||||
|
* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
|
||||||
|
#ifdef LIBSSH2_CRYPT_NONE
|
||||||
|
|
||||||
|
/* crypt_none_crypt
|
||||||
|
* Minimalist cipher: VERY secure *wink*
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf,
|
||||||
|
void **abstract)
|
||||||
|
{
|
||||||
|
/* Do nothing to the data! */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = {
|
||||||
|
"none",
|
||||||
|
"DEK-Info: NONE",
|
||||||
|
8, /* blocksize (SSH2 defines minimum blocksize as 8) */
|
||||||
|
0, /* iv_len */
|
||||||
|
0, /* secret_len */
|
||||||
|
0, /* flags */
|
||||||
|
NULL,
|
||||||
|
crypt_none_crypt,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
#endif /* LIBSSH2_CRYPT_NONE */
|
||||||
|
|
||||||
|
struct crypt_ctx
|
||||||
|
{
|
||||||
|
int encrypt;
|
||||||
|
_libssh2_cipher_type(algo);
|
||||||
|
_libssh2_cipher_ctx h;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
crypt_init(LIBSSH2_SESSION * session,
|
||||||
|
const LIBSSH2_CRYPT_METHOD * method,
|
||||||
|
unsigned char *iv, int *free_iv,
|
||||||
|
unsigned char *secret, int *free_secret,
|
||||||
|
int encrypt, void **abstract)
|
||||||
|
{
|
||||||
|
struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
|
||||||
|
sizeof(struct crypt_ctx));
|
||||||
|
if(!ctx)
|
||||||
|
return LIBSSH2_ERROR_ALLOC;
|
||||||
|
|
||||||
|
ctx->encrypt = encrypt;
|
||||||
|
ctx->algo = method->algo;
|
||||||
|
if(_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) {
|
||||||
|
LIBSSH2_FREE(session, ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*abstract = ctx;
|
||||||
|
*free_iv = 1;
|
||||||
|
*free_secret = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
crypt_encrypt(LIBSSH2_SESSION * session, unsigned char *block,
|
||||||
|
size_t blocksize, void **abstract)
|
||||||
|
{
|
||||||
|
struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
|
||||||
|
(void) session;
|
||||||
|
return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block,
|
||||||
|
blocksize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
crypt_dtor(LIBSSH2_SESSION * session, void **abstract)
|
||||||
|
{
|
||||||
|
struct crypt_ctx **cctx = (struct crypt_ctx **) abstract;
|
||||||
|
if(cctx && *cctx) {
|
||||||
|
_libssh2_cipher_dtor(&(*cctx)->h);
|
||||||
|
LIBSSH2_FREE(session, *cctx);
|
||||||
|
*abstract = NULL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LIBSSH2_AES_CTR
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = {
|
||||||
|
"aes128-ctr",
|
||||||
|
"",
|
||||||
|
16, /* blocksize */
|
||||||
|
16, /* initial value length */
|
||||||
|
16, /* secret length -- 16*8 == 128bit */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_aes128ctr
|
||||||
|
};
|
||||||
|
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_ctr = {
|
||||||
|
"aes192-ctr",
|
||||||
|
"",
|
||||||
|
16, /* blocksize */
|
||||||
|
16, /* initial value length */
|
||||||
|
24, /* secret length -- 24*8 == 192bit */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_aes192ctr
|
||||||
|
};
|
||||||
|
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = {
|
||||||
|
"aes256-ctr",
|
||||||
|
"",
|
||||||
|
16, /* blocksize */
|
||||||
|
16, /* initial value length */
|
||||||
|
32, /* secret length -- 32*8 == 256bit */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_aes256ctr
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LIBSSH2_AES
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
|
||||||
|
"aes128-cbc",
|
||||||
|
"DEK-Info: AES-128-CBC",
|
||||||
|
16, /* blocksize */
|
||||||
|
16, /* initial value length */
|
||||||
|
16, /* secret length -- 16*8 == 128bit */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_aes128
|
||||||
|
};
|
||||||
|
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
|
||||||
|
"aes192-cbc",
|
||||||
|
"DEK-Info: AES-192-CBC",
|
||||||
|
16, /* blocksize */
|
||||||
|
16, /* initial value length */
|
||||||
|
24, /* secret length -- 24*8 == 192bit */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_aes192
|
||||||
|
};
|
||||||
|
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
|
||||||
|
"aes256-cbc",
|
||||||
|
"DEK-Info: AES-256-CBC",
|
||||||
|
16, /* blocksize */
|
||||||
|
16, /* initial value length */
|
||||||
|
32, /* secret length -- 32*8 == 256bit */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_aes256
|
||||||
|
};
|
||||||
|
|
||||||
|
/* rijndael-cbc@lysator.liu.se == aes256-cbc */
|
||||||
|
static const LIBSSH2_CRYPT_METHOD
|
||||||
|
libssh2_crypt_method_rijndael_cbc_lysator_liu_se = {
|
||||||
|
"rijndael-cbc@lysator.liu.se",
|
||||||
|
"DEK-Info: AES-256-CBC",
|
||||||
|
16, /* blocksize */
|
||||||
|
16, /* initial value length */
|
||||||
|
32, /* secret length -- 32*8 == 256bit */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_aes256
|
||||||
|
};
|
||||||
|
#endif /* LIBSSH2_AES */
|
||||||
|
|
||||||
|
#if LIBSSH2_BLOWFISH
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = {
|
||||||
|
"blowfish-cbc",
|
||||||
|
"",
|
||||||
|
8, /* blocksize */
|
||||||
|
8, /* initial value length */
|
||||||
|
16, /* secret length */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_blowfish
|
||||||
|
};
|
||||||
|
#endif /* LIBSSH2_BLOWFISH */
|
||||||
|
|
||||||
|
#if LIBSSH2_RC4
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
|
||||||
|
"arcfour",
|
||||||
|
"DEK-Info: RC4",
|
||||||
|
8, /* blocksize */
|
||||||
|
8, /* initial value length */
|
||||||
|
16, /* secret length */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_arcfour
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
crypt_init_arcfour128(LIBSSH2_SESSION * session,
|
||||||
|
const LIBSSH2_CRYPT_METHOD * method,
|
||||||
|
unsigned char *iv, int *free_iv,
|
||||||
|
unsigned char *secret, int *free_secret,
|
||||||
|
int encrypt, void **abstract)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = crypt_init(session, method, iv, free_iv, secret, free_secret,
|
||||||
|
encrypt, abstract);
|
||||||
|
if(rc == 0) {
|
||||||
|
struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
|
||||||
|
unsigned char block[8];
|
||||||
|
size_t discard = 1536;
|
||||||
|
for(; discard; discard -= 8)
|
||||||
|
_libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block,
|
||||||
|
method->blocksize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour128 = {
|
||||||
|
"arcfour128",
|
||||||
|
"",
|
||||||
|
8, /* blocksize */
|
||||||
|
8, /* initial value length */
|
||||||
|
16, /* secret length */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init_arcfour128,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_arcfour
|
||||||
|
};
|
||||||
|
#endif /* LIBSSH2_RC4 */
|
||||||
|
|
||||||
|
#if LIBSSH2_CAST
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
|
||||||
|
"cast128-cbc",
|
||||||
|
"",
|
||||||
|
8, /* blocksize */
|
||||||
|
8, /* initial value length */
|
||||||
|
16, /* secret length */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_cast5
|
||||||
|
};
|
||||||
|
#endif /* LIBSSH2_CAST */
|
||||||
|
|
||||||
|
#if LIBSSH2_3DES
|
||||||
|
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
|
||||||
|
"3des-cbc",
|
||||||
|
"DEK-Info: DES-EDE3-CBC",
|
||||||
|
8, /* blocksize */
|
||||||
|
8, /* initial value length */
|
||||||
|
24, /* secret length */
|
||||||
|
0, /* flags */
|
||||||
|
&crypt_init,
|
||||||
|
&crypt_encrypt,
|
||||||
|
&crypt_dtor,
|
||||||
|
_libssh2_cipher_3des
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* These are the crypt methods that are available to be negotiated. Methods
|
||||||
|
towards the start are chosen in preference to ones further down the list. */
|
||||||
|
static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
|
||||||
|
#if LIBSSH2_AES_CTR
|
||||||
|
&libssh2_crypt_method_aes256_ctr,
|
||||||
|
&libssh2_crypt_method_aes192_ctr,
|
||||||
|
&libssh2_crypt_method_aes128_ctr,
|
||||||
|
#endif /* LIBSSH2_AES */
|
||||||
|
#if LIBSSH2_AES
|
||||||
|
&libssh2_crypt_method_aes256_cbc,
|
||||||
|
&libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */
|
||||||
|
&libssh2_crypt_method_aes192_cbc,
|
||||||
|
&libssh2_crypt_method_aes128_cbc,
|
||||||
|
#endif /* LIBSSH2_AES */
|
||||||
|
#if LIBSSH2_BLOWFISH
|
||||||
|
&libssh2_crypt_method_blowfish_cbc,
|
||||||
|
#endif /* LIBSSH2_BLOWFISH */
|
||||||
|
#if LIBSSH2_RC4
|
||||||
|
&libssh2_crypt_method_arcfour128,
|
||||||
|
&libssh2_crypt_method_arcfour,
|
||||||
|
#endif /* LIBSSH2_RC4 */
|
||||||
|
#if LIBSSH2_CAST
|
||||||
|
&libssh2_crypt_method_cast128_cbc,
|
||||||
|
#endif /* LIBSSH2_CAST */
|
||||||
|
#if LIBSSH2_3DES
|
||||||
|
&libssh2_crypt_method_3des_cbc,
|
||||||
|
#endif /* LIBSSH2_DES */
|
||||||
|
#ifdef LIBSSH2_CRYPT_NONE
|
||||||
|
&libssh2_crypt_method_none,
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Expose to kex.c */
|
||||||
|
const LIBSSH2_CRYPT_METHOD **
|
||||||
|
libssh2_crypt_methods(void)
|
||||||
|
{
|
||||||
|
return _libssh2_crypt_methods;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,338 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_CRYPTO_H
|
||||||
|
#define __LIBSSH2_CRYPTO_H
|
||||||
|
/* Copyright (C) 2009, 2010 Simon Josefsson
|
||||||
|
* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2010-2019 Daniel Stenberg
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(LIBSSH2_OPENSSL) || defined(LIBSSH2_WOLFSSL)
|
||||||
|
#include "openssl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIBSSH2_LIBGCRYPT
|
||||||
|
#include "libgcrypt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIBSSH2_WINCNG
|
||||||
|
#include "wincng.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIBSSH2_OS400QC3
|
||||||
|
#include "os400qc3.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LIBSSH2_MBEDTLS
|
||||||
|
#include "mbedtls.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LIBSSH2_ED25519_KEY_LEN 32
|
||||||
|
#define LIBSSH2_ED25519_PRIVATE_KEY_LEN 64
|
||||||
|
#define LIBSSH2_ED25519_SIG_LEN 64
|
||||||
|
|
||||||
|
#if LIBSSH2_RSA
|
||||||
|
int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
|
||||||
|
const unsigned char *edata,
|
||||||
|
unsigned long elen,
|
||||||
|
const unsigned char *ndata,
|
||||||
|
unsigned long nlen,
|
||||||
|
const unsigned char *ddata,
|
||||||
|
unsigned long dlen,
|
||||||
|
const unsigned char *pdata,
|
||||||
|
unsigned long plen,
|
||||||
|
const unsigned char *qdata,
|
||||||
|
unsigned long qlen,
|
||||||
|
const unsigned char *e1data,
|
||||||
|
unsigned long e1len,
|
||||||
|
const unsigned char *e2data,
|
||||||
|
unsigned long e2len,
|
||||||
|
const unsigned char *coeffdata, unsigned long coefflen);
|
||||||
|
int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filename,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
|
||||||
|
const unsigned char *sig,
|
||||||
|
unsigned long sig_len,
|
||||||
|
const unsigned char *m, unsigned long m_len);
|
||||||
|
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||||
|
libssh2_rsa_ctx * rsactx,
|
||||||
|
const unsigned char *hash,
|
||||||
|
size_t hash_len,
|
||||||
|
unsigned char **signature,
|
||||||
|
size_t *signature_len);
|
||||||
|
#if LIBSSH2_RSA_SHA2
|
||||||
|
int _libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session,
|
||||||
|
libssh2_rsa_ctx * rsactx,
|
||||||
|
const unsigned char *hash,
|
||||||
|
size_t hash_len,
|
||||||
|
unsigned char **signature,
|
||||||
|
size_t *signature_len);
|
||||||
|
int _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsa,
|
||||||
|
size_t hash_len,
|
||||||
|
const unsigned char *sig,
|
||||||
|
unsigned long sig_len,
|
||||||
|
const unsigned char *m, unsigned long m_len);
|
||||||
|
#endif
|
||||||
|
int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata,
|
||||||
|
size_t filedata_len,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LIBSSH2_DSA
|
||||||
|
int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
|
||||||
|
const unsigned char *pdata,
|
||||||
|
unsigned long plen,
|
||||||
|
const unsigned char *qdata,
|
||||||
|
unsigned long qlen,
|
||||||
|
const unsigned char *gdata,
|
||||||
|
unsigned long glen,
|
||||||
|
const unsigned char *ydata,
|
||||||
|
unsigned long ylen,
|
||||||
|
const unsigned char *x, unsigned long x_len);
|
||||||
|
int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filename,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
|
||||||
|
const unsigned char *sig,
|
||||||
|
const unsigned char *m, unsigned long m_len);
|
||||||
|
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||||
|
const unsigned char *hash,
|
||||||
|
unsigned long hash_len, unsigned char *sig);
|
||||||
|
int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata,
|
||||||
|
size_t filedata_len,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LIBSSH2_ECDSA
|
||||||
|
int
|
||||||
|
_libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ecdsactx,
|
||||||
|
const unsigned char *k,
|
||||||
|
size_t k_len,
|
||||||
|
libssh2_curve_type type);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filename,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ecdsa_new_private_sk(libssh2_ecdsa_ctx ** ec_ctx,
|
||||||
|
unsigned char *flags,
|
||||||
|
const char **application,
|
||||||
|
const unsigned char **key_handle,
|
||||||
|
size_t *handle_len,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filename,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx,
|
||||||
|
const unsigned char *r, size_t r_len,
|
||||||
|
const unsigned char *s, size_t s_len,
|
||||||
|
const unsigned char *m, size_t m_len);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ecdsa_create_key(LIBSSH2_SESSION *session,
|
||||||
|
_libssh2_ec_key **out_private_key,
|
||||||
|
unsigned char **out_public_key_octal,
|
||||||
|
size_t *out_public_key_octal_len,
|
||||||
|
libssh2_curve_type curve_type);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key,
|
||||||
|
const unsigned char *server_public_key,
|
||||||
|
size_t server_public_key_len);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ecdsa_sign(LIBSSH2_SESSION *session, libssh2_ecdsa_ctx *ec_ctx,
|
||||||
|
const unsigned char *hash, unsigned long hash_len,
|
||||||
|
unsigned char **signature, size_t *signature_len);
|
||||||
|
|
||||||
|
int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata,
|
||||||
|
size_t filedata_len,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
|
||||||
|
int _libssh2_ecdsa_new_private_frommemory_sk(libssh2_ecdsa_ctx ** ec_ctx,
|
||||||
|
unsigned char *flags,
|
||||||
|
const char **application,
|
||||||
|
const unsigned char **key_handle,
|
||||||
|
size_t *handle_len,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata,
|
||||||
|
size_t filedata_len,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
|
||||||
|
libssh2_curve_type
|
||||||
|
_libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ecdsa_curve_type_from_name(const char *name,
|
||||||
|
libssh2_curve_type *out_type);
|
||||||
|
|
||||||
|
#endif /* LIBSSH2_ECDSA */
|
||||||
|
|
||||||
|
#if LIBSSH2_ED25519
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_curve25519_new(LIBSSH2_SESSION *session, uint8_t **out_public_key,
|
||||||
|
uint8_t **out_private_key);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_curve25519_gen_k(_libssh2_bn **k,
|
||||||
|
uint8_t private_key[LIBSSH2_ED25519_KEY_LEN],
|
||||||
|
uint8_t server_public_key[LIBSSH2_ED25519_KEY_LEN]);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s,
|
||||||
|
size_t s_len, const uint8_t *m, size_t m_len);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ed25519_new_private(libssh2_ed25519_ctx **ed_ctx,
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
const char *filename, const uint8_t *passphrase);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ed25519_new_private_sk(libssh2_ed25519_ctx **ed_ctx,
|
||||||
|
unsigned char *flags,
|
||||||
|
const char **application,
|
||||||
|
const unsigned char **key_handle,
|
||||||
|
size_t *handle_len,
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
const char *filename,
|
||||||
|
const uint8_t *passphrase);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ed25519_new_public(libssh2_ed25519_ctx **ed_ctx,
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
const unsigned char *raw_pub_key,
|
||||||
|
const uint8_t key_len);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session,
|
||||||
|
uint8_t **out_sig, size_t *out_sig_len,
|
||||||
|
const uint8_t *message, size_t message_len);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx **ed_ctx,
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
const char *filedata,
|
||||||
|
size_t filedata_len,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_ed25519_new_private_frommemory_sk(libssh2_ed25519_ctx **ed_ctx,
|
||||||
|
unsigned char *flags,
|
||||||
|
const char **application,
|
||||||
|
const unsigned char **key_handle,
|
||||||
|
size_t *handle_len,
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
const char *filedata,
|
||||||
|
size_t filedata_len,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
|
||||||
|
#endif /* LIBSSH2_ED25519 */
|
||||||
|
|
||||||
|
|
||||||
|
int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
|
||||||
|
_libssh2_cipher_type(algo),
|
||||||
|
unsigned char *iv,
|
||||||
|
unsigned char *secret, int encrypt);
|
||||||
|
|
||||||
|
int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||||
|
_libssh2_cipher_type(algo),
|
||||||
|
int encrypt, unsigned char *block, size_t blocksize);
|
||||||
|
|
||||||
|
int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
const char *privatekey,
|
||||||
|
const char *passphrase);
|
||||||
|
|
||||||
|
int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
const char *privatekeydata,
|
||||||
|
size_t privatekeydata_len,
|
||||||
|
const char *passphrase);
|
||||||
|
|
||||||
|
|
||||||
|
int _libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
int *algorithm,
|
||||||
|
unsigned char *flags,
|
||||||
|
const char **application,
|
||||||
|
const unsigned char **key_handle,
|
||||||
|
size_t *handle_len,
|
||||||
|
const char *privatekeydata,
|
||||||
|
size_t privatekeydata_len,
|
||||||
|
const char *passphrase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function _libssh2_supported_key_sign_algorithms
|
||||||
|
* @abstract Returns supported algorithms used for upgrading public
|
||||||
|
* key signing RFC 8332
|
||||||
|
* @discussion Based on the incoming key_method value, this function
|
||||||
|
* will return supported algorithms that can upgrade the key method
|
||||||
|
* @related _libssh2_key_sign_algorithm()
|
||||||
|
* @param key_method current key method, usually the default key sig method
|
||||||
|
* @param key_method_len length of the key method buffer
|
||||||
|
* @result comma seperated list of supported upgrade options per RFC 8332, if
|
||||||
|
* there is no upgrade option return NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *
|
||||||
|
_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char *key_method,
|
||||||
|
size_t key_method_len);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_CRYPTO_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,80 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2010 Lars Nordin <Lars.Nordin@SDlabs.se>
|
||||||
|
* Copyright (C) 2010 Simon Josefsson <simon@josefsson.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
|
||||||
|
static int _libssh2_initialized = 0;
|
||||||
|
static int _libssh2_init_flags = 0;
|
||||||
|
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_init(int flags)
|
||||||
|
{
|
||||||
|
if(_libssh2_initialized == 0 && !(flags & LIBSSH2_INIT_NO_CRYPTO)) {
|
||||||
|
libssh2_crypto_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
_libssh2_initialized++;
|
||||||
|
_libssh2_init_flags |= flags;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBSSH2_API void
|
||||||
|
libssh2_exit(void)
|
||||||
|
{
|
||||||
|
if(_libssh2_initialized == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_libssh2_initialized--;
|
||||||
|
|
||||||
|
if(_libssh2_initialized == 0 &&
|
||||||
|
!(_libssh2_init_flags & LIBSSH2_INIT_NO_CRYPTO)) {
|
||||||
|
libssh2_crypto_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_libssh2_init_if_needed(void)
|
||||||
|
{
|
||||||
|
if(_libssh2_initialized == 0)
|
||||||
|
(void)libssh2_init (0);
|
||||||
|
}
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,102 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (C) 2010 Simon Josefsson
|
||||||
|
* Author: Simon Josefsson
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include "transport.h" /* _libssh2_transport_write */
|
||||||
|
|
||||||
|
/* Keep-alive stuff. */
|
||||||
|
|
||||||
|
LIBSSH2_API void
|
||||||
|
libssh2_keepalive_config (LIBSSH2_SESSION *session,
|
||||||
|
int want_reply,
|
||||||
|
unsigned interval)
|
||||||
|
{
|
||||||
|
if(interval == 1)
|
||||||
|
session->keepalive_interval = 2;
|
||||||
|
else
|
||||||
|
session->keepalive_interval = interval;
|
||||||
|
session->keepalive_want_reply = want_reply ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_keepalive_send (LIBSSH2_SESSION *session,
|
||||||
|
int *seconds_to_next)
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
if(!session->keepalive_interval) {
|
||||||
|
if(seconds_to_next)
|
||||||
|
*seconds_to_next = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
|
||||||
|
if(session->keepalive_last_sent + session->keepalive_interval <= now) {
|
||||||
|
/* Format is
|
||||||
|
"SSH_MSG_GLOBAL_REQUEST || 4-byte len || str || want-reply". */
|
||||||
|
unsigned char keepalive_data[]
|
||||||
|
= "\x50\x00\x00\x00\x15keepalive@libssh2.orgW";
|
||||||
|
size_t len = sizeof(keepalive_data) - 1;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
keepalive_data[len - 1] =
|
||||||
|
(unsigned char)session->keepalive_want_reply;
|
||||||
|
|
||||||
|
rc = _libssh2_transport_send(session, keepalive_data, len, NULL, 0);
|
||||||
|
/* Silently ignore PACKET_EAGAIN here: if the write buffer is
|
||||||
|
already full, sending another keepalive is not useful. */
|
||||||
|
if(rc && rc != LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||||
|
"Unable to send keepalive message");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->keepalive_last_sent = now;
|
||||||
|
if(seconds_to_next)
|
||||||
|
*seconds_to_next = session->keepalive_interval;
|
||||||
|
}
|
||||||
|
else if(seconds_to_next) {
|
||||||
|
*seconds_to_next = (int) (session->keepalive_last_sent - now)
|
||||||
|
+ session->keepalive_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,240 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_LIBGCRYPT_H
|
||||||
|
#define __LIBSSH2_LIBGCRYPT_H
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2008, 2009, 2010 Simon Josefsson
|
||||||
|
* Copyright (C) 2006, 2007, The Written Word, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gcrypt.h>
|
||||||
|
|
||||||
|
#define LIBSSH2_MD5 1
|
||||||
|
|
||||||
|
#define LIBSSH2_HMAC_RIPEMD 1
|
||||||
|
#define LIBSSH2_HMAC_SHA256 1
|
||||||
|
#define LIBSSH2_HMAC_SHA512 1
|
||||||
|
|
||||||
|
#define LIBSSH2_AES 1
|
||||||
|
#define LIBSSH2_AES_CTR 1
|
||||||
|
#define LIBSSH2_BLOWFISH 1
|
||||||
|
#define LIBSSH2_RC4 1
|
||||||
|
#define LIBSSH2_CAST 1
|
||||||
|
#define LIBSSH2_3DES 1
|
||||||
|
|
||||||
|
#define LIBSSH2_RSA 1
|
||||||
|
#define LIBSSH2_RSA_SHA2 0
|
||||||
|
#define LIBSSH2_DSA 1
|
||||||
|
#define LIBSSH2_ECDSA 0
|
||||||
|
#define LIBSSH2_ED25519 0
|
||||||
|
|
||||||
|
#define MD5_DIGEST_LENGTH 16
|
||||||
|
#define SHA_DIGEST_LENGTH 20
|
||||||
|
#define SHA256_DIGEST_LENGTH 32
|
||||||
|
#define SHA384_DIGEST_LENGTH 48
|
||||||
|
#define SHA512_DIGEST_LENGTH 64
|
||||||
|
|
||||||
|
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
|
||||||
|
|
||||||
|
#define _libssh2_random(buf, len) \
|
||||||
|
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 0)
|
||||||
|
|
||||||
|
#define libssh2_prepare_iovec(vec, len) /* Empty. */
|
||||||
|
|
||||||
|
#define libssh2_sha1_ctx gcry_md_hd_t
|
||||||
|
|
||||||
|
/* returns 0 in case of failure */
|
||||||
|
#define libssh2_sha1_init(ctx) \
|
||||||
|
(GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA1, 0))
|
||||||
|
#define libssh2_sha1_update(ctx, data, len) \
|
||||||
|
gcry_md_write(ctx, (unsigned char *) data, len)
|
||||||
|
#define libssh2_sha1_final(ctx, out) \
|
||||||
|
memcpy(out, gcry_md_read(ctx, 0), SHA_DIGEST_LENGTH), gcry_md_close(ctx)
|
||||||
|
#define libssh2_sha1(message, len, out) \
|
||||||
|
gcry_md_hash_buffer(GCRY_MD_SHA1, out, message, len)
|
||||||
|
|
||||||
|
#define libssh2_sha256_ctx gcry_md_hd_t
|
||||||
|
|
||||||
|
#define libssh2_sha256_init(ctx) \
|
||||||
|
(GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA256, 0))
|
||||||
|
#define libssh2_sha256_update(ctx, data, len) \
|
||||||
|
gcry_md_write(ctx, (unsigned char *) data, len)
|
||||||
|
#define libssh2_sha256_final(ctx, out) \
|
||||||
|
memcpy(out, gcry_md_read(ctx, 0), SHA256_DIGEST_LENGTH), gcry_md_close(ctx)
|
||||||
|
#define libssh2_sha256(message, len, out) \
|
||||||
|
gcry_md_hash_buffer(GCRY_MD_SHA256, out, message, len)
|
||||||
|
|
||||||
|
#define libssh2_sha384_ctx gcry_md_hd_t
|
||||||
|
|
||||||
|
#define libssh2_sha384_init(ctx) \
|
||||||
|
(GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA384, 0))
|
||||||
|
#define libssh2_sha384_update(ctx, data, len) \
|
||||||
|
gcry_md_write(ctx, (unsigned char *) data, len)
|
||||||
|
#define libssh2_sha384_final(ctx, out) \
|
||||||
|
memcpy(out, gcry_md_read(ctx, 0), SHA384_DIGEST_LENGTH), gcry_md_close(ctx)
|
||||||
|
#define libssh2_sha384(message, len, out) \
|
||||||
|
gcry_md_hash_buffer(GCRY_MD_SHA384, out, message, len)
|
||||||
|
|
||||||
|
#define libssh2_sha512_ctx gcry_md_hd_t
|
||||||
|
|
||||||
|
#define libssh2_sha512_init(ctx) \
|
||||||
|
(GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA512, 0))
|
||||||
|
#define libssh2_sha512_update(ctx, data, len) \
|
||||||
|
gcry_md_write(ctx, (unsigned char *) data, len)
|
||||||
|
#define libssh2_sha512_final(ctx, out) \
|
||||||
|
memcpy(out, gcry_md_read(ctx, 0), SHA512_DIGEST_LENGTH), gcry_md_close(ctx)
|
||||||
|
#define libssh2_sha512(message, len, out) \
|
||||||
|
gcry_md_hash_buffer(GCRY_MD_SHA512, out, message, len)
|
||||||
|
|
||||||
|
#define libssh2_md5_ctx gcry_md_hd_t
|
||||||
|
|
||||||
|
/* returns 0 in case of failure */
|
||||||
|
#define libssh2_md5_init(ctx) \
|
||||||
|
(GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_MD5, 0))
|
||||||
|
|
||||||
|
#define libssh2_md5_update(ctx, data, len) \
|
||||||
|
gcry_md_write(ctx, (unsigned char *) data, len)
|
||||||
|
#define libssh2_md5_final(ctx, out) \
|
||||||
|
memcpy(out, gcry_md_read(ctx, 0), MD5_DIGEST_LENGTH), gcry_md_close(ctx)
|
||||||
|
#define libssh2_md5(message, len, out) \
|
||||||
|
gcry_md_hash_buffer(GCRY_MD_MD5, out, message, len)
|
||||||
|
|
||||||
|
#define libssh2_hmac_ctx gcry_md_hd_t
|
||||||
|
#define libssh2_hmac_ctx_init(ctx)
|
||||||
|
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
|
||||||
|
gcry_md_open(ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \
|
||||||
|
gcry_md_setkey(*ctx, key, keylen)
|
||||||
|
#define libssh2_hmac_md5_init(ctx, key, keylen) \
|
||||||
|
gcry_md_open(ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \
|
||||||
|
gcry_md_setkey(*ctx, key, keylen)
|
||||||
|
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
|
||||||
|
gcry_md_open(ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \
|
||||||
|
gcry_md_setkey(*ctx, key, keylen)
|
||||||
|
#define libssh2_hmac_sha256_init(ctx, key, keylen) \
|
||||||
|
gcry_md_open(ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC), \
|
||||||
|
gcry_md_setkey(*ctx, key, keylen)
|
||||||
|
#define libssh2_hmac_sha512_init(ctx, key, keylen) \
|
||||||
|
gcry_md_open(ctx, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC), \
|
||||||
|
gcry_md_setkey(*ctx, key, keylen)
|
||||||
|
#define libssh2_hmac_update(ctx, data, datalen) \
|
||||||
|
gcry_md_write(ctx, (unsigned char *) data, datalen)
|
||||||
|
#define libssh2_hmac_final(ctx, data) \
|
||||||
|
memcpy(data, gcry_md_read(ctx, 0), \
|
||||||
|
gcry_md_get_algo_dlen(gcry_md_get_algo(ctx)))
|
||||||
|
#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx);
|
||||||
|
|
||||||
|
#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM)
|
||||||
|
#define libssh2_crypto_exit()
|
||||||
|
|
||||||
|
#define libssh2_rsa_ctx struct gcry_sexp
|
||||||
|
|
||||||
|
#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx)
|
||||||
|
|
||||||
|
#define libssh2_dsa_ctx struct gcry_sexp
|
||||||
|
|
||||||
|
#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx)
|
||||||
|
|
||||||
|
#if LIBSSH2_ECDSA
|
||||||
|
#else
|
||||||
|
#define _libssh2_ec_key void
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _libssh2_cipher_type(name) int name
|
||||||
|
#define _libssh2_cipher_ctx gcry_cipher_hd_t
|
||||||
|
|
||||||
|
#define _libssh2_gcry_ciphermode(c,m) ((c << 8) | m)
|
||||||
|
#define _libssh2_gcry_cipher(c) (c >> 8)
|
||||||
|
#define _libssh2_gcry_mode(m) (m & 0xFF)
|
||||||
|
|
||||||
|
#define _libssh2_cipher_aes256ctr \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR)
|
||||||
|
#define _libssh2_cipher_aes192ctr \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR)
|
||||||
|
#define _libssh2_cipher_aes128ctr \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR)
|
||||||
|
#define _libssh2_cipher_aes256 \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC)
|
||||||
|
#define _libssh2_cipher_aes192 \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC)
|
||||||
|
#define _libssh2_cipher_aes128 \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC)
|
||||||
|
#define _libssh2_cipher_blowfish \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC)
|
||||||
|
#define _libssh2_cipher_arcfour \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM)
|
||||||
|
#define _libssh2_cipher_cast5 \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC)
|
||||||
|
#define _libssh2_cipher_3des \
|
||||||
|
_libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC)
|
||||||
|
|
||||||
|
|
||||||
|
#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx))
|
||||||
|
|
||||||
|
#define _libssh2_bn struct gcry_mpi
|
||||||
|
#define _libssh2_bn_ctx int
|
||||||
|
#define _libssh2_bn_ctx_new() 0
|
||||||
|
#define _libssh2_bn_ctx_free(bnctx) ((void)0)
|
||||||
|
#define _libssh2_bn_init() gcry_mpi_new(0)
|
||||||
|
#define _libssh2_bn_init_from_bin() NULL /* because gcry_mpi_scan() creates a
|
||||||
|
new bignum */
|
||||||
|
#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val)
|
||||||
|
#define _libssh2_bn_from_bin(bn, len, val) \
|
||||||
|
gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL)
|
||||||
|
#define _libssh2_bn_to_bin(bn, val) \
|
||||||
|
gcry_mpi_print(GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn)
|
||||||
|
#define _libssh2_bn_bytes(bn) \
|
||||||
|
(gcry_mpi_get_nbits (bn) / 8 + \
|
||||||
|
((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
|
||||||
|
#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
|
||||||
|
#define _libssh2_bn_free(bn) gcry_mpi_release(bn)
|
||||||
|
|
||||||
|
#define _libssh2_dh_ctx struct gcry_mpi *
|
||||||
|
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
|
||||||
|
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
|
||||||
|
_libssh2_dh_key_pair(dhctx, public, g, p, group_order)
|
||||||
|
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
|
||||||
|
_libssh2_dh_secret(dhctx, secret, f, p)
|
||||||
|
#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx)
|
||||||
|
extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx);
|
||||||
|
extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
|
||||||
|
_libssh2_bn *g, _libssh2_bn *p,
|
||||||
|
int group_order);
|
||||||
|
extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
|
||||||
|
_libssh2_bn *f, _libssh2_bn *p);
|
||||||
|
extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_LIBGCRYPT_H */
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,75 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2014 Alexander Lamaison <alexander.lamaison@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Headers */
|
||||||
|
#define LIBSSH2_MBEDTLS
|
||||||
|
#define HAVE_O_NONBLOCK
|
||||||
|
#define HAVE_UNISTD_H
|
||||||
|
#define HAVE_INTTYPES_H
|
||||||
|
#define HAVE_STDLIB_H
|
||||||
|
#define HAVE_SYS_SELECT_H
|
||||||
|
#define HAVE_SYS_SOCKET_H
|
||||||
|
#define HAVE_SYS_TIME_H
|
||||||
|
#define HAVE_ARPA_INET_H
|
||||||
|
#define HAVE_NETINET_IN_H
|
||||||
|
|
||||||
|
/* Functions */
|
||||||
|
#define HAVE_STRCASECMP
|
||||||
|
#define HAVE__STRICMP
|
||||||
|
#define HAVE_SNPRINTF
|
||||||
|
#define HAVE__SNPRINTF
|
||||||
|
|
||||||
|
/* Workaround for platforms without POSIX strcasecmp (e.g. Windows) */
|
||||||
|
#ifndef HAVE_STRCASECMP
|
||||||
|
# ifdef HAVE__STRICMP
|
||||||
|
# define strcasecmp _stricmp
|
||||||
|
# define HAVE_STRCASECMP
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Symbols */
|
||||||
|
#define HAVE___FUNC__
|
||||||
|
#define HAVE___FUNCTION__
|
||||||
|
|
||||||
|
/* Workaround for platforms without C90 __func__ */
|
||||||
|
#ifndef HAVE___FUNC__
|
||||||
|
# ifdef HAVE___FUNCTION__
|
||||||
|
# define __func__ __FUNCTION__
|
||||||
|
# define HAVE___FUNC__
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,124 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Note: This include file is only needed for using the
|
||||||
|
* publickey SUBSYSTEM which is not the same as publickey
|
||||||
|
* authentication. For authentication you only need libssh2.h
|
||||||
|
*
|
||||||
|
* For more information on the publickey subsystem,
|
||||||
|
* refer to IETF draft: secsh-publickey
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBSSH2_PUBLICKEY_H
|
||||||
|
#define LIBSSH2_PUBLICKEY_H 1
|
||||||
|
|
||||||
|
#include "libssh2.h"
|
||||||
|
|
||||||
|
typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY;
|
||||||
|
|
||||||
|
typedef struct _libssh2_publickey_attribute {
|
||||||
|
const char *name;
|
||||||
|
unsigned long name_len;
|
||||||
|
const char *value;
|
||||||
|
unsigned long value_len;
|
||||||
|
char mandatory;
|
||||||
|
} libssh2_publickey_attribute;
|
||||||
|
|
||||||
|
typedef struct _libssh2_publickey_list {
|
||||||
|
unsigned char *packet; /* For freeing */
|
||||||
|
|
||||||
|
const unsigned char *name;
|
||||||
|
unsigned long name_len;
|
||||||
|
const unsigned char *blob;
|
||||||
|
unsigned long blob_len;
|
||||||
|
unsigned long num_attrs;
|
||||||
|
libssh2_publickey_attribute *attrs; /* free me */
|
||||||
|
} libssh2_publickey_list;
|
||||||
|
|
||||||
|
/* Generally use the first macro here, but if both name and value are string
|
||||||
|
literals, you can use _fast() to take advantage of preprocessing */
|
||||||
|
#define libssh2_publickey_attribute(name, value, mandatory) \
|
||||||
|
{ (name), strlen(name), (value), strlen(value), (mandatory) },
|
||||||
|
#define libssh2_publickey_attribute_fast(name, value, mandatory) \
|
||||||
|
{ (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) },
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Publickey Subsystem */
|
||||||
|
LIBSSH2_API LIBSSH2_PUBLICKEY *
|
||||||
|
libssh2_publickey_init(LIBSSH2_SESSION *session);
|
||||||
|
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey,
|
||||||
|
const unsigned char *name,
|
||||||
|
unsigned long name_len,
|
||||||
|
const unsigned char *blob,
|
||||||
|
unsigned long blob_len, char overwrite,
|
||||||
|
unsigned long num_attrs,
|
||||||
|
const libssh2_publickey_attribute attrs[]);
|
||||||
|
#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \
|
||||||
|
num_attrs, attrs) \
|
||||||
|
libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), \
|
||||||
|
(overwrite), (num_attrs), (attrs))
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey,
|
||||||
|
const unsigned char *name,
|
||||||
|
unsigned long name_len,
|
||||||
|
const unsigned char *blob,
|
||||||
|
unsigned long blob_len);
|
||||||
|
#define libssh2_publickey_remove(pkey, name, blob, blob_len) \
|
||||||
|
libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len))
|
||||||
|
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey,
|
||||||
|
unsigned long *num_keys,
|
||||||
|
libssh2_publickey_list **pkey_list);
|
||||||
|
LIBSSH2_API void
|
||||||
|
libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey,
|
||||||
|
libssh2_publickey_list *pkey_list);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ifndef: LIBSSH2_PUBLICKEY_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,353 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBSSH2_SFTP_H
|
||||||
|
#define LIBSSH2_SFTP_H 1
|
||||||
|
|
||||||
|
#include "libssh2.h"
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Note: Version 6 was documented at the time of writing
|
||||||
|
* However it was marked as "DO NOT IMPLEMENT" due to pending changes
|
||||||
|
*
|
||||||
|
* Let's start with Version 3 (The version found in OpenSSH) and go from there
|
||||||
|
*/
|
||||||
|
#define LIBSSH2_SFTP_VERSION 3
|
||||||
|
|
||||||
|
typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP;
|
||||||
|
typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE;
|
||||||
|
typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES;
|
||||||
|
typedef struct _LIBSSH2_SFTP_STATVFS LIBSSH2_SFTP_STATVFS;
|
||||||
|
|
||||||
|
/* Flags for open_ex() */
|
||||||
|
#define LIBSSH2_SFTP_OPENFILE 0
|
||||||
|
#define LIBSSH2_SFTP_OPENDIR 1
|
||||||
|
|
||||||
|
/* Flags for rename_ex() */
|
||||||
|
#define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001
|
||||||
|
#define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002
|
||||||
|
#define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004
|
||||||
|
|
||||||
|
/* Flags for stat_ex() */
|
||||||
|
#define LIBSSH2_SFTP_STAT 0
|
||||||
|
#define LIBSSH2_SFTP_LSTAT 1
|
||||||
|
#define LIBSSH2_SFTP_SETSTAT 2
|
||||||
|
|
||||||
|
/* Flags for symlink_ex() */
|
||||||
|
#define LIBSSH2_SFTP_SYMLINK 0
|
||||||
|
#define LIBSSH2_SFTP_READLINK 1
|
||||||
|
#define LIBSSH2_SFTP_REALPATH 2
|
||||||
|
|
||||||
|
/* Flags for sftp_mkdir() */
|
||||||
|
#define LIBSSH2_SFTP_DEFAULT_MODE -1
|
||||||
|
|
||||||
|
/* SFTP attribute flag bits */
|
||||||
|
#define LIBSSH2_SFTP_ATTR_SIZE 0x00000001
|
||||||
|
#define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002
|
||||||
|
#define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004
|
||||||
|
#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008
|
||||||
|
#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000
|
||||||
|
|
||||||
|
/* SFTP statvfs flag bits */
|
||||||
|
#define LIBSSH2_SFTP_ST_RDONLY 0x00000001
|
||||||
|
#define LIBSSH2_SFTP_ST_NOSUID 0x00000002
|
||||||
|
|
||||||
|
struct _LIBSSH2_SFTP_ATTRIBUTES {
|
||||||
|
/* If flags & ATTR_* bit is set, then the value in this struct will be
|
||||||
|
* meaningful Otherwise it should be ignored
|
||||||
|
*/
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
libssh2_uint64_t filesize;
|
||||||
|
unsigned long uid, gid;
|
||||||
|
unsigned long permissions;
|
||||||
|
unsigned long atime, mtime;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _LIBSSH2_SFTP_STATVFS {
|
||||||
|
libssh2_uint64_t f_bsize; /* file system block size */
|
||||||
|
libssh2_uint64_t f_frsize; /* fragment size */
|
||||||
|
libssh2_uint64_t f_blocks; /* size of fs in f_frsize units */
|
||||||
|
libssh2_uint64_t f_bfree; /* # free blocks */
|
||||||
|
libssh2_uint64_t f_bavail; /* # free blocks for non-root */
|
||||||
|
libssh2_uint64_t f_files; /* # inodes */
|
||||||
|
libssh2_uint64_t f_ffree; /* # free inodes */
|
||||||
|
libssh2_uint64_t f_favail; /* # free inodes for non-root */
|
||||||
|
libssh2_uint64_t f_fsid; /* file system ID */
|
||||||
|
libssh2_uint64_t f_flag; /* mount flags */
|
||||||
|
libssh2_uint64_t f_namemax; /* maximum filename length */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SFTP filetypes */
|
||||||
|
#define LIBSSH2_SFTP_TYPE_REGULAR 1
|
||||||
|
#define LIBSSH2_SFTP_TYPE_DIRECTORY 2
|
||||||
|
#define LIBSSH2_SFTP_TYPE_SYMLINK 3
|
||||||
|
#define LIBSSH2_SFTP_TYPE_SPECIAL 4
|
||||||
|
#define LIBSSH2_SFTP_TYPE_UNKNOWN 5
|
||||||
|
#define LIBSSH2_SFTP_TYPE_SOCKET 6
|
||||||
|
#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7
|
||||||
|
#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8
|
||||||
|
#define LIBSSH2_SFTP_TYPE_FIFO 9
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reproduce the POSIX file modes here for systems that are not POSIX
|
||||||
|
* compliant.
|
||||||
|
*
|
||||||
|
* These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES"
|
||||||
|
*/
|
||||||
|
/* File type */
|
||||||
|
#define LIBSSH2_SFTP_S_IFMT 0170000 /* type of file mask */
|
||||||
|
#define LIBSSH2_SFTP_S_IFIFO 0010000 /* named pipe (fifo) */
|
||||||
|
#define LIBSSH2_SFTP_S_IFCHR 0020000 /* character special */
|
||||||
|
#define LIBSSH2_SFTP_S_IFDIR 0040000 /* directory */
|
||||||
|
#define LIBSSH2_SFTP_S_IFBLK 0060000 /* block special */
|
||||||
|
#define LIBSSH2_SFTP_S_IFREG 0100000 /* regular */
|
||||||
|
#define LIBSSH2_SFTP_S_IFLNK 0120000 /* symbolic link */
|
||||||
|
#define LIBSSH2_SFTP_S_IFSOCK 0140000 /* socket */
|
||||||
|
|
||||||
|
/* File mode */
|
||||||
|
/* Read, write, execute/search by owner */
|
||||||
|
#define LIBSSH2_SFTP_S_IRWXU 0000700 /* RWX mask for owner */
|
||||||
|
#define LIBSSH2_SFTP_S_IRUSR 0000400 /* R for owner */
|
||||||
|
#define LIBSSH2_SFTP_S_IWUSR 0000200 /* W for owner */
|
||||||
|
#define LIBSSH2_SFTP_S_IXUSR 0000100 /* X for owner */
|
||||||
|
/* Read, write, execute/search by group */
|
||||||
|
#define LIBSSH2_SFTP_S_IRWXG 0000070 /* RWX mask for group */
|
||||||
|
#define LIBSSH2_SFTP_S_IRGRP 0000040 /* R for group */
|
||||||
|
#define LIBSSH2_SFTP_S_IWGRP 0000020 /* W for group */
|
||||||
|
#define LIBSSH2_SFTP_S_IXGRP 0000010 /* X for group */
|
||||||
|
/* Read, write, execute/search by others */
|
||||||
|
#define LIBSSH2_SFTP_S_IRWXO 0000007 /* RWX mask for other */
|
||||||
|
#define LIBSSH2_SFTP_S_IROTH 0000004 /* R for other */
|
||||||
|
#define LIBSSH2_SFTP_S_IWOTH 0000002 /* W for other */
|
||||||
|
#define LIBSSH2_SFTP_S_IXOTH 0000001 /* X for other */
|
||||||
|
|
||||||
|
/* macros to check for specific file types, added in 1.2.5 */
|
||||||
|
#define LIBSSH2_SFTP_S_ISLNK(m) \
|
||||||
|
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK)
|
||||||
|
#define LIBSSH2_SFTP_S_ISREG(m) \
|
||||||
|
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG)
|
||||||
|
#define LIBSSH2_SFTP_S_ISDIR(m) \
|
||||||
|
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR)
|
||||||
|
#define LIBSSH2_SFTP_S_ISCHR(m) \
|
||||||
|
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR)
|
||||||
|
#define LIBSSH2_SFTP_S_ISBLK(m) \
|
||||||
|
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK)
|
||||||
|
#define LIBSSH2_SFTP_S_ISFIFO(m) \
|
||||||
|
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO)
|
||||||
|
#define LIBSSH2_SFTP_S_ISSOCK(m) \
|
||||||
|
(((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK)
|
||||||
|
|
||||||
|
/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open())
|
||||||
|
* Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */
|
||||||
|
#define LIBSSH2_FXF_READ 0x00000001
|
||||||
|
#define LIBSSH2_FXF_WRITE 0x00000002
|
||||||
|
#define LIBSSH2_FXF_APPEND 0x00000004
|
||||||
|
#define LIBSSH2_FXF_CREAT 0x00000008
|
||||||
|
#define LIBSSH2_FXF_TRUNC 0x00000010
|
||||||
|
#define LIBSSH2_FXF_EXCL 0x00000020
|
||||||
|
|
||||||
|
/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */
|
||||||
|
#define LIBSSH2_FX_OK 0UL
|
||||||
|
#define LIBSSH2_FX_EOF 1UL
|
||||||
|
#define LIBSSH2_FX_NO_SUCH_FILE 2UL
|
||||||
|
#define LIBSSH2_FX_PERMISSION_DENIED 3UL
|
||||||
|
#define LIBSSH2_FX_FAILURE 4UL
|
||||||
|
#define LIBSSH2_FX_BAD_MESSAGE 5UL
|
||||||
|
#define LIBSSH2_FX_NO_CONNECTION 6UL
|
||||||
|
#define LIBSSH2_FX_CONNECTION_LOST 7UL
|
||||||
|
#define LIBSSH2_FX_OP_UNSUPPORTED 8UL
|
||||||
|
#define LIBSSH2_FX_INVALID_HANDLE 9UL
|
||||||
|
#define LIBSSH2_FX_NO_SUCH_PATH 10UL
|
||||||
|
#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11UL
|
||||||
|
#define LIBSSH2_FX_WRITE_PROTECT 12UL
|
||||||
|
#define LIBSSH2_FX_NO_MEDIA 13UL
|
||||||
|
#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14UL
|
||||||
|
#define LIBSSH2_FX_QUOTA_EXCEEDED 15UL
|
||||||
|
#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16UL /* Initial mis-spelling */
|
||||||
|
#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16UL
|
||||||
|
#define LIBSSH2_FX_LOCK_CONFlICT 17UL /* Initial mis-spelling */
|
||||||
|
#define LIBSSH2_FX_LOCK_CONFLICT 17UL
|
||||||
|
#define LIBSSH2_FX_DIR_NOT_EMPTY 18UL
|
||||||
|
#define LIBSSH2_FX_NOT_A_DIRECTORY 19UL
|
||||||
|
#define LIBSSH2_FX_INVALID_FILENAME 20UL
|
||||||
|
#define LIBSSH2_FX_LINK_LOOP 21UL
|
||||||
|
|
||||||
|
/* Returned by any function that would block during a read/write operation */
|
||||||
|
#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN
|
||||||
|
|
||||||
|
/* SFTP API */
|
||||||
|
LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
|
||||||
|
LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
|
||||||
|
LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
|
||||||
|
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp);
|
||||||
|
|
||||||
|
/* File / Directory Ops */
|
||||||
|
LIBSSH2_API LIBSSH2_SFTP_HANDLE *
|
||||||
|
libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *filename,
|
||||||
|
unsigned int filename_len,
|
||||||
|
unsigned long flags,
|
||||||
|
long mode, int open_type);
|
||||||
|
#define libssh2_sftp_open(sftp, filename, flags, mode) \
|
||||||
|
libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), \
|
||||||
|
(mode), LIBSSH2_SFTP_OPENFILE)
|
||||||
|
#define libssh2_sftp_opendir(sftp, path) \
|
||||||
|
libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, \
|
||||||
|
LIBSSH2_SFTP_OPENDIR)
|
||||||
|
|
||||||
|
LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle,
|
||||||
|
char *buffer, size_t buffer_maxlen);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \
|
||||||
|
char *buffer, size_t buffer_maxlen,
|
||||||
|
char *longentry,
|
||||||
|
size_t longentry_maxlen,
|
||||||
|
LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||||
|
#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \
|
||||||
|
libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, \
|
||||||
|
(attrs))
|
||||||
|
|
||||||
|
LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
|
||||||
|
const char *buffer, size_t count);
|
||||||
|
LIBSSH2_API int libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
|
||||||
|
#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
|
||||||
|
#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle)
|
||||||
|
|
||||||
|
LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
|
||||||
|
LIBSSH2_API void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle,
|
||||||
|
libssh2_uint64_t offset);
|
||||||
|
#define libssh2_sftp_rewind(handle) libssh2_sftp_seek64((handle), 0)
|
||||||
|
|
||||||
|
LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle);
|
||||||
|
LIBSSH2_API libssh2_uint64_t libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle,
|
||||||
|
LIBSSH2_SFTP_ATTRIBUTES *attrs,
|
||||||
|
int setstat);
|
||||||
|
#define libssh2_sftp_fstat(handle, attrs) \
|
||||||
|
libssh2_sftp_fstat_ex((handle), (attrs), 0)
|
||||||
|
#define libssh2_sftp_fsetstat(handle, attrs) \
|
||||||
|
libssh2_sftp_fstat_ex((handle), (attrs), 1)
|
||||||
|
|
||||||
|
/* Miscellaneous Ops */
|
||||||
|
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *source_filename,
|
||||||
|
unsigned int srouce_filename_len,
|
||||||
|
const char *dest_filename,
|
||||||
|
unsigned int dest_filename_len,
|
||||||
|
long flags);
|
||||||
|
#define libssh2_sftp_rename(sftp, sourcefile, destfile) \
|
||||||
|
libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \
|
||||||
|
(destfile), strlen(destfile), \
|
||||||
|
LIBSSH2_SFTP_RENAME_OVERWRITE | \
|
||||||
|
LIBSSH2_SFTP_RENAME_ATOMIC | \
|
||||||
|
LIBSSH2_SFTP_RENAME_NATIVE)
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *filename,
|
||||||
|
unsigned int filename_len);
|
||||||
|
#define libssh2_sftp_unlink(sftp, filename) \
|
||||||
|
libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle,
|
||||||
|
LIBSSH2_SFTP_STATVFS *st);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
size_t path_len,
|
||||||
|
LIBSSH2_SFTP_STATVFS *st);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
unsigned int path_len, long mode);
|
||||||
|
#define libssh2_sftp_mkdir(sftp, path, mode) \
|
||||||
|
libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
unsigned int path_len);
|
||||||
|
#define libssh2_sftp_rmdir(sftp, path) \
|
||||||
|
libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
unsigned int path_len,
|
||||||
|
int stat_type,
|
||||||
|
LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||||
|
#define libssh2_sftp_stat(sftp, path, attrs) \
|
||||||
|
libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, \
|
||||||
|
(attrs))
|
||||||
|
#define libssh2_sftp_lstat(sftp, path, attrs) \
|
||||||
|
libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, \
|
||||||
|
(attrs))
|
||||||
|
#define libssh2_sftp_setstat(sftp, path, attrs) \
|
||||||
|
libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, \
|
||||||
|
(attrs))
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
unsigned int path_len,
|
||||||
|
char *target,
|
||||||
|
unsigned int target_len,
|
||||||
|
int link_type);
|
||||||
|
#define libssh2_sftp_symlink(sftp, orig, linkpath) \
|
||||||
|
libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), \
|
||||||
|
strlen(linkpath), LIBSSH2_SFTP_SYMLINK)
|
||||||
|
#define libssh2_sftp_readlink(sftp, path, target, maxlen) \
|
||||||
|
libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \
|
||||||
|
LIBSSH2_SFTP_READLINK)
|
||||||
|
#define libssh2_sftp_realpath(sftp, path, target, maxlen) \
|
||||||
|
libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \
|
||||||
|
LIBSSH2_SFTP_REALPATH)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* LIBSSH2_SFTP_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,416 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include "mac.h"
|
||||||
|
|
||||||
|
#ifdef LIBSSH2_MAC_NONE
|
||||||
|
/* mac_none_MAC
|
||||||
|
* Minimalist MAC: No MAC
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf,
|
||||||
|
uint32_t seqno, const unsigned char *packet,
|
||||||
|
uint32_t packet_len, const unsigned char *addtl,
|
||||||
|
uint32_t addtl_len, void **abstract)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static LIBSSH2_MAC_METHOD mac_method_none = {
|
||||||
|
"none",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
mac_none_MAC,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
#endif /* LIBSSH2_MAC_NONE */
|
||||||
|
|
||||||
|
/* mac_method_common_init
|
||||||
|
* Initialize simple mac methods
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key,
|
||||||
|
int *free_key, void **abstract)
|
||||||
|
{
|
||||||
|
*abstract = key;
|
||||||
|
*free_key = 0;
|
||||||
|
(void) session;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* mac_method_common_dtor
|
||||||
|
* Cleanup simple mac methods
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract)
|
||||||
|
{
|
||||||
|
if(*abstract) {
|
||||||
|
LIBSSH2_FREE(session, *abstract);
|
||||||
|
}
|
||||||
|
*abstract = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if LIBSSH2_HMAC_SHA512
|
||||||
|
/* mac_method_hmac_sha512_hash
|
||||||
|
* Calculate hash using full sha512 value
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_method_hmac_sha2_512_hash(LIBSSH2_SESSION * session,
|
||||||
|
unsigned char *buf, uint32_t seqno,
|
||||||
|
const unsigned char *packet,
|
||||||
|
uint32_t packet_len,
|
||||||
|
const unsigned char *addtl,
|
||||||
|
uint32_t addtl_len, void **abstract)
|
||||||
|
{
|
||||||
|
libssh2_hmac_ctx ctx;
|
||||||
|
unsigned char seqno_buf[4];
|
||||||
|
(void) session;
|
||||||
|
|
||||||
|
_libssh2_htonu32(seqno_buf, seqno);
|
||||||
|
|
||||||
|
libssh2_hmac_ctx_init(ctx);
|
||||||
|
libssh2_hmac_sha512_init(&ctx, *abstract, 64);
|
||||||
|
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||||
|
libssh2_hmac_update(ctx, packet, packet_len);
|
||||||
|
if(addtl && addtl_len) {
|
||||||
|
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||||
|
}
|
||||||
|
libssh2_hmac_final(ctx, buf);
|
||||||
|
libssh2_hmac_cleanup(&ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512 = {
|
||||||
|
"hmac-sha2-512",
|
||||||
|
64,
|
||||||
|
64,
|
||||||
|
mac_method_common_init,
|
||||||
|
mac_method_hmac_sha2_512_hash,
|
||||||
|
mac_method_common_dtor,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if LIBSSH2_HMAC_SHA256
|
||||||
|
/* mac_method_hmac_sha256_hash
|
||||||
|
* Calculate hash using full sha256 value
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_method_hmac_sha2_256_hash(LIBSSH2_SESSION * session,
|
||||||
|
unsigned char *buf, uint32_t seqno,
|
||||||
|
const unsigned char *packet,
|
||||||
|
uint32_t packet_len,
|
||||||
|
const unsigned char *addtl,
|
||||||
|
uint32_t addtl_len, void **abstract)
|
||||||
|
{
|
||||||
|
libssh2_hmac_ctx ctx;
|
||||||
|
unsigned char seqno_buf[4];
|
||||||
|
(void) session;
|
||||||
|
|
||||||
|
_libssh2_htonu32(seqno_buf, seqno);
|
||||||
|
|
||||||
|
libssh2_hmac_ctx_init(ctx);
|
||||||
|
libssh2_hmac_sha256_init(&ctx, *abstract, 32);
|
||||||
|
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||||
|
libssh2_hmac_update(ctx, packet, packet_len);
|
||||||
|
if(addtl && addtl_len) {
|
||||||
|
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||||
|
}
|
||||||
|
libssh2_hmac_final(ctx, buf);
|
||||||
|
libssh2_hmac_cleanup(&ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_256 = {
|
||||||
|
"hmac-sha2-256",
|
||||||
|
32,
|
||||||
|
32,
|
||||||
|
mac_method_common_init,
|
||||||
|
mac_method_hmac_sha2_256_hash,
|
||||||
|
mac_method_common_dtor,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* mac_method_hmac_sha1_hash
|
||||||
|
* Calculate hash using full sha1 value
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session,
|
||||||
|
unsigned char *buf, uint32_t seqno,
|
||||||
|
const unsigned char *packet,
|
||||||
|
uint32_t packet_len,
|
||||||
|
const unsigned char *addtl,
|
||||||
|
uint32_t addtl_len, void **abstract)
|
||||||
|
{
|
||||||
|
libssh2_hmac_ctx ctx;
|
||||||
|
unsigned char seqno_buf[4];
|
||||||
|
(void) session;
|
||||||
|
|
||||||
|
_libssh2_htonu32(seqno_buf, seqno);
|
||||||
|
|
||||||
|
libssh2_hmac_ctx_init(ctx);
|
||||||
|
libssh2_hmac_sha1_init(&ctx, *abstract, 20);
|
||||||
|
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||||
|
libssh2_hmac_update(ctx, packet, packet_len);
|
||||||
|
if(addtl && addtl_len) {
|
||||||
|
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||||
|
}
|
||||||
|
libssh2_hmac_final(ctx, buf);
|
||||||
|
libssh2_hmac_cleanup(&ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1 = {
|
||||||
|
"hmac-sha1",
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
mac_method_common_init,
|
||||||
|
mac_method_hmac_sha1_hash,
|
||||||
|
mac_method_common_dtor,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* mac_method_hmac_sha1_96_hash
|
||||||
|
* Calculate hash using first 96 bits of sha1 value
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session,
|
||||||
|
unsigned char *buf, uint32_t seqno,
|
||||||
|
const unsigned char *packet,
|
||||||
|
uint32_t packet_len,
|
||||||
|
const unsigned char *addtl,
|
||||||
|
uint32_t addtl_len, void **abstract)
|
||||||
|
{
|
||||||
|
unsigned char temp[SHA_DIGEST_LENGTH];
|
||||||
|
|
||||||
|
mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len,
|
||||||
|
addtl, addtl_len, abstract);
|
||||||
|
memcpy(buf, (char *) temp, 96 / 8);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_96 = {
|
||||||
|
"hmac-sha1-96",
|
||||||
|
12,
|
||||||
|
20,
|
||||||
|
mac_method_common_init,
|
||||||
|
mac_method_hmac_sha1_96_hash,
|
||||||
|
mac_method_common_dtor,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if LIBSSH2_MD5
|
||||||
|
/* mac_method_hmac_md5_hash
|
||||||
|
* Calculate hash using full md5 value
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf,
|
||||||
|
uint32_t seqno,
|
||||||
|
const unsigned char *packet,
|
||||||
|
uint32_t packet_len,
|
||||||
|
const unsigned char *addtl,
|
||||||
|
uint32_t addtl_len, void **abstract)
|
||||||
|
{
|
||||||
|
libssh2_hmac_ctx ctx;
|
||||||
|
unsigned char seqno_buf[4];
|
||||||
|
(void) session;
|
||||||
|
|
||||||
|
_libssh2_htonu32(seqno_buf, seqno);
|
||||||
|
|
||||||
|
libssh2_hmac_ctx_init(ctx);
|
||||||
|
libssh2_hmac_md5_init(&ctx, *abstract, 16);
|
||||||
|
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||||
|
libssh2_hmac_update(ctx, packet, packet_len);
|
||||||
|
if(addtl && addtl_len) {
|
||||||
|
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||||
|
}
|
||||||
|
libssh2_hmac_final(ctx, buf);
|
||||||
|
libssh2_hmac_cleanup(&ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const LIBSSH2_MAC_METHOD mac_method_hmac_md5 = {
|
||||||
|
"hmac-md5",
|
||||||
|
16,
|
||||||
|
16,
|
||||||
|
mac_method_common_init,
|
||||||
|
mac_method_hmac_md5_hash,
|
||||||
|
mac_method_common_dtor,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* mac_method_hmac_md5_96_hash
|
||||||
|
* Calculate hash using first 96 bits of md5 value
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session,
|
||||||
|
unsigned char *buf, uint32_t seqno,
|
||||||
|
const unsigned char *packet,
|
||||||
|
uint32_t packet_len,
|
||||||
|
const unsigned char *addtl,
|
||||||
|
uint32_t addtl_len, void **abstract)
|
||||||
|
{
|
||||||
|
unsigned char temp[MD5_DIGEST_LENGTH];
|
||||||
|
mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len,
|
||||||
|
addtl, addtl_len, abstract);
|
||||||
|
memcpy(buf, (char *) temp, 96 / 8);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const LIBSSH2_MAC_METHOD mac_method_hmac_md5_96 = {
|
||||||
|
"hmac-md5-96",
|
||||||
|
12,
|
||||||
|
16,
|
||||||
|
mac_method_common_init,
|
||||||
|
mac_method_hmac_md5_96_hash,
|
||||||
|
mac_method_common_dtor,
|
||||||
|
};
|
||||||
|
#endif /* LIBSSH2_MD5 */
|
||||||
|
|
||||||
|
#if LIBSSH2_HMAC_RIPEMD
|
||||||
|
/* mac_method_hmac_ripemd160_hash
|
||||||
|
* Calculate hash using ripemd160 value
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session,
|
||||||
|
unsigned char *buf, uint32_t seqno,
|
||||||
|
const unsigned char *packet,
|
||||||
|
uint32_t packet_len,
|
||||||
|
const unsigned char *addtl,
|
||||||
|
uint32_t addtl_len,
|
||||||
|
void **abstract)
|
||||||
|
{
|
||||||
|
libssh2_hmac_ctx ctx;
|
||||||
|
unsigned char seqno_buf[4];
|
||||||
|
(void) session;
|
||||||
|
|
||||||
|
_libssh2_htonu32(seqno_buf, seqno);
|
||||||
|
|
||||||
|
libssh2_hmac_ctx_init(ctx);
|
||||||
|
libssh2_hmac_ripemd160_init(&ctx, *abstract, 20);
|
||||||
|
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||||
|
libssh2_hmac_update(ctx, packet, packet_len);
|
||||||
|
if(addtl && addtl_len) {
|
||||||
|
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||||
|
}
|
||||||
|
libssh2_hmac_final(ctx, buf);
|
||||||
|
libssh2_hmac_cleanup(&ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160 = {
|
||||||
|
"hmac-ripemd160",
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
mac_method_common_init,
|
||||||
|
mac_method_hmac_ripemd160_hash,
|
||||||
|
mac_method_common_dtor,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = {
|
||||||
|
"hmac-ripemd160@openssh.com",
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
mac_method_common_init,
|
||||||
|
mac_method_hmac_ripemd160_hash,
|
||||||
|
mac_method_common_dtor,
|
||||||
|
};
|
||||||
|
#endif /* LIBSSH2_HMAC_RIPEMD */
|
||||||
|
|
||||||
|
static const LIBSSH2_MAC_METHOD *mac_methods[] = {
|
||||||
|
#if LIBSSH2_HMAC_SHA256
|
||||||
|
&mac_method_hmac_sha2_256,
|
||||||
|
#endif
|
||||||
|
#if LIBSSH2_HMAC_SHA512
|
||||||
|
&mac_method_hmac_sha2_512,
|
||||||
|
#endif
|
||||||
|
&mac_method_hmac_sha1,
|
||||||
|
&mac_method_hmac_sha1_96,
|
||||||
|
#if LIBSSH2_MD5
|
||||||
|
&mac_method_hmac_md5,
|
||||||
|
&mac_method_hmac_md5_96,
|
||||||
|
#endif
|
||||||
|
#if LIBSSH2_HMAC_RIPEMD
|
||||||
|
&mac_method_hmac_ripemd160,
|
||||||
|
&mac_method_hmac_ripemd160_openssh_com,
|
||||||
|
#endif /* LIBSSH2_HMAC_RIPEMD */
|
||||||
|
#ifdef LIBSSH2_MAC_NONE
|
||||||
|
&mac_method_none,
|
||||||
|
#endif /* LIBSSH2_MAC_NONE */
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
const LIBSSH2_MAC_METHOD **
|
||||||
|
_libssh2_mac_methods(void)
|
||||||
|
{
|
||||||
|
return mac_methods;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,68 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_MAC_H
|
||||||
|
#define __LIBSSH2_MAC_H
|
||||||
|
/* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
|
||||||
|
struct _LIBSSH2_MAC_METHOD
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
/* The length of a given MAC packet */
|
||||||
|
int mac_len;
|
||||||
|
|
||||||
|
/* integrity key length */
|
||||||
|
int key_len;
|
||||||
|
|
||||||
|
/* Message Authentication Code Hashing algo */
|
||||||
|
int (*init) (LIBSSH2_SESSION * session, unsigned char *key, int *free_key,
|
||||||
|
void **abstract);
|
||||||
|
int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf,
|
||||||
|
uint32_t seqno, const unsigned char *packet,
|
||||||
|
uint32_t packet_len, const unsigned char *addtl,
|
||||||
|
uint32_t addtl_len, void **abstract);
|
||||||
|
int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD;
|
||||||
|
|
||||||
|
const LIBSSH2_MAC_METHOD **_libssh2_mac_methods(void);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_MAC_H */
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,611 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_MBEDTLS_H
|
||||||
|
#define __LIBSSH2_MBEDTLS_H
|
||||||
|
/* Copyright (c) 2016, Art <https://github.com/wildart>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mbedtls/platform.h>
|
||||||
|
#include <mbedtls/md.h>
|
||||||
|
#include <mbedtls/rsa.h>
|
||||||
|
#include <mbedtls/bignum.h>
|
||||||
|
#include <mbedtls/cipher.h>
|
||||||
|
#ifdef MBEDTLS_ECDH_C
|
||||||
|
# include <mbedtls/ecdh.h>
|
||||||
|
#endif
|
||||||
|
#ifdef MBEDTLS_ECDSA_C
|
||||||
|
# include <mbedtls/ecdsa.h>
|
||||||
|
#endif
|
||||||
|
#include <mbedtls/entropy.h>
|
||||||
|
#include <mbedtls/ctr_drbg.h>
|
||||||
|
#include <mbedtls/pk.h>
|
||||||
|
#include <mbedtls/error.h>
|
||||||
|
|
||||||
|
/* Define which features are supported. */
|
||||||
|
#define LIBSSH2_MD5 1
|
||||||
|
|
||||||
|
#define LIBSSH2_HMAC_RIPEMD 1
|
||||||
|
#define LIBSSH2_HMAC_SHA256 1
|
||||||
|
#define LIBSSH2_HMAC_SHA512 1
|
||||||
|
|
||||||
|
#define LIBSSH2_AES 1
|
||||||
|
#define LIBSSH2_AES_CTR 1
|
||||||
|
#ifdef MBEDTLS_CIPHER_BLOWFISH_CBC
|
||||||
|
# define LIBSSH2_BLOWFISH 1
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_BLOWFISH 0
|
||||||
|
#endif
|
||||||
|
#ifdef MBEDTLS_CIPHER_ARC4_128
|
||||||
|
# define LIBSSH2_RC4 1
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_RC4 0
|
||||||
|
#endif
|
||||||
|
#define LIBSSH2_CAST 0
|
||||||
|
#define LIBSSH2_3DES 1
|
||||||
|
|
||||||
|
#define LIBSSH2_RSA 1
|
||||||
|
#define LIBSSH2_RSA_SHA2 1
|
||||||
|
#define LIBSSH2_DSA 0
|
||||||
|
#ifdef MBEDTLS_ECDSA_C
|
||||||
|
# define LIBSSH2_ECDSA 1
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_ECDSA 0
|
||||||
|
#endif
|
||||||
|
#define LIBSSH2_ED25519 0
|
||||||
|
|
||||||
|
#define MD5_DIGEST_LENGTH 16
|
||||||
|
#define SHA_DIGEST_LENGTH 20
|
||||||
|
#define SHA256_DIGEST_LENGTH 32
|
||||||
|
#define SHA384_DIGEST_LENGTH 48
|
||||||
|
#define SHA512_DIGEST_LENGTH 64
|
||||||
|
|
||||||
|
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: Generic functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define libssh2_crypto_init() \
|
||||||
|
_libssh2_mbedtls_init()
|
||||||
|
#define libssh2_crypto_exit() \
|
||||||
|
_libssh2_mbedtls_free()
|
||||||
|
|
||||||
|
#define _libssh2_random(buf, len) \
|
||||||
|
_libssh2_mbedtls_random(buf, len)
|
||||||
|
|
||||||
|
#define libssh2_prepare_iovec(vec, len) /* Empty. */
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: HMAC functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define libssh2_hmac_ctx mbedtls_md_context_t
|
||||||
|
|
||||||
|
#define libssh2_hmac_ctx_init(ctx)
|
||||||
|
#define libssh2_hmac_cleanup(pctx) \
|
||||||
|
mbedtls_md_free(pctx)
|
||||||
|
#define libssh2_hmac_update(ctx, data, datalen) \
|
||||||
|
mbedtls_md_hmac_update(&ctx, (unsigned char *) data, datalen)
|
||||||
|
#define libssh2_hmac_final(ctx, hash) \
|
||||||
|
mbedtls_md_hmac_finish(&ctx, hash)
|
||||||
|
|
||||||
|
#define libssh2_hmac_sha1_init(pctx, key, keylen) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, key, keylen)
|
||||||
|
#define libssh2_hmac_md5_init(pctx, key, keylen) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, key, keylen)
|
||||||
|
#define libssh2_hmac_ripemd160_init(pctx, key, keylen) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_RIPEMD160, key, keylen)
|
||||||
|
#define libssh2_hmac_sha256_init(pctx, key, keylen) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, key, keylen)
|
||||||
|
#define libssh2_hmac_sha384_init(pctx, key, keylen) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, key, keylen)
|
||||||
|
#define libssh2_hmac_sha512_init(pctx, key, keylen) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, key, keylen)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: SHA1 functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define libssh2_sha1_ctx mbedtls_md_context_t
|
||||||
|
|
||||||
|
#define libssh2_sha1_init(pctx) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, NULL, 0)
|
||||||
|
#define libssh2_sha1_update(ctx, data, datalen) \
|
||||||
|
mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
|
||||||
|
#define libssh2_sha1_final(ctx, hash) \
|
||||||
|
_libssh2_mbedtls_hash_final(&ctx, hash)
|
||||||
|
#define libssh2_sha1(data, datalen, hash) \
|
||||||
|
_libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA1, hash)
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: SHA256 functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define libssh2_sha256_ctx mbedtls_md_context_t
|
||||||
|
|
||||||
|
#define libssh2_sha256_init(pctx) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, NULL, 0)
|
||||||
|
#define libssh2_sha256_update(ctx, data, datalen) \
|
||||||
|
mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
|
||||||
|
#define libssh2_sha256_final(ctx, hash) \
|
||||||
|
_libssh2_mbedtls_hash_final(&ctx, hash)
|
||||||
|
#define libssh2_sha256(data, datalen, hash) \
|
||||||
|
_libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA256, hash)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: SHA384 functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define libssh2_sha384_ctx mbedtls_md_context_t
|
||||||
|
|
||||||
|
#define libssh2_sha384_init(pctx) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, NULL, 0)
|
||||||
|
#define libssh2_sha384_update(ctx, data, datalen) \
|
||||||
|
mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
|
||||||
|
#define libssh2_sha384_final(ctx, hash) \
|
||||||
|
_libssh2_mbedtls_hash_final(&ctx, hash)
|
||||||
|
#define libssh2_sha384(data, datalen, hash) \
|
||||||
|
_libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA384, hash)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: SHA512 functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define libssh2_sha512_ctx mbedtls_md_context_t
|
||||||
|
|
||||||
|
#define libssh2_sha512_init(pctx) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, NULL, 0)
|
||||||
|
#define libssh2_sha512_update(ctx, data, datalen) \
|
||||||
|
mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
|
||||||
|
#define libssh2_sha512_final(ctx, hash) \
|
||||||
|
_libssh2_mbedtls_hash_final(&ctx, hash)
|
||||||
|
#define libssh2_sha512(data, datalen, hash) \
|
||||||
|
_libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA512, hash)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: MD5 functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define libssh2_md5_ctx mbedtls_md_context_t
|
||||||
|
|
||||||
|
#define libssh2_md5_init(pctx) \
|
||||||
|
_libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, NULL, 0)
|
||||||
|
#define libssh2_md5_update(ctx, data, datalen) \
|
||||||
|
mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
|
||||||
|
#define libssh2_md5_final(ctx, hash) \
|
||||||
|
_libssh2_mbedtls_hash_final(&ctx, hash)
|
||||||
|
#define libssh2_md5(data, datalen, hash) \
|
||||||
|
_libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_MD5, hash)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: RSA functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define libssh2_rsa_ctx mbedtls_rsa_context
|
||||||
|
|
||||||
|
#define _libssh2_rsa_new(rsactx, e, e_len, n, n_len, \
|
||||||
|
d, d_len, p, p_len, q, q_len, \
|
||||||
|
e1, e1_len, e2, e2_len, c, c_len) \
|
||||||
|
_libssh2_mbedtls_rsa_new(rsactx, e, e_len, n, n_len, \
|
||||||
|
d, d_len, p, p_len, q, q_len, \
|
||||||
|
e1, e1_len, e2, e2_len, c, c_len)
|
||||||
|
|
||||||
|
#define _libssh2_rsa_new_private(rsactx, s, filename, passphrase) \
|
||||||
|
_libssh2_mbedtls_rsa_new_private(rsactx, s, filename, passphrase)
|
||||||
|
|
||||||
|
#define _libssh2_rsa_new_private_frommemory(rsactx, s, filedata, \
|
||||||
|
filedata_len, passphrase) \
|
||||||
|
_libssh2_mbedtls_rsa_new_private_frommemory(rsactx, s, filedata, \
|
||||||
|
filedata_len, passphrase)
|
||||||
|
|
||||||
|
#define _libssh2_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) \
|
||||||
|
_libssh2_mbedtls_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len)
|
||||||
|
|
||||||
|
#define _libssh2_rsa_sha2_sign(s, rsactx, hash, hash_len, sig, sig_len) \
|
||||||
|
_libssh2_mbedtls_rsa_sha2_sign(s, rsactx, hash, hash_len, sig, sig_len)
|
||||||
|
|
||||||
|
|
||||||
|
#define _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) \
|
||||||
|
_libssh2_mbedtls_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len)
|
||||||
|
|
||||||
|
#define _libssh2_rsa_sha2_verify(rsactx, hash_len, sig, sig_len, m, m_len) \
|
||||||
|
_libssh2_mbedtls_rsa_sha2_verify(rsactx, hash_len, sig, sig_len, m, m_len)
|
||||||
|
|
||||||
|
#define _libssh2_rsa_free(rsactx) \
|
||||||
|
_libssh2_mbedtls_rsa_free(rsactx)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: ECDSA structures
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if LIBSSH2_ECDSA
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
#ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||||
|
LIBSSH2_EC_CURVE_NISTP256 = MBEDTLS_ECP_DP_SECP256R1,
|
||||||
|
#else
|
||||||
|
LIBSSH2_EC_CURVE_NISTP256 = MBEDTLS_ECP_DP_NONE,
|
||||||
|
#endif
|
||||||
|
#ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED
|
||||||
|
LIBSSH2_EC_CURVE_NISTP384 = MBEDTLS_ECP_DP_SECP384R1,
|
||||||
|
#else
|
||||||
|
LIBSSH2_EC_CURVE_NISTP384 = MBEDTLS_ECP_DP_NONE,
|
||||||
|
#endif
|
||||||
|
#ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED
|
||||||
|
LIBSSH2_EC_CURVE_NISTP521 = MBEDTLS_ECP_DP_SECP521R1
|
||||||
|
#else
|
||||||
|
LIBSSH2_EC_CURVE_NISTP521 = MBEDTLS_ECP_DP_NONE,
|
||||||
|
#endif
|
||||||
|
} libssh2_curve_type;
|
||||||
|
|
||||||
|
# define _libssh2_ec_key mbedtls_ecp_keypair
|
||||||
|
#else
|
||||||
|
# define _libssh2_ec_key void
|
||||||
|
#endif /* LIBSSH2_ECDSA */
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: ECDSA functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if LIBSSH2_ECDSA
|
||||||
|
|
||||||
|
#define libssh2_ecdsa_ctx mbedtls_ecdsa_context
|
||||||
|
|
||||||
|
#define _libssh2_ecdsa_create_key(session, privkey, pubkey_octal, \
|
||||||
|
pubkey_octal_len, curve) \
|
||||||
|
_libssh2_mbedtls_ecdsa_create_key(session, privkey, pubkey_octal, \
|
||||||
|
pubkey_octal_len, curve)
|
||||||
|
|
||||||
|
#define _libssh2_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve) \
|
||||||
|
_libssh2_mbedtls_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve)
|
||||||
|
|
||||||
|
#define _libssh2_ecdh_gen_k(k, privkey, server_pubkey, server_pubkey_len) \
|
||||||
|
_libssh2_mbedtls_ecdh_gen_k(k, privkey, server_pubkey, server_pubkey_len)
|
||||||
|
|
||||||
|
#define _libssh2_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len) \
|
||||||
|
_libssh2_mbedtls_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len)
|
||||||
|
|
||||||
|
#define _libssh2_ecdsa_new_private(ctx, session, filename, passphrase) \
|
||||||
|
_libssh2_mbedtls_ecdsa_new_private(ctx, session, filename, passphrase)
|
||||||
|
|
||||||
|
#define _libssh2_ecdsa_new_private_frommemory(ctx, session, filedata, \
|
||||||
|
filedata_len, passphrase) \
|
||||||
|
_libssh2_mbedtls_ecdsa_new_private_frommemory(ctx, session, filedata, \
|
||||||
|
filedata_len, passphrase)
|
||||||
|
|
||||||
|
#define _libssh2_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len) \
|
||||||
|
_libssh2_mbedtls_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len)
|
||||||
|
|
||||||
|
#define _libssh2_ecdsa_get_curve_type(ctx) \
|
||||||
|
_libssh2_mbedtls_ecdsa_get_curve_type(ctx)
|
||||||
|
|
||||||
|
#define _libssh2_ecdsa_free(ctx) \
|
||||||
|
_libssh2_mbedtls_ecdsa_free(ctx)
|
||||||
|
|
||||||
|
#endif /* LIBSSH2_ECDSA */
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: Key functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _libssh2_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) \
|
||||||
|
_libssh2_mbedtls_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw)
|
||||||
|
#define _libssh2_pub_priv_keyfilememory(s, m, m_len, p, p_len, \
|
||||||
|
pk, pk_len, pw) \
|
||||||
|
_libssh2_mbedtls_pub_priv_keyfilememory(s, m, m_len, p, p_len, \
|
||||||
|
pk, pk_len, pw)
|
||||||
|
#define _libssh2_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \
|
||||||
|
f, kh, kh_len, pk, pk_len, pw) \
|
||||||
|
_libssh2_mbedtls_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \
|
||||||
|
f, kh, kh_len, pk, pk_len, pw)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: Cipher Context structure
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _libssh2_cipher_ctx mbedtls_cipher_context_t
|
||||||
|
|
||||||
|
#define _libssh2_cipher_type(algo) mbedtls_cipher_type_t algo
|
||||||
|
|
||||||
|
#define _libssh2_cipher_aes256ctr MBEDTLS_CIPHER_AES_256_CTR
|
||||||
|
#define _libssh2_cipher_aes192ctr MBEDTLS_CIPHER_AES_192_CTR
|
||||||
|
#define _libssh2_cipher_aes128ctr MBEDTLS_CIPHER_AES_128_CTR
|
||||||
|
#define _libssh2_cipher_aes256 MBEDTLS_CIPHER_AES_256_CBC
|
||||||
|
#define _libssh2_cipher_aes192 MBEDTLS_CIPHER_AES_192_CBC
|
||||||
|
#define _libssh2_cipher_aes128 MBEDTLS_CIPHER_AES_128_CBC
|
||||||
|
#ifdef MBEDTLS_CIPHER_BLOWFISH_CBC
|
||||||
|
#define _libssh2_cipher_blowfish MBEDTLS_CIPHER_BLOWFISH_CBC
|
||||||
|
#endif
|
||||||
|
#ifdef MBEDTLS_CIPHER_ARC4_128
|
||||||
|
#define _libssh2_cipher_arcfour MBEDTLS_CIPHER_ARC4_128
|
||||||
|
#endif
|
||||||
|
#define _libssh2_cipher_3des MBEDTLS_CIPHER_DES_EDE3_CBC
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: Cipher functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _libssh2_cipher_init(ctx, type, iv, secret, encrypt) \
|
||||||
|
_libssh2_mbedtls_cipher_init(ctx, type, iv, secret, encrypt)
|
||||||
|
#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen) \
|
||||||
|
_libssh2_mbedtls_cipher_crypt(ctx, type, encrypt, block, blocklen)
|
||||||
|
#define _libssh2_cipher_dtor(ctx) \
|
||||||
|
_libssh2_mbedtls_cipher_dtor(ctx)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: BigNumber Support
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _libssh2_bn_ctx int /* not used */
|
||||||
|
#define _libssh2_bn_ctx_new() 0 /* not used */
|
||||||
|
#define _libssh2_bn_ctx_free(bnctx) ((void)0) /* not used */
|
||||||
|
|
||||||
|
#define _libssh2_bn mbedtls_mpi
|
||||||
|
|
||||||
|
#define _libssh2_bn_init() \
|
||||||
|
_libssh2_mbedtls_bignum_init()
|
||||||
|
#define _libssh2_bn_init_from_bin() \
|
||||||
|
_libssh2_mbedtls_bignum_init()
|
||||||
|
#define _libssh2_bn_set_word(bn, word) \
|
||||||
|
mbedtls_mpi_lset(bn, word)
|
||||||
|
#define _libssh2_bn_from_bin(bn, len, bin) \
|
||||||
|
mbedtls_mpi_read_binary(bn, bin, len)
|
||||||
|
#define _libssh2_bn_to_bin(bn, bin) \
|
||||||
|
mbedtls_mpi_write_binary(bn, bin, mbedtls_mpi_size(bn))
|
||||||
|
#define _libssh2_bn_bytes(bn) \
|
||||||
|
mbedtls_mpi_size(bn)
|
||||||
|
#define _libssh2_bn_bits(bn) \
|
||||||
|
mbedtls_mpi_bitlen(bn)
|
||||||
|
#define _libssh2_bn_free(bn) \
|
||||||
|
_libssh2_mbedtls_bignum_free(bn)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: Diffie-Hellman support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _libssh2_dh_ctx mbedtls_mpi *
|
||||||
|
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
|
||||||
|
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
|
||||||
|
_libssh2_dh_key_pair(dhctx, public, g, p, group_order)
|
||||||
|
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
|
||||||
|
_libssh2_dh_secret(dhctx, secret, f, p)
|
||||||
|
#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/*
|
||||||
|
* mbedTLS backend: forward declarations
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
_libssh2_mbedtls_init(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
_libssh2_mbedtls_free(void);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_random(unsigned char *buf, int len);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_cipher_init(_libssh2_cipher_ctx *ctx,
|
||||||
|
_libssh2_cipher_type(type),
|
||||||
|
unsigned char *iv,
|
||||||
|
unsigned char *secret,
|
||||||
|
int encrypt);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_cipher_crypt(_libssh2_cipher_ctx *ctx,
|
||||||
|
_libssh2_cipher_type(type),
|
||||||
|
int encrypt,
|
||||||
|
unsigned char *block,
|
||||||
|
size_t blocklen);
|
||||||
|
void
|
||||||
|
_libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx,
|
||||||
|
mbedtls_md_type_t mdtype,
|
||||||
|
const unsigned char *key, unsigned long keylen);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen,
|
||||||
|
mbedtls_md_type_t mdtype, unsigned char *hash);
|
||||||
|
|
||||||
|
_libssh2_bn *
|
||||||
|
_libssh2_mbedtls_bignum_init(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
_libssh2_mbedtls_bignum_free(_libssh2_bn *bn);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa,
|
||||||
|
const unsigned char *edata,
|
||||||
|
unsigned long elen,
|
||||||
|
const unsigned char *ndata,
|
||||||
|
unsigned long nlen,
|
||||||
|
const unsigned char *ddata,
|
||||||
|
unsigned long dlen,
|
||||||
|
const unsigned char *pdata,
|
||||||
|
unsigned long plen,
|
||||||
|
const unsigned char *qdata,
|
||||||
|
unsigned long qlen,
|
||||||
|
const unsigned char *e1data,
|
||||||
|
unsigned long e1len,
|
||||||
|
const unsigned char *e2data,
|
||||||
|
unsigned long e2len,
|
||||||
|
const unsigned char *coeffdata,
|
||||||
|
unsigned long coefflen);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa,
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
const char *filename,
|
||||||
|
const unsigned char *passphrase);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa,
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
const char *filedata,
|
||||||
|
size_t filedata_len,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
|
||||||
|
const unsigned char *sig,
|
||||||
|
unsigned long sig_len,
|
||||||
|
const unsigned char *m,
|
||||||
|
unsigned long m_len);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session,
|
||||||
|
libssh2_rsa_ctx *rsa,
|
||||||
|
const unsigned char *hash,
|
||||||
|
size_t hash_len,
|
||||||
|
unsigned char **signature,
|
||||||
|
size_t *signature_len);
|
||||||
|
void
|
||||||
|
_libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *rsa);
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
const char *privatekey,
|
||||||
|
const char *passphrase);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
const char *privatekeydata,
|
||||||
|
size_t privatekeydata_len,
|
||||||
|
const char *passphrase);
|
||||||
|
#if LIBSSH2_ECDSA
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_ecdsa_create_key(LIBSSH2_SESSION *session,
|
||||||
|
_libssh2_ec_key **privkey,
|
||||||
|
unsigned char **pubkey_octal,
|
||||||
|
size_t *pubkey_octal_len,
|
||||||
|
libssh2_curve_type curve);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ctx,
|
||||||
|
const unsigned char *k,
|
||||||
|
size_t k_len,
|
||||||
|
libssh2_curve_type curve);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_ecdh_gen_k(_libssh2_bn **k,
|
||||||
|
_libssh2_ec_key *privkey,
|
||||||
|
const unsigned char *server_pubkey,
|
||||||
|
size_t server_pubkey_len);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_ecdsa_verify(libssh2_ecdsa_ctx *ctx,
|
||||||
|
const unsigned char *r, size_t r_len,
|
||||||
|
const unsigned char *s, size_t s_len,
|
||||||
|
const unsigned char *m, size_t m_len);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_ecdsa_new_private(libssh2_ecdsa_ctx **ctx,
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
const char *filename,
|
||||||
|
const unsigned char *passphrase);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx **ctx,
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
const char *filedata,
|
||||||
|
size_t filedata_len,
|
||||||
|
const unsigned char *passphrase);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session,
|
||||||
|
libssh2_ecdsa_ctx *ctx,
|
||||||
|
const unsigned char *hash,
|
||||||
|
unsigned long hash_len,
|
||||||
|
unsigned char **signature,
|
||||||
|
size_t *signature_len);
|
||||||
|
libssh2_curve_type
|
||||||
|
_libssh2_mbedtls_ecdsa_key_get_curve_type(libssh2_ecdsa_ctx *ctx);
|
||||||
|
int
|
||||||
|
_libssh2_mbedtls_ecdsa_curve_type_from_name(const char *name,
|
||||||
|
libssh2_curve_type *type);
|
||||||
|
void
|
||||||
|
_libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx);
|
||||||
|
#endif /* LIBSSH2_ECDSA */
|
||||||
|
|
||||||
|
extern void
|
||||||
|
_libssh2_dh_init(_libssh2_dh_ctx *dhctx);
|
||||||
|
extern int
|
||||||
|
_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
|
||||||
|
_libssh2_bn *g, _libssh2_bn *p, int group_order);
|
||||||
|
extern int
|
||||||
|
_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
|
||||||
|
_libssh2_bn *f, _libssh2_bn *p);
|
||||||
|
extern void
|
||||||
|
_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_MBEDTLS_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,932 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
||||||
|
* Copyright (c) 2009-2019 by Daniel Stenberg
|
||||||
|
* Copyright (c) 2010 Simon Josefsson
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "blf.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_TIME_H
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode,
|
||||||
|
const char *errmsg, int errflags)
|
||||||
|
{
|
||||||
|
if(session == NULL) {
|
||||||
|
if(errmsg != NULL)
|
||||||
|
fprintf(stderr, "Session is NULL, error: %s\n", errmsg);
|
||||||
|
return errcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(session->err_flags & LIBSSH2_ERR_FLAG_DUP)
|
||||||
|
LIBSSH2_FREE(session, (char *)session->err_msg);
|
||||||
|
|
||||||
|
session->err_code = errcode;
|
||||||
|
session->err_flags = 0;
|
||||||
|
|
||||||
|
if((errmsg != NULL) && ((errflags & LIBSSH2_ERR_FLAG_DUP) != 0)) {
|
||||||
|
size_t len = strlen(errmsg);
|
||||||
|
char *copy = LIBSSH2_ALLOC(session, len + 1);
|
||||||
|
if(copy) {
|
||||||
|
memcpy(copy, errmsg, len + 1);
|
||||||
|
session->err_flags = LIBSSH2_ERR_FLAG_DUP;
|
||||||
|
session->err_msg = copy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Out of memory: this code path is very unlikely */
|
||||||
|
session->err_msg = "former error forgotten (OOM)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
session->err_msg = errmsg;
|
||||||
|
|
||||||
|
#ifdef LIBSSH2DEBUG
|
||||||
|
if((errcode == LIBSSH2_ERROR_EAGAIN) && !session->api_block_mode)
|
||||||
|
/* if this is EAGAIN and we're in non-blocking mode, don't generate
|
||||||
|
a debug output for this */
|
||||||
|
return errcode;
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code,
|
||||||
|
session->err_msg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return errcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char *errmsg)
|
||||||
|
{
|
||||||
|
return _libssh2_error_flags(session, errcode, errmsg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
static int wsa2errno(void)
|
||||||
|
{
|
||||||
|
switch(WSAGetLastError()) {
|
||||||
|
case WSAEWOULDBLOCK:
|
||||||
|
return EAGAIN;
|
||||||
|
|
||||||
|
case WSAENOTSOCK:
|
||||||
|
return EBADF;
|
||||||
|
|
||||||
|
case WSAEINTR:
|
||||||
|
return EINTR;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* It is most important to ensure errno does not stay at EAGAIN
|
||||||
|
* when a different error occurs so just set errno to a generic
|
||||||
|
* error */
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* _libssh2_recv
|
||||||
|
*
|
||||||
|
* Replacement for the standard recv, return -errno on failure.
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
_libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length,
|
||||||
|
int flags, void **abstract)
|
||||||
|
{
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
(void) abstract;
|
||||||
|
|
||||||
|
rc = recv(sock, buffer, length, flags);
|
||||||
|
#ifdef WIN32
|
||||||
|
if(rc < 0)
|
||||||
|
return -wsa2errno();
|
||||||
|
#else
|
||||||
|
if(rc < 0) {
|
||||||
|
/* Sometimes the first recv() function call sets errno to ENOENT on
|
||||||
|
Solaris and HP-UX */
|
||||||
|
if(errno == ENOENT)
|
||||||
|
return -EAGAIN;
|
||||||
|
#ifdef EWOULDBLOCK /* For VMS and other special unixes */
|
||||||
|
else if(errno == EWOULDBLOCK)
|
||||||
|
return -EAGAIN;
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _libssh2_send
|
||||||
|
*
|
||||||
|
* Replacement for the standard send, return -errno on failure.
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
_libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length,
|
||||||
|
int flags, void **abstract)
|
||||||
|
{
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
(void) abstract;
|
||||||
|
|
||||||
|
rc = send(sock, buffer, length, flags);
|
||||||
|
#ifdef WIN32
|
||||||
|
if(rc < 0)
|
||||||
|
return -wsa2errno();
|
||||||
|
#else
|
||||||
|
if(rc < 0) {
|
||||||
|
#ifdef EWOULDBLOCK /* For VMS and other special unixes */
|
||||||
|
if(errno == EWOULDBLOCK)
|
||||||
|
return -EAGAIN;
|
||||||
|
#endif
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* libssh2_ntohu32
|
||||||
|
*/
|
||||||
|
unsigned int
|
||||||
|
_libssh2_ntohu32(const unsigned char *buf)
|
||||||
|
{
|
||||||
|
return (((unsigned int)buf[0] << 24)
|
||||||
|
| ((unsigned int)buf[1] << 16)
|
||||||
|
| ((unsigned int)buf[2] << 8)
|
||||||
|
| ((unsigned int)buf[3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* _libssh2_ntohu64
|
||||||
|
*/
|
||||||
|
libssh2_uint64_t
|
||||||
|
_libssh2_ntohu64(const unsigned char *buf)
|
||||||
|
{
|
||||||
|
unsigned long msl, lsl;
|
||||||
|
|
||||||
|
msl = ((libssh2_uint64_t)buf[0] << 24) | ((libssh2_uint64_t)buf[1] << 16)
|
||||||
|
| ((libssh2_uint64_t)buf[2] << 8) | (libssh2_uint64_t)buf[3];
|
||||||
|
lsl = ((libssh2_uint64_t)buf[4] << 24) | ((libssh2_uint64_t)buf[5] << 16)
|
||||||
|
| ((libssh2_uint64_t)buf[6] << 8) | (libssh2_uint64_t)buf[7];
|
||||||
|
|
||||||
|
return ((libssh2_uint64_t)msl <<32) | lsl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _libssh2_htonu32
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_libssh2_htonu32(unsigned char *buf, uint32_t value)
|
||||||
|
{
|
||||||
|
buf[0] = (value >> 24) & 0xFF;
|
||||||
|
buf[1] = (value >> 16) & 0xFF;
|
||||||
|
buf[2] = (value >> 8) & 0xFF;
|
||||||
|
buf[3] = value & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _libssh2_store_u32
|
||||||
|
*/
|
||||||
|
void _libssh2_store_u32(unsigned char **buf, uint32_t value)
|
||||||
|
{
|
||||||
|
_libssh2_htonu32(*buf, value);
|
||||||
|
*buf += sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _libssh2_store_str
|
||||||
|
*/
|
||||||
|
void _libssh2_store_str(unsigned char **buf, const char *str, size_t len)
|
||||||
|
{
|
||||||
|
_libssh2_store_u32(buf, (uint32_t)len);
|
||||||
|
if(len) {
|
||||||
|
memcpy(*buf, str, len);
|
||||||
|
*buf += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _libssh2_store_bignum2_bytes
|
||||||
|
*/
|
||||||
|
void _libssh2_store_bignum2_bytes(unsigned char **buf,
|
||||||
|
const unsigned char *bytes,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
int extraByte = 0;
|
||||||
|
const unsigned char *p;
|
||||||
|
for(p = bytes; len > 0 && *p == 0; --len, ++p) {}
|
||||||
|
|
||||||
|
extraByte = (len > 0 && (p[0] & 0x80) != 0);
|
||||||
|
_libssh2_store_u32(buf, len + extraByte);
|
||||||
|
|
||||||
|
if(extraByte) {
|
||||||
|
*buf[0] = 0;
|
||||||
|
*buf += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(len > 0) {
|
||||||
|
memcpy(*buf, p, len);
|
||||||
|
*buf += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Base64 Conversion */
|
||||||
|
|
||||||
|
static const short base64_reverse_table[256] = {
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
|
||||||
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||||
|
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||||
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* libssh2_base64_decode
|
||||||
|
*
|
||||||
|
* Decode a base64 chunk and store it into a newly alloc'd buffer
|
||||||
|
*/
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_base64_decode(LIBSSH2_SESSION *session, char **data,
|
||||||
|
unsigned int *datalen, const char *src,
|
||||||
|
unsigned int src_len)
|
||||||
|
{
|
||||||
|
unsigned char *s, *d;
|
||||||
|
short v;
|
||||||
|
int i = 0, len = 0;
|
||||||
|
|
||||||
|
*data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
|
||||||
|
d = (unsigned char *) *data;
|
||||||
|
if(!d) {
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for base64 decoding");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) {
|
||||||
|
v = base64_reverse_table[*s];
|
||||||
|
if(v < 0)
|
||||||
|
continue;
|
||||||
|
switch(i % 4) {
|
||||||
|
case 0:
|
||||||
|
d[len] = (unsigned char)(v << 2);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
d[len++] |= v >> 4;
|
||||||
|
d[len] = (unsigned char)(v << 4);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
d[len++] |= v >> 2;
|
||||||
|
d[len] = (unsigned char)(v << 6);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
d[len++] |= v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if((i % 4) == 1) {
|
||||||
|
/* Invalid -- We have a byte which belongs exclusively to a partial
|
||||||
|
octet */
|
||||||
|
LIBSSH2_FREE(session, *data);
|
||||||
|
*data = NULL;
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid base64");
|
||||||
|
}
|
||||||
|
|
||||||
|
*datalen = len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Base64 Encoding/Decoding Table --- */
|
||||||
|
static const char table64[]=
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_base64_encode()
|
||||||
|
*
|
||||||
|
* Returns the length of the newly created base64 string. The third argument
|
||||||
|
* is a pointer to an allocated area holding the base64 data. If something
|
||||||
|
* went wrong, 0 is returned.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
size_t _libssh2_base64_encode(LIBSSH2_SESSION *session,
|
||||||
|
const char *inp, size_t insize, char **outptr)
|
||||||
|
{
|
||||||
|
unsigned char ibuf[3];
|
||||||
|
unsigned char obuf[4];
|
||||||
|
int i;
|
||||||
|
int inputparts;
|
||||||
|
char *output;
|
||||||
|
char *base64data;
|
||||||
|
const char *indata = inp;
|
||||||
|
|
||||||
|
*outptr = NULL; /* set to NULL in case of failure before we reach the
|
||||||
|
end */
|
||||||
|
|
||||||
|
if(0 == insize)
|
||||||
|
insize = strlen(indata);
|
||||||
|
|
||||||
|
base64data = output = LIBSSH2_ALLOC(session, insize * 4 / 3 + 4);
|
||||||
|
if(NULL == output)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while(insize > 0) {
|
||||||
|
for(i = inputparts = 0; i < 3; i++) {
|
||||||
|
if(insize > 0) {
|
||||||
|
inputparts++;
|
||||||
|
ibuf[i] = *indata;
|
||||||
|
indata++;
|
||||||
|
insize--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ibuf[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2);
|
||||||
|
obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
|
||||||
|
((ibuf[1] & 0xF0) >> 4));
|
||||||
|
obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
|
||||||
|
((ibuf[2] & 0xC0) >> 6));
|
||||||
|
obuf[3] = (unsigned char) (ibuf[2] & 0x3F);
|
||||||
|
|
||||||
|
switch(inputparts) {
|
||||||
|
case 1: /* only one byte read */
|
||||||
|
snprintf(output, 5, "%c%c==",
|
||||||
|
table64[obuf[0]],
|
||||||
|
table64[obuf[1]]);
|
||||||
|
break;
|
||||||
|
case 2: /* two bytes read */
|
||||||
|
snprintf(output, 5, "%c%c%c=",
|
||||||
|
table64[obuf[0]],
|
||||||
|
table64[obuf[1]],
|
||||||
|
table64[obuf[2]]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(output, 5, "%c%c%c%c",
|
||||||
|
table64[obuf[0]],
|
||||||
|
table64[obuf[1]],
|
||||||
|
table64[obuf[2]],
|
||||||
|
table64[obuf[3]]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
output += 4;
|
||||||
|
}
|
||||||
|
*output = 0;
|
||||||
|
*outptr = base64data; /* make it return the actual data memory */
|
||||||
|
|
||||||
|
return strlen(base64data); /* return the length of the new data */
|
||||||
|
}
|
||||||
|
/* ---- End of Base64 Encoding ---- */
|
||||||
|
|
||||||
|
LIBSSH2_API void
|
||||||
|
libssh2_free(LIBSSH2_SESSION *session, void *ptr)
|
||||||
|
{
|
||||||
|
LIBSSH2_FREE(session, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LIBSSH2DEBUG
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
|
||||||
|
{
|
||||||
|
session->showmask = bitmask;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context,
|
||||||
|
libssh2_trace_handler_func callback)
|
||||||
|
{
|
||||||
|
session->tracehandler = callback;
|
||||||
|
session->tracehandler_context = handler_context;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
||||||
|
{
|
||||||
|
char buffer[1536];
|
||||||
|
int len, msglen, buflen = sizeof(buffer);
|
||||||
|
va_list vargs;
|
||||||
|
struct timeval now;
|
||||||
|
static int firstsec;
|
||||||
|
static const char *const contexts[] = {
|
||||||
|
"Unknown",
|
||||||
|
"Transport",
|
||||||
|
"Key Ex",
|
||||||
|
"Userauth",
|
||||||
|
"Conn",
|
||||||
|
"SCP",
|
||||||
|
"SFTP",
|
||||||
|
"Failure Event",
|
||||||
|
"Publickey",
|
||||||
|
"Socket",
|
||||||
|
};
|
||||||
|
const char *contexttext = contexts[0];
|
||||||
|
unsigned int contextindex;
|
||||||
|
|
||||||
|
if(!(session->showmask & context)) {
|
||||||
|
/* no such output asked for */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the first matching context string for this message */
|
||||||
|
for(contextindex = 0; contextindex < ARRAY_SIZE(contexts);
|
||||||
|
contextindex++) {
|
||||||
|
if((context & (1 << contextindex)) != 0) {
|
||||||
|
contexttext = contexts[contextindex];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_libssh2_gettimeofday(&now, NULL);
|
||||||
|
if(!firstsec) {
|
||||||
|
firstsec = now.tv_sec;
|
||||||
|
}
|
||||||
|
now.tv_sec -= firstsec;
|
||||||
|
|
||||||
|
len = snprintf(buffer, buflen, "[libssh2] %d.%06d %s: ",
|
||||||
|
(int)now.tv_sec, (int)now.tv_usec, contexttext);
|
||||||
|
|
||||||
|
if(len >= buflen)
|
||||||
|
msglen = buflen - 1;
|
||||||
|
else {
|
||||||
|
buflen -= len;
|
||||||
|
msglen = len;
|
||||||
|
va_start(vargs, format);
|
||||||
|
len = vsnprintf(buffer + msglen, buflen, format, vargs);
|
||||||
|
va_end(vargs);
|
||||||
|
msglen += len < buflen ? len : buflen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(session->tracehandler)
|
||||||
|
(session->tracehandler)(session, session->tracehandler_context, buffer,
|
||||||
|
msglen);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%s\n", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
|
||||||
|
{
|
||||||
|
(void) session;
|
||||||
|
(void) bitmask;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context,
|
||||||
|
libssh2_trace_handler_func callback)
|
||||||
|
{
|
||||||
|
(void) session;
|
||||||
|
(void) handler_context;
|
||||||
|
(void) callback;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* init the list head */
|
||||||
|
void _libssh2_list_init(struct list_head *head)
|
||||||
|
{
|
||||||
|
head->first = head->last = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add a node to the list */
|
||||||
|
void _libssh2_list_add(struct list_head *head,
|
||||||
|
struct list_node *entry)
|
||||||
|
{
|
||||||
|
/* store a pointer to the head */
|
||||||
|
entry->head = head;
|
||||||
|
|
||||||
|
/* we add this entry at the "top" so it has no next */
|
||||||
|
entry->next = NULL;
|
||||||
|
|
||||||
|
/* make our prev point to what the head thinks is last */
|
||||||
|
entry->prev = head->last;
|
||||||
|
|
||||||
|
/* and make head's last be us now */
|
||||||
|
head->last = entry;
|
||||||
|
|
||||||
|
/* make sure our 'prev' node points to us next */
|
||||||
|
if(entry->prev)
|
||||||
|
entry->prev->next = entry;
|
||||||
|
else
|
||||||
|
head->first = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return the "first" node in the list this head points to */
|
||||||
|
void *_libssh2_list_first(struct list_head *head)
|
||||||
|
{
|
||||||
|
return head->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return the next node in the list */
|
||||||
|
void *_libssh2_list_next(struct list_node *node)
|
||||||
|
{
|
||||||
|
return node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return the prev node in the list */
|
||||||
|
void *_libssh2_list_prev(struct list_node *node)
|
||||||
|
{
|
||||||
|
return node->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove this node from the list */
|
||||||
|
void _libssh2_list_remove(struct list_node *entry)
|
||||||
|
{
|
||||||
|
if(entry->prev)
|
||||||
|
entry->prev->next = entry->next;
|
||||||
|
else
|
||||||
|
entry->head->first = entry->next;
|
||||||
|
|
||||||
|
if(entry->next)
|
||||||
|
entry->next->prev = entry->prev;
|
||||||
|
else
|
||||||
|
entry->head->last = entry->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* insert a node before the given 'after' entry */
|
||||||
|
void _libssh2_list_insert(struct list_node *after, /* insert before this */
|
||||||
|
struct list_node *entry)
|
||||||
|
{
|
||||||
|
/* 'after' is next to 'entry' */
|
||||||
|
bentry->next = after;
|
||||||
|
|
||||||
|
/* entry's prev is then made to be the prev after current has */
|
||||||
|
entry->prev = after->prev;
|
||||||
|
|
||||||
|
/* the node that is now before 'entry' was previously before 'after'
|
||||||
|
and must be made to point to 'entry' correctly */
|
||||||
|
if(entry->prev)
|
||||||
|
entry->prev->next = entry;
|
||||||
|
else
|
||||||
|
/* there was no node before this, so we make sure we point the head
|
||||||
|
pointer to this node */
|
||||||
|
after->head->first = entry;
|
||||||
|
|
||||||
|
/* after's prev entry points back to entry */
|
||||||
|
after->prev = entry;
|
||||||
|
|
||||||
|
/* after's next entry is still the same as before */
|
||||||
|
|
||||||
|
/* entry's head is the same as after's */
|
||||||
|
entry->head = after->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* this define is defined in misc.h for the correct platforms */
|
||||||
|
#ifdef LIBSSH2_GETTIMEOFDAY_WIN32
|
||||||
|
/*
|
||||||
|
* gettimeofday
|
||||||
|
* Implementation according to:
|
||||||
|
* The Open Group Base Specifications Issue 6
|
||||||
|
* IEEE Std 1003.1, 2004 Edition
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS NOT COPYRIGHTED
|
||||||
|
*
|
||||||
|
* This source code is offered for use in the public domain. You may
|
||||||
|
* use, modify or distribute it freely.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful but
|
||||||
|
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
||||||
|
* DISCLAIMED. This includes but is not limited to warranties of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* Contributed by:
|
||||||
|
* Danny Smith <dannysmith@users.sourceforge.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
|
||||||
|
#define _W32_FT_OFFSET (116444736000000000)
|
||||||
|
|
||||||
|
int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */
|
||||||
|
FILETIME ft;
|
||||||
|
} _now;
|
||||||
|
(void)tzp;
|
||||||
|
if(tp) {
|
||||||
|
GetSystemTimeAsFileTime(&_now.ft);
|
||||||
|
tp->tv_usec = (long)((_now.ns100 / 10) % 1000000);
|
||||||
|
tp->tv_sec = (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000);
|
||||||
|
}
|
||||||
|
/* Always return 0 as per Open Group Base Specifications Issue 6.
|
||||||
|
Do not set errno on error. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *_libssh2_calloc(LIBSSH2_SESSION* session, size_t size)
|
||||||
|
{
|
||||||
|
void *p = LIBSSH2_ALLOC(session, size);
|
||||||
|
if(p) {
|
||||||
|
memset(p, 0, size);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XOR operation on buffers input1 and input2, result in output.
|
||||||
|
It is safe to use an input buffer as the output buffer. */
|
||||||
|
void _libssh2_xor_data(unsigned char *output,
|
||||||
|
const unsigned char *input1,
|
||||||
|
const unsigned char *input2,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for(i = 0; i < length; i++)
|
||||||
|
*output++ = *input1++ ^ *input2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increments an AES CTR buffer to prepare it for use with the
|
||||||
|
next AES block. */
|
||||||
|
void _libssh2_aes_ctr_increment(unsigned char *ctr,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
unsigned char *pc;
|
||||||
|
unsigned int val, carry;
|
||||||
|
|
||||||
|
pc = ctr + length - 1;
|
||||||
|
carry = 1;
|
||||||
|
|
||||||
|
while(pc >= ctr) {
|
||||||
|
val = (unsigned int)*pc + carry;
|
||||||
|
*pc-- = val & 0xFF;
|
||||||
|
carry = val >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(WIN32) && !defined(HAVE_MEMSET_S)
|
||||||
|
static void * (* const volatile memset_libssh)(void *, int, size_t) = memset;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void _libssh2_explicit_zero(void *buf, size_t size)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
SecureZeroMemory(buf, size);
|
||||||
|
#elif defined(HAVE_MEMSET_S)
|
||||||
|
(void)memset_s(buf, size, 0, size);
|
||||||
|
#else
|
||||||
|
memset_libssh(buf, 0, size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* String buffer */
|
||||||
|
|
||||||
|
struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session)
|
||||||
|
{
|
||||||
|
struct string_buf *ret;
|
||||||
|
|
||||||
|
ret = _libssh2_calloc(session, sizeof(*ret));
|
||||||
|
if(ret == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _libssh2_string_buf_free(LIBSSH2_SESSION *session, struct string_buf *buf)
|
||||||
|
{
|
||||||
|
if(buf == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(buf->data != NULL)
|
||||||
|
LIBSSH2_FREE(session, buf->data);
|
||||||
|
|
||||||
|
LIBSSH2_FREE(session, buf);
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_get_byte(struct string_buf *buf, unsigned char *out)
|
||||||
|
{
|
||||||
|
if(!_libssh2_check_length(buf, 1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = buf->dataptr[0];
|
||||||
|
buf->dataptr += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out)
|
||||||
|
{
|
||||||
|
if(!_libssh2_check_length(buf, 1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*out = buf->dataptr[0] == 0 ? 0 : 1;
|
||||||
|
buf->dataptr += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out)
|
||||||
|
{
|
||||||
|
if(!_libssh2_check_length(buf, 4)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = _libssh2_ntohu32(buf->dataptr);
|
||||||
|
buf->dataptr += 4;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out)
|
||||||
|
{
|
||||||
|
if(!_libssh2_check_length(buf, 8)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = _libssh2_ntohu64(buf->dataptr);
|
||||||
|
buf->dataptr += 8;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_match_string(struct string_buf *buf, const char *match)
|
||||||
|
{
|
||||||
|
unsigned char *out;
|
||||||
|
size_t len = 0;
|
||||||
|
if(_libssh2_get_string(buf, &out, &len) || len != strlen(match) ||
|
||||||
|
strncmp((char *)out, match, strlen(match)) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_get_string(struct string_buf *buf, unsigned char **outbuf,
|
||||||
|
size_t *outlen)
|
||||||
|
{
|
||||||
|
uint32_t data_len;
|
||||||
|
if(_libssh2_get_u32(buf, &data_len) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(!_libssh2_check_length(buf, data_len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*outbuf = buf->dataptr;
|
||||||
|
buf->dataptr += data_len;
|
||||||
|
|
||||||
|
if(outlen)
|
||||||
|
*outlen = (size_t)data_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_copy_string(LIBSSH2_SESSION *session, struct string_buf *buf,
|
||||||
|
unsigned char **outbuf, size_t *outlen)
|
||||||
|
{
|
||||||
|
size_t str_len;
|
||||||
|
unsigned char *str;
|
||||||
|
|
||||||
|
if(_libssh2_get_string(buf, &str, &str_len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(str_len) {
|
||||||
|
*outbuf = LIBSSH2_ALLOC(session, str_len);
|
||||||
|
if(*outbuf) {
|
||||||
|
memcpy(*outbuf, str, str_len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*outlen = 0;
|
||||||
|
*outbuf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(outlen)
|
||||||
|
*outlen = str_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_get_bignum_bytes(struct string_buf *buf, unsigned char **outbuf,
|
||||||
|
size_t *outlen)
|
||||||
|
{
|
||||||
|
uint32_t data_len;
|
||||||
|
uint32_t bn_len;
|
||||||
|
unsigned char *bnptr;
|
||||||
|
|
||||||
|
if(_libssh2_get_u32(buf, &data_len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(!_libssh2_check_length(buf, data_len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bn_len = data_len;
|
||||||
|
bnptr = buf->dataptr;
|
||||||
|
|
||||||
|
/* trim leading zeros */
|
||||||
|
while(bn_len > 0 && *bnptr == 0x00) {
|
||||||
|
bn_len--;
|
||||||
|
bnptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outbuf = bnptr;
|
||||||
|
buf->dataptr += data_len;
|
||||||
|
|
||||||
|
if(outlen)
|
||||||
|
*outlen = (size_t)bn_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given the current location in buf, _libssh2_check_length ensures
|
||||||
|
callers can read the next len number of bytes out of the buffer
|
||||||
|
before reading the buffer content */
|
||||||
|
|
||||||
|
int _libssh2_check_length(struct string_buf *buf, size_t len)
|
||||||
|
{
|
||||||
|
unsigned char *endp = &buf->data[buf->len];
|
||||||
|
size_t left = endp - buf->dataptr;
|
||||||
|
return ((len <= left) && (left <= buf->len));
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_eob(struct string_buf *buf)
|
||||||
|
{
|
||||||
|
unsigned char *endp = &buf->data[buf->len];
|
||||||
|
return buf->dataptr >= endp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrappers */
|
||||||
|
|
||||||
|
int _libssh2_bcrypt_pbkdf(const char *pass,
|
||||||
|
size_t passlen,
|
||||||
|
const uint8_t *salt,
|
||||||
|
size_t saltlen,
|
||||||
|
uint8_t *key,
|
||||||
|
size_t keylen,
|
||||||
|
unsigned int rounds)
|
||||||
|
{
|
||||||
|
/* defined in bcrypt_pbkdf.c */
|
||||||
|
return bcrypt_pbkdf(pass,
|
||||||
|
passlen,
|
||||||
|
salt,
|
||||||
|
saltlen,
|
||||||
|
key,
|
||||||
|
keylen,
|
||||||
|
rounds);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,133 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_MISC_H
|
||||||
|
#define __LIBSSH2_MISC_H
|
||||||
|
/* Copyright (c) 2009-2019 by Daniel Stenberg
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct list_head {
|
||||||
|
struct list_node *last;
|
||||||
|
struct list_node *first;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct list_node {
|
||||||
|
struct list_node *next;
|
||||||
|
struct list_node *prev;
|
||||||
|
struct list_head *head;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct string_buf {
|
||||||
|
unsigned char *data;
|
||||||
|
unsigned char *dataptr;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode,
|
||||||
|
const char *errmsg, int errflags);
|
||||||
|
int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char *errmsg);
|
||||||
|
|
||||||
|
void _libssh2_list_init(struct list_head *head);
|
||||||
|
|
||||||
|
/* add a node last in the list */
|
||||||
|
void _libssh2_list_add(struct list_head *head,
|
||||||
|
struct list_node *entry);
|
||||||
|
|
||||||
|
/* return the "first" node in the list this head points to */
|
||||||
|
void *_libssh2_list_first(struct list_head *head);
|
||||||
|
|
||||||
|
/* return the next node in the list */
|
||||||
|
void *_libssh2_list_next(struct list_node *node);
|
||||||
|
|
||||||
|
/* return the prev node in the list */
|
||||||
|
void *_libssh2_list_prev(struct list_node *node);
|
||||||
|
|
||||||
|
/* remove this node from the list */
|
||||||
|
void _libssh2_list_remove(struct list_node *entry);
|
||||||
|
|
||||||
|
size_t _libssh2_base64_encode(LIBSSH2_SESSION *session,
|
||||||
|
const char *inp, size_t insize, char **outptr);
|
||||||
|
|
||||||
|
unsigned int _libssh2_ntohu32(const unsigned char *buf);
|
||||||
|
libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf);
|
||||||
|
void _libssh2_htonu32(unsigned char *buf, uint32_t val);
|
||||||
|
void _libssh2_store_u32(unsigned char **buf, uint32_t value);
|
||||||
|
void _libssh2_store_str(unsigned char **buf, const char *str, size_t len);
|
||||||
|
void _libssh2_store_bignum2_bytes(unsigned char **buf,
|
||||||
|
const unsigned char *bytes,
|
||||||
|
size_t len);
|
||||||
|
void *_libssh2_calloc(LIBSSH2_SESSION *session, size_t size);
|
||||||
|
void _libssh2_explicit_zero(void *buf, size_t size);
|
||||||
|
|
||||||
|
struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session);
|
||||||
|
void _libssh2_string_buf_free(LIBSSH2_SESSION *session,
|
||||||
|
struct string_buf *buf);
|
||||||
|
int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out);
|
||||||
|
int _libssh2_get_byte(struct string_buf *buf, unsigned char *out);
|
||||||
|
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out);
|
||||||
|
int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out);
|
||||||
|
int _libssh2_match_string(struct string_buf *buf, const char *match);
|
||||||
|
int _libssh2_get_string(struct string_buf *buf, unsigned char **outbuf,
|
||||||
|
size_t *outlen);
|
||||||
|
int _libssh2_copy_string(LIBSSH2_SESSION* session, struct string_buf *buf,
|
||||||
|
unsigned char **outbuf, size_t *outlen);
|
||||||
|
int _libssh2_get_bignum_bytes(struct string_buf *buf, unsigned char **outbuf,
|
||||||
|
size_t *outlen);
|
||||||
|
int _libssh2_check_length(struct string_buf *buf, size_t requested_len);
|
||||||
|
int _libssh2_eob(struct string_buf *buf);
|
||||||
|
|
||||||
|
#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||||
|
/* provide a private one */
|
||||||
|
#undef HAVE_GETTIMEOFDAY
|
||||||
|
int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp);
|
||||||
|
#define HAVE_LIBSSH2_GETTIMEOFDAY
|
||||||
|
#define LIBSSH2_GETTIMEOFDAY_WIN32 /* enable the win32 implementation */
|
||||||
|
#else
|
||||||
|
#ifdef HAVE_GETTIMEOFDAY
|
||||||
|
#define _libssh2_gettimeofday(x,y) gettimeofday(x,y)
|
||||||
|
#define HAVE_LIBSSH2_GETTIMEOFDAY
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void _libssh2_xor_data(unsigned char *output,
|
||||||
|
const unsigned char *input1,
|
||||||
|
const unsigned char *input2,
|
||||||
|
size_t length);
|
||||||
|
|
||||||
|
void _libssh2_aes_ctr_increment(unsigned char *ctr, size_t length);
|
||||||
|
|
||||||
|
#endif /* _LIBSSH2_MISC_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,445 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_OPENSSL_H
|
||||||
|
#define __LIBSSH2_OPENSSL_H
|
||||||
|
/* Copyright (C) 2009, 2010 Simon Josefsson
|
||||||
|
* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Author: Simon Josefsson
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* disable deprecated warnings in OpenSSL 3 */
|
||||||
|
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||||
|
|
||||||
|
#ifdef LIBSSH2_WOLFSSL
|
||||||
|
|
||||||
|
#include <wolfssl/options.h>
|
||||||
|
#include <openssl/ecdh.h>
|
||||||
|
|
||||||
|
#if defined(NO_DSA) || defined(HAVE_FIPS)
|
||||||
|
#define OPENSSL_NO_DSA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NO_MD5) || defined(HAVE_FIPS)
|
||||||
|
#define OPENSSL_NO_MD5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(WOLFSSL_RIPEMD) || defined(HAVE_FIPS)
|
||||||
|
#define OPENSSL_NO_RIPEMD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NO_RC4) || defined(HAVE_FIPS)
|
||||||
|
#define OPENSSL_NO_RC4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_DES3
|
||||||
|
#define OPENSSL_NO_DES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef EVP_aes_128_ctr
|
||||||
|
#define HAVE_EVP_AES_128_CTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* wolfSSL doesn't support Blowfish or CAST. */
|
||||||
|
#define OPENSSL_NO_BF
|
||||||
|
#define OPENSSL_NO_CAST
|
||||||
|
/* wolfSSL has no engine framework. */
|
||||||
|
#define OPENSSL_NO_ENGINE
|
||||||
|
|
||||||
|
#endif /* LIBSSH2_WOLFSSL */
|
||||||
|
|
||||||
|
#include <openssl/opensslconf.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
|
#include <openssl/engine.h>
|
||||||
|
#endif
|
||||||
|
#ifndef OPENSSL_NO_DSA
|
||||||
|
#include <openssl/dsa.h>
|
||||||
|
#endif
|
||||||
|
#ifndef OPENSSL_NO_MD5
|
||||||
|
#include <openssl/md5.h>
|
||||||
|
#endif
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && \
|
||||||
|
!defined(LIBRESSL_VERSION_NUMBER)) || defined(LIBSSH2_WOLFSSL) || \
|
||||||
|
LIBRESSL_VERSION_NUMBER >= 0x3050000fL
|
||||||
|
/* For wolfSSL, whether the structs are truly opaque or not, it's best to not
|
||||||
|
* rely on their internal data members being exposed publicly. */
|
||||||
|
# define HAVE_OPAQUE_STRUCTS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NO_RSA
|
||||||
|
# define LIBSSH2_RSA 0
|
||||||
|
# define LIBSSH2_RSA_SHA2 0
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_RSA 1
|
||||||
|
# define LIBSSH2_RSA_SHA2 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NO_DSA
|
||||||
|
# define LIBSSH2_DSA 0
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_DSA 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OPENSSL_NO_ECDSA) || defined(OPENSSL_NO_EC)
|
||||||
|
# define LIBSSH2_ECDSA 0
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_ECDSA 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
|
||||||
|
!defined(LIBRESSL_VERSION_NUMBER)) || \
|
||||||
|
LIBRESSL_VERSION_NUMBER >= 0x3070000fL
|
||||||
|
# define LIBSSH2_ED25519 1
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_ED25519 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NO_MD5
|
||||||
|
# define LIBSSH2_MD5 0
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_MD5 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OPENSSL_NO_RIPEMD) || defined(OPENSSL_NO_RMD160)
|
||||||
|
# define LIBSSH2_HMAC_RIPEMD 0
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_HMAC_RIPEMD 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LIBSSH2_HMAC_SHA256 1
|
||||||
|
#define LIBSSH2_HMAC_SHA512 1
|
||||||
|
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)) || \
|
||||||
|
(defined(LIBSSH2_WOLFSSL) && defined(WOLFSSL_AES_COUNTER))
|
||||||
|
# define LIBSSH2_AES_CTR 1
|
||||||
|
# define LIBSSH2_AES 1
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_AES_CTR 0
|
||||||
|
# define LIBSSH2_AES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NO_BF
|
||||||
|
# define LIBSSH2_BLOWFISH 0
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_BLOWFISH 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NO_RC4
|
||||||
|
# define LIBSSH2_RC4 0
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_RC4 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NO_CAST
|
||||||
|
# define LIBSSH2_CAST 0
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_CAST 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NO_DES
|
||||||
|
# define LIBSSH2_3DES 0
|
||||||
|
#else
|
||||||
|
# define LIBSSH2_3DES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
|
||||||
|
|
||||||
|
#define _libssh2_random(buf, len) (RAND_bytes((buf), (len)) == 1 ? 0 : -1)
|
||||||
|
|
||||||
|
#define libssh2_prepare_iovec(vec, len) /* Empty. */
|
||||||
|
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_sha1_ctx EVP_MD_CTX *
|
||||||
|
#else
|
||||||
|
#define libssh2_sha1_ctx EVP_MD_CTX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* returns 0 in case of failure */
|
||||||
|
int _libssh2_sha1_init(libssh2_sha1_ctx *ctx);
|
||||||
|
#define libssh2_sha1_init(x) _libssh2_sha1_init(x)
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
|
||||||
|
#define libssh2_sha1_final(ctx, out) do { \
|
||||||
|
EVP_DigestFinal(ctx, out, NULL); \
|
||||||
|
EVP_MD_CTX_free(ctx); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len)
|
||||||
|
#define libssh2_sha1_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
|
||||||
|
#endif
|
||||||
|
int _libssh2_sha1(const unsigned char *message, unsigned long len,
|
||||||
|
unsigned char *out);
|
||||||
|
#define libssh2_sha1(x,y,z) _libssh2_sha1(x,y,z)
|
||||||
|
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_sha256_ctx EVP_MD_CTX *
|
||||||
|
#else
|
||||||
|
#define libssh2_sha256_ctx EVP_MD_CTX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* returns 0 in case of failure */
|
||||||
|
int _libssh2_sha256_init(libssh2_sha256_ctx *ctx);
|
||||||
|
#define libssh2_sha256_init(x) _libssh2_sha256_init(x)
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_sha256_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
|
||||||
|
#define libssh2_sha256_final(ctx, out) do { \
|
||||||
|
EVP_DigestFinal(ctx, out, NULL); \
|
||||||
|
EVP_MD_CTX_free(ctx); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define libssh2_sha256_update(ctx, data, len) \
|
||||||
|
EVP_DigestUpdate(&(ctx), data, len)
|
||||||
|
#define libssh2_sha256_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
|
||||||
|
#endif
|
||||||
|
int _libssh2_sha256(const unsigned char *message, unsigned long len,
|
||||||
|
unsigned char *out);
|
||||||
|
#define libssh2_sha256(x,y,z) _libssh2_sha256(x,y,z)
|
||||||
|
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_sha384_ctx EVP_MD_CTX *
|
||||||
|
#else
|
||||||
|
#define libssh2_sha384_ctx EVP_MD_CTX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* returns 0 in case of failure */
|
||||||
|
int _libssh2_sha384_init(libssh2_sha384_ctx *ctx);
|
||||||
|
#define libssh2_sha384_init(x) _libssh2_sha384_init(x)
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_sha384_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
|
||||||
|
#define libssh2_sha384_final(ctx, out) do { \
|
||||||
|
EVP_DigestFinal(ctx, out, NULL); \
|
||||||
|
EVP_MD_CTX_free(ctx); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define libssh2_sha384_update(ctx, data, len) \
|
||||||
|
EVP_DigestUpdate(&(ctx), data, len)
|
||||||
|
#define libssh2_sha384_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
|
||||||
|
#endif
|
||||||
|
int _libssh2_sha384(const unsigned char *message, unsigned long len,
|
||||||
|
unsigned char *out);
|
||||||
|
#define libssh2_sha384(x,y,z) _libssh2_sha384(x,y,z)
|
||||||
|
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_sha512_ctx EVP_MD_CTX *
|
||||||
|
#else
|
||||||
|
#define libssh2_sha512_ctx EVP_MD_CTX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* returns 0 in case of failure */
|
||||||
|
int _libssh2_sha512_init(libssh2_sha512_ctx *ctx);
|
||||||
|
#define libssh2_sha512_init(x) _libssh2_sha512_init(x)
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_sha512_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
|
||||||
|
#define libssh2_sha512_final(ctx, out) do { \
|
||||||
|
EVP_DigestFinal(ctx, out, NULL); \
|
||||||
|
EVP_MD_CTX_free(ctx); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define libssh2_sha512_update(ctx, data, len) \
|
||||||
|
EVP_DigestUpdate(&(ctx), data, len)
|
||||||
|
#define libssh2_sha512_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
|
||||||
|
#endif
|
||||||
|
int _libssh2_sha512(const unsigned char *message, unsigned long len,
|
||||||
|
unsigned char *out);
|
||||||
|
#define libssh2_sha512(x,y,z) _libssh2_sha512(x,y,z)
|
||||||
|
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_md5_ctx EVP_MD_CTX *
|
||||||
|
#else
|
||||||
|
#define libssh2_md5_ctx EVP_MD_CTX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* returns 0 in case of failure */
|
||||||
|
int _libssh2_md5_init(libssh2_md5_ctx *ctx);
|
||||||
|
#define libssh2_md5_init(x) _libssh2_md5_init(x)
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
|
||||||
|
#define libssh2_md5_final(ctx, out) do { \
|
||||||
|
EVP_DigestFinal(ctx, out, NULL); \
|
||||||
|
EVP_MD_CTX_free(ctx); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len)
|
||||||
|
#define libssh2_md5_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define libssh2_hmac_ctx HMAC_CTX *
|
||||||
|
#define libssh2_hmac_ctx_init(ctx) ctx = HMAC_CTX_new()
|
||||||
|
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(*(ctx), key, keylen, EVP_sha1(), NULL)
|
||||||
|
#define libssh2_hmac_md5_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(*(ctx), key, keylen, EVP_md5(), NULL)
|
||||||
|
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(*(ctx), key, keylen, EVP_ripemd160(), NULL)
|
||||||
|
#define libssh2_hmac_sha256_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(*(ctx), key, keylen, EVP_sha256(), NULL)
|
||||||
|
#define libssh2_hmac_sha512_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(*(ctx), key, keylen, EVP_sha512(), NULL)
|
||||||
|
|
||||||
|
#define libssh2_hmac_update(ctx, data, datalen) \
|
||||||
|
HMAC_Update(ctx, data, datalen)
|
||||||
|
#define libssh2_hmac_final(ctx, data) HMAC_Final(ctx, data, NULL)
|
||||||
|
#define libssh2_hmac_cleanup(ctx) HMAC_CTX_free(*(ctx))
|
||||||
|
#else
|
||||||
|
#define libssh2_hmac_ctx HMAC_CTX
|
||||||
|
#define libssh2_hmac_ctx_init(ctx) \
|
||||||
|
HMAC_CTX_init(&ctx)
|
||||||
|
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(ctx, key, keylen, EVP_sha1(), NULL)
|
||||||
|
#define libssh2_hmac_md5_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(ctx, key, keylen, EVP_md5(), NULL)
|
||||||
|
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(ctx, key, keylen, EVP_ripemd160(), NULL)
|
||||||
|
#define libssh2_hmac_sha256_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(ctx, key, keylen, EVP_sha256(), NULL)
|
||||||
|
#define libssh2_hmac_sha512_init(ctx, key, keylen) \
|
||||||
|
HMAC_Init_ex(ctx, key, keylen, EVP_sha512(), NULL)
|
||||||
|
|
||||||
|
#define libssh2_hmac_update(ctx, data, datalen) \
|
||||||
|
HMAC_Update(&(ctx), data, datalen)
|
||||||
|
#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
|
||||||
|
#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void _libssh2_openssl_crypto_init(void);
|
||||||
|
extern void _libssh2_openssl_crypto_exit(void);
|
||||||
|
#define libssh2_crypto_init() _libssh2_openssl_crypto_init()
|
||||||
|
#define libssh2_crypto_exit() _libssh2_openssl_crypto_exit()
|
||||||
|
|
||||||
|
#define libssh2_rsa_ctx RSA
|
||||||
|
|
||||||
|
#define _libssh2_rsa_free(rsactx) RSA_free(rsactx)
|
||||||
|
|
||||||
|
#define libssh2_dsa_ctx DSA
|
||||||
|
|
||||||
|
#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
|
||||||
|
|
||||||
|
#if LIBSSH2_ECDSA
|
||||||
|
#define libssh2_ecdsa_ctx EC_KEY
|
||||||
|
#define _libssh2_ecdsa_free(ecdsactx) EC_KEY_free(ecdsactx)
|
||||||
|
#define _libssh2_ec_key EC_KEY
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LIBSSH2_EC_CURVE_NISTP256 = NID_X9_62_prime256v1,
|
||||||
|
LIBSSH2_EC_CURVE_NISTP384 = NID_secp384r1,
|
||||||
|
LIBSSH2_EC_CURVE_NISTP521 = NID_secp521r1
|
||||||
|
}
|
||||||
|
libssh2_curve_type;
|
||||||
|
#else
|
||||||
|
#define _libssh2_ec_key void
|
||||||
|
#endif /* LIBSSH2_ECDSA */
|
||||||
|
|
||||||
|
#if LIBSSH2_ED25519
|
||||||
|
#define libssh2_ed25519_ctx EVP_PKEY
|
||||||
|
|
||||||
|
#define _libssh2_ed25519_free(ctx) EVP_PKEY_free(ctx)
|
||||||
|
#endif /* ED25519 */
|
||||||
|
|
||||||
|
#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define _libssh2_cipher_ctx EVP_CIPHER_CTX *
|
||||||
|
#else
|
||||||
|
#define _libssh2_cipher_ctx EVP_CIPHER_CTX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _libssh2_cipher_aes256 EVP_aes_256_cbc
|
||||||
|
#define _libssh2_cipher_aes192 EVP_aes_192_cbc
|
||||||
|
#define _libssh2_cipher_aes128 EVP_aes_128_cbc
|
||||||
|
#ifdef HAVE_EVP_AES_128_CTR
|
||||||
|
#define _libssh2_cipher_aes128ctr EVP_aes_128_ctr
|
||||||
|
#define _libssh2_cipher_aes192ctr EVP_aes_192_ctr
|
||||||
|
#define _libssh2_cipher_aes256ctr EVP_aes_256_ctr
|
||||||
|
#else
|
||||||
|
#define _libssh2_cipher_aes128ctr _libssh2_EVP_aes_128_ctr
|
||||||
|
#define _libssh2_cipher_aes192ctr _libssh2_EVP_aes_192_ctr
|
||||||
|
#define _libssh2_cipher_aes256ctr _libssh2_EVP_aes_256_ctr
|
||||||
|
#endif
|
||||||
|
#define _libssh2_cipher_blowfish EVP_bf_cbc
|
||||||
|
#define _libssh2_cipher_arcfour EVP_rc4
|
||||||
|
#define _libssh2_cipher_cast5 EVP_cast5_cbc
|
||||||
|
#define _libssh2_cipher_3des EVP_des_ede3_cbc
|
||||||
|
|
||||||
|
#ifdef HAVE_OPAQUE_STRUCTS
|
||||||
|
#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_free(*(ctx))
|
||||||
|
#else
|
||||||
|
#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _libssh2_bn BIGNUM
|
||||||
|
#define _libssh2_bn_ctx BN_CTX
|
||||||
|
#define _libssh2_bn_ctx_new() BN_CTX_new()
|
||||||
|
#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx)
|
||||||
|
#define _libssh2_bn_init() BN_new()
|
||||||
|
#define _libssh2_bn_init_from_bin() _libssh2_bn_init()
|
||||||
|
#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val)
|
||||||
|
#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn)
|
||||||
|
#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val)
|
||||||
|
#define _libssh2_bn_bytes(bn) BN_num_bytes(bn)
|
||||||
|
#define _libssh2_bn_bits(bn) BN_num_bits(bn)
|
||||||
|
#define _libssh2_bn_free(bn) BN_clear_free(bn)
|
||||||
|
|
||||||
|
#define _libssh2_dh_ctx BIGNUM *
|
||||||
|
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
|
||||||
|
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
|
||||||
|
_libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx)
|
||||||
|
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
|
||||||
|
_libssh2_dh_secret(dhctx, secret, f, p, bnctx)
|
||||||
|
#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx)
|
||||||
|
extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx);
|
||||||
|
extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
|
||||||
|
_libssh2_bn *g, _libssh2_bn *p,
|
||||||
|
int group_order,
|
||||||
|
_libssh2_bn_ctx *bnctx);
|
||||||
|
extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
|
||||||
|
_libssh2_bn *f, _libssh2_bn *p,
|
||||||
|
_libssh2_bn_ctx *bnctx);
|
||||||
|
extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
|
||||||
|
|
||||||
|
const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void);
|
||||||
|
const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void);
|
||||||
|
const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_OPENSSL_H */
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,78 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_PACKET_H
|
||||||
|
#define __LIBSSH2_PACKET_H
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 by Daniel Stenberg
|
||||||
|
* Author: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int _libssh2_packet_read(LIBSSH2_SESSION * session);
|
||||||
|
|
||||||
|
int _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
|
||||||
|
unsigned char **data, size_t *data_len,
|
||||||
|
int match_ofs,
|
||||||
|
const unsigned char *match_buf,
|
||||||
|
size_t match_len);
|
||||||
|
|
||||||
|
int _libssh2_packet_askv(LIBSSH2_SESSION * session,
|
||||||
|
const unsigned char *packet_types,
|
||||||
|
unsigned char **data, size_t *data_len,
|
||||||
|
int match_ofs,
|
||||||
|
const unsigned char *match_buf,
|
||||||
|
size_t match_len);
|
||||||
|
int _libssh2_packet_require(LIBSSH2_SESSION * session,
|
||||||
|
unsigned char packet_type, unsigned char **data,
|
||||||
|
size_t *data_len, int match_ofs,
|
||||||
|
const unsigned char *match_buf,
|
||||||
|
size_t match_len,
|
||||||
|
packet_require_state_t * state);
|
||||||
|
int _libssh2_packet_requirev(LIBSSH2_SESSION *session,
|
||||||
|
const unsigned char *packet_types,
|
||||||
|
unsigned char **data, size_t *data_len,
|
||||||
|
int match_ofs,
|
||||||
|
const unsigned char *match_buf,
|
||||||
|
size_t match_len,
|
||||||
|
packet_requirev_state_t * state);
|
||||||
|
int _libssh2_packet_burn(LIBSSH2_SESSION * session,
|
||||||
|
libssh2_nonblocking_states * state);
|
||||||
|
int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||||
|
unsigned long data_len);
|
||||||
|
int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||||
|
size_t datalen, int macstate);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_PACKET_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,913 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (C) 2007 The Written Word, Inc.
|
||||||
|
* Copyright (C) 2008, Simon Josefsson
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
readline(char *line, int line_size, FILE * fp)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if(!line) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(!fgets(line, line_size, fp)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*line) {
|
||||||
|
len = strlen(line);
|
||||||
|
if(len > 0 && line[len - 1] == '\n') {
|
||||||
|
line[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*line) {
|
||||||
|
len = strlen(line);
|
||||||
|
if(len > 0 && line[len - 1] == '\r') {
|
||||||
|
line[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
readline_memory(char *line, size_t line_size,
|
||||||
|
const char *filedata, size_t filedata_len,
|
||||||
|
size_t *filedata_offset)
|
||||||
|
{
|
||||||
|
size_t off, len;
|
||||||
|
|
||||||
|
off = *filedata_offset;
|
||||||
|
|
||||||
|
for(len = 0; off + len < filedata_len && len < line_size - 1; len++) {
|
||||||
|
if(filedata[off + len] == '\n' ||
|
||||||
|
filedata[off + len] == '\r') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(len) {
|
||||||
|
memcpy(line, filedata + off, len);
|
||||||
|
*filedata_offset += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
line[len] = '\0';
|
||||||
|
*filedata_offset += 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LINE_SIZE 128
|
||||||
|
|
||||||
|
static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED";
|
||||||
|
|
||||||
|
static unsigned char hex_decode(char digit)
|
||||||
|
{
|
||||||
|
return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_pem_parse(LIBSSH2_SESSION * session,
|
||||||
|
const char *headerbegin,
|
||||||
|
const char *headerend,
|
||||||
|
const unsigned char *passphrase,
|
||||||
|
FILE * fp, unsigned char **data, unsigned int *datalen)
|
||||||
|
{
|
||||||
|
char line[LINE_SIZE];
|
||||||
|
unsigned char iv[LINE_SIZE];
|
||||||
|
char *b64data = NULL;
|
||||||
|
unsigned int b64datalen = 0;
|
||||||
|
int ret;
|
||||||
|
const LIBSSH2_CRYPT_METHOD *method = NULL;
|
||||||
|
|
||||||
|
do {
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
if(readline(line, LINE_SIZE, fp)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(strcmp(line, headerbegin) != 0);
|
||||||
|
|
||||||
|
if(readline(line, LINE_SIZE, fp)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(passphrase &&
|
||||||
|
memcmp(line, crypt_annotation, strlen(crypt_annotation)) == 0) {
|
||||||
|
const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(readline(line, LINE_SIZE, fp)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
all_methods = libssh2_crypt_methods();
|
||||||
|
while((cur_method = *all_methods++) != NULL) {
|
||||||
|
if(*cur_method->pem_annotation &&
|
||||||
|
memcmp(line, cur_method->pem_annotation,
|
||||||
|
strlen(cur_method->pem_annotation)) == 0) {
|
||||||
|
method = cur_method;
|
||||||
|
memcpy(iv, line + strlen(method->pem_annotation) + 1,
|
||||||
|
2*method->iv_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* None of the available crypt methods were able to decrypt the key */
|
||||||
|
if(method == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Decode IV from hex */
|
||||||
|
for(i = 0; i < method->iv_len; ++i) {
|
||||||
|
iv[i] = hex_decode(iv[2*i]) << 4;
|
||||||
|
iv[i] |= hex_decode(iv[2*i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip to the next line */
|
||||||
|
if(readline(line, LINE_SIZE, fp)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(*line) {
|
||||||
|
char *tmp;
|
||||||
|
size_t linelen;
|
||||||
|
|
||||||
|
linelen = strlen(line);
|
||||||
|
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
|
||||||
|
if(!tmp) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for PEM parsing");
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memcpy(tmp + b64datalen, line, linelen);
|
||||||
|
b64data = tmp;
|
||||||
|
b64datalen += linelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
if(readline(line, LINE_SIZE, fp)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} while(strcmp(line, headerend) != 0);
|
||||||
|
|
||||||
|
if(!b64data) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(libssh2_base64_decode(session, (char **) data, datalen,
|
||||||
|
b64data, b64datalen)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(method) {
|
||||||
|
/* Set up decryption */
|
||||||
|
int free_iv = 0, free_secret = 0, len_decrypted = 0, padding = 0;
|
||||||
|
int blocksize = method->blocksize;
|
||||||
|
void *abstract;
|
||||||
|
unsigned char secret[2*MD5_DIGEST_LENGTH];
|
||||||
|
libssh2_md5_ctx fingerprint_ctx;
|
||||||
|
|
||||||
|
/* Perform key derivation (PBKDF1/MD5) */
|
||||||
|
if(!libssh2_md5_init(&fingerprint_ctx)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
libssh2_md5_update(fingerprint_ctx, passphrase,
|
||||||
|
strlen((char *)passphrase));
|
||||||
|
libssh2_md5_update(fingerprint_ctx, iv, 8);
|
||||||
|
libssh2_md5_final(fingerprint_ctx, secret);
|
||||||
|
if(method->secret_len > MD5_DIGEST_LENGTH) {
|
||||||
|
if(!libssh2_md5_init(&fingerprint_ctx)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
libssh2_md5_update(fingerprint_ctx, secret, MD5_DIGEST_LENGTH);
|
||||||
|
libssh2_md5_update(fingerprint_ctx, passphrase,
|
||||||
|
strlen((char *)passphrase));
|
||||||
|
libssh2_md5_update(fingerprint_ctx, iv, 8);
|
||||||
|
libssh2_md5_final(fingerprint_ctx, secret + MD5_DIGEST_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the decryption */
|
||||||
|
if(method->init(session, method, iv, &free_iv, secret,
|
||||||
|
&free_secret, 0, &abstract)) {
|
||||||
|
_libssh2_explicit_zero((char *)secret, sizeof(secret));
|
||||||
|
LIBSSH2_FREE(session, data);
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(free_secret) {
|
||||||
|
_libssh2_explicit_zero((char *)secret, sizeof(secret));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the actual decryption */
|
||||||
|
if((*datalen % blocksize) != 0) {
|
||||||
|
_libssh2_explicit_zero((char *)secret, sizeof(secret));
|
||||||
|
method->dtor(session, &abstract);
|
||||||
|
_libssh2_explicit_zero(*data, *datalen);
|
||||||
|
LIBSSH2_FREE(session, *data);
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(len_decrypted <= (int)*datalen - blocksize) {
|
||||||
|
if(method->crypt(session, *data + len_decrypted, blocksize,
|
||||||
|
&abstract)) {
|
||||||
|
ret = LIBSSH2_ERROR_DECRYPT;
|
||||||
|
_libssh2_explicit_zero((char *)secret, sizeof(secret));
|
||||||
|
method->dtor(session, &abstract);
|
||||||
|
_libssh2_explicit_zero(*data, *datalen);
|
||||||
|
LIBSSH2_FREE(session, *data);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
len_decrypted += blocksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account for padding */
|
||||||
|
padding = (*data)[*datalen - 1];
|
||||||
|
memset(&(*data)[*datalen-padding], 0, padding);
|
||||||
|
*datalen -= padding;
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
_libssh2_explicit_zero((char *)secret, sizeof(secret));
|
||||||
|
method->dtor(session, &abstract);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
if(b64data) {
|
||||||
|
_libssh2_explicit_zero(b64data, b64datalen);
|
||||||
|
LIBSSH2_FREE(session, b64data);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
|
||||||
|
const char *headerbegin,
|
||||||
|
const char *headerend,
|
||||||
|
const char *filedata, size_t filedata_len,
|
||||||
|
unsigned char **data, unsigned int *datalen)
|
||||||
|
{
|
||||||
|
char line[LINE_SIZE];
|
||||||
|
char *b64data = NULL;
|
||||||
|
unsigned int b64datalen = 0;
|
||||||
|
size_t off = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
do {
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(strcmp(line, headerbegin) != 0);
|
||||||
|
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(*line) {
|
||||||
|
char *tmp;
|
||||||
|
size_t linelen;
|
||||||
|
|
||||||
|
linelen = strlen(line);
|
||||||
|
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
|
||||||
|
if(!tmp) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for PEM parsing");
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memcpy(tmp + b64datalen, line, linelen);
|
||||||
|
b64data = tmp;
|
||||||
|
b64datalen += linelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} while(strcmp(line, headerend) != 0);
|
||||||
|
|
||||||
|
if(!b64data) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(libssh2_base64_decode(session, (char **) data, datalen,
|
||||||
|
b64data, b64datalen)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
if(b64data) {
|
||||||
|
_libssh2_explicit_zero(b64data, b64datalen);
|
||||||
|
LIBSSH2_FREE(session, b64data);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OpenSSH formatted keys */
|
||||||
|
#define AUTH_MAGIC "openssh-key-v1"
|
||||||
|
#define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
|
||||||
|
#define OPENSSH_HEADER_END "-----END OPENSSH PRIVATE KEY-----"
|
||||||
|
|
||||||
|
static int
|
||||||
|
_libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
|
||||||
|
const unsigned char *passphrase,
|
||||||
|
const char *b64data, size_t b64datalen,
|
||||||
|
struct string_buf **decrypted_buf)
|
||||||
|
{
|
||||||
|
const LIBSSH2_CRYPT_METHOD *method = NULL;
|
||||||
|
struct string_buf decoded, decrypted, kdf_buf;
|
||||||
|
unsigned char *ciphername = NULL;
|
||||||
|
unsigned char *kdfname = NULL;
|
||||||
|
unsigned char *kdf = NULL;
|
||||||
|
unsigned char *buf = NULL;
|
||||||
|
unsigned char *salt = NULL;
|
||||||
|
uint32_t nkeys, check1, check2;
|
||||||
|
uint32_t rounds = 0;
|
||||||
|
unsigned char *key = NULL;
|
||||||
|
unsigned char *key_part = NULL;
|
||||||
|
unsigned char *iv_part = NULL;
|
||||||
|
unsigned char *f = NULL;
|
||||||
|
unsigned int f_len = 0;
|
||||||
|
int ret = 0, keylen = 0, ivlen = 0, total_len = 0;
|
||||||
|
size_t kdf_len = 0, tmp_len = 0, salt_len = 0;
|
||||||
|
|
||||||
|
if(decrypted_buf)
|
||||||
|
*decrypted_buf = NULL;
|
||||||
|
|
||||||
|
/* decode file */
|
||||||
|
if(libssh2_base64_decode(session, (char **)&f, &f_len,
|
||||||
|
b64data, b64datalen)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the file */
|
||||||
|
decoded.data = (unsigned char *)f;
|
||||||
|
decoded.dataptr = (unsigned char *)f;
|
||||||
|
decoded.len = f_len;
|
||||||
|
|
||||||
|
if(decoded.len < strlen(AUTH_MAGIC)) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "key too short");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strncmp((char *) decoded.dataptr, AUTH_MAGIC,
|
||||||
|
strlen(AUTH_MAGIC)) != 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"key auth magic mismatch");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded.dataptr += strlen(AUTH_MAGIC) + 1;
|
||||||
|
|
||||||
|
if(_libssh2_get_string(&decoded, &ciphername, &tmp_len) ||
|
||||||
|
tmp_len == 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"ciphername is missing");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) ||
|
||||||
|
tmp_len == 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"kdfname is missing");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_libssh2_get_string(&decoded, &kdf, &kdf_len)) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"kdf is missing");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kdf_buf.data = kdf;
|
||||||
|
kdf_buf.dataptr = kdf;
|
||||||
|
kdf_buf.len = kdf_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((passphrase == NULL || strlen((const char *)passphrase) == 0) &&
|
||||||
|
strcmp((const char *)ciphername, "none") != 0) {
|
||||||
|
/* passphrase required */
|
||||||
|
ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp((const char *)kdfname, "none") != 0 &&
|
||||||
|
strcmp((const char *)kdfname, "bcrypt") != 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"unknown cipher");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp((const char *)kdfname, "none") &&
|
||||||
|
strcmp((const char *)ciphername, "none") != 0) {
|
||||||
|
ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"invalid format");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_libssh2_get_u32(&decoded, &nkeys) != 0 || nkeys != 1) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Multiple keys are unsupported");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unencrypted public key */
|
||||||
|
|
||||||
|
if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Invalid private key; "
|
||||||
|
"expect embedded public key");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Private key data not found");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode encrypted private key */
|
||||||
|
decrypted.data = decrypted.dataptr = buf;
|
||||||
|
decrypted.len = tmp_len;
|
||||||
|
|
||||||
|
if(ciphername && strcmp((const char *)ciphername, "none") != 0) {
|
||||||
|
const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
|
||||||
|
|
||||||
|
all_methods = libssh2_crypt_methods();
|
||||||
|
while((cur_method = *all_methods++) != NULL) {
|
||||||
|
if(*cur_method->name &&
|
||||||
|
memcmp(ciphername, cur_method->name,
|
||||||
|
strlen(cur_method->name)) == 0) {
|
||||||
|
method = cur_method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* None of the available crypt methods were able to decrypt the key */
|
||||||
|
|
||||||
|
if(method == NULL) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"No supported cipher found");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(method) {
|
||||||
|
int free_iv = 0, free_secret = 0, len_decrypted = 0;
|
||||||
|
int blocksize;
|
||||||
|
void *abstract = NULL;
|
||||||
|
|
||||||
|
keylen = method->secret_len;
|
||||||
|
ivlen = method->iv_len;
|
||||||
|
total_len = keylen + ivlen;
|
||||||
|
|
||||||
|
key = LIBSSH2_CALLOC(session, total_len);
|
||||||
|
if(key == NULL) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Could not alloc key");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp((const char *)kdfname, "bcrypt") == 0 &&
|
||||||
|
passphrase != NULL) {
|
||||||
|
if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) ||
|
||||||
|
(_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"kdf contains unexpected values");
|
||||||
|
LIBSSH2_FREE(session, key);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_libssh2_bcrypt_pbkdf((const char *)passphrase,
|
||||||
|
strlen((const char *)passphrase),
|
||||||
|
salt, salt_len, key,
|
||||||
|
keylen + ivlen, rounds) < 0) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
|
||||||
|
"invalid format");
|
||||||
|
LIBSSH2_FREE(session, key);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED,
|
||||||
|
"bcrypted without passphrase");
|
||||||
|
LIBSSH2_FREE(session, key);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up decryption */
|
||||||
|
blocksize = method->blocksize;
|
||||||
|
|
||||||
|
key_part = LIBSSH2_CALLOC(session, keylen);
|
||||||
|
if(key_part == NULL) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Could not alloc key part");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
iv_part = LIBSSH2_CALLOC(session, ivlen);
|
||||||
|
if(iv_part == NULL) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Could not alloc iv part");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(key_part, key, keylen);
|
||||||
|
memcpy(iv_part, key + keylen, ivlen);
|
||||||
|
|
||||||
|
/* Initialize the decryption */
|
||||||
|
if(method->init(session, method, iv_part, &free_iv, key_part,
|
||||||
|
&free_secret, 0, &abstract)) {
|
||||||
|
ret = LIBSSH2_ERROR_DECRYPT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the actual decryption */
|
||||||
|
if((decrypted.len % blocksize) != 0) {
|
||||||
|
method->dtor(session, &abstract);
|
||||||
|
ret = LIBSSH2_ERROR_DECRYPT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while((size_t)len_decrypted <= decrypted.len - blocksize) {
|
||||||
|
if(method->crypt(session, decrypted.data + len_decrypted,
|
||||||
|
blocksize,
|
||||||
|
&abstract)) {
|
||||||
|
ret = LIBSSH2_ERROR_DECRYPT;
|
||||||
|
method->dtor(session, &abstract);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
len_decrypted += blocksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No padding */
|
||||||
|
|
||||||
|
method->dtor(session, &abstract);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check random bytes match */
|
||||||
|
|
||||||
|
if(_libssh2_get_u32(&decrypted, &check1) != 0 ||
|
||||||
|
_libssh2_get_u32(&decrypted, &check2) != 0 ||
|
||||||
|
check1 != check2) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Private key unpack failed (correct password?)");
|
||||||
|
ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(decrypted_buf != NULL) {
|
||||||
|
/* copy data to out-going buffer */
|
||||||
|
struct string_buf *out_buf = _libssh2_string_buf_new(session);
|
||||||
|
if(!out_buf) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"decrypted struct");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_buf->data = LIBSSH2_CALLOC(session, decrypted.len);
|
||||||
|
if(out_buf->data == NULL) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"decrypted struct");
|
||||||
|
_libssh2_string_buf_free(session, out_buf);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memcpy(out_buf->data, decrypted.data, decrypted.len);
|
||||||
|
out_buf->dataptr = out_buf->data +
|
||||||
|
(decrypted.dataptr - decrypted.data);
|
||||||
|
out_buf->len = decrypted.len;
|
||||||
|
|
||||||
|
*decrypted_buf = out_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
if(key) {
|
||||||
|
_libssh2_explicit_zero(key, total_len);
|
||||||
|
LIBSSH2_FREE(session, key);
|
||||||
|
}
|
||||||
|
if(key_part) {
|
||||||
|
_libssh2_explicit_zero(key_part, keylen);
|
||||||
|
LIBSSH2_FREE(session, key_part);
|
||||||
|
}
|
||||||
|
if(iv_part) {
|
||||||
|
_libssh2_explicit_zero(iv_part, ivlen);
|
||||||
|
LIBSSH2_FREE(session, iv_part);
|
||||||
|
}
|
||||||
|
if(f) {
|
||||||
|
_libssh2_explicit_zero(f, f_len);
|
||||||
|
LIBSSH2_FREE(session, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
|
||||||
|
const unsigned char *passphrase,
|
||||||
|
FILE * fp, struct string_buf **decrypted_buf)
|
||||||
|
{
|
||||||
|
char line[LINE_SIZE];
|
||||||
|
char *b64data = NULL;
|
||||||
|
unsigned int b64datalen = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* read file */
|
||||||
|
|
||||||
|
do {
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
if(readline(line, LINE_SIZE, fp)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
|
||||||
|
|
||||||
|
if(readline(line, LINE_SIZE, fp)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(*line) {
|
||||||
|
char *tmp;
|
||||||
|
size_t linelen;
|
||||||
|
|
||||||
|
linelen = strlen(line);
|
||||||
|
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
|
||||||
|
if(!tmp) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for PEM parsing");
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memcpy(tmp + b64datalen, line, linelen);
|
||||||
|
b64data = tmp;
|
||||||
|
b64datalen += linelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
if(readline(line, LINE_SIZE, fp)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} while(strcmp(line, OPENSSH_HEADER_END) != 0);
|
||||||
|
|
||||||
|
if(!b64data) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = _libssh2_openssh_pem_parse_data(session,
|
||||||
|
passphrase,
|
||||||
|
(const char *)b64data,
|
||||||
|
(size_t)b64datalen,
|
||||||
|
decrypted_buf);
|
||||||
|
|
||||||
|
if(b64data) {
|
||||||
|
_libssh2_explicit_zero(b64data, b64datalen);
|
||||||
|
LIBSSH2_FREE(session, b64data);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
|
||||||
|
const unsigned char *passphrase,
|
||||||
|
const char *filedata, size_t filedata_len,
|
||||||
|
struct string_buf **decrypted_buf)
|
||||||
|
{
|
||||||
|
char line[LINE_SIZE];
|
||||||
|
char *b64data = NULL;
|
||||||
|
unsigned int b64datalen = 0;
|
||||||
|
size_t off = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if(filedata == NULL || filedata_len <= 0)
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Error parsing PEM: filedata missing");
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
if(off >= filedata_len)
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Error parsing PEM: offset out of bounds");
|
||||||
|
|
||||||
|
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
|
||||||
|
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (*line) {
|
||||||
|
char *tmp;
|
||||||
|
size_t linelen;
|
||||||
|
|
||||||
|
linelen = strlen(line);
|
||||||
|
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
|
||||||
|
if(!tmp) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"PEM parsing");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memcpy(tmp + b64datalen, line, linelen);
|
||||||
|
b64data = tmp;
|
||||||
|
b64datalen += linelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
*line = '\0';
|
||||||
|
|
||||||
|
if(off >= filedata_len) {
|
||||||
|
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Error parsing PEM: offset out of bounds");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} while(strcmp(line, OPENSSH_HEADER_END) != 0);
|
||||||
|
|
||||||
|
if(!b64data)
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Error parsing PEM: base 64 data missing");
|
||||||
|
|
||||||
|
ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data,
|
||||||
|
b64datalen, decrypted_buf);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if(b64data) {
|
||||||
|
_libssh2_explicit_zero(b64data, b64datalen);
|
||||||
|
LIBSSH2_FREE(session, b64data);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
read_asn1_length(const unsigned char *data,
|
||||||
|
unsigned int datalen, unsigned int *len)
|
||||||
|
{
|
||||||
|
unsigned int lenlen;
|
||||||
|
int nextpos;
|
||||||
|
|
||||||
|
if(datalen < 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*len = data[0];
|
||||||
|
|
||||||
|
if(*len >= 0x80) {
|
||||||
|
lenlen = *len & 0x7F;
|
||||||
|
*len = data[1];
|
||||||
|
if(1 + lenlen > datalen) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(lenlen > 1) {
|
||||||
|
*len <<= 8;
|
||||||
|
*len |= data[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lenlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextpos = 1 + lenlen;
|
||||||
|
if(lenlen > 2 || 1 + lenlen + *len > datalen) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
|
||||||
|
{
|
||||||
|
unsigned int len;
|
||||||
|
int lenlen;
|
||||||
|
|
||||||
|
if(*datalen < 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((*data)[0] != '\x30') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*data)++;
|
||||||
|
(*datalen)--;
|
||||||
|
|
||||||
|
lenlen = read_asn1_length(*data, *datalen, &len);
|
||||||
|
if(lenlen < 0 || lenlen + len != *datalen) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data += lenlen;
|
||||||
|
*datalen -= lenlen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
|
||||||
|
unsigned char **i, unsigned int *ilen)
|
||||||
|
{
|
||||||
|
unsigned int len;
|
||||||
|
int lenlen;
|
||||||
|
|
||||||
|
if(*datalen < 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((*data)[0] != '\x02') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*data)++;
|
||||||
|
(*datalen)--;
|
||||||
|
|
||||||
|
lenlen = read_asn1_length(*data, *datalen, &len);
|
||||||
|
if(lenlen < 0 || lenlen + len > *datalen) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data += lenlen;
|
||||||
|
*datalen -= lenlen;
|
||||||
|
|
||||||
|
*i = *data;
|
||||||
|
*ilen = len;
|
||||||
|
|
||||||
|
*data += len;
|
||||||
|
*datalen -= len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,95 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_SESSION_H
|
||||||
|
#define __LIBSSH2_SESSION_H
|
||||||
|
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
||||||
|
* Copyright (c) 2009-2010 by Daniel Stenberg
|
||||||
|
* Copyright (c) 2010 Simon Josefsson <simon@josefsson.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Conveniance-macros to allow code like this;
|
||||||
|
|
||||||
|
int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock) );
|
||||||
|
|
||||||
|
int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock) );
|
||||||
|
|
||||||
|
The point of course being to make sure that while in non-blocking mode
|
||||||
|
these always return no matter what the return code is, but in blocking mode
|
||||||
|
it blocks if EAGAIN is the reason for the return from the underlying
|
||||||
|
function.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#define BLOCK_ADJUST(rc, sess, x) \
|
||||||
|
do { \
|
||||||
|
time_t entry_time = time(NULL); \
|
||||||
|
do { \
|
||||||
|
rc = x; \
|
||||||
|
/* the order of the check below is important to properly deal with \
|
||||||
|
the case when the 'sess' is freed */ \
|
||||||
|
if((rc != LIBSSH2_ERROR_EAGAIN) || !sess->api_block_mode) \
|
||||||
|
break; \
|
||||||
|
rc = _libssh2_wait_socket(sess, entry_time); \
|
||||||
|
} while(!rc); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For functions that returns a pointer, we need to check if the API is
|
||||||
|
* non-blocking and return immediately. If the pointer is non-NULL we return
|
||||||
|
* immediately. If the API is blocking and we get a NULL we check the errno
|
||||||
|
* and *only* if that is EAGAIN we loop and wait for socket action.
|
||||||
|
*/
|
||||||
|
#define BLOCK_ADJUST_ERRNO(ptr, sess, x) \
|
||||||
|
do { \
|
||||||
|
time_t entry_time = time(NULL); \
|
||||||
|
int rc; \
|
||||||
|
do { \
|
||||||
|
ptr = x; \
|
||||||
|
if(!sess->api_block_mode || \
|
||||||
|
(ptr != NULL) || \
|
||||||
|
(libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN) ) \
|
||||||
|
break; \
|
||||||
|
rc = _libssh2_wait_socket(sess, entry_time); \
|
||||||
|
} while(!rc); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t entry_time);
|
||||||
|
|
||||||
|
/* this is the lib-internal set blocking function */
|
||||||
|
int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_SESSION_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,240 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_SFTP_H
|
||||||
|
#define __LIBSSH2_SFTP_H
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 - 2012 by Daniel Stenberg
|
||||||
|
* Author: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MAX_SFTP_OUTGOING_SIZE MUST not be larger than 32500 or so. This is the
|
||||||
|
* amount of data sent in each FXP_WRITE packet
|
||||||
|
*/
|
||||||
|
#define MAX_SFTP_OUTGOING_SIZE 30000
|
||||||
|
|
||||||
|
/* MAX_SFTP_READ_SIZE is how much data is asked for at max in each FXP_READ
|
||||||
|
* packets.
|
||||||
|
*/
|
||||||
|
#define MAX_SFTP_READ_SIZE 30000
|
||||||
|
|
||||||
|
struct sftp_pipeline_chunk {
|
||||||
|
struct list_node node;
|
||||||
|
libssh2_uint64_t offset; /* READ: offset at which to start reading
|
||||||
|
WRITE: not used */
|
||||||
|
size_t len; /* WRITE: size of the data to write
|
||||||
|
READ: how many bytes that was asked for */
|
||||||
|
size_t sent;
|
||||||
|
ssize_t lefttosend; /* if 0, the entire packet has been sent off */
|
||||||
|
uint32_t request_id;
|
||||||
|
unsigned char packet[1]; /* data */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sftp_zombie_requests {
|
||||||
|
struct list_node node;
|
||||||
|
uint32_t request_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(x,y) ((x)<(y)?(x):(y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct _LIBSSH2_SFTP_PACKET
|
||||||
|
{
|
||||||
|
struct list_node node; /* linked list header */
|
||||||
|
uint32_t request_id;
|
||||||
|
unsigned char *data;
|
||||||
|
size_t data_len; /* payload size */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _LIBSSH2_SFTP_PACKET LIBSSH2_SFTP_PACKET;
|
||||||
|
|
||||||
|
#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */
|
||||||
|
|
||||||
|
struct _LIBSSH2_SFTP_HANDLE
|
||||||
|
{
|
||||||
|
struct list_node node;
|
||||||
|
|
||||||
|
LIBSSH2_SFTP *sftp;
|
||||||
|
|
||||||
|
char handle[SFTP_HANDLE_MAXLEN];
|
||||||
|
size_t handle_len;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LIBSSH2_SFTP_HANDLE_FILE,
|
||||||
|
LIBSSH2_SFTP_HANDLE_DIR
|
||||||
|
} handle_type;
|
||||||
|
|
||||||
|
union _libssh2_sftp_handle_data
|
||||||
|
{
|
||||||
|
struct _libssh2_sftp_handle_file_data
|
||||||
|
{
|
||||||
|
libssh2_uint64_t offset;
|
||||||
|
libssh2_uint64_t offset_sent;
|
||||||
|
size_t acked; /* container for acked data that hasn't been
|
||||||
|
returned to caller yet, used for sftp_write */
|
||||||
|
|
||||||
|
/* 'data' is used by sftp_read() and is allocated data that has
|
||||||
|
been received already from the server but wasn't returned to
|
||||||
|
the caller yet. It is of size 'data_len' and 'data_left is the
|
||||||
|
number of bytes not yet returned, counted from the end of the
|
||||||
|
buffer. */
|
||||||
|
unsigned char *data;
|
||||||
|
size_t data_len;
|
||||||
|
size_t data_left;
|
||||||
|
|
||||||
|
char eof; /* we have read to the end */
|
||||||
|
} file;
|
||||||
|
struct _libssh2_sftp_handle_dir_data
|
||||||
|
{
|
||||||
|
uint32_t names_left;
|
||||||
|
void *names_packet;
|
||||||
|
char *next_name;
|
||||||
|
size_t names_packet_len;
|
||||||
|
} dir;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_close_handle() */
|
||||||
|
libssh2_nonblocking_states close_state;
|
||||||
|
uint32_t close_request_id;
|
||||||
|
unsigned char *close_packet;
|
||||||
|
|
||||||
|
/* list of outstanding packets sent to server */
|
||||||
|
struct list_head packet_list;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _LIBSSH2_SFTP
|
||||||
|
{
|
||||||
|
LIBSSH2_CHANNEL *channel;
|
||||||
|
|
||||||
|
uint32_t request_id, version;
|
||||||
|
|
||||||
|
struct list_head packets;
|
||||||
|
|
||||||
|
/* List of FXP_READ responses to ignore because EOF already received. */
|
||||||
|
struct list_head zombie_requests;
|
||||||
|
|
||||||
|
/* a list of _LIBSSH2_SFTP_HANDLE structs */
|
||||||
|
struct list_head sftp_handles;
|
||||||
|
|
||||||
|
uint32_t last_errno;
|
||||||
|
|
||||||
|
/* Holder for partial packet, use in libssh2_sftp_packet_read() */
|
||||||
|
unsigned char partial_size[4]; /* buffer for size field */
|
||||||
|
size_t partial_size_len; /* size field length */
|
||||||
|
unsigned char *partial_packet; /* The data */
|
||||||
|
uint32_t partial_len; /* Desired number of bytes */
|
||||||
|
size_t partial_received; /* Bytes received so far */
|
||||||
|
|
||||||
|
/* Time that libssh2_sftp_packet_requirev() started reading */
|
||||||
|
time_t requirev_start;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_open_ex() */
|
||||||
|
libssh2_nonblocking_states open_state;
|
||||||
|
unsigned char *open_packet;
|
||||||
|
uint32_t open_packet_len; /* 32 bit on the wire */
|
||||||
|
size_t open_packet_sent;
|
||||||
|
uint32_t open_request_id;
|
||||||
|
|
||||||
|
/* State variable used in sftp_read() */
|
||||||
|
libssh2_nonblocking_states read_state;
|
||||||
|
|
||||||
|
/* State variable used in sftp_packet_read() */
|
||||||
|
libssh2_nonblocking_states packet_state;
|
||||||
|
|
||||||
|
/* State variable used in sftp_write() */
|
||||||
|
libssh2_nonblocking_states write_state;
|
||||||
|
|
||||||
|
/* State variables used in sftp_fsync() */
|
||||||
|
libssh2_nonblocking_states fsync_state;
|
||||||
|
unsigned char *fsync_packet;
|
||||||
|
uint32_t fsync_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_readdir() */
|
||||||
|
libssh2_nonblocking_states readdir_state;
|
||||||
|
unsigned char *readdir_packet;
|
||||||
|
uint32_t readdir_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_fstat_ex() */
|
||||||
|
libssh2_nonblocking_states fstat_state;
|
||||||
|
unsigned char *fstat_packet;
|
||||||
|
uint32_t fstat_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_unlink_ex() */
|
||||||
|
libssh2_nonblocking_states unlink_state;
|
||||||
|
unsigned char *unlink_packet;
|
||||||
|
uint32_t unlink_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_rename_ex() */
|
||||||
|
libssh2_nonblocking_states rename_state;
|
||||||
|
unsigned char *rename_packet;
|
||||||
|
unsigned char *rename_s;
|
||||||
|
uint32_t rename_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_fstatvfs() */
|
||||||
|
libssh2_nonblocking_states fstatvfs_state;
|
||||||
|
unsigned char *fstatvfs_packet;
|
||||||
|
uint32_t fstatvfs_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_statvfs() */
|
||||||
|
libssh2_nonblocking_states statvfs_state;
|
||||||
|
unsigned char *statvfs_packet;
|
||||||
|
uint32_t statvfs_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_mkdir() */
|
||||||
|
libssh2_nonblocking_states mkdir_state;
|
||||||
|
unsigned char *mkdir_packet;
|
||||||
|
uint32_t mkdir_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_rmdir() */
|
||||||
|
libssh2_nonblocking_states rmdir_state;
|
||||||
|
unsigned char *rmdir_packet;
|
||||||
|
uint32_t rmdir_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_stat() */
|
||||||
|
libssh2_nonblocking_states stat_state;
|
||||||
|
unsigned char *stat_packet;
|
||||||
|
uint32_t stat_request_id;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_sftp_symlink() */
|
||||||
|
libssh2_nonblocking_states symlink_state;
|
||||||
|
unsigned char *symlink_packet;
|
||||||
|
uint32_t symlink_request_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_SFTP_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,933 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||||
|
* Author: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file handles reading and writing to the SECSH transport layer. RFC4253.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#ifdef LIBSSH2DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "transport.h"
|
||||||
|
#include "mac.h"
|
||||||
|
|
||||||
|
#define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */
|
||||||
|
#define MAX_MACSIZE 64 /* MUST fit biggest MAC length we support */
|
||||||
|
|
||||||
|
#ifdef LIBSSH2DEBUG
|
||||||
|
#define UNPRINTABLE_CHAR '.'
|
||||||
|
static void
|
||||||
|
debugdump(LIBSSH2_SESSION * session,
|
||||||
|
const char *desc, const unsigned char *ptr, size_t size)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
size_t c;
|
||||||
|
unsigned int width = 0x10;
|
||||||
|
char buffer[256]; /* Must be enough for width*4 + about 30 or so */
|
||||||
|
size_t used;
|
||||||
|
static const char *hex_chars = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
if(!(session->showmask & LIBSSH2_TRACE_TRANS)) {
|
||||||
|
/* not asked for, bail out */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
used = snprintf(buffer, sizeof(buffer), "=> %s (%d bytes)\n",
|
||||||
|
desc, (int) size);
|
||||||
|
if(session->tracehandler)
|
||||||
|
(session->tracehandler)(session, session->tracehandler_context,
|
||||||
|
buffer, used);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%s", buffer);
|
||||||
|
|
||||||
|
for(i = 0; i < size; i += width) {
|
||||||
|
|
||||||
|
used = snprintf(buffer, sizeof(buffer), "%04lx: ", (long)i);
|
||||||
|
|
||||||
|
/* hex not disabled, show it */
|
||||||
|
for(c = 0; c < width; c++) {
|
||||||
|
if(i + c < size) {
|
||||||
|
buffer[used++] = hex_chars[(ptr[i + c] >> 4) & 0xF];
|
||||||
|
buffer[used++] = hex_chars[ptr[i + c] & 0xF];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buffer[used++] = ' ';
|
||||||
|
buffer[used++] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[used++] = ' ';
|
||||||
|
if((width/2) - 1 == c)
|
||||||
|
buffer[used++] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[used++] = ':';
|
||||||
|
buffer[used++] = ' ';
|
||||||
|
|
||||||
|
for(c = 0; (c < width) && (i + c < size); c++) {
|
||||||
|
buffer[used++] = isprint(ptr[i + c]) ?
|
||||||
|
ptr[i + c] : UNPRINTABLE_CHAR;
|
||||||
|
}
|
||||||
|
buffer[used++] = '\n';
|
||||||
|
buffer[used] = 0;
|
||||||
|
|
||||||
|
if(session->tracehandler)
|
||||||
|
(session->tracehandler)(session, session->tracehandler_context,
|
||||||
|
buffer, used);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%s", buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define debugdump(a,x,y,z) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* decrypt() decrypts 'len' bytes from 'source' to 'dest' in units of
|
||||||
|
* blocksize.
|
||||||
|
*
|
||||||
|
* returns 0 on success and negative on failure
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
decrypt(LIBSSH2_SESSION * session, unsigned char *source,
|
||||||
|
unsigned char *dest, int len)
|
||||||
|
{
|
||||||
|
struct transportpacket *p = &session->packet;
|
||||||
|
int blocksize = session->remote.crypt->blocksize;
|
||||||
|
|
||||||
|
/* if we get called with a len that isn't an even number of blocksizes
|
||||||
|
we risk losing those extra bytes */
|
||||||
|
assert((len % blocksize) == 0);
|
||||||
|
|
||||||
|
while(len >= blocksize) {
|
||||||
|
if(session->remote.crypt->crypt(session, source, blocksize,
|
||||||
|
&session->remote.crypt_abstract)) {
|
||||||
|
LIBSSH2_FREE(session, p->payload);
|
||||||
|
return LIBSSH2_ERROR_DECRYPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the crypt() function would write to a given address it
|
||||||
|
wouldn't have to memcpy() and we could avoid this memcpy()
|
||||||
|
too */
|
||||||
|
memcpy(dest, source, blocksize);
|
||||||
|
|
||||||
|
len -= blocksize; /* less bytes left */
|
||||||
|
dest += blocksize; /* advance write pointer */
|
||||||
|
source += blocksize; /* advance read pointer */
|
||||||
|
}
|
||||||
|
return LIBSSH2_ERROR_NONE; /* all is fine */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fullpacket() gets called when a full packet has been received and properly
|
||||||
|
* collected.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
||||||
|
{
|
||||||
|
unsigned char macbuf[MAX_MACSIZE];
|
||||||
|
struct transportpacket *p = &session->packet;
|
||||||
|
int rc;
|
||||||
|
int compressed;
|
||||||
|
|
||||||
|
if(session->fullpacket_state == libssh2_NB_state_idle) {
|
||||||
|
session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
|
||||||
|
session->fullpacket_payload_len = p->packet_length - 1;
|
||||||
|
|
||||||
|
if(encrypted) {
|
||||||
|
|
||||||
|
/* Calculate MAC hash */
|
||||||
|
session->remote.mac->hash(session, macbuf, /* store hash here */
|
||||||
|
session->remote.seqno,
|
||||||
|
p->init, 5,
|
||||||
|
p->payload,
|
||||||
|
session->fullpacket_payload_len,
|
||||||
|
&session->remote.mac_abstract);
|
||||||
|
|
||||||
|
/* Compare the calculated hash with the MAC we just read from
|
||||||
|
* the network. The read one is at the very end of the payload
|
||||||
|
* buffer. Note that 'payload_len' here is the packet_length
|
||||||
|
* field which includes the padding but not the MAC.
|
||||||
|
*/
|
||||||
|
if(memcmp(macbuf, p->payload + session->fullpacket_payload_len,
|
||||||
|
session->remote.mac->mac_len)) {
|
||||||
|
session->fullpacket_macstate = LIBSSH2_MAC_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session->remote.seqno++;
|
||||||
|
|
||||||
|
/* ignore the padding */
|
||||||
|
session->fullpacket_payload_len -= p->padding_length;
|
||||||
|
|
||||||
|
/* Check for and deal with decompression */
|
||||||
|
compressed =
|
||||||
|
session->local.comp != NULL &&
|
||||||
|
session->local.comp->compress &&
|
||||||
|
((session->state & LIBSSH2_STATE_AUTHENTICATED) ||
|
||||||
|
session->local.comp->use_in_auth);
|
||||||
|
|
||||||
|
if(compressed && session->remote.comp_abstract) {
|
||||||
|
/*
|
||||||
|
* The buffer for the decompression (remote.comp_abstract) is
|
||||||
|
* initialised in time when it is needed so as long it is NULL we
|
||||||
|
* cannot decompress.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned char *data;
|
||||||
|
size_t data_len;
|
||||||
|
rc = session->remote.comp->decomp(session,
|
||||||
|
&data, &data_len,
|
||||||
|
LIBSSH2_PACKET_MAXDECOMP,
|
||||||
|
p->payload,
|
||||||
|
session->fullpacket_payload_len,
|
||||||
|
&session->remote.comp_abstract);
|
||||||
|
LIBSSH2_FREE(session, p->payload);
|
||||||
|
if(rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
p->payload = data;
|
||||||
|
session->fullpacket_payload_len = data_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->fullpacket_packet_type = p->payload[0];
|
||||||
|
|
||||||
|
debugdump(session, "libssh2_transport_read() plain",
|
||||||
|
p->payload, session->fullpacket_payload_len);
|
||||||
|
|
||||||
|
session->fullpacket_state = libssh2_NB_state_created;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(session->fullpacket_state == libssh2_NB_state_created) {
|
||||||
|
rc = _libssh2_packet_add(session, p->payload,
|
||||||
|
session->fullpacket_payload_len,
|
||||||
|
session->fullpacket_macstate);
|
||||||
|
if(rc == LIBSSH2_ERROR_EAGAIN)
|
||||||
|
return rc;
|
||||||
|
if(rc) {
|
||||||
|
session->fullpacket_state = libssh2_NB_state_idle;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session->fullpacket_state = libssh2_NB_state_idle;
|
||||||
|
|
||||||
|
return session->fullpacket_packet_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_transport_read
|
||||||
|
*
|
||||||
|
* Collect a packet into the input queue.
|
||||||
|
*
|
||||||
|
* Returns packet type added to input queue (0 if nothing added), or a
|
||||||
|
* negative error number.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function reads the binary stream as specified in chapter 6 of RFC4253
|
||||||
|
* "The Secure Shell (SSH) Transport Layer Protocol"
|
||||||
|
*
|
||||||
|
* DOES NOT call _libssh2_error() for ANY error case.
|
||||||
|
*/
|
||||||
|
int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct transportpacket *p = &session->packet;
|
||||||
|
int remainpack; /* how much there is left to add to the current payload
|
||||||
|
package */
|
||||||
|
int remainbuf; /* how much data there is remaining in the buffer to deal
|
||||||
|
with before we should read more from the network */
|
||||||
|
int numbytes; /* how much data to deal with from the buffer on this
|
||||||
|
iteration through the loop */
|
||||||
|
int numdecrypt; /* number of bytes to decrypt this iteration */
|
||||||
|
unsigned char block[MAX_BLOCKSIZE]; /* working block buffer */
|
||||||
|
int blocksize; /* minimum number of bytes we need before we can
|
||||||
|
use them */
|
||||||
|
int encrypted = 1; /* whether the packet is encrypted or not */
|
||||||
|
|
||||||
|
/* default clear the bit */
|
||||||
|
session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All channels, systems, subsystems, etc eventually make it down here
|
||||||
|
* when looking for more incoming data. If a key exchange is going on
|
||||||
|
* (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end will
|
||||||
|
* ONLY send key exchange related traffic. In non-blocking mode, there is
|
||||||
|
* a chance to break out of the kex_exchange function with an EAGAIN
|
||||||
|
* status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS is
|
||||||
|
* active, then we must redirect to the key exchange. However, if
|
||||||
|
* kex_exchange is active (as in it is the one that calls this execution
|
||||||
|
* of packet_read, then don't redirect, as that would be an infinite loop!
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
|
||||||
|
!(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {
|
||||||
|
|
||||||
|
/* Whoever wants a packet won't get anything until the key re-exchange
|
||||||
|
* is done!
|
||||||
|
*/
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the"
|
||||||
|
" key re-exchange from _libssh2_transport_read");
|
||||||
|
rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state);
|
||||||
|
if(rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* =============================== NOTE ===============================
|
||||||
|
* I know this is very ugly and not a really good use of "goto", but
|
||||||
|
* this case statement would be even uglier to do it any other way
|
||||||
|
*/
|
||||||
|
if(session->readPack_state == libssh2_NB_state_jump1) {
|
||||||
|
session->readPack_state = libssh2_NB_state_idle;
|
||||||
|
encrypted = session->readPack_encrypted;
|
||||||
|
goto libssh2_transport_read_point1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
|
||||||
|
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(session->state & LIBSSH2_STATE_NEWKEYS) {
|
||||||
|
blocksize = session->remote.crypt->blocksize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
encrypted = 0; /* not encrypted */
|
||||||
|
blocksize = 5; /* not strictly true, but we can use 5 here to
|
||||||
|
make the checks below work fine still */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read/use a whole big chunk into a temporary area stored in
|
||||||
|
the LIBSSH2_SESSION struct. We will decrypt data from that
|
||||||
|
buffer into the packet buffer so this temp one doesn't have
|
||||||
|
to be able to keep a whole SSH packet, just be large enough
|
||||||
|
so that we can read big chunks from the network layer. */
|
||||||
|
|
||||||
|
/* how much data there is remaining in the buffer to deal with
|
||||||
|
before we should read more from the network */
|
||||||
|
remainbuf = p->writeidx - p->readidx;
|
||||||
|
|
||||||
|
/* if remainbuf turns negative we have a bad internal error */
|
||||||
|
assert(remainbuf >= 0);
|
||||||
|
|
||||||
|
if(remainbuf < blocksize) {
|
||||||
|
/* If we have less than a blocksize left, it is too
|
||||||
|
little data to deal with, read more */
|
||||||
|
ssize_t nread;
|
||||||
|
|
||||||
|
/* move any remainder to the start of the buffer so
|
||||||
|
that we can do a full refill */
|
||||||
|
if(remainbuf) {
|
||||||
|
memmove(p->buf, &p->buf[p->readidx], remainbuf);
|
||||||
|
p->readidx = 0;
|
||||||
|
p->writeidx = remainbuf;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* nothing to move, just zero the indexes */
|
||||||
|
p->readidx = p->writeidx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now read a big chunk from the network into the temp buffer */
|
||||||
|
nread =
|
||||||
|
LIBSSH2_RECV(session, &p->buf[remainbuf],
|
||||||
|
PACKETBUFSIZE - remainbuf,
|
||||||
|
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||||
|
if(nread <= 0) {
|
||||||
|
/* check if this is due to EAGAIN and return the special
|
||||||
|
return code if so, error out normally otherwise */
|
||||||
|
if((nread < 0) && (nread == -EAGAIN)) {
|
||||||
|
session->socket_block_directions |=
|
||||||
|
LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||||
|
return LIBSSH2_ERROR_EAGAIN;
|
||||||
|
}
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
|
"Error recving %d bytes (got %d)",
|
||||||
|
PACKETBUFSIZE - remainbuf, -nread);
|
||||||
|
return LIBSSH2_ERROR_SOCKET_RECV;
|
||||||
|
}
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
|
"Recved %d/%d bytes to %p+%d", nread,
|
||||||
|
PACKETBUFSIZE - remainbuf, p->buf, remainbuf);
|
||||||
|
|
||||||
|
debugdump(session, "libssh2_transport_read() raw",
|
||||||
|
&p->buf[remainbuf], nread);
|
||||||
|
/* advance write pointer */
|
||||||
|
p->writeidx += nread;
|
||||||
|
|
||||||
|
/* update remainbuf counter */
|
||||||
|
remainbuf = p->writeidx - p->readidx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* how much data to deal with from the buffer */
|
||||||
|
numbytes = remainbuf;
|
||||||
|
|
||||||
|
if(!p->total_num) {
|
||||||
|
size_t total_num; /* the number of bytes following the initial
|
||||||
|
(5 bytes) packet length and padding length
|
||||||
|
fields */
|
||||||
|
|
||||||
|
/* No payload package area allocated yet. To know the
|
||||||
|
size of this payload, we need to decrypt the first
|
||||||
|
blocksize data. */
|
||||||
|
|
||||||
|
if(numbytes < blocksize) {
|
||||||
|
/* we can't act on anything less than blocksize, but this
|
||||||
|
check is only done for the initial block since once we have
|
||||||
|
got the start of a block we can in fact deal with fractions
|
||||||
|
*/
|
||||||
|
session->socket_block_directions |=
|
||||||
|
LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||||
|
return LIBSSH2_ERROR_EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encrypted) {
|
||||||
|
rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
|
||||||
|
if(rc != LIBSSH2_ERROR_NONE) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
/* save the first 5 bytes of the decrypted package, to be
|
||||||
|
used in the hash calculation later down. */
|
||||||
|
memcpy(p->init, block, 5);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* the data is plain, just copy it verbatim to
|
||||||
|
the working block buffer */
|
||||||
|
memcpy(block, &p->buf[p->readidx], blocksize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* advance the read pointer */
|
||||||
|
p->readidx += blocksize;
|
||||||
|
|
||||||
|
/* we now have the initial blocksize bytes decrypted,
|
||||||
|
* and we can extract packet and padding length from it
|
||||||
|
*/
|
||||||
|
p->packet_length = _libssh2_ntohu32(block);
|
||||||
|
if(p->packet_length < 1) {
|
||||||
|
return LIBSSH2_ERROR_DECRYPT;
|
||||||
|
}
|
||||||
|
else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
|
||||||
|
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->padding_length = block[4];
|
||||||
|
if(p->padding_length > p->packet_length - 1) {
|
||||||
|
return LIBSSH2_ERROR_DECRYPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* total_num is the number of bytes following the initial
|
||||||
|
(5 bytes) packet length and padding length fields */
|
||||||
|
total_num =
|
||||||
|
p->packet_length - 1 +
|
||||||
|
(encrypted ? session->remote.mac->mac_len : 0);
|
||||||
|
|
||||||
|
/* RFC4253 section 6.1 Maximum Packet Length says:
|
||||||
|
*
|
||||||
|
* "All implementations MUST be able to process
|
||||||
|
* packets with uncompressed payload length of 32768
|
||||||
|
* bytes or less and total packet size of 35000 bytes
|
||||||
|
* or less (including length, padding length, payload,
|
||||||
|
* padding, and MAC.)."
|
||||||
|
*/
|
||||||
|
if(total_num > LIBSSH2_PACKET_MAXPAYLOAD || total_num == 0) {
|
||||||
|
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get a packet handle put data into. We get one to
|
||||||
|
hold all data, including padding and MAC. */
|
||||||
|
p->payload = LIBSSH2_ALLOC(session, total_num);
|
||||||
|
if(!p->payload) {
|
||||||
|
return LIBSSH2_ERROR_ALLOC;
|
||||||
|
}
|
||||||
|
p->total_num = total_num;
|
||||||
|
/* init write pointer to start of payload buffer */
|
||||||
|
p->wptr = p->payload;
|
||||||
|
|
||||||
|
if(blocksize > 5) {
|
||||||
|
/* copy the data from index 5 to the end of
|
||||||
|
the blocksize from the temporary buffer to
|
||||||
|
the start of the decrypted buffer */
|
||||||
|
if(blocksize - 5 <= (int) total_num) {
|
||||||
|
memcpy(p->wptr, &block[5], blocksize - 5);
|
||||||
|
p->wptr += blocksize - 5; /* advance write pointer */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(p->payload)
|
||||||
|
LIBSSH2_FREE(session, p->payload);
|
||||||
|
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* init the data_num field to the number of bytes of
|
||||||
|
the package read so far */
|
||||||
|
p->data_num = p->wptr - p->payload;
|
||||||
|
|
||||||
|
/* we already dealt with a blocksize worth of data */
|
||||||
|
numbytes -= blocksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* how much there is left to add to the current payload
|
||||||
|
package */
|
||||||
|
remainpack = p->total_num - p->data_num;
|
||||||
|
|
||||||
|
if(numbytes > remainpack) {
|
||||||
|
/* if we have more data in the buffer than what is going into this
|
||||||
|
particular packet, we limit this round to this packet only */
|
||||||
|
numbytes = remainpack;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encrypted) {
|
||||||
|
/* At the end of the incoming stream, there is a MAC,
|
||||||
|
and we don't want to decrypt that since we need it
|
||||||
|
"raw". We MUST however decrypt the padding data
|
||||||
|
since it is used for the hash later on. */
|
||||||
|
int skip = session->remote.mac->mac_len;
|
||||||
|
|
||||||
|
/* if what we have plus numbytes is bigger than the
|
||||||
|
total minus the skip margin, we should lower the
|
||||||
|
amount to decrypt even more */
|
||||||
|
if((p->data_num + numbytes) > (p->total_num - skip)) {
|
||||||
|
numdecrypt = (p->total_num - skip) - p->data_num;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int frac;
|
||||||
|
numdecrypt = numbytes;
|
||||||
|
frac = numdecrypt % blocksize;
|
||||||
|
if(frac) {
|
||||||
|
/* not an aligned amount of blocks,
|
||||||
|
align it */
|
||||||
|
numdecrypt -= frac;
|
||||||
|
/* and make it no unencrypted data
|
||||||
|
after it */
|
||||||
|
numbytes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* unencrypted data should not be decrypted at all */
|
||||||
|
numdecrypt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if there are bytes to decrypt, do that */
|
||||||
|
if(numdecrypt > 0) {
|
||||||
|
/* now decrypt the lot */
|
||||||
|
rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt);
|
||||||
|
if(rc != LIBSSH2_ERROR_NONE) {
|
||||||
|
p->total_num = 0; /* no packet buffer available */
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* advance the read pointer */
|
||||||
|
p->readidx += numdecrypt;
|
||||||
|
/* advance write pointer */
|
||||||
|
p->wptr += numdecrypt;
|
||||||
|
/* increase data_num */
|
||||||
|
p->data_num += numdecrypt;
|
||||||
|
|
||||||
|
/* bytes left to take care of without decryption */
|
||||||
|
numbytes -= numdecrypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if there are bytes to copy that aren't decrypted, simply
|
||||||
|
copy them as-is to the target buffer */
|
||||||
|
if(numbytes > 0) {
|
||||||
|
|
||||||
|
if(numbytes <= (int)(p->total_num - (p->wptr - p->payload))) {
|
||||||
|
memcpy(p->wptr, &p->buf[p->readidx], numbytes);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(p->payload)
|
||||||
|
LIBSSH2_FREE(session, p->payload);
|
||||||
|
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* advance the read pointer */
|
||||||
|
p->readidx += numbytes;
|
||||||
|
/* advance write pointer */
|
||||||
|
p->wptr += numbytes;
|
||||||
|
/* increase data_num */
|
||||||
|
p->data_num += numbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now check how much data there's left to read to finish the
|
||||||
|
current packet */
|
||||||
|
remainpack = p->total_num - p->data_num;
|
||||||
|
|
||||||
|
if(!remainpack) {
|
||||||
|
/* we have a full packet */
|
||||||
|
libssh2_transport_read_point1:
|
||||||
|
rc = fullpacket(session, encrypted);
|
||||||
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
|
||||||
|
if(session->packAdd_state != libssh2_NB_state_idle) {
|
||||||
|
/* fullpacket only returns LIBSSH2_ERROR_EAGAIN if
|
||||||
|
* libssh2_packet_add returns LIBSSH2_ERROR_EAGAIN. If
|
||||||
|
* that returns LIBSSH2_ERROR_EAGAIN but the packAdd_state
|
||||||
|
* is idle, then the packet has been added to the brigade,
|
||||||
|
* but some immediate action that was taken based on the
|
||||||
|
* packet type (such as key re-exchange) is not yet
|
||||||
|
* complete. Clear the way for a new packet to be read
|
||||||
|
* in.
|
||||||
|
*/
|
||||||
|
session->readPack_encrypted = encrypted;
|
||||||
|
session->readPack_state = libssh2_NB_state_jump1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->total_num = 0; /* no packet buffer available */
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} while(1); /* loop */
|
||||||
|
|
||||||
|
return LIBSSH2_ERROR_SOCKET_RECV; /* we never reach this point */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
send_existing(LIBSSH2_SESSION *session, const unsigned char *data,
|
||||||
|
size_t data_len, ssize_t *ret)
|
||||||
|
{
|
||||||
|
ssize_t rc;
|
||||||
|
ssize_t length;
|
||||||
|
struct transportpacket *p = &session->packet;
|
||||||
|
|
||||||
|
if(!p->olen) {
|
||||||
|
*ret = 0;
|
||||||
|
return LIBSSH2_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send as much as possible of the existing packet */
|
||||||
|
if((data != p->odata) || (data_len != p->olen)) {
|
||||||
|
/* When we are about to complete the sending of a packet, it is vital
|
||||||
|
that the caller doesn't try to send a new/different packet since
|
||||||
|
we don't add this one up until the previous one has been sent. To
|
||||||
|
make the caller really notice his/hers flaw, we return error for
|
||||||
|
this case */
|
||||||
|
return LIBSSH2_ERROR_BAD_USE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = 1; /* set to make our parent return */
|
||||||
|
|
||||||
|
/* number of bytes left to send */
|
||||||
|
length = p->ototal_num - p->osent;
|
||||||
|
|
||||||
|
rc = LIBSSH2_SEND(session, &p->outbuf[p->osent], length,
|
||||||
|
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||||
|
if(rc < 0)
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
|
"Error sending %d bytes: %d", length, -rc);
|
||||||
|
else {
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
|
"Sent %d/%d bytes at %p+%d", rc, length, p->outbuf,
|
||||||
|
p->osent);
|
||||||
|
debugdump(session, "libssh2_transport_write send()",
|
||||||
|
&p->outbuf[p->osent], rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rc == length) {
|
||||||
|
/* the remainder of the package was sent */
|
||||||
|
p->ototal_num = 0;
|
||||||
|
p->olen = 0;
|
||||||
|
/* we leave *ret set so that the parent returns as we MUST return back
|
||||||
|
a send success now, so that we don't risk sending EAGAIN later
|
||||||
|
which then would confuse the parent function */
|
||||||
|
return LIBSSH2_ERROR_NONE;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(rc < 0) {
|
||||||
|
/* nothing was sent */
|
||||||
|
if(rc != -EAGAIN)
|
||||||
|
/* send failure! */
|
||||||
|
return LIBSSH2_ERROR_SOCKET_SEND;
|
||||||
|
|
||||||
|
session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||||
|
return LIBSSH2_ERROR_EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->osent += rc; /* we sent away this much data */
|
||||||
|
|
||||||
|
return rc < length ? LIBSSH2_ERROR_EAGAIN : LIBSSH2_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libssh2_transport_send
|
||||||
|
*
|
||||||
|
* Send a packet, encrypting it and adding a MAC code if necessary
|
||||||
|
* Returns 0 on success, non-zero on failure.
|
||||||
|
*
|
||||||
|
* The data is provided as _two_ data areas that are combined by this
|
||||||
|
* function. The 'data' part is sent immediately before 'data2'. 'data2' may
|
||||||
|
* be set to NULL to only use a single part.
|
||||||
|
*
|
||||||
|
* Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was
|
||||||
|
* not sent yet. If it does so, the caller should call this function again as
|
||||||
|
* soon as it is likely that more data can be sent, and this function MUST
|
||||||
|
* then be called with the same argument set (same data pointer and same
|
||||||
|
* data_len) until ERROR_NONE or failure is returned.
|
||||||
|
*
|
||||||
|
* This function DOES NOT call _libssh2_error() on any errors.
|
||||||
|
*/
|
||||||
|
int _libssh2_transport_send(LIBSSH2_SESSION *session,
|
||||||
|
const unsigned char *data, size_t data_len,
|
||||||
|
const unsigned char *data2, size_t data2_len)
|
||||||
|
{
|
||||||
|
int blocksize =
|
||||||
|
(session->state & LIBSSH2_STATE_NEWKEYS) ?
|
||||||
|
session->local.crypt->blocksize : 8;
|
||||||
|
int padding_length;
|
||||||
|
size_t packet_length;
|
||||||
|
int total_length;
|
||||||
|
#ifdef RANDOM_PADDING
|
||||||
|
int rand_max;
|
||||||
|
int seed = data[0]; /* FIXME: make this random */
|
||||||
|
#endif
|
||||||
|
struct transportpacket *p = &session->packet;
|
||||||
|
int encrypted;
|
||||||
|
int compressed;
|
||||||
|
ssize_t ret;
|
||||||
|
int rc;
|
||||||
|
const unsigned char *orgdata = data;
|
||||||
|
size_t orgdata_len = data_len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the last read operation was interrupted in the middle of a key
|
||||||
|
* exchange, we must complete that key exchange before continuing to write
|
||||||
|
* further data.
|
||||||
|
*
|
||||||
|
* See the similar block in _libssh2_transport_read for more details.
|
||||||
|
*/
|
||||||
|
if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
|
||||||
|
!(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {
|
||||||
|
/* Don't write any new packets if we're still in the middle of a key
|
||||||
|
* exchange. */
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the"
|
||||||
|
" key re-exchange from _libssh2_transport_send");
|
||||||
|
rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state);
|
||||||
|
if(rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugdump(session, "libssh2_transport_write plain", data, data_len);
|
||||||
|
if(data2)
|
||||||
|
debugdump(session, "libssh2_transport_write plain2", data2, data2_len);
|
||||||
|
|
||||||
|
/* FIRST, check if we have a pending write to complete. send_existing
|
||||||
|
only sanity-check data and data_len and not data2 and data2_len!! */
|
||||||
|
rc = send_existing(session, data, data_len, &ret);
|
||||||
|
if(rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||||
|
|
||||||
|
if(ret)
|
||||||
|
/* set by send_existing if data was sent */
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
|
||||||
|
|
||||||
|
compressed =
|
||||||
|
session->local.comp != NULL &&
|
||||||
|
session->local.comp->compress &&
|
||||||
|
((session->state & LIBSSH2_STATE_AUTHENTICATED) ||
|
||||||
|
session->local.comp->use_in_auth);
|
||||||
|
|
||||||
|
if(encrypted && compressed && session->local.comp_abstract) {
|
||||||
|
/* the idea here is that these function must fail if the output gets
|
||||||
|
larger than what fits in the assigned buffer so thus they don't
|
||||||
|
check the input size as we don't know how much it compresses */
|
||||||
|
size_t dest_len = MAX_SSH_PACKET_LEN-5-256;
|
||||||
|
size_t dest2_len = dest_len;
|
||||||
|
|
||||||
|
/* compress directly to the target buffer */
|
||||||
|
rc = session->local.comp->comp(session,
|
||||||
|
&p->outbuf[5], &dest_len,
|
||||||
|
data, data_len,
|
||||||
|
&session->local.comp_abstract);
|
||||||
|
if(rc)
|
||||||
|
return rc; /* compression failure */
|
||||||
|
|
||||||
|
if(data2 && data2_len) {
|
||||||
|
/* compress directly to the target buffer right after where the
|
||||||
|
previous call put data */
|
||||||
|
dest2_len -= dest_len;
|
||||||
|
|
||||||
|
rc = session->local.comp->comp(session,
|
||||||
|
&p->outbuf[5 + dest_len],
|
||||||
|
&dest2_len,
|
||||||
|
data2, data2_len,
|
||||||
|
&session->local.comp_abstract);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dest2_len = 0;
|
||||||
|
if(rc)
|
||||||
|
return rc; /* compression failure */
|
||||||
|
|
||||||
|
data_len = dest_len + dest2_len; /* use the combined length */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if((data_len + data2_len) >= (MAX_SSH_PACKET_LEN-0x100))
|
||||||
|
/* too large packet, return error for this until we make this
|
||||||
|
function split it up and send multiple SSH packets */
|
||||||
|
return LIBSSH2_ERROR_INVAL;
|
||||||
|
|
||||||
|
/* copy the payload data */
|
||||||
|
memcpy(&p->outbuf[5], data, data_len);
|
||||||
|
if(data2 && data2_len)
|
||||||
|
memcpy(&p->outbuf[5 + data_len], data2, data2_len);
|
||||||
|
data_len += data2_len; /* use the combined length */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* RFC4253 says: Note that the length of the concatenation of
|
||||||
|
'packet_length', 'padding_length', 'payload', and 'random padding'
|
||||||
|
MUST be a multiple of the cipher block size or 8, whichever is
|
||||||
|
larger. */
|
||||||
|
|
||||||
|
/* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */
|
||||||
|
|
||||||
|
packet_length = data_len + 1 + 4; /* 1 is for padding_length field
|
||||||
|
4 for the packet_length field */
|
||||||
|
|
||||||
|
/* at this point we have it all except the padding */
|
||||||
|
|
||||||
|
/* first figure out our minimum padding amount to make it an even
|
||||||
|
block size */
|
||||||
|
padding_length = blocksize - (packet_length % blocksize);
|
||||||
|
|
||||||
|
/* if the padding becomes too small we add another blocksize worth
|
||||||
|
of it (taken from the original libssh2 where it didn't have any
|
||||||
|
real explanation) */
|
||||||
|
if(padding_length < 4) {
|
||||||
|
padding_length += blocksize;
|
||||||
|
}
|
||||||
|
#ifdef RANDOM_PADDING
|
||||||
|
/* FIXME: we can add padding here, but that also makes the packets
|
||||||
|
bigger etc */
|
||||||
|
|
||||||
|
/* now we can add 'blocksize' to the padding_length N number of times
|
||||||
|
(to "help thwart traffic analysis") but it must be less than 255 in
|
||||||
|
total */
|
||||||
|
rand_max = (255 - padding_length) / blocksize + 1;
|
||||||
|
padding_length += blocksize * (seed % rand_max);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
packet_length += padding_length;
|
||||||
|
|
||||||
|
/* append the MAC length to the total_length size */
|
||||||
|
total_length =
|
||||||
|
packet_length + (encrypted ? session->local.mac->mac_len : 0);
|
||||||
|
|
||||||
|
/* store packet_length, which is the size of the whole packet except
|
||||||
|
the MAC and the packet_length field itself */
|
||||||
|
_libssh2_htonu32(p->outbuf, packet_length - 4);
|
||||||
|
/* store padding_length */
|
||||||
|
p->outbuf[4] = (unsigned char)padding_length;
|
||||||
|
|
||||||
|
/* fill the padding area with random junk */
|
||||||
|
if(_libssh2_random(p->outbuf + 5 + data_len, padding_length)) {
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN,
|
||||||
|
"Unable to get random bytes for packet padding");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encrypted) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Calculate MAC hash. Put the output at index packet_length,
|
||||||
|
since that size includes the whole packet. The MAC is
|
||||||
|
calculated on the entire unencrypted packet, including all
|
||||||
|
fields except the MAC field itself. */
|
||||||
|
session->local.mac->hash(session, p->outbuf + packet_length,
|
||||||
|
session->local.seqno, p->outbuf,
|
||||||
|
packet_length, NULL, 0,
|
||||||
|
&session->local.mac_abstract);
|
||||||
|
|
||||||
|
/* Encrypt the whole packet data, one block size at a time.
|
||||||
|
The MAC field is not encrypted. */
|
||||||
|
for(i = 0; i < packet_length; i += session->local.crypt->blocksize) {
|
||||||
|
unsigned char *ptr = &p->outbuf[i];
|
||||||
|
if(session->local.crypt->crypt(session, ptr,
|
||||||
|
session->local.crypt->blocksize,
|
||||||
|
&session->local.crypt_abstract))
|
||||||
|
return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session->local.seqno++;
|
||||||
|
|
||||||
|
ret = LIBSSH2_SEND(session, p->outbuf, total_length,
|
||||||
|
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||||
|
if(ret < 0)
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||||
|
"Error sending %d bytes: %d", total_length, -ret);
|
||||||
|
else {
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p",
|
||||||
|
ret, total_length, p->outbuf);
|
||||||
|
debugdump(session, "libssh2_transport_write send()", p->outbuf, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ret != total_length) {
|
||||||
|
if(ret >= 0 || ret == -EAGAIN) {
|
||||||
|
/* the whole packet could not be sent, save the rest */
|
||||||
|
session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||||
|
p->odata = orgdata;
|
||||||
|
p->olen = orgdata_len;
|
||||||
|
p->osent = ret <= 0 ? 0 : ret;
|
||||||
|
p->ototal_num = total_length;
|
||||||
|
return LIBSSH2_ERROR_EAGAIN;
|
||||||
|
}
|
||||||
|
return LIBSSH2_ERROR_SOCKET_SEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the whole thing got sent away */
|
||||||
|
p->odata = NULL;
|
||||||
|
p->olen = 0;
|
||||||
|
|
||||||
|
return LIBSSH2_ERROR_NONE; /* all is good */
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,88 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_TRANSPORT_H
|
||||||
|
#define __LIBSSH2_TRANSPORT_H
|
||||||
|
/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||||
|
* Author: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file handles reading and writing to the SECSH transport layer. RFC4253.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libssh2_transport_send
|
||||||
|
*
|
||||||
|
* Send a packet, encrypting it and adding a MAC code if necessary
|
||||||
|
* Returns 0 on success, non-zero on failure.
|
||||||
|
*
|
||||||
|
* The data is provided as _two_ data areas that are combined by this
|
||||||
|
* function. The 'data' part is sent immediately before 'data2'. 'data2' can
|
||||||
|
* be set to NULL (or data2_len to 0) to only use a single part.
|
||||||
|
*
|
||||||
|
* Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was
|
||||||
|
* not sent yet. If it does so, the caller should call this function again as
|
||||||
|
* soon as it is likely that more data can be sent, and this function MUST
|
||||||
|
* then be called with the same argument set (same data pointer and same
|
||||||
|
* data_len) until ERROR_NONE or failure is returned.
|
||||||
|
*
|
||||||
|
* This function DOES NOT call _libssh2_error() on any errors.
|
||||||
|
*/
|
||||||
|
int _libssh2_transport_send(LIBSSH2_SESSION *session,
|
||||||
|
const unsigned char *data, size_t data_len,
|
||||||
|
const unsigned char *data2, size_t data2_len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _libssh2_transport_read
|
||||||
|
*
|
||||||
|
* Collect a packet into the input brigade block only controls whether or not
|
||||||
|
* to wait for a packet to start.
|
||||||
|
*
|
||||||
|
* Returns packet type added to input brigade (PACKET_NONE if nothing added),
|
||||||
|
* or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full
|
||||||
|
* packet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function reads the binary stream as specified in chapter 6 of RFC4253
|
||||||
|
* "The Secure Shell (SSH) Transport Layer Protocol"
|
||||||
|
*/
|
||||||
|
int _libssh2_transport_read(LIBSSH2_SESSION * session);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_TRANSPORT_H */
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,53 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
#ifndef __LIBSSH2_USERAUTH_H
|
||||||
|
#define __LIBSSH2_USERAUTH_H
|
||||||
|
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||||
|
* Copyright (c) 2009-2010 by Daniel Stenberg
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||||
|
const char *username,
|
||||||
|
unsigned int username_len,
|
||||||
|
const unsigned char *pubkeydata,
|
||||||
|
unsigned long pubkeydata_len,
|
||||||
|
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC
|
||||||
|
((*sign_callback)),
|
||||||
|
void *abstract);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_USERAUTH_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,164 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2022, Xaver Loppenstedt <xaver@loppenstedt.de>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include "userauth_kbd_packet.h"
|
||||||
|
|
||||||
|
int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *session)
|
||||||
|
{
|
||||||
|
unsigned char *language_tag;
|
||||||
|
size_t language_tag_len;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned char packet_type;
|
||||||
|
|
||||||
|
struct string_buf decoded;
|
||||||
|
|
||||||
|
decoded.data = session->userauth_kybd_data;
|
||||||
|
decoded.dataptr = session->userauth_kybd_data;
|
||||||
|
decoded.len = session->userauth_kybd_data_len;
|
||||||
|
|
||||||
|
if(session->userauth_kybd_data_len < 17) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
||||||
|
"userauth keyboard data buffer too small "
|
||||||
|
"to get length");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* byte SSH_MSG_USERAUTH_INFO_REQUEST */
|
||||||
|
_libssh2_get_byte(&decoded, &packet_type);
|
||||||
|
|
||||||
|
/* string name (ISO-10646 UTF-8) */
|
||||||
|
if(_libssh2_copy_string(session, &decoded,
|
||||||
|
&session->userauth_kybd_auth_name,
|
||||||
|
&session->userauth_kybd_auth_name_len) == -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive 'name' "
|
||||||
|
"request field");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* string instruction (ISO-10646 UTF-8) */
|
||||||
|
if(_libssh2_copy_string(session, &decoded,
|
||||||
|
&session->userauth_kybd_auth_instruction,
|
||||||
|
&session->userauth_kybd_auth_instruction_len)
|
||||||
|
== -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive 'instruction' "
|
||||||
|
"request field");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* string language tag (as defined in [RFC-3066]) */
|
||||||
|
if(_libssh2_get_string(&decoded, &language_tag,
|
||||||
|
&language_tag_len) == -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive 'language tag' "
|
||||||
|
"request field");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* int num-prompts */
|
||||||
|
if(_libssh2_get_u32(&decoded, &session->userauth_kybd_num_prompts) == -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive number of keyboard prompts");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(session->userauth_kybd_num_prompts > 100) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
|
||||||
|
"Too many replies for "
|
||||||
|
"keyboard-interactive prompts");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(session->userauth_kybd_num_prompts == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->userauth_kybd_prompts =
|
||||||
|
LIBSSH2_CALLOC(session,
|
||||||
|
sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
|
||||||
|
session->userauth_kybd_num_prompts);
|
||||||
|
if(!session->userauth_kybd_prompts) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"keyboard-interactive prompts array");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->userauth_kybd_responses =
|
||||||
|
LIBSSH2_CALLOC(session,
|
||||||
|
sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
|
||||||
|
session->userauth_kybd_num_prompts);
|
||||||
|
if(!session->userauth_kybd_responses) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"keyboard-interactive responses array");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
|
||||||
|
/* string prompt[1] (ISO-10646 UTF-8) */
|
||||||
|
if(_libssh2_copy_string(session, &decoded,
|
||||||
|
&session->userauth_kybd_prompts[i].text,
|
||||||
|
&session->userauth_kybd_prompts[i].length)
|
||||||
|
== -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive prompt message");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* boolean echo[1] */
|
||||||
|
if(_libssh2_get_boolean(&decoded,
|
||||||
|
&session->userauth_kybd_prompts[i].echo)
|
||||||
|
== -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
||||||
|
"Unable to decode "
|
||||||
|
"user auth keyboard prompt echo");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,45 @@
|
||||||
|
#if defined(ESP32)
|
||||||
|
/* Copyright (c) 2022, Xaver Loppenstedt <xaver@loppenstedt.de>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBSSH2_USERAUTH_KBD_PARSE_H
|
||||||
|
#define __LIBSSH2_USERAUTH_KBD_PARSE_H
|
||||||
|
|
||||||
|
int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_USERAUTH_KBD_PARSE_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,572 @@
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* SLIP Interface
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is built upon the file: src/arch/rtxc/netif/sioslip.c
|
||||||
|
*
|
||||||
|
* Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com>
|
||||||
|
* Simon Goldschmidt
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup slipif SLIP
|
||||||
|
* @ingroup netifs
|
||||||
|
*
|
||||||
|
* This is an arch independent SLIP netif. The specific serial hooks must be
|
||||||
|
* provided by another file. They are sio_open, sio_read/sio_tryread and sio_send
|
||||||
|
*
|
||||||
|
* Usage: This netif can be used in three ways:
|
||||||
|
* 1. For NO_SYS==0, an RX thread can be used which blocks on sio_read()
|
||||||
|
* until data is received.
|
||||||
|
* 2. In your main loop, call slipif_poll() to check for new RX bytes,
|
||||||
|
* completed packets are fed into netif->input().
|
||||||
|
* 3. Call slipif_received_byte[s]() from your serial RX ISR and
|
||||||
|
* slipif_process_rxqueue() from your main loop. ISR level decodes
|
||||||
|
* packets and puts completed packets on a queue which is fed into
|
||||||
|
* the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for
|
||||||
|
* pbuf_alloc to work on ISR level!).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "slipif.h"
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/pbuf.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "lwip/snmp.h"
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
#include "lwip/sio.h"
|
||||||
|
|
||||||
|
|
||||||
|
void* sio_open (u8_t sid)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
u32_t sio_read (sio_fd_t fd, u8_t *data, u32_t len)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
u32_t sio_tryread (sio_fd_t fd, u8_t *data, u32_t len)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void sio_send (u8_t c, void *s) {}
|
||||||
|
#define SLIP_END 0xC0 /* 0300: start and end of every packet */
|
||||||
|
#define SLIP_ESC 0xDB /* 0333: escape start (one byte escaped data follows) */
|
||||||
|
#define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */
|
||||||
|
#define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */
|
||||||
|
|
||||||
|
/** Maximum packet size that is received by this netif */
|
||||||
|
#ifndef SLIP_MAX_SIZE
|
||||||
|
#define SLIP_MAX_SIZE 1500
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Define this to the interface speed for SNMP
|
||||||
|
* (sio_fd is the sio_fd_t returned by sio_open).
|
||||||
|
* The default value of zero means 'unknown'.
|
||||||
|
*/
|
||||||
|
#ifndef SLIP_SIO_SPEED
|
||||||
|
#define SLIP_SIO_SPEED(sio_fd) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum slipif_recv_state {
|
||||||
|
SLIP_RECV_NORMAL,
|
||||||
|
SLIP_RECV_ESCAPE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct slipif_priv {
|
||||||
|
sio_fd_t sd;
|
||||||
|
/* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
|
||||||
|
struct pbuf *p, *q;
|
||||||
|
u8_t state;
|
||||||
|
u16_t i, recved;
|
||||||
|
#if SLIP_RX_FROM_ISR
|
||||||
|
struct pbuf *rxpackets;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a pbuf doing the necessary SLIP encapsulation
|
||||||
|
*
|
||||||
|
* Uses the serial layer's sio_send()
|
||||||
|
*
|
||||||
|
* @param netif the lwip network interface structure for this slipif
|
||||||
|
* @param p the pbuf chain packet to send
|
||||||
|
* @return always returns ERR_OK since the serial layer does not provide return values
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
slipif_output(struct netif *netif, struct pbuf *p)
|
||||||
|
{
|
||||||
|
struct slipif_priv *priv;
|
||||||
|
struct pbuf *q;
|
||||||
|
u16_t i;
|
||||||
|
u8_t c;
|
||||||
|
|
||||||
|
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||||
|
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||||
|
LWIP_ASSERT("p != NULL", (p != NULL));
|
||||||
|
|
||||||
|
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output: sending %"U16_F" bytes\n", p->tot_len));
|
||||||
|
priv = (struct slipif_priv *)netif->state;
|
||||||
|
|
||||||
|
/* Send pbuf out on the serial I/O device. */
|
||||||
|
/* Start with packet delimiter. */
|
||||||
|
sio_send(SLIP_END, priv->sd);
|
||||||
|
|
||||||
|
for (q = p; q != NULL; q = q->next) {
|
||||||
|
for (i = 0; i < q->len; i++) {
|
||||||
|
c = ((u8_t *)q->payload)[i];
|
||||||
|
switch (c) {
|
||||||
|
case SLIP_END:
|
||||||
|
/* need to escape this byte (0xC0 -> 0xDB, 0xDC) */
|
||||||
|
sio_send(SLIP_ESC, priv->sd);
|
||||||
|
sio_send(SLIP_ESC_END, priv->sd);
|
||||||
|
break;
|
||||||
|
case SLIP_ESC:
|
||||||
|
/* need to escape this byte (0xDB -> 0xDB, 0xDD) */
|
||||||
|
sio_send(SLIP_ESC, priv->sd);
|
||||||
|
sio_send(SLIP_ESC_ESC, priv->sd);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* normal byte - no need for escaping */
|
||||||
|
sio_send(c, priv->sd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* End with packet delimiter. */
|
||||||
|
sio_send(SLIP_END, priv->sd);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_IPV4
|
||||||
|
/**
|
||||||
|
* Send a pbuf doing the necessary SLIP encapsulation
|
||||||
|
*
|
||||||
|
* Uses the serial layer's sio_send()
|
||||||
|
*
|
||||||
|
* @param netif the lwip network interface structure for this slipif
|
||||||
|
* @param p the pbuf chain packet to send
|
||||||
|
* @param ipaddr the ip address to send the packet to (not used for slipif)
|
||||||
|
* @return always returns ERR_OK since the serial layer does not provide return values
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
slipif_output_v4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
LWIP_UNUSED_ARG(ipaddr);
|
||||||
|
return slipif_output(netif, p);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_IPV4 */
|
||||||
|
|
||||||
|
#if LWIP_IPV6
|
||||||
|
/**
|
||||||
|
* Send a pbuf doing the necessary SLIP encapsulation
|
||||||
|
*
|
||||||
|
* Uses the serial layer's sio_send()
|
||||||
|
*
|
||||||
|
* @param netif the lwip network interface structure for this slipif
|
||||||
|
* @param p the pbuf chain packet to send
|
||||||
|
* @param ipaddr the ip address to send the packet to (not used for slipif)
|
||||||
|
* @return always returns ERR_OK since the serial layer does not provide return values
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
slipif_output_v6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
LWIP_UNUSED_ARG(ipaddr);
|
||||||
|
return slipif_output(netif, p);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_IPV6 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the incoming SLIP stream character by character
|
||||||
|
*
|
||||||
|
* @param netif the lwip network interface structure for this slipif
|
||||||
|
* @param c received character (multiple calls to this function will
|
||||||
|
* return a complete packet, NULL is returned before - used for polling)
|
||||||
|
* @return The IP packet when SLIP_END is received
|
||||||
|
*/
|
||||||
|
static struct pbuf *
|
||||||
|
slipif_rxbyte(struct netif *netif, u8_t c)
|
||||||
|
{
|
||||||
|
struct slipif_priv *priv;
|
||||||
|
struct pbuf *t;
|
||||||
|
|
||||||
|
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||||
|
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||||
|
|
||||||
|
priv = (struct slipif_priv *)netif->state;
|
||||||
|
|
||||||
|
switch (priv->state) {
|
||||||
|
case SLIP_RECV_NORMAL:
|
||||||
|
switch (c) {
|
||||||
|
case SLIP_END:
|
||||||
|
if (priv->recved > 0) {
|
||||||
|
/* Received whole packet. */
|
||||||
|
/* Trim the pbuf to the size of the received packet. */
|
||||||
|
pbuf_realloc(priv->q, priv->recved);
|
||||||
|
|
||||||
|
LINK_STATS_INC(link.recv);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved));
|
||||||
|
t = priv->q;
|
||||||
|
priv->p = priv->q = NULL;
|
||||||
|
priv->i = priv->recved = 0;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
case SLIP_ESC:
|
||||||
|
priv->state = SLIP_RECV_ESCAPE;
|
||||||
|
return NULL;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
} /* end switch (c) */
|
||||||
|
break;
|
||||||
|
case SLIP_RECV_ESCAPE:
|
||||||
|
/* un-escape END or ESC bytes, leave other bytes
|
||||||
|
(although that would be a protocol error) */
|
||||||
|
switch (c) {
|
||||||
|
case SLIP_ESC_END:
|
||||||
|
c = SLIP_END;
|
||||||
|
break;
|
||||||
|
case SLIP_ESC_ESC:
|
||||||
|
c = SLIP_ESC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
priv->state = SLIP_RECV_NORMAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
} /* end switch (priv->state) */
|
||||||
|
|
||||||
|
/* byte received, packet not yet completely received */
|
||||||
|
if (priv->p == NULL) {
|
||||||
|
/* allocate a new pbuf */
|
||||||
|
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
|
||||||
|
priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - PBUF_LINK_ENCAPSULATION_HLEN), PBUF_POOL);
|
||||||
|
|
||||||
|
if (priv->p == NULL) {
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
|
||||||
|
/* don't process any further since we got no pbuf to receive to */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->q != NULL) {
|
||||||
|
/* 'chain' the pbuf to the existing chain */
|
||||||
|
pbuf_cat(priv->q, priv->p);
|
||||||
|
} else {
|
||||||
|
/* p is the first pbuf in the chain */
|
||||||
|
priv->q = priv->p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this automatically drops bytes if > SLIP_MAX_SIZE */
|
||||||
|
if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
|
||||||
|
((u8_t *)priv->p->payload)[priv->i] = c;
|
||||||
|
priv->recved++;
|
||||||
|
priv->i++;
|
||||||
|
if (priv->i >= priv->p->len) {
|
||||||
|
/* on to the next pbuf */
|
||||||
|
priv->i = 0;
|
||||||
|
if (priv->p->next != NULL && priv->p->next->len > 0) {
|
||||||
|
/* p is a chain, on to the next in the chain */
|
||||||
|
priv->p = priv->p->next;
|
||||||
|
} else {
|
||||||
|
/* p is a single pbuf, set it to NULL so next time a new
|
||||||
|
* pbuf is allocated */
|
||||||
|
priv->p = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Like slipif_rxbyte, but passes completed packets to netif->input
|
||||||
|
*
|
||||||
|
* @param netif The lwip network interface structure for this slipif
|
||||||
|
* @param c received character
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
slipif_rxbyte_input(struct netif *netif, u8_t c)
|
||||||
|
{
|
||||||
|
struct pbuf *p;
|
||||||
|
p = slipif_rxbyte(netif, c);
|
||||||
|
if (p != NULL) {
|
||||||
|
if (netif->input(p, netif) != ERR_OK) {
|
||||||
|
pbuf_free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SLIP_USE_RX_THREAD
|
||||||
|
/**
|
||||||
|
* The SLIP input thread.
|
||||||
|
*
|
||||||
|
* Feed the IP layer with incoming packets
|
||||||
|
*
|
||||||
|
* @param nf the lwip network interface structure for this slipif
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
slipif_loop_thread(void *nf)
|
||||||
|
{
|
||||||
|
u8_t c;
|
||||||
|
struct netif *netif = (struct netif *)nf;
|
||||||
|
struct slipif_priv *priv = (struct slipif_priv *)netif->state;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (sio_read(priv->sd, &c, 1) > 0) {
|
||||||
|
slipif_rxbyte_input(netif, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* SLIP_USE_RX_THREAD */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup slipif
|
||||||
|
* SLIP netif initialization
|
||||||
|
*
|
||||||
|
* Call the arch specific sio_open and remember
|
||||||
|
* the opened device in the state field of the netif.
|
||||||
|
*
|
||||||
|
* @param netif the lwip network interface structure for this slipif
|
||||||
|
* @return ERR_OK if serial line could be opened,
|
||||||
|
* ERR_MEM if no memory could be allocated,
|
||||||
|
* ERR_IF is serial line couldn't be opened
|
||||||
|
*
|
||||||
|
* @note If netif->state is interpreted as an u8_t serial port number.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
slipif_init(struct netif *netif)
|
||||||
|
{
|
||||||
|
struct slipif_priv *priv;
|
||||||
|
u8_t sio_num;
|
||||||
|
|
||||||
|
LWIP_ASSERT("slipif needs an input callback", netif->input != NULL);
|
||||||
|
|
||||||
|
/* netif->state contains serial port number */
|
||||||
|
sio_num = LWIP_PTR_NUMERIC_CAST(u8_t, netif->state);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)sio_num));
|
||||||
|
|
||||||
|
/* Allocate private data */
|
||||||
|
priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv));
|
||||||
|
if (!priv) {
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
netif->name[0] = 's';
|
||||||
|
netif->name[1] = 'l';
|
||||||
|
#if LWIP_IPV4
|
||||||
|
netif->output = slipif_output_v4;
|
||||||
|
#endif /* LWIP_IPV4 */
|
||||||
|
#if LWIP_IPV6
|
||||||
|
netif->output_ip6 = slipif_output_v6;
|
||||||
|
#endif /* LWIP_IPV6 */
|
||||||
|
netif->mtu = SLIP_MAX_SIZE;
|
||||||
|
|
||||||
|
/* Try to open the serial port. */
|
||||||
|
priv->sd = sio_open(sio_num);
|
||||||
|
if (!priv->sd) {
|
||||||
|
/* Opening the serial port failed. */
|
||||||
|
mem_free(priv);
|
||||||
|
return ERR_IF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize private data */
|
||||||
|
priv->p = NULL;
|
||||||
|
priv->q = NULL;
|
||||||
|
priv->state = SLIP_RECV_NORMAL;
|
||||||
|
priv->i = 0;
|
||||||
|
priv->recved = 0;
|
||||||
|
#if SLIP_RX_FROM_ISR
|
||||||
|
priv->rxpackets = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
netif->state = priv;
|
||||||
|
|
||||||
|
/* initialize the snmp variables and counters inside the struct netif */
|
||||||
|
MIB2_INIT_NETIF(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd));
|
||||||
|
|
||||||
|
#if SLIP_USE_RX_THREAD
|
||||||
|
/* Create a thread to poll the serial line. */
|
||||||
|
sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
|
||||||
|
SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
|
||||||
|
#endif /* SLIP_USE_RX_THREAD */
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup slipif
|
||||||
|
* Polls the serial device and feeds the IP layer with incoming packets.
|
||||||
|
*
|
||||||
|
* @param netif The lwip network interface structure for this slipif
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
slipif_poll(struct netif *netif)
|
||||||
|
{
|
||||||
|
u8_t c;
|
||||||
|
struct slipif_priv *priv;
|
||||||
|
|
||||||
|
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||||
|
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||||
|
|
||||||
|
priv = (struct slipif_priv *)netif->state;
|
||||||
|
|
||||||
|
while (sio_tryread(priv->sd, &c, 1) > 0) {
|
||||||
|
slipif_rxbyte_input(netif, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SLIP_RX_FROM_ISR
|
||||||
|
/**
|
||||||
|
* @ingroup slipif
|
||||||
|
* Feeds the IP layer with incoming packets that were receive
|
||||||
|
*
|
||||||
|
* @param netif The lwip network interface structure for this slipif
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
slipif_process_rxqueue(struct netif *netif)
|
||||||
|
{
|
||||||
|
struct slipif_priv *priv;
|
||||||
|
SYS_ARCH_DECL_PROTECT(old_level);
|
||||||
|
|
||||||
|
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||||
|
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||||
|
|
||||||
|
priv = (struct slipif_priv *)netif->state;
|
||||||
|
|
||||||
|
SYS_ARCH_PROTECT(old_level);
|
||||||
|
while (priv->rxpackets != NULL) {
|
||||||
|
struct pbuf *p = priv->rxpackets;
|
||||||
|
#if SLIP_RX_QUEUE
|
||||||
|
/* dequeue packet */
|
||||||
|
struct pbuf *q = p;
|
||||||
|
while ((q->len != q->tot_len) && (q->next != NULL)) {
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
priv->rxpackets = q->next;
|
||||||
|
q->next = NULL;
|
||||||
|
#else /* SLIP_RX_QUEUE */
|
||||||
|
priv->rxpackets = NULL;
|
||||||
|
#endif /* SLIP_RX_QUEUE */
|
||||||
|
SYS_ARCH_UNPROTECT(old_level);
|
||||||
|
if (netif->input(p, netif) != ERR_OK) {
|
||||||
|
pbuf_free(p);
|
||||||
|
}
|
||||||
|
SYS_ARCH_PROTECT(old_level);
|
||||||
|
}
|
||||||
|
SYS_ARCH_UNPROTECT(old_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Like slipif_rxbyte, but queues completed packets.
|
||||||
|
*
|
||||||
|
* @param netif The lwip network interface structure for this slipif
|
||||||
|
* @param data Received serial byte
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
slipif_rxbyte_enqueue(struct netif *netif, u8_t data)
|
||||||
|
{
|
||||||
|
struct pbuf *p;
|
||||||
|
struct slipif_priv *priv = (struct slipif_priv *)netif->state;
|
||||||
|
SYS_ARCH_DECL_PROTECT(old_level);
|
||||||
|
|
||||||
|
p = slipif_rxbyte(netif, data);
|
||||||
|
if (p != NULL) {
|
||||||
|
SYS_ARCH_PROTECT(old_level);
|
||||||
|
if (priv->rxpackets != NULL) {
|
||||||
|
#if SLIP_RX_QUEUE
|
||||||
|
/* queue multiple pbufs */
|
||||||
|
struct pbuf *q = p;
|
||||||
|
while (q->next != NULL) {
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
q->next = p;
|
||||||
|
} else {
|
||||||
|
#else /* SLIP_RX_QUEUE */
|
||||||
|
pbuf_free(priv->rxpackets);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
#endif /* SLIP_RX_QUEUE */
|
||||||
|
priv->rxpackets = p;
|
||||||
|
}
|
||||||
|
SYS_ARCH_UNPROTECT(old_level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup slipif
|
||||||
|
* Process a received byte, completed packets are put on a queue that is
|
||||||
|
* fed into IP through slipif_process_rxqueue().
|
||||||
|
*
|
||||||
|
* This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
|
||||||
|
*
|
||||||
|
* @param netif The lwip network interface structure for this slipif
|
||||||
|
* @param data received character
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
slipif_received_byte(struct netif *netif, u8_t data)
|
||||||
|
{
|
||||||
|
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||||
|
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||||
|
slipif_rxbyte_enqueue(netif, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup slipif
|
||||||
|
* Process multiple received byte, completed packets are put on a queue that is
|
||||||
|
* fed into IP through slipif_process_rxqueue().
|
||||||
|
*
|
||||||
|
* This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
|
||||||
|
*
|
||||||
|
* @param netif The lwip network interface structure for this slipif
|
||||||
|
* @param data received character
|
||||||
|
* @param len Number of received characters
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len)
|
||||||
|
{
|
||||||
|
u8_t i;
|
||||||
|
u8_t *rxdata = data;
|
||||||
|
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||||
|
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++, rxdata++) {
|
||||||
|
slipif_rxbyte_enqueue(netif, *rxdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* SLIP_RX_FROM_ISR */
|
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* SLIP netif API
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef LWIP_HDR_NETIF_SLIPIF_H
|
||||||
|
#define LWIP_HDR_NETIF_SLIPIF_H
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
|
||||||
|
/** Set this to 1 to start a thread that blocks reading on the serial line
|
||||||
|
* (using sio_read()).
|
||||||
|
*/
|
||||||
|
#ifndef SLIP_USE_RX_THREAD
|
||||||
|
#define SLIP_USE_RX_THREAD !NO_SYS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Set this to 1 to enable functions to pass in RX bytes from ISR context.
|
||||||
|
* If enabled, slipif_received_byte[s]() process incoming bytes and put assembled
|
||||||
|
* packets on a queue, which is fed into lwIP from slipif_poll().
|
||||||
|
* If disabled, slipif_poll() polls the serial line (using sio_tryread()).
|
||||||
|
*/
|
||||||
|
#ifndef SLIP_RX_FROM_ISR
|
||||||
|
#define SLIP_RX_FROM_ISR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets
|
||||||
|
* received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available.
|
||||||
|
* If disabled, packets will be dropped if more than one packet is received.
|
||||||
|
*/
|
||||||
|
#ifndef SLIP_RX_QUEUE
|
||||||
|
#define SLIP_RX_QUEUE SLIP_RX_FROM_ISR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
err_t slipif_init(struct netif * netif);
|
||||||
|
void slipif_poll(struct netif *netif);
|
||||||
|
#if SLIP_RX_FROM_ISR
|
||||||
|
void slipif_process_rxqueue(struct netif *netif);
|
||||||
|
void slipif_received_byte(struct netif *netif, u8_t data);
|
||||||
|
void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len);
|
||||||
|
#endif /* SLIP_RX_FROM_ISR */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* LWIP_HDR_NETIF_SLIPIF_H */
|
|
@ -0,0 +1,15 @@
|
||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:esp12e]
|
||||||
|
platform = espressif8266
|
||||||
|
board = esp12e
|
||||||
|
framework = arduino
|
||||||
|
lib_deps =
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ConnSettings::ConnSettings(int flagBitmap)
|
||||||
|
{
|
||||||
|
petscii = (flagBitmap & FLAG_PETSCII) > 0;
|
||||||
|
telnet = (flagBitmap & FLAG_TELNET) > 0;
|
||||||
|
echo = (flagBitmap & FLAG_ECHO) > 0;
|
||||||
|
xonxoff = (flagBitmap & FLAG_XONXOFF) > 0;
|
||||||
|
rtscts = (flagBitmap & FLAG_RTSCTS) > 0;
|
||||||
|
secure = (flagBitmap & FLAG_SECURE) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnSettings::ConnSettings(const char *dmodifiers)
|
||||||
|
{
|
||||||
|
petscii=((strchr(dmodifiers,'p')!=null) || (strchr(dmodifiers,'P')!=null));
|
||||||
|
telnet=((strchr(dmodifiers,'t')!=null) || (strchr(dmodifiers,'T')!=null));
|
||||||
|
echo=((strchr(dmodifiers,'e')!=null) || (strchr(dmodifiers,'E')!=null));
|
||||||
|
xonxoff=((strchr(dmodifiers,'x')!=null) || (strchr(dmodifiers,'X')!=null));
|
||||||
|
rtscts=((strchr(dmodifiers,'r')!=null) || (strchr(dmodifiers,'R')!=null));
|
||||||
|
secure=((strchr(dmodifiers,'s')!=null) || (strchr(dmodifiers,'S')!=null));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnSettings::ConnSettings(String modifiers) : ConnSettings(modifiers.c_str())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnSettings::getBitmap()
|
||||||
|
{
|
||||||
|
int flagsBitmap = 0;
|
||||||
|
if(petscii)
|
||||||
|
flagsBitmap = flagsBitmap | FLAG_PETSCII;
|
||||||
|
if(telnet)
|
||||||
|
flagsBitmap = flagsBitmap | FLAG_TELNET;
|
||||||
|
if(echo)
|
||||||
|
flagsBitmap = flagsBitmap | FLAG_ECHO;
|
||||||
|
if(xonxoff)
|
||||||
|
flagsBitmap = flagsBitmap | FLAG_XONXOFF;
|
||||||
|
if(rtscts)
|
||||||
|
flagsBitmap = flagsBitmap | FLAG_RTSCTS;
|
||||||
|
if(secure)
|
||||||
|
flagsBitmap = flagsBitmap | FLAG_SECURE;
|
||||||
|
return flagsBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnSettings::getBitmap(FlowControlType forceCheck)
|
||||||
|
{
|
||||||
|
int flagsBitmap = getBitmap();
|
||||||
|
if(((flagsBitmap & (FLAG_XONXOFF | FLAG_RTSCTS))==0)
|
||||||
|
&&(forceCheck==FCT_RTSCTS))
|
||||||
|
flagsBitmap |= FLAG_RTSCTS;
|
||||||
|
return flagsBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ConnSettings::getFlagString()
|
||||||
|
{
|
||||||
|
String lastOptions =(petscii?"p":"");
|
||||||
|
lastOptions += (petscii?"p":"");
|
||||||
|
lastOptions += (telnet?"t":"");
|
||||||
|
lastOptions += (echo?"e":"");
|
||||||
|
lastOptions += (xonxoff?"x":"");
|
||||||
|
lastOptions += (rtscts?"r":"");
|
||||||
|
lastOptions += (secure?"s":"");
|
||||||
|
return lastOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnSettings::setFlag(ConnFlag flagMask, boolean newVal)
|
||||||
|
{
|
||||||
|
switch(flagMask)
|
||||||
|
{
|
||||||
|
case FLAG_DISCONNECT_ON_EXIT: break;
|
||||||
|
case FLAG_PETSCII: petscii = newVal; break;
|
||||||
|
case FLAG_TELNET: telnet = newVal; break;
|
||||||
|
case FLAG_ECHO: echo = newVal; break;
|
||||||
|
case FLAG_XONXOFF: xonxoff = newVal; break;
|
||||||
|
case FLAG_SECURE: secure = newVal; break;
|
||||||
|
case FLAG_RTSCTS: rtscts = newVal; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnSettings::IPtoStr(IPAddress *ip, String &str)
|
||||||
|
{
|
||||||
|
if(ip == null)
|
||||||
|
{
|
||||||
|
str="";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char temp[20];
|
||||||
|
sprintf(temp,"%d.%d.%d.%d",(*ip)[0],(*ip)[1],(*ip)[2],(*ip)[3]);
|
||||||
|
str = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress *ConnSettings::parseIP(const char *ipStr)
|
||||||
|
{
|
||||||
|
uint8_t dots[4];
|
||||||
|
int dotDex=0;
|
||||||
|
char *le = (char *)ipStr;
|
||||||
|
const char *ld = ipStr+strlen(ipStr);
|
||||||
|
if(strlen(ipStr)<7)
|
||||||
|
return null;
|
||||||
|
for(char *e=le;e<=ld;e++)
|
||||||
|
{
|
||||||
|
if((*e=='.')||(e==ld))
|
||||||
|
{
|
||||||
|
if(le==e)
|
||||||
|
break;
|
||||||
|
*e=0;
|
||||||
|
String sdot = le;
|
||||||
|
sdot.trim();
|
||||||
|
if((sdot.length()==0)||(dotDex>3))
|
||||||
|
{
|
||||||
|
dotDex=99;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dots[dotDex++]=(uint8_t)atoi(sdot.c_str());
|
||||||
|
if(e==ld)
|
||||||
|
le=e;
|
||||||
|
else
|
||||||
|
le=e+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((dotDex!=4)||(*le != 0))
|
||||||
|
return null;
|
||||||
|
return new IPAddress(dots[0],dots[1],dots[2],dots[3]);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,284 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
static char HD[3];
|
||||||
|
static char HDL[17];
|
||||||
|
|
||||||
|
static unsigned long logStartTime = millis();
|
||||||
|
static unsigned long lastLogTime = millis();
|
||||||
|
static unsigned long logCurCount = 0;
|
||||||
|
static LogOutputState logOutputState = LOS_NADA;
|
||||||
|
|
||||||
|
static uint8_t FROMHEXDIGIT(uint8_t a1)
|
||||||
|
{
|
||||||
|
a1 = lc(a1);
|
||||||
|
if((a1 >= '0')&&(a1 <= '9'))
|
||||||
|
return a1-'0';
|
||||||
|
if((a1 >= 'a')&&(a1 <= 'f'))
|
||||||
|
return 10 + (a1-'a');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t FROMHEX(uint8_t a1, uint8_t a2)
|
||||||
|
{
|
||||||
|
return (FROMHEXDIGIT(a1) * 16) + FROMHEXDIGIT(a2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *FROMHEX(const char *hex, char *s, const size_t len)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
for(const char *h=hex;*h != 0 && (*(h+1)!=0) && (i<len-1);i++,h+=2)
|
||||||
|
s[i]=FROMHEX((uint8_t)*h,(uint8_t)*(h+1));
|
||||||
|
s[i]=0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t *FROMHEX(uint8_t *s, const size_t len)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
for(int i=0;i<len;i+=2)
|
||||||
|
s[i/2]=FROMHEX(s[i],s[i+1]);
|
||||||
|
s[i]=0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *TOHEX(const char *s, char *hex, const size_t len)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
for(const char *t=s;*t != 0 && (i<len-2);i+=2,t++)
|
||||||
|
{
|
||||||
|
char *x=TOHEX(*t);
|
||||||
|
hex[i]=x[0];
|
||||||
|
hex[i+1]=x[1];
|
||||||
|
}
|
||||||
|
hex[i]=0;
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *TOHEX(uint8_t a)
|
||||||
|
{
|
||||||
|
HD[0] = "0123456789ABCDEF"[(a >> 4) & 0x0f];
|
||||||
|
HD[1] = "0123456789ABCDEF"[a & 0x0f];
|
||||||
|
HD[2] = 0;
|
||||||
|
return HD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *tohex(uint8_t a)
|
||||||
|
{
|
||||||
|
HD[0] = "0123456789abcdef"[(a >> 4) & 0x0f];
|
||||||
|
HD[1] = "0123456789abcdef"[a & 0x0f];
|
||||||
|
HD[2] = 0;
|
||||||
|
return HD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *TOHEX(unsigned long a)
|
||||||
|
{
|
||||||
|
for(int i=7;i>=0;i--)
|
||||||
|
{
|
||||||
|
HDL[i] = "0123456789ABCDEF"[a & 0x0f];
|
||||||
|
a = a >> 4;
|
||||||
|
}
|
||||||
|
HDL[8] = 0;
|
||||||
|
char *H=HDL;
|
||||||
|
if((strlen(H)>2) && (strstr(H,"00")==H))
|
||||||
|
H+=2;
|
||||||
|
return H;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *TOHEX(unsigned int a)
|
||||||
|
{
|
||||||
|
for(int i=3;i>=0;i--)
|
||||||
|
{
|
||||||
|
HDL[i] = "0123456789ABCDEF"[a & 0x0f];
|
||||||
|
a = a >> 4;
|
||||||
|
}
|
||||||
|
HDL[4] = 0;
|
||||||
|
char *H=HDL;
|
||||||
|
if((strlen(H)>2) && (strstr(H,"00")==H))
|
||||||
|
H+=2;
|
||||||
|
return H;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *TOHEX(int a)
|
||||||
|
{
|
||||||
|
return TOHEX((unsigned int)a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *TOHEX(long a)
|
||||||
|
{
|
||||||
|
return TOHEX((unsigned long)a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logInternalOut(const LogOutputState m, const uint8_t c)
|
||||||
|
{
|
||||||
|
if(logFileOpen)
|
||||||
|
{
|
||||||
|
if((m != logOutputState)
|
||||||
|
||(++logCurCount > DBG_BYT_CTR)
|
||||||
|
||((millis()-lastLogTime)>expectedSerialTime))
|
||||||
|
{
|
||||||
|
logCurCount=0;
|
||||||
|
|
||||||
|
logOutputState = m;
|
||||||
|
rawLogPrintln("");
|
||||||
|
switch(m)
|
||||||
|
{
|
||||||
|
case LOS_NADA:
|
||||||
|
break;
|
||||||
|
case LOS_SocketIn:
|
||||||
|
rawLogPrintf("%s SocI: ",TOHEX(millis()-logStartTime));
|
||||||
|
break;
|
||||||
|
case LOS_SocketOut:
|
||||||
|
rawLogPrintf("%s SocO: ",TOHEX(millis()-logStartTime));
|
||||||
|
break;
|
||||||
|
case LOS_SerialIn:
|
||||||
|
rawLogPrintf("%s SerI: ",TOHEX(millis()-logStartTime));
|
||||||
|
break;
|
||||||
|
case LOS_SerialOut:
|
||||||
|
rawLogPrintf("%s SerO: ",TOHEX(millis()-logStartTime));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastLogTime=millis();
|
||||||
|
rawLogPrint(TOHEX(c));
|
||||||
|
rawLogPrint(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logSerialOut(const uint8_t c)
|
||||||
|
{
|
||||||
|
logInternalOut(LOS_SerialOut,c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logSocketOut(const uint8_t c)
|
||||||
|
{
|
||||||
|
logInternalOut(LOS_SocketOut,c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logSerialIn(const uint8_t c)
|
||||||
|
{
|
||||||
|
logInternalOut(LOS_SerialIn,c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logSocketIn(const uint8_t c)
|
||||||
|
{
|
||||||
|
logInternalOut(LOS_SocketIn,c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logSocketIn(const uint8_t *c, int n)
|
||||||
|
{
|
||||||
|
if(logFileOpen)
|
||||||
|
{
|
||||||
|
for(int i=0;i<n;i++)
|
||||||
|
logInternalOut(LOS_SocketIn,c[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rawLogPrintf(const char* format, ...)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
va_list arglist;
|
||||||
|
va_start(arglist, format);
|
||||||
|
vsnprintf(FBUF,sizeof(FBUF), format, arglist);
|
||||||
|
rawLogPrint(FBUF);
|
||||||
|
va_end(arglist);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rawLogPrint(const char* str)
|
||||||
|
{
|
||||||
|
if(logFileDebug)
|
||||||
|
debugPrintf(str);
|
||||||
|
else
|
||||||
|
logFile.print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rawLogPrintln(const char* str)
|
||||||
|
{
|
||||||
|
if(logFileDebug)
|
||||||
|
{
|
||||||
|
debugPrintf(str);
|
||||||
|
debugPrintf("\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logFile.println(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logPrintfln(const char* format, ...)
|
||||||
|
{
|
||||||
|
if(logFileOpen)
|
||||||
|
{
|
||||||
|
if(logOutputState != LOS_NADA)
|
||||||
|
{
|
||||||
|
rawLogPrintln("");
|
||||||
|
logOutputState = LOS_NADA;
|
||||||
|
}
|
||||||
|
int ret;
|
||||||
|
va_list arglist;
|
||||||
|
va_start(arglist, format);
|
||||||
|
vsnprintf(FBUF,sizeof(FBUF), format, arglist);
|
||||||
|
rawLogPrintln(FBUF);
|
||||||
|
va_end(arglist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logPrintf(const char* format, ...)
|
||||||
|
{
|
||||||
|
if(logFileOpen)
|
||||||
|
{
|
||||||
|
if(logOutputState != LOS_NADA)
|
||||||
|
{
|
||||||
|
rawLogPrintln("");
|
||||||
|
logOutputState = LOS_NADA;
|
||||||
|
}
|
||||||
|
int ret;
|
||||||
|
va_list arglist;
|
||||||
|
va_start(arglist, format);
|
||||||
|
vsnprintf(FBUF, sizeof(FBUF), format, arglist);
|
||||||
|
rawLogPrint(FBUF);
|
||||||
|
va_end(arglist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logPrint(const char* msg)
|
||||||
|
{
|
||||||
|
if(logFileOpen)
|
||||||
|
{
|
||||||
|
if(logOutputState != LOS_NADA)
|
||||||
|
{
|
||||||
|
rawLogPrintln("");
|
||||||
|
logOutputState = LOS_NADA;
|
||||||
|
}
|
||||||
|
rawLogPrint(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logPrintln(const char* msg)
|
||||||
|
{
|
||||||
|
if(logFileOpen)
|
||||||
|
{
|
||||||
|
if(logOutputState != LOS_NADA)
|
||||||
|
{
|
||||||
|
rawLogPrintln("");
|
||||||
|
logOutputState = LOS_NADA;
|
||||||
|
}
|
||||||
|
rawLogPrintln(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,350 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// courtesy Craig Bruce, 1995
|
||||||
|
|
||||||
|
unsigned char petToAscTable[256] PROGMEM = {
|
||||||
|
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0d,0x11,0x93,0x0a,0x0e,0x0f,
|
||||||
|
0x10,0x0b,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
|
||||||
|
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
|
||||||
|
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
|
||||||
|
0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
|
||||||
|
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
|
||||||
|
0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
|
||||||
|
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f,
|
||||||
|
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
|
||||||
|
0x90,0x91,0x92,0x0c,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
|
||||||
|
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
|
||||||
|
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
|
||||||
|
0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
|
||||||
|
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
|
||||||
|
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
|
||||||
|
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char ascToPetTable[256] PROGMEM = {
|
||||||
|
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x20,0x0a,0x11,0x93,0x0d,0x0e,0x0f,
|
||||||
|
0x10,0x0b,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
|
||||||
|
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
|
||||||
|
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
|
||||||
|
0x40,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
|
||||||
|
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0x5b,0x5c,0x5d,0x5e,0x5f,
|
||||||
|
0xc0,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
|
||||||
|
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0xdb,0xdc,0xdd,0xde,0xdf,
|
||||||
|
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
|
||||||
|
0x90,0x91,0x92,0x0c,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
|
||||||
|
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
|
||||||
|
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
|
||||||
|
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
|
||||||
|
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
|
||||||
|
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
|
||||||
|
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TELNET_BINARY 0
|
||||||
|
/** TELNET CODE: echo */
|
||||||
|
#define TELNET_ECHO 1
|
||||||
|
/** TELNET CODE: echo */
|
||||||
|
#define TELNET_LOGOUT 18
|
||||||
|
/** TELNET CODE: supress go ahead*/
|
||||||
|
#define TELNET_SUPRESS_GO_AHEAD 3
|
||||||
|
/** TELNET CODE: sending terminal type*/
|
||||||
|
#define TELNET_TERMTYPE 24
|
||||||
|
/** TELNET CODE: Negotiate About Window Size.*/
|
||||||
|
#define TELNET_NAWS 31
|
||||||
|
/** TELNET CODE: Remote Flow Control.*/
|
||||||
|
#define TELNET_TOGGLE_FLOW_CONTROL 33
|
||||||
|
/** TELNET CODE: Linemode*/
|
||||||
|
#define TELNET_LINEMODE 34
|
||||||
|
/** TELNET CODE: MSDP protocol*/
|
||||||
|
#define TELNET_MSDP 69
|
||||||
|
/** TELNET CODE: MSSP Server Status protocol*/
|
||||||
|
#define TELNET_MSSP 70
|
||||||
|
/** TELNET CODE: text compression, protocol 1*/
|
||||||
|
#define TELNET_COMPRESS 85
|
||||||
|
/** TELNET CODE: text compression, protocol 2*/
|
||||||
|
#define TELNET_COMPRESS2 86
|
||||||
|
/** TELNET CODE: MSP SOund protocol*/
|
||||||
|
#define TELNET_MSP 90
|
||||||
|
/** TELNET CODE: MXP Extended protocol*/
|
||||||
|
#define TELNET_MXP 91
|
||||||
|
/** TELNET CODE: AARD protocol*/
|
||||||
|
#define TELNET_AARD 102
|
||||||
|
/** TELNET CODE: End of subnegotiation parameters*/
|
||||||
|
#define TELNET_SE 240
|
||||||
|
/** TELNET CODE: Are You There*/
|
||||||
|
#define TELNET_AYT 246
|
||||||
|
/** TELNET CODE: Erase character*/
|
||||||
|
#define TELNET_EC 247
|
||||||
|
/** TELNET CODE: ATCP protocol*/
|
||||||
|
#define TELNET_ATCP 200
|
||||||
|
/** TELNET CODE: GMCP protocol*/
|
||||||
|
#define TELNET_GMCP 201
|
||||||
|
/** TELNET CODE: Indicates that what follows is subnegotiation of the indicated option*/
|
||||||
|
#define TELNET_SB 250
|
||||||
|
/** TELNET CODE: Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option*/
|
||||||
|
#define TELNET_WILL 251
|
||||||
|
/** TELNET CODE: Indicates the refusal to perform, or continue performing, the indicated option*/
|
||||||
|
#define TELNET_WONT 252
|
||||||
|
/** TELNET CODE: Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option*/
|
||||||
|
#define TELNET_DO 253
|
||||||
|
/** TELNET CODE: 253 doubles as fake ansi telnet code*/
|
||||||
|
#define TELNET_ANSI 253
|
||||||
|
/** TELNET CODE: Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option.*/
|
||||||
|
#define TELNET_DONT 254
|
||||||
|
/** TELNET CODE: Indicates that the other party can go ahead and transmit -- I'm done.*/
|
||||||
|
#define TELNET_GA 249
|
||||||
|
/** TELNET CODE: Indicates that there is nothing to do?*/
|
||||||
|
#define TELNET_NOP 241
|
||||||
|
/** TELNET CODE: IAC*/
|
||||||
|
#define TELNET_IAC 255
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t streamAvailRead(Stream *stream)
|
||||||
|
{
|
||||||
|
int ct=0;
|
||||||
|
while((stream->available()==0)
|
||||||
|
&&(ct++)<250)
|
||||||
|
delay(1);
|
||||||
|
return stream->read();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handleAsciiIAC(char *c, Stream *stream)
|
||||||
|
{
|
||||||
|
if(*c == 255)
|
||||||
|
{
|
||||||
|
*c=streamAvailRead(stream);
|
||||||
|
logSocketIn(*c);
|
||||||
|
if(*c==TELNET_IAC)
|
||||||
|
{
|
||||||
|
*c = 255;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(*c==TELNET_WILL)
|
||||||
|
{
|
||||||
|
char what=streamAvailRead(stream);
|
||||||
|
logSocketIn(what);
|
||||||
|
uint8_t iacDont[] = {TELNET_IAC, TELNET_DONT, what};
|
||||||
|
if(what == TELNET_TERMTYPE)
|
||||||
|
iacDont[1] = TELNET_DO;
|
||||||
|
for(int i=0;i<3;i++)
|
||||||
|
logSocketOut(iacDont[i]);
|
||||||
|
stream->write(iacDont,3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(*c==TELNET_DONT)
|
||||||
|
{
|
||||||
|
char what=streamAvailRead(stream);
|
||||||
|
logSocketIn(what);
|
||||||
|
uint8_t iacWont[] = {TELNET_IAC, TELNET_WONT, what};
|
||||||
|
for(int i=0;i<3;i++)
|
||||||
|
logSocketOut(iacWont[i]);
|
||||||
|
stream->write(iacWont,3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(*c==TELNET_WONT)
|
||||||
|
{
|
||||||
|
char what=streamAvailRead(stream);
|
||||||
|
logSocketIn(what);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(*c==TELNET_DO)
|
||||||
|
{
|
||||||
|
char what=streamAvailRead(stream);
|
||||||
|
logSocketIn(what);
|
||||||
|
uint8_t iacWont[] = {TELNET_IAC, TELNET_WONT, what};
|
||||||
|
if(what == TELNET_TERMTYPE)
|
||||||
|
iacWont[1] = TELNET_WILL;
|
||||||
|
for(int i=0;i<3;i++)
|
||||||
|
logSocketOut(iacWont[i]);
|
||||||
|
stream->write(iacWont,3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(*c==TELNET_SB)
|
||||||
|
{
|
||||||
|
char what=streamAvailRead(stream);
|
||||||
|
logSocketIn(what);
|
||||||
|
char lastC=*c;
|
||||||
|
while(((lastC!=TELNET_IAC)||(*c!=TELNET_SE))&&(*c>=0))
|
||||||
|
{
|
||||||
|
lastC=*c;
|
||||||
|
*c=streamAvailRead(stream);
|
||||||
|
logSocketIn(*c);
|
||||||
|
}
|
||||||
|
if(what == TELNET_TERMTYPE)
|
||||||
|
{
|
||||||
|
int respLen = termType.length() + 6;
|
||||||
|
uint8_t buf[respLen];
|
||||||
|
buf[0]=TELNET_IAC;
|
||||||
|
buf[1]=TELNET_SB;
|
||||||
|
buf[2]=TELNET_TERMTYPE;
|
||||||
|
buf[3]=(uint8_t)0;
|
||||||
|
sprintf((char *)buf+4,termType.c_str());
|
||||||
|
buf[respLen-2]=TELNET_IAC;
|
||||||
|
buf[respLen-1]=TELNET_SE;
|
||||||
|
for(int i=0;i<respLen;i++)
|
||||||
|
logSocketOut(buf[i]);
|
||||||
|
stream->write(buf,respLen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ansiColorToPetsciiColor(char *c, Stream *stream)
|
||||||
|
{
|
||||||
|
if(*c == 27)
|
||||||
|
{
|
||||||
|
*c=streamAvailRead(stream);
|
||||||
|
logSocketIn(*c);
|
||||||
|
if(*c=='[')
|
||||||
|
{
|
||||||
|
int code1=0;
|
||||||
|
int code2=-1;
|
||||||
|
*c=streamAvailRead(stream);
|
||||||
|
logSocketIn(*c);
|
||||||
|
while((*c>='0')&&(*c<='9'))
|
||||||
|
{
|
||||||
|
code1=(code1*10) + (*c-'0');
|
||||||
|
*c=streamAvailRead(stream);
|
||||||
|
logSocketIn(*c);
|
||||||
|
}
|
||||||
|
while(*c==';')
|
||||||
|
{
|
||||||
|
*c=streamAvailRead(stream);
|
||||||
|
logSocketIn(*c);
|
||||||
|
if((*c>='0')&&(*c<='9'))
|
||||||
|
code2=0;
|
||||||
|
while((*c>='0')&&(*c<='9'))
|
||||||
|
{
|
||||||
|
code2=(code2*10) + (*c-'0');
|
||||||
|
*c=streamAvailRead(stream);
|
||||||
|
logSocketIn(*c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch(code1)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
// dark...
|
||||||
|
switch(code2)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
case 0:
|
||||||
|
*c= 146; // rvs off
|
||||||
|
return true;
|
||||||
|
case 30: // black
|
||||||
|
*c= 155;//144;
|
||||||
|
return true;
|
||||||
|
case 31: // red
|
||||||
|
*c= 28;
|
||||||
|
return true;
|
||||||
|
case 32: // green
|
||||||
|
*c= 30;
|
||||||
|
return true;
|
||||||
|
case 33: // yellow
|
||||||
|
*c= 129;
|
||||||
|
return true;
|
||||||
|
case 34: // blue
|
||||||
|
*c= 31;
|
||||||
|
return true;
|
||||||
|
case 35: // purple
|
||||||
|
*c= 149;
|
||||||
|
return true;
|
||||||
|
case 36: // cyan
|
||||||
|
*c= 152;
|
||||||
|
return true;
|
||||||
|
case 37: // white/grey
|
||||||
|
default:
|
||||||
|
*c= 155;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// light..
|
||||||
|
switch(code2)
|
||||||
|
{
|
||||||
|
case -1:/* bold */
|
||||||
|
*c= 0;
|
||||||
|
return true;
|
||||||
|
case 0:
|
||||||
|
*c= 146; // rvs off
|
||||||
|
return true;
|
||||||
|
case 30: // black
|
||||||
|
*c= 151;
|
||||||
|
return true;
|
||||||
|
case 31: // red
|
||||||
|
*c= 150;
|
||||||
|
return true;
|
||||||
|
case 32: // green
|
||||||
|
*c= 153;
|
||||||
|
return true;
|
||||||
|
case 33: // yellow
|
||||||
|
*c= 158;
|
||||||
|
return true;
|
||||||
|
case 34: // blue
|
||||||
|
*c= 154;
|
||||||
|
return true;
|
||||||
|
case 35: // purple
|
||||||
|
*c= 156;
|
||||||
|
return true;
|
||||||
|
case 36: // cyan
|
||||||
|
*c= 159;
|
||||||
|
return true;
|
||||||
|
case 37: // white/grey
|
||||||
|
default:
|
||||||
|
*c= 5;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: /*?*/
|
||||||
|
case 3: /*?*/
|
||||||
|
case 4: /*underline*/
|
||||||
|
case 5: /*blink*/
|
||||||
|
case 6: /*italics*/
|
||||||
|
*c=0;
|
||||||
|
return true;
|
||||||
|
case 40: case 41: case 42: case 43: case 44:
|
||||||
|
case 45: case 46: case 47: case 48: case 49:
|
||||||
|
*c=18; // rvs on
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*c = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char petToAsc(char c)
|
||||||
|
{
|
||||||
|
return pgm_read_byte_near(petToAscTable + (int)c);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ascToPet(char *c, Stream *stream)
|
||||||
|
{
|
||||||
|
if(!ansiColorToPetsciiColor(c,stream))
|
||||||
|
*c = pgm_read_byte_near(ascToPetTable + (int)(*c));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char ascToPetcii(char c)
|
||||||
|
{
|
||||||
|
return pgm_read_byte_near(ascToPetTable + (int)c);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,191 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PhoneBookEntry::PhoneBookEntry(unsigned long phnum, const char *addr, const char *mod, const char *note)
|
||||||
|
{
|
||||||
|
number=phnum;
|
||||||
|
address = new char[strlen(addr)+1];
|
||||||
|
strcpy((char *)address,addr);
|
||||||
|
modifiers = new char[strlen(mod)+1];
|
||||||
|
strcpy((char *)modifiers,mod);
|
||||||
|
notes = new char[strlen(note)+1];
|
||||||
|
strcpy((char *)notes,note);
|
||||||
|
|
||||||
|
if(phonebook == null)
|
||||||
|
{
|
||||||
|
phonebook = this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PhoneBookEntry *last = phonebook;
|
||||||
|
if(last->number > number)
|
||||||
|
{
|
||||||
|
phonebook = this;
|
||||||
|
next = last;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while(last->next != null)
|
||||||
|
{
|
||||||
|
if(last->next->number > number)
|
||||||
|
{
|
||||||
|
next = last->next;
|
||||||
|
last->next = this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
last = last->next;
|
||||||
|
}
|
||||||
|
last->next = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhoneBookEntry::~PhoneBookEntry()
|
||||||
|
{
|
||||||
|
if(phonebook == this)
|
||||||
|
phonebook = next;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PhoneBookEntry *last = phonebook;
|
||||||
|
while((last != null) && (last->next != this)) // don't change this!
|
||||||
|
last = last->next;
|
||||||
|
if(last != null)
|
||||||
|
last->next = next;
|
||||||
|
}
|
||||||
|
freeCharArray((char **)&address);
|
||||||
|
freeCharArray((char **)&modifiers);
|
||||||
|
freeCharArray((char **)¬es);
|
||||||
|
next=null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneBookEntry::loadPhonebook()
|
||||||
|
{
|
||||||
|
clearPhonebook();
|
||||||
|
if(SPIFFS.exists("/zphonebook.txt"))
|
||||||
|
{
|
||||||
|
File f = SPIFFS.open("/zphonebook.txt", "r");
|
||||||
|
while(f.available()>0)
|
||||||
|
{
|
||||||
|
String str="";
|
||||||
|
char c=f.read();
|
||||||
|
while((c != '\n') && (f.available()>0))
|
||||||
|
{
|
||||||
|
str += c;
|
||||||
|
c=f.read();
|
||||||
|
}
|
||||||
|
int argn=0;
|
||||||
|
String configArguments[4];
|
||||||
|
for(int i=0;i<4;i++)
|
||||||
|
configArguments[i]="";
|
||||||
|
for(int i=0;i<str.length();i++)
|
||||||
|
{
|
||||||
|
if((str[i]==',')&&(argn<=2))
|
||||||
|
argn++;
|
||||||
|
else
|
||||||
|
configArguments[argn] += str[i];
|
||||||
|
}
|
||||||
|
PhoneBookEntry *phb = new PhoneBookEntry(atol(configArguments[0].c_str()),configArguments[1].c_str(),configArguments[2].c_str(),configArguments[3].c_str());
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PhoneBookEntry::checkPhonebookEntry(String cmd)
|
||||||
|
{
|
||||||
|
const char *vbuf=(char *)cmd.c_str();
|
||||||
|
bool error = false;
|
||||||
|
for(char *cptr=(char *)vbuf;*cptr!=0;cptr++)
|
||||||
|
{
|
||||||
|
if(strchr("0123456789",*cptr) < 0)
|
||||||
|
{
|
||||||
|
error =true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(error || (strlen((char *)vbuf)>9))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhoneBookEntry *PhoneBookEntry::findPhonebookEntry(long number)
|
||||||
|
{
|
||||||
|
PhoneBookEntry *p = phonebook;
|
||||||
|
while(p != null)
|
||||||
|
{
|
||||||
|
if(p->number == number)
|
||||||
|
return p;
|
||||||
|
p=p->next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhoneBookEntry *PhoneBookEntry::findPhonebookEntry(String number)
|
||||||
|
{
|
||||||
|
if(!checkPhonebookEntry(number))
|
||||||
|
return null;
|
||||||
|
return findPhonebookEntry(atol(number.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneBookEntry::clearPhonebook()
|
||||||
|
{
|
||||||
|
PhoneBookEntry *phb = phonebook;
|
||||||
|
while(phonebook != null)
|
||||||
|
delete phonebook;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneBookEntry::savePhonebook()
|
||||||
|
{
|
||||||
|
SPIFFS.remove("/zphonebook.txt");
|
||||||
|
delay(500);
|
||||||
|
File f = SPIFFS.open("/zphonebook.txt", "w");
|
||||||
|
int ct=0;
|
||||||
|
PhoneBookEntry *phb=phonebook;
|
||||||
|
while(phb != null)
|
||||||
|
{
|
||||||
|
f.printf("%ul,%s,%s,%s\n",phb->number,phb->address,phb->modifiers,phb->notes);
|
||||||
|
phb = phb->next;
|
||||||
|
ct++;
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
delay(500);
|
||||||
|
if(SPIFFS.exists("/zphonebook.txt"))
|
||||||
|
{
|
||||||
|
File f = SPIFFS.open("/zphonebook.txt", "r");
|
||||||
|
while(f.available()>0)
|
||||||
|
{
|
||||||
|
String str="";
|
||||||
|
char c=f.read();
|
||||||
|
while((c != '\n') && (f.available()>0))
|
||||||
|
{
|
||||||
|
str += c;
|
||||||
|
c=f.read();
|
||||||
|
}
|
||||||
|
int argn=0;
|
||||||
|
if(str.length()>0)
|
||||||
|
{
|
||||||
|
for(int i=0;i<str.length();i++)
|
||||||
|
{
|
||||||
|
if((str[i]==',')&&(argn<=2))
|
||||||
|
argn++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(argn!=3)
|
||||||
|
{
|
||||||
|
delay(100);
|
||||||
|
f.close();
|
||||||
|
savePhonebook();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,542 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2018-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
|
||||||
|
FTPHost::~FTPHost()
|
||||||
|
{
|
||||||
|
freeCharArray(&hostIp);
|
||||||
|
freeCharArray(&username);
|
||||||
|
freeCharArray(&pw);
|
||||||
|
freeCharArray(&path);
|
||||||
|
freeCharArray(&file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FTPHost::doGet(FS *fs, const char *localpath, const char *remotepath)
|
||||||
|
{
|
||||||
|
fixPath(remotepath);
|
||||||
|
return doFTPGet(fs,hostIp,port,localpath,file,username,pw,doSSL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FTPHost::doPut(File &f, const char *remotepath)
|
||||||
|
{
|
||||||
|
fixPath(remotepath);
|
||||||
|
return doFTPPut(f,hostIp,port,file,username,pw,doSSL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FTPHost::doLS(ZSerial *serial, const char *remotepath)
|
||||||
|
{
|
||||||
|
fixPath(remotepath);
|
||||||
|
bool kaplah = doFTPLS(serial,hostIp,port,file,username,pw,doSSL);
|
||||||
|
if((kaplah)
|
||||||
|
&& (strcmp(file,path) != 0)
|
||||||
|
&& (strlen(file)>0))
|
||||||
|
{
|
||||||
|
if(file[strlen(file)-1]=='/')
|
||||||
|
setCharArray(&path, file);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char buf[strlen(file)+2];
|
||||||
|
sprintf(buf,"%s/",file);
|
||||||
|
setCharArray(&path, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kaplah;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FTPHost::fixPath(const char *remotepath)
|
||||||
|
{
|
||||||
|
if(remotepath == 0)
|
||||||
|
return;
|
||||||
|
char *end = strrchr(remotepath, '/');
|
||||||
|
int buflen = ((path == 0) ? 0 : strlen(path)) + strlen(remotepath) + 3;
|
||||||
|
char fbuf[buflen];
|
||||||
|
char pbuf[buflen];
|
||||||
|
if(remotepath[0] == '/')
|
||||||
|
{
|
||||||
|
strcpy(fbuf, remotepath);
|
||||||
|
if(end > 0)
|
||||||
|
{
|
||||||
|
*end = 0;
|
||||||
|
sprintf(pbuf,"%s/",remotepath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strcpy(pbuf, "/");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(fbuf,"%s%s",path,remotepath);
|
||||||
|
if(end > 0)
|
||||||
|
{
|
||||||
|
*end = 0;
|
||||||
|
sprintf(pbuf,"%s%s/",path,remotepath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strcpy(pbuf, path);
|
||||||
|
}
|
||||||
|
setCharArray(&path, pbuf);
|
||||||
|
setCharArray(&file, fbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FTPHost::parseUrl(uint8_t *vbuf, char **req)
|
||||||
|
{
|
||||||
|
char *newHostIp;
|
||||||
|
int newPort;
|
||||||
|
bool newDoSSL;
|
||||||
|
char *newUsername;
|
||||||
|
char *newPassword;
|
||||||
|
if(parseFTPUrl(vbuf,&newHostIp,req,&newPort,&newDoSSL,&newUsername,&newPassword))
|
||||||
|
{
|
||||||
|
setCharArray(&hostIp,newHostIp);
|
||||||
|
port = newPort;
|
||||||
|
doSSL = newDoSSL;
|
||||||
|
setCharArray(&username,newUsername);
|
||||||
|
setCharArray(&pw,newPassword);
|
||||||
|
setCharArray(&path,"/");
|
||||||
|
setCharArray(&file,"");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FTPHost *makeFTPHost(bool isUrl, FTPHost *host, uint8_t *buf, char **req)
|
||||||
|
{
|
||||||
|
if(isUrl)
|
||||||
|
{
|
||||||
|
if(host != 0)
|
||||||
|
delete host;
|
||||||
|
host = new FTPHost();
|
||||||
|
if(!(host->parseUrl(buf,req)))
|
||||||
|
{
|
||||||
|
delete host;
|
||||||
|
host=0;
|
||||||
|
*req=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*req=(char *)buf;
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseFTPUrl(uint8_t *vbuf, char **hostIp, char **req, int *port, bool *doSSL, char **username, char **pw)
|
||||||
|
{
|
||||||
|
*doSSL = false;
|
||||||
|
if(strstr((char *)vbuf,"ftp:")==(char *)vbuf)
|
||||||
|
vbuf = vbuf + 4;
|
||||||
|
else
|
||||||
|
if(strstr((char *)vbuf,"ftps:")==(char *)vbuf)
|
||||||
|
{
|
||||||
|
vbuf = vbuf + 5;
|
||||||
|
*doSSL = true;
|
||||||
|
}
|
||||||
|
while(*vbuf == '/')
|
||||||
|
vbuf++;
|
||||||
|
|
||||||
|
*port= 21;
|
||||||
|
*hostIp = (char *)vbuf;
|
||||||
|
char *atSign=strchr((char *)vbuf,'@');
|
||||||
|
*username=NULL;
|
||||||
|
*pw = NULL;
|
||||||
|
if(atSign != NULL)
|
||||||
|
{
|
||||||
|
*hostIp = atSign + 1;
|
||||||
|
*atSign = 0;
|
||||||
|
*username = (char *)vbuf;
|
||||||
|
vbuf = (uint8_t *)(atSign + 1);
|
||||||
|
char *pwB = strchr(*username, ':');
|
||||||
|
if(pwB != NULL)
|
||||||
|
{
|
||||||
|
*pw = pwB+1;
|
||||||
|
*pwB=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char *portB=strchr((char *)vbuf,':');
|
||||||
|
int len=strlen((char *)vbuf);
|
||||||
|
*req = strchr((char *)vbuf,'/');
|
||||||
|
if(*req != NULL)
|
||||||
|
{
|
||||||
|
*(*req)=0;
|
||||||
|
if((*req) != (char *)(vbuf+len-1))
|
||||||
|
(*req)++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*req = (char *)(vbuf + len);
|
||||||
|
if(portB != NULL)
|
||||||
|
{
|
||||||
|
*portB = 0;
|
||||||
|
portB++;
|
||||||
|
*port = atoi(portB);
|
||||||
|
if(port <= 0)
|
||||||
|
return ZERROR;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool doFTPQuit(WiFiClient **c)
|
||||||
|
{
|
||||||
|
if((*c)->connected())
|
||||||
|
{
|
||||||
|
(*c)->printf("QUIT\r\n");
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
(*c)->stop();
|
||||||
|
delete (*c);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String readLine(WiFiClient *c, int timeout)
|
||||||
|
{
|
||||||
|
unsigned long now=millis();
|
||||||
|
String line = "";
|
||||||
|
while(((millis()-now < timeout) || (c->available()>0))
|
||||||
|
&& (c->connected()|| (c->available()>0)))
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
if(c->available()>0)
|
||||||
|
{
|
||||||
|
char ch=c->read();
|
||||||
|
if((ch=='\n')||(ch=='\r'))
|
||||||
|
{
|
||||||
|
if(line.length()>0)
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((ch >= 32 ) && (ch <= 127))
|
||||||
|
line += ch;
|
||||||
|
now=millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getFTPResponseCode(WiFiClient *c, char *buf)
|
||||||
|
{
|
||||||
|
String resp = readLine(c,5000);
|
||||||
|
if(resp.length() == 0)
|
||||||
|
return -1; // timeout total
|
||||||
|
while((resp.length()<3)
|
||||||
|
||(resp[0] < '0')||(resp[0] > '9')
|
||||||
|
||(resp[1] < '0')||(resp[1] > '9')
|
||||||
|
||(resp[2] < '0')||(resp[2] > '9'))
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
resp = readLine(c,1000);
|
||||||
|
if(resp.length()==0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if((buf != NULL)&&(resp.length()<132))
|
||||||
|
strcpy(buf,resp.substring(4).c_str());
|
||||||
|
return atoi(resp.substring(0,3).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void readBytesToSilence(WiFiClient *cc)
|
||||||
|
{
|
||||||
|
unsigned long now = millis(); // just eat the intro for 1 second of silence
|
||||||
|
while(millis()-now < 1000)
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
if(cc->available()>0)
|
||||||
|
{
|
||||||
|
cc->read();
|
||||||
|
now=millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doFTPGet(FS *fs, const char *hostIp, int port, const char *localpath, const char *remotepath, const char *username, const char *pw, const bool doSSL)
|
||||||
|
{
|
||||||
|
WiFiClient *cc = createWiFiClient(doSSL);
|
||||||
|
if(WiFi.status() != WL_CONNECTED)
|
||||||
|
return false;
|
||||||
|
if(!cc->connect(hostIp, port))
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
cc->setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
readBytesToSilence(cc);
|
||||||
|
if(username == NULL)
|
||||||
|
cc->printf("USER anonymous\r\n");
|
||||||
|
else
|
||||||
|
cc->printf("USER %s\r\n",username);
|
||||||
|
int respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if(respCode != 331)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
if(pw == NULL)
|
||||||
|
cc->printf("PASS zimodem@zimtime.net\r\n");
|
||||||
|
else
|
||||||
|
cc->printf("PASS %s\r\n",pw);
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if(respCode != 230)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
readBytesToSilence(cc);
|
||||||
|
cc->printf("TYPE I\r\n");
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if(respCode < 0)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
char ipbuf[129];
|
||||||
|
cc->printf("PASV\r\n");
|
||||||
|
respCode = getFTPResponseCode(cc, ipbuf);
|
||||||
|
if(respCode != 227)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
// now parse the pasv result in .* (ipv4,ipv4,ipv4,ipv4,
|
||||||
|
char *ipptr = strchr(ipbuf,'(');
|
||||||
|
while((ipptr != NULL) && (strchr(ipptr+1,'(')!= NULL))
|
||||||
|
ipptr=strchr(ipptr+1,'(');
|
||||||
|
if(ipptr == NULL)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
int digitCount=0;
|
||||||
|
int digits[10];
|
||||||
|
char *commaPtr=strchr(ipptr+1,',');
|
||||||
|
while((commaPtr != NULL)&&(digitCount < 10))
|
||||||
|
{
|
||||||
|
*commaPtr = 0;
|
||||||
|
digits[digitCount++] = atoi(ipptr+1);
|
||||||
|
ipptr=commaPtr;
|
||||||
|
commaPtr=strchr(ipptr+1,',');
|
||||||
|
if(commaPtr == NULL)
|
||||||
|
commaPtr=strchr(ipptr+1,')');
|
||||||
|
}
|
||||||
|
if(digitCount < 6)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
sprintf(ipbuf,"%d.%d.%d.%d",digits[0],digits[1],digits[2],digits[3]);
|
||||||
|
int dataPort = (256 * digits[4]) + digits[5];
|
||||||
|
// ok, now we are ready for DATA!
|
||||||
|
if(WiFi.status() != WL_CONNECTED)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
WiFiClient *c = createWiFiClient(doSSL);
|
||||||
|
if(!c->connect(ipbuf, dataPort))
|
||||||
|
{
|
||||||
|
doFTPQuit(&c);
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
}
|
||||||
|
c->setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
cc->printf("RETR %s\r\n",remotepath);
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if((respCode < 0)||(respCode > 400))
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
File f = fs->open(localpath, "w");
|
||||||
|
unsigned long now=millis();
|
||||||
|
while((c->connected()||(c->available()>0))
|
||||||
|
&& ((millis()-now) < 30000)) // loop for data, with nice long timeout
|
||||||
|
{
|
||||||
|
if(c->available()>=0)
|
||||||
|
{
|
||||||
|
now=millis();
|
||||||
|
uint8_t ch=c->read();
|
||||||
|
//logSocketIn(ch); // this is ALSO not socket input!
|
||||||
|
f.write(ch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
f.flush();
|
||||||
|
f.close();
|
||||||
|
c->stop();
|
||||||
|
delete c;
|
||||||
|
doFTPQuit(&cc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doFTPPut(File &f, const char *hostIp, int port, const char *remotepath, const char *username, const char *pw, const bool doSSL)
|
||||||
|
{
|
||||||
|
WiFiClient *cc = createWiFiClient(doSSL);
|
||||||
|
if(WiFi.status() != WL_CONNECTED)
|
||||||
|
return false;
|
||||||
|
if(!cc->connect(hostIp, port))
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
cc->setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
readBytesToSilence(cc);
|
||||||
|
if(username == NULL)
|
||||||
|
cc->printf("USER anonymous\r\n");
|
||||||
|
else
|
||||||
|
cc->printf("USER %s\r\n",username);
|
||||||
|
int respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if(respCode != 331)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
if(pw == NULL)
|
||||||
|
cc->printf("PASS zimodem@zimtime.net\r\n");
|
||||||
|
else
|
||||||
|
cc->printf("PASS %s\r\n",pw);
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if(respCode != 230)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
readBytesToSilence(cc);
|
||||||
|
cc->printf("TYPE I\r\n");
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if(respCode < 0)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
char ipbuf[129];
|
||||||
|
cc->printf("PASV\r\n");
|
||||||
|
debugPrintf("PASV\r\n");
|
||||||
|
respCode = getFTPResponseCode(cc, ipbuf);
|
||||||
|
if(respCode != 227)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
// now parse the pasv result in .* (ipv4,ipv4,ipv4,ipv4,
|
||||||
|
char *ipptr = strchr(ipbuf,'(');
|
||||||
|
while((ipptr != NULL) && (strchr(ipptr+1,'(')!= NULL))
|
||||||
|
ipptr=strchr(ipptr+1,'(');
|
||||||
|
if(ipptr == NULL)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
int digitCount=0;
|
||||||
|
int digits[10];
|
||||||
|
char *commaPtr=strchr(ipptr+1,',');
|
||||||
|
while((commaPtr != NULL)&&(digitCount < 10))
|
||||||
|
{
|
||||||
|
*commaPtr = 0;
|
||||||
|
digits[digitCount++] = atoi(ipptr+1);
|
||||||
|
ipptr=commaPtr;
|
||||||
|
commaPtr=strchr(ipptr+1,',');
|
||||||
|
if(commaPtr == NULL)
|
||||||
|
commaPtr=strchr(ipptr+1,')');
|
||||||
|
}
|
||||||
|
if(digitCount < 6)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
sprintf(ipbuf,"%d.%d.%d.%d",digits[0],digits[1],digits[2],digits[3]);
|
||||||
|
debugPrintf(ipbuf,"%d.%d.%d.%d",digits[0],digits[1],digits[2],digits[3]);
|
||||||
|
int dataPort = (256 * digits[4]) + digits[5];
|
||||||
|
// ok, now we are ready for DATA!
|
||||||
|
if(WiFi.status() != WL_CONNECTED)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
WiFiClient *c = createWiFiClient(doSSL);
|
||||||
|
if(!c->connect(ipbuf, dataPort))
|
||||||
|
{
|
||||||
|
doFTPQuit(&c);
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
}
|
||||||
|
c->setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
debugPrintf(" STOR %s\r\n",remotepath);
|
||||||
|
cc->printf("STOR %s\r\n",remotepath);
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if((respCode < 0)||(respCode > 400))
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
unsigned long now=millis();
|
||||||
|
debugPrintf(" Storing... %d\r\n",f.available());
|
||||||
|
while((c->connected())
|
||||||
|
&& (f.available()>0) && ((millis()-now) < 30000)) // loop for data, with nice long timeout
|
||||||
|
{
|
||||||
|
if(f.available()>=0)
|
||||||
|
{
|
||||||
|
now=millis();
|
||||||
|
uint8_t ch=f.read();
|
||||||
|
//logSocketIn(ch); // this is ALSO not socket input!
|
||||||
|
c->write(ch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
debugPrintf("FPUT: Done\r\n");
|
||||||
|
c->flush();
|
||||||
|
c->stop();
|
||||||
|
delete c;
|
||||||
|
doFTPQuit(&cc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doFTPLS(ZSerial *serial, const char *hostIp, int port, const char *remotepath, const char *username, const char *pw, const bool doSSL)
|
||||||
|
{
|
||||||
|
WiFiClient *cc = createWiFiClient(doSSL);
|
||||||
|
if(WiFi.status() != WL_CONNECTED)
|
||||||
|
return false;
|
||||||
|
if(!cc->connect(hostIp, port))
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
cc->setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
readBytesToSilence(cc);
|
||||||
|
if(username == NULL)
|
||||||
|
cc->printf("USER anonymous\r\n");
|
||||||
|
else
|
||||||
|
cc->printf("USER %s\r\n",username);
|
||||||
|
int respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if(respCode != 331)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
if(pw == NULL)
|
||||||
|
cc->printf("PASS zimodem@zimtime.net\r\n");
|
||||||
|
else
|
||||||
|
cc->printf("PASS %s\r\n",pw);
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if(respCode != 230)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
readBytesToSilence(cc);
|
||||||
|
cc->printf("TYPE A\r\n");
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if(respCode < 0)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
if((remotepath != NULL)&& (*remotepath != NULL))
|
||||||
|
{
|
||||||
|
cc->printf("CWD %s\r\n",remotepath);
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if((respCode < 0)||(respCode > 400))
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
readBytesToSilence(cc);
|
||||||
|
}
|
||||||
|
char ipbuf[129];
|
||||||
|
cc->printf("PASV\r\n");
|
||||||
|
respCode = getFTPResponseCode(cc, ipbuf);
|
||||||
|
if(respCode != 227)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
// now parse the pasv result in .* (ipv4,ipv4,ipv4,ipv4,
|
||||||
|
char *ipptr = strchr(ipbuf,'(');
|
||||||
|
while((ipptr != NULL) && (strchr(ipptr+1,'(')!= NULL))
|
||||||
|
ipptr=strchr(ipptr+1,'(');
|
||||||
|
if(ipptr == NULL)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
int digitCount=0;
|
||||||
|
int digits[10];
|
||||||
|
char *commaPtr=strchr(ipptr+1,',');
|
||||||
|
while((commaPtr != NULL)&&(digitCount < 10))
|
||||||
|
{
|
||||||
|
*commaPtr = 0;
|
||||||
|
digits[digitCount++] = atoi(ipptr+1);
|
||||||
|
ipptr=commaPtr;
|
||||||
|
commaPtr=strchr(ipptr+1,',');
|
||||||
|
if(commaPtr == NULL)
|
||||||
|
commaPtr=strchr(ipptr+1,')');
|
||||||
|
}
|
||||||
|
if(digitCount < 6)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
sprintf(ipbuf,"%d.%d.%d.%d",digits[0],digits[1],digits[2],digits[3]);
|
||||||
|
int dataPort = (256 * digits[4]) + digits[5];
|
||||||
|
// ok, now we are ready for DATA!
|
||||||
|
if(WiFi.status() != WL_CONNECTED)
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
WiFiClient *c = createWiFiClient(doSSL);
|
||||||
|
if(!c->connect(ipbuf, dataPort))
|
||||||
|
{
|
||||||
|
doFTPQuit(&c);
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
}
|
||||||
|
c->setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
cc->printf("LIST\r\n",remotepath);
|
||||||
|
respCode = getFTPResponseCode(cc, NULL);
|
||||||
|
if((respCode < 0)||(respCode > 400))
|
||||||
|
return doFTPQuit(&cc);
|
||||||
|
unsigned long now=millis();
|
||||||
|
while((c->connected()||(c->available()>0))
|
||||||
|
&& ((millis()-now) < 30000)) // loop for data, with nice long timeout
|
||||||
|
{
|
||||||
|
if(c->available()>=0)
|
||||||
|
{
|
||||||
|
now=millis();
|
||||||
|
uint8_t ch=c->read();
|
||||||
|
//logSocketIn(ch); // this is ALSO not socket input!
|
||||||
|
serial->print((char)ch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
c->stop();
|
||||||
|
delete c;
|
||||||
|
doFTPQuit(&cc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,691 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
#ifdef INCLUDE_HOSTCM
|
||||||
|
/* Converted from Rob Ferguson's code by Bo Zimmerman
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Robert Ferguson All rights reserved.
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||||
|
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *basename(char *path)
|
||||||
|
{
|
||||||
|
char *base = strrchr(path, '/');
|
||||||
|
return base ? base+1 : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *dirname(char *path)
|
||||||
|
{
|
||||||
|
char *base = strrchr(path, '/');
|
||||||
|
if(base)
|
||||||
|
{
|
||||||
|
*base = 0;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
HostCM::HostCM(FS *fs)
|
||||||
|
{
|
||||||
|
hFS = fs;
|
||||||
|
for(int i=0;i<HCM_MAXFN;i++)
|
||||||
|
{
|
||||||
|
files[i].f = (File)0;
|
||||||
|
files[i].descriptor = 'A' + i;
|
||||||
|
delFileEntry(&files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HostCM::~HostCM()
|
||||||
|
{
|
||||||
|
closeAllFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool HostCM::closeAllFiles()
|
||||||
|
{
|
||||||
|
for(int i=0;i<HCM_MAXFN;i++)
|
||||||
|
delFileEntry(&files[i]);
|
||||||
|
if(renameF != 0)
|
||||||
|
renameF.close();
|
||||||
|
renameF = (File)0;
|
||||||
|
if(openDirF != 0)
|
||||||
|
openDirF.close();
|
||||||
|
openDirF = (File)0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
HCMFile *HostCM::addNewFileEntry()
|
||||||
|
{
|
||||||
|
for(int i=0;i<HCM_MAXFN;i++)
|
||||||
|
{
|
||||||
|
if(files[i].f == 0)
|
||||||
|
return &files[i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::delFileEntry(HCMFile *e)
|
||||||
|
{
|
||||||
|
if(e->f != 0)
|
||||||
|
e->f.close();
|
||||||
|
char d = e->descriptor;
|
||||||
|
memset(e,sizeof(struct _HCMFile),0);
|
||||||
|
e->descriptor = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HCMFile *HostCM::getFileByDescriptor(char c)
|
||||||
|
{
|
||||||
|
for(int i=0;i<HCM_MAXFN;i++)
|
||||||
|
{
|
||||||
|
if(files[i].descriptor == c)
|
||||||
|
return &files[i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HostCM::numOpenFiles()
|
||||||
|
{
|
||||||
|
int n=0;
|
||||||
|
for(int i=0;i<HCM_MAXFN;i++)
|
||||||
|
{
|
||||||
|
if(files[i].f != 0)
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::checkDoPlusPlusPlus(const int c, const unsigned long tm)
|
||||||
|
{
|
||||||
|
if(c == '+')
|
||||||
|
{
|
||||||
|
if((plussesInARow>0)||((tm-lastNonPlusTm)>800))
|
||||||
|
{
|
||||||
|
plussesInARow++;
|
||||||
|
if(plussesInARow > 2)
|
||||||
|
plusTimeExpire = tm + 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plusTimeExpire = 0;
|
||||||
|
lastNonPlusTm = tm;
|
||||||
|
plussesInARow = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HostCM::checkPlusPlusPlusExpire(const unsigned long tm)
|
||||||
|
{
|
||||||
|
if(aborted)
|
||||||
|
return true;
|
||||||
|
if((plusTimeExpire>0)&&(tm>plusTimeExpire)&&(plussesInARow>2))
|
||||||
|
{
|
||||||
|
aborted = true;
|
||||||
|
plusTimeExpire = 0;
|
||||||
|
lastNonPlusTm = tm;
|
||||||
|
plussesInARow = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HostCM::isAborted()
|
||||||
|
{
|
||||||
|
return aborted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoCloseFile()
|
||||||
|
{
|
||||||
|
HCMFile *h = getFileByDescriptor((char)inbuf[1]);
|
||||||
|
if (h==0) {
|
||||||
|
sendError("error: invalid descriptor %c", inbuf[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h->f == 0)
|
||||||
|
{
|
||||||
|
sendError("error: file not open %c", inbuf[1]); // should this be an error though?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delFileEntry(h);
|
||||||
|
sendACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoPutToFile()
|
||||||
|
{
|
||||||
|
HCMFile *h = getFileByDescriptor((char)inbuf[1]);
|
||||||
|
if (h==0) {
|
||||||
|
sendError("error: invalid descriptor %c", inbuf[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t eor = (uint8_t)lc((char)inbuf[2]);
|
||||||
|
if (h->f == 0)
|
||||||
|
{
|
||||||
|
sendError("error: file not open %c", inbuf[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*if((h->mode)=='r')||(h->mode=='l'))
|
||||||
|
{
|
||||||
|
sendError("error: read-only file %c", inbuf[1]);
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
if(h->format == 'b')
|
||||||
|
{
|
||||||
|
FROMHEX(&inbuf[3], idex - 4);
|
||||||
|
idex = ((idex - 4) / 2) + 4;
|
||||||
|
}
|
||||||
|
if((eor=='z')
|
||||||
|
&&((h->format == 't')
|
||||||
|
||(h->type != 'f')))
|
||||||
|
{
|
||||||
|
inbuf[idex-1] = opt.lineend;
|
||||||
|
idex++;
|
||||||
|
}
|
||||||
|
if(h->f.write(&inbuf[3],idex-4) != idex-4)
|
||||||
|
{
|
||||||
|
sendError("error: write failed to file %c", inbuf[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoGetFileBytes()
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
HCMFile *h = getFileByDescriptor((char)inbuf[1]);
|
||||||
|
if (h==0)
|
||||||
|
{
|
||||||
|
sendError("error: invalid descriptor %c", inbuf[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((h->f == 0)
|
||||||
|
||((h->mode != 'r') && (h->mode != 'u') && (h->mode != 'l')))
|
||||||
|
{
|
||||||
|
sendError("error: file not open/readable %c", inbuf[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
odex = 0;
|
||||||
|
outbuf[odex++] = opt.response;
|
||||||
|
if(h->format == 't')
|
||||||
|
{
|
||||||
|
outbuf[odex++] = 'b';
|
||||||
|
outbuf[odex] = 'z';
|
||||||
|
do
|
||||||
|
{
|
||||||
|
odex++;
|
||||||
|
c = h->f.read();
|
||||||
|
outbuf[odex] = (uint8_t)(c & 0xff);
|
||||||
|
}
|
||||||
|
while((c >= 0) && (odex < (HCM_SENDBUF - 2)) && (outbuf[odex] != 0xd));
|
||||||
|
|
||||||
|
if(c<0)
|
||||||
|
{
|
||||||
|
outbuf[1] = 'e';
|
||||||
|
outbuf[2] = checksum(&outbuf[1], 1);
|
||||||
|
odex=3; // abandon anything between EOL and EOF
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (odex >= (HCM_SENDBUF - 2))
|
||||||
|
outbuf[2] = 'n';
|
||||||
|
outbuf[odex] = checksum(&outbuf[1], odex - 1);
|
||||||
|
odex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (h->format == 'b')
|
||||||
|
{
|
||||||
|
int rdcount = HCM_SENDBUF;
|
||||||
|
char eor = 'n';
|
||||||
|
if(h->reclen)
|
||||||
|
{
|
||||||
|
if (h->reclen < HCM_SENDBUF)
|
||||||
|
{
|
||||||
|
rdcount = h->reclen;
|
||||||
|
eor = 'z';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int pos = h->f.position();
|
||||||
|
if((pos & h->reclen) > ((pos + rdcount) & h->reclen))
|
||||||
|
{
|
||||||
|
rdcount = ((pos + rdcount) / h->reclen) * h->reclen - pos;
|
||||||
|
eor = 'z';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t rdbuf[rdcount];
|
||||||
|
int n = h->f.read(rdbuf, rdcount);
|
||||||
|
if (n <= 0)
|
||||||
|
{
|
||||||
|
outbuf[odex++] = 'e';
|
||||||
|
outbuf[odex] = checksum(&outbuf[1], odex - 1);
|
||||||
|
odex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outbuf[odex++] = 'b';
|
||||||
|
outbuf[odex++] = eor;
|
||||||
|
for(int i=0;i<n;i++)
|
||||||
|
memcpy(TOHEX(rdbuf[i]), &outbuf[odex+(i*2)], 2);
|
||||||
|
odex += n * 2;
|
||||||
|
outbuf[odex] = checksum(&outbuf[1], odex - 1);
|
||||||
|
odex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outbuf[odex++] = opt.lineend;
|
||||||
|
outbuf[odex++] = opt.prompt;
|
||||||
|
hserial.write(outbuf, odex);
|
||||||
|
hserial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoOpenFile()
|
||||||
|
{
|
||||||
|
uint8_t *eobuf = inbuf + idex;
|
||||||
|
int n=numOpenFiles();
|
||||||
|
if(n >= HCM_MAXFN)
|
||||||
|
{
|
||||||
|
sendError("error: too many open files");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(idex<8)
|
||||||
|
{
|
||||||
|
sendError("error: command too short");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t mode = (uint8_t)lc((char)inbuf[1]);
|
||||||
|
if(strchr("rlwsua",(char)mode)==0)
|
||||||
|
{
|
||||||
|
sendError("error: illegal mode %c",(char)mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool isRead = strchr("rl",(char)mode)!=0;
|
||||||
|
uint8_t format = (uint8_t)lc((char)inbuf[2]);
|
||||||
|
uint8_t *ptr = (uint8_t *)memchr(inbuf+3, '(', idex-3);
|
||||||
|
if(ptr == 0)
|
||||||
|
{
|
||||||
|
sendError("error: missing (");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t type = (uint8_t)lc((char)ptr[1]);
|
||||||
|
uint8_t reclen = 0;
|
||||||
|
if(ptr[2]==':')
|
||||||
|
reclen=atoi((char *)(ptr+3));
|
||||||
|
ptr = (uint8_t *)memchr(ptr+2, ')', eobuf-(ptr+1));
|
||||||
|
if(ptr == 0)
|
||||||
|
{
|
||||||
|
sendError("error: missing )");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inbuf[idex - 1] = 0;
|
||||||
|
uint8_t *fnptr = ptr + 1;
|
||||||
|
HCMFile *newF = addNewFileEntry();
|
||||||
|
if (type == 'f')
|
||||||
|
{
|
||||||
|
char *bn = basename((char *)ptr+1);
|
||||||
|
char *dn = dirname((char *)ptr+1);
|
||||||
|
if(reclen == 0)
|
||||||
|
reclen = 80;
|
||||||
|
snprintf(newF->filename, sizeof(newF->filename), "%s/(f:%d)%s", dn, reclen, bn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strncpy(newF->filename, (char *)ptr+1, sizeof(newF->filename));
|
||||||
|
if(isRead)
|
||||||
|
{
|
||||||
|
newF->f = SD.open(newF->filename);
|
||||||
|
if(newF->f == 0)
|
||||||
|
{
|
||||||
|
if(strchr(basename(newF->filename), ',') == 0)
|
||||||
|
{
|
||||||
|
if(strlen(newF->filename) + 5 < HCM_FNSIZ)
|
||||||
|
{
|
||||||
|
if((mode == 'l') || (mode == 's'))
|
||||||
|
strcat(newF->filename, ",prg");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(type == 'f')
|
||||||
|
strcat(newF->filename, ",rel");
|
||||||
|
else
|
||||||
|
strcat(newF->filename, ",seq");
|
||||||
|
}
|
||||||
|
newF->f = SD.open(newF->filename);
|
||||||
|
if(newF == 0)
|
||||||
|
{
|
||||||
|
sendError("error: file '%s' not found", newF->filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendError("error: file '%s' not found", newF->filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newF->f = SD.open(newF->filename,FILE_WRITE);
|
||||||
|
if(newF->f == 0)
|
||||||
|
{
|
||||||
|
sendError("error: failed to open '%s'", newF->filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(newF->f && (mode == 'a'))
|
||||||
|
newF->f.seek(EOF);
|
||||||
|
}
|
||||||
|
newF->mode = mode;
|
||||||
|
newF->format = format;
|
||||||
|
newF->type = type;
|
||||||
|
newF->reclen = reclen;
|
||||||
|
|
||||||
|
odex = 0;
|
||||||
|
outbuf[odex++] = opt.response;
|
||||||
|
outbuf[odex++] = 'b';
|
||||||
|
outbuf[odex++] = newF->descriptor;
|
||||||
|
outbuf[odex++] = checksum(&(outbuf[1]), 2);
|
||||||
|
outbuf[odex++] = opt.lineend;
|
||||||
|
outbuf[odex++] = opt.prompt;
|
||||||
|
hserial.write(outbuf, odex);
|
||||||
|
hserial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoOpenDir()
|
||||||
|
{
|
||||||
|
if(openDirF != 0)
|
||||||
|
{
|
||||||
|
sendError("error: directory open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(idex > 2)
|
||||||
|
inbuf[idex - 1] = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy((char *)&inbuf[1], "/");
|
||||||
|
idex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
openDirF = SD.open((char *)&inbuf[1]);
|
||||||
|
if((openDirF == 0)||(!openDirF.isDirectory()))
|
||||||
|
{
|
||||||
|
sendError("error: directory not found %s",(char *)&inbuf[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoCloseDir()
|
||||||
|
{
|
||||||
|
if(openDirF == 0)
|
||||||
|
{
|
||||||
|
sendError("error: directory not open"); // should this really be an error?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openDirF.close();
|
||||||
|
openDirF = (File)0;
|
||||||
|
sendACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoNextDirFile()
|
||||||
|
{
|
||||||
|
if(openDirF == 0)
|
||||||
|
{
|
||||||
|
sendError("error: directory not open"); // should this really be an error?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
odex = 0;
|
||||||
|
outbuf[odex++] = opt.response;
|
||||||
|
|
||||||
|
File nf = openDirF.openNextFile();
|
||||||
|
if(nf == 0)
|
||||||
|
outbuf[odex++] = 'e';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *fname = (char *)nf.name();
|
||||||
|
char *paren = strchr(fname,')');
|
||||||
|
int reclen = 0;
|
||||||
|
if((strncmp("(f:", fname, 3) == 0) && (paren != 0))
|
||||||
|
{
|
||||||
|
fname = paren + 1;
|
||||||
|
reclen = atoi((char *)&fname[3]);
|
||||||
|
}
|
||||||
|
outbuf[odex++] = 'b';
|
||||||
|
|
||||||
|
if(reclen)
|
||||||
|
odex += snprintf((char *)&outbuf[odex], HCM_BUFSIZ - odex, "%-20s %8llu (%d)",
|
||||||
|
fname, (unsigned long long)nf.size(), reclen);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(nf.isDirectory())
|
||||||
|
odex += snprintf((char *)&outbuf[odex], HCM_BUFSIZ - odex, "%s/", fname);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
odex += snprintf((char *)&outbuf[odex], HCM_BUFSIZ - odex, "%-20s %8llu",
|
||||||
|
fname, (unsigned long long)nf.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nf.close();
|
||||||
|
outbuf[odex] = checksum(&(outbuf[1]), odex - 1);
|
||||||
|
odex++;
|
||||||
|
outbuf[odex++] = opt.lineend;
|
||||||
|
outbuf[odex++] = opt.prompt;
|
||||||
|
hserial.write(outbuf, odex);
|
||||||
|
hserial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoSetRenameFile()
|
||||||
|
{
|
||||||
|
if (renameF != 0)
|
||||||
|
{
|
||||||
|
sendError("error: rename in progress");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idex > 2)
|
||||||
|
{
|
||||||
|
inbuf[idex - 1] = 0;
|
||||||
|
renameF = SD.open((char *)&inbuf[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendError("error: missing filename");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoFinRenameFile()
|
||||||
|
{
|
||||||
|
if (renameF == 0)
|
||||||
|
{
|
||||||
|
sendError("error: rename not started");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idex > 2)
|
||||||
|
inbuf[idex - 1] = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendError("error: missing filename");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String on = renameF.name();
|
||||||
|
renameF.close();
|
||||||
|
if(!SD.rename(on,(char *)&inbuf[1]))
|
||||||
|
{
|
||||||
|
renameF = (File)0;
|
||||||
|
sendError("error: rename %s failed",on);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renameF = (File)0;
|
||||||
|
sendACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoEraseFile()
|
||||||
|
{
|
||||||
|
if (idex > 2)
|
||||||
|
inbuf[idex - 1] = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendError("error: missing filename");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!SD.remove((char *)&inbuf[1]))
|
||||||
|
{
|
||||||
|
sendError("error: erase %s failed",(char *)&inbuf[1] );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::protoSeekFile()
|
||||||
|
{
|
||||||
|
HCMFile *h = getFileByDescriptor((char)inbuf[1]);
|
||||||
|
if (h==0)
|
||||||
|
{
|
||||||
|
sendError("error: invalid descriptor %c", inbuf[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(h->f == 0)
|
||||||
|
{
|
||||||
|
sendError("error: file not open/readable %c", inbuf[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inbuf[idex - 1] = 0;
|
||||||
|
|
||||||
|
unsigned long offset = atoi((char *)&inbuf[2]) * ((h->reclen == 0)? 1 : h->reclen);
|
||||||
|
if(!h->f.seek(offset))
|
||||||
|
{
|
||||||
|
sendError("error: seek failed on %s @ %ul", h->f.name(),offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
char HostCM::checksum(uint8_t *b, int n)
|
||||||
|
{
|
||||||
|
int i, s = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
s += b[i] & 0xf;
|
||||||
|
return ('A' + (s&0xf));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::sendError(const char* format, ...)
|
||||||
|
{
|
||||||
|
odex = 0;
|
||||||
|
outbuf[odex++] = opt.response;
|
||||||
|
outbuf[odex++] = 'x';
|
||||||
|
va_list arglist;
|
||||||
|
va_start(arglist, format);
|
||||||
|
odex += vsnprintf((char *)&outbuf[2], 80, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
outbuf[odex] = checksum(&outbuf[1], odex - 1);
|
||||||
|
odex++;
|
||||||
|
outbuf[odex++] = opt.lineend;
|
||||||
|
outbuf[odex++] = opt.prompt;
|
||||||
|
hserial.write(outbuf, odex);
|
||||||
|
hserial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::sendNAK()
|
||||||
|
{
|
||||||
|
odex = 0;
|
||||||
|
outbuf[odex++] = opt.response;
|
||||||
|
outbuf[odex++] = 'N';
|
||||||
|
outbuf[odex++] = opt.lineend;
|
||||||
|
outbuf[odex++] = opt.prompt;
|
||||||
|
hserial.write(outbuf, odex);
|
||||||
|
hserial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::sendACK()
|
||||||
|
{
|
||||||
|
odex = 0;
|
||||||
|
outbuf[odex++] = opt.response;
|
||||||
|
outbuf[odex++] = 'b';
|
||||||
|
outbuf[odex++] = checksum(&(outbuf[1]), 1);
|
||||||
|
outbuf[odex++] = opt.lineend;
|
||||||
|
outbuf[odex++] = opt.prompt;
|
||||||
|
hserial.write(outbuf, odex);
|
||||||
|
hserial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostCM::receiveLoop()
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
unsigned long tm = millis();
|
||||||
|
if(checkPlusPlusPlusExpire(tm))
|
||||||
|
return;
|
||||||
|
int c;
|
||||||
|
while(hserial.available() > 0)
|
||||||
|
{
|
||||||
|
c=hserial.read();
|
||||||
|
if(idex<HCM_BUFSIZ)
|
||||||
|
inbuf[idex++]=c;
|
||||||
|
checkDoPlusPlusPlus(c, tm);
|
||||||
|
if(checkPlusPlusPlusExpire(tm))
|
||||||
|
return;
|
||||||
|
yield();
|
||||||
|
if(c==opt.lineend)
|
||||||
|
{
|
||||||
|
inbuf[idex-1]=c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((idex==0)
|
||||||
|
||(inbuf[idex-1]!=opt.lineend))
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
idex--;
|
||||||
|
if((idex>1)&&(inbuf[idex-1]!=checksum(inbuf,idex-1)))
|
||||||
|
sendNAK();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logPrintf("HOSTCM received: %c\n",inbuf[0]);
|
||||||
|
switch(inbuf[0])
|
||||||
|
{
|
||||||
|
case 'N':
|
||||||
|
hserial.write(outbuf, odex);
|
||||||
|
hserial.flush();
|
||||||
|
break;
|
||||||
|
case 'v': sendACK(); break;
|
||||||
|
case 'q': aborted = closeAllFiles(); break;
|
||||||
|
case 'o': protoOpenFile(); break;
|
||||||
|
case 'c': protoCloseFile(); break;
|
||||||
|
case 'p': protoPutToFile(); break;
|
||||||
|
case 'g': protoGetFileBytes(); break;
|
||||||
|
case 'd': protoOpenDir(); break;
|
||||||
|
case 'f': protoNextDirFile(); break;
|
||||||
|
case 'k': protoCloseDir(); break;
|
||||||
|
case 'w': protoSetRenameFile(); break;
|
||||||
|
case 'b': protoFinRenameFile(); break;
|
||||||
|
case 'y': protoEraseFile(); break;
|
||||||
|
case 'r': protoSeekFile(); break;
|
||||||
|
default:
|
||||||
|
sendNAK();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idex=0; // we are ready for the next packet!
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,399 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
bool parseWebUrl(uint8_t *vbuf, char **hostIp, char **req, int *port, bool *doSSL)
|
||||||
|
{
|
||||||
|
*doSSL = false;
|
||||||
|
if(strstr((char *)vbuf,"http:")==(char *)vbuf)
|
||||||
|
vbuf = vbuf + 5;
|
||||||
|
else
|
||||||
|
if(strstr((char *)vbuf,"https:")==(char *)vbuf)
|
||||||
|
{
|
||||||
|
vbuf = vbuf + 6;
|
||||||
|
*doSSL = true;
|
||||||
|
}
|
||||||
|
while(*vbuf == '/')
|
||||||
|
vbuf++;
|
||||||
|
|
||||||
|
*port= (*doSSL) ? 443 : 80;
|
||||||
|
*hostIp = (char *)vbuf;
|
||||||
|
char *portB=strchr((char *)vbuf,':');
|
||||||
|
*req = strchr((char *)vbuf,'/');
|
||||||
|
if(*req != NULL)
|
||||||
|
{
|
||||||
|
*(*req)=0;
|
||||||
|
(*req)++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int len=strlen((char *)vbuf);
|
||||||
|
*req = (char *)(vbuf + len);
|
||||||
|
}
|
||||||
|
if(portB != NULL)
|
||||||
|
{
|
||||||
|
*portB = 0;
|
||||||
|
portB++;
|
||||||
|
*port = atoi(portB);
|
||||||
|
if(port <= 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* It just breaks too many things to allow a stream to go forward without
|
||||||
|
* a determined length. For example: firmware updates, and even at&g returns
|
||||||
|
* a page length for the client. Let true clients use sockets and handle
|
||||||
|
* their own chunked encoding.
|
||||||
|
class ChunkedStream : public WiFiClient
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
WiFiClient *wifi = null;
|
||||||
|
int chunkCount = 0;
|
||||||
|
int chunkSize = 0;
|
||||||
|
uint8_t state = 0; //0
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ChunkedStream(WiFiClient *s)
|
||||||
|
{
|
||||||
|
wifi = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ChunkedStream()
|
||||||
|
{
|
||||||
|
if(wifi != null)
|
||||||
|
{
|
||||||
|
wifi->stop();
|
||||||
|
delete wifi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int read()
|
||||||
|
{
|
||||||
|
if(available()==0)
|
||||||
|
return -1;
|
||||||
|
char c=wifi->read();
|
||||||
|
bool gotC = false;
|
||||||
|
int errors = 0;
|
||||||
|
while((!gotC) && (errors < 5000))
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if(c=='0')
|
||||||
|
return '\0';
|
||||||
|
if((c>='0')&&(c<='9'))
|
||||||
|
{
|
||||||
|
chunkSize = (c - '0');
|
||||||
|
state=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((c>='a')&&(c<='f'))
|
||||||
|
{
|
||||||
|
chunkSize = 10 + (c-'a');
|
||||||
|
state=1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
if((c>='0')&&(c<='9'))
|
||||||
|
chunkSize = (chunkSize * 16) + (c - '0');
|
||||||
|
else
|
||||||
|
if((c>='a')&&(c<='f'))
|
||||||
|
chunkSize = (chunkSize * 16) + (c-'a');
|
||||||
|
else
|
||||||
|
if(c=='\r')
|
||||||
|
state=2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if(c == '\n')
|
||||||
|
{
|
||||||
|
state = 3;
|
||||||
|
chunkCount=0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
state = 0;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if(chunkCount < chunkSize)
|
||||||
|
{
|
||||||
|
gotC = true;
|
||||||
|
chunkCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c == '\r')
|
||||||
|
state = 4;
|
||||||
|
else
|
||||||
|
state = 0;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if(c == '\n')
|
||||||
|
state = 0;
|
||||||
|
else
|
||||||
|
state = 0; // what else is there to do?!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while((!gotC) && (errors < 5000))
|
||||||
|
{
|
||||||
|
if(available()>0)
|
||||||
|
{
|
||||||
|
c=wifi->read();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(++errors > 5000)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
virtual int peek()
|
||||||
|
{
|
||||||
|
return wifi->peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int read(uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
if(size == 0)
|
||||||
|
return 0;
|
||||||
|
int num = available();
|
||||||
|
if(num > size)
|
||||||
|
num=size;
|
||||||
|
for(int i=0;i<num;i++)
|
||||||
|
buf[i]=read();
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getNoDelay()
|
||||||
|
{
|
||||||
|
return wifi->getNoDelay();
|
||||||
|
}
|
||||||
|
void setNoDelay(bool nodelay)
|
||||||
|
{
|
||||||
|
wifi->setNoDelay(nodelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int available()
|
||||||
|
{
|
||||||
|
return wifi->available();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void stop()
|
||||||
|
{
|
||||||
|
wifi->stop();
|
||||||
|
}
|
||||||
|
virtual uint8_t connected()
|
||||||
|
{
|
||||||
|
return wifi->connected();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
WiFiClient *doWebGetStream(const char *hostIp, int port, const char *req, bool doSSL, uint32_t *responseSize)
|
||||||
|
{
|
||||||
|
*responseSize = 0;
|
||||||
|
if(WiFi.status() != WL_CONNECTED)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
WiFiClient *c = createWiFiClient(doSSL);
|
||||||
|
if(port == 0)
|
||||||
|
port = 80;
|
||||||
|
if(!c->connect(hostIp, port))
|
||||||
|
{
|
||||||
|
c->stop();
|
||||||
|
delete c;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
c->setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
|
||||||
|
const char *root = "";
|
||||||
|
if(req == NULL)
|
||||||
|
req=root;
|
||||||
|
if(*req == '/')
|
||||||
|
req++;
|
||||||
|
|
||||||
|
c->printf("GET /%s HTTP/1.1\r\n",req);
|
||||||
|
c->printf("User-Agent: Zimodem Firmware\r\n");
|
||||||
|
c->printf("Host: %s\r\n",hostIp);
|
||||||
|
c->printf("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
|
String ln = "";
|
||||||
|
String reUrl = "";
|
||||||
|
uint32_t respLength = 0;
|
||||||
|
int respCode = -1;
|
||||||
|
bool chunked = false;
|
||||||
|
while(c->connected() || (c->available()>0))
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
if(c->available()==0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char ch = (char)c->read();
|
||||||
|
logSocketIn(ch); // this is very much socket input!
|
||||||
|
if(ch == '\r')
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
if(ch == '\n')
|
||||||
|
{
|
||||||
|
if(ln.length()==0)
|
||||||
|
break;
|
||||||
|
if(respCode < 0)
|
||||||
|
{
|
||||||
|
int sp = ln.indexOf(' ');
|
||||||
|
if(sp<=0)
|
||||||
|
break;
|
||||||
|
ln.remove(0,sp+1);
|
||||||
|
sp = ln.indexOf(' ');
|
||||||
|
if(sp<=0)
|
||||||
|
break;
|
||||||
|
ln.remove(sp);
|
||||||
|
respCode = atoi(ln.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int x=ln.indexOf(':');
|
||||||
|
if(x>0)
|
||||||
|
{
|
||||||
|
String header = ln.substring(0,x);
|
||||||
|
header.toLowerCase();
|
||||||
|
if(header == "content-length")
|
||||||
|
{
|
||||||
|
ln.remove(0,16);
|
||||||
|
respLength = atoi(ln.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(header == "location")
|
||||||
|
{
|
||||||
|
reUrl = ln;
|
||||||
|
reUrl.remove(0,10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(header == "transfer-encoding")
|
||||||
|
{
|
||||||
|
ln.toLowerCase();
|
||||||
|
chunked = ln.indexOf("chunked") > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ln = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ln.concat(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((respCode >= 300)
|
||||||
|
&& (respCode <= 399)
|
||||||
|
&& (reUrl.length() > 0)
|
||||||
|
&& (reUrl.length() < 1024))
|
||||||
|
{
|
||||||
|
char newUrlBuf[reUrl.length()+1];
|
||||||
|
strcpy(newUrlBuf,reUrl.c_str());
|
||||||
|
char *hostIp2;
|
||||||
|
char *req2;
|
||||||
|
int port2;
|
||||||
|
bool doSSL2;
|
||||||
|
if(parseWebUrl((uint8_t *)newUrlBuf, &hostIp2,&req2,&port2,&doSSL2))
|
||||||
|
{
|
||||||
|
c->stop();
|
||||||
|
delete c;
|
||||||
|
return doWebGetStream(hostIp2,port2,req2,doSSL2,responseSize);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*responseSize = respLength;
|
||||||
|
if(((!c->connected())&&(c->available()==0))
|
||||||
|
||(respCode != 200)
|
||||||
|
||(respLength <= 0))
|
||||||
|
{
|
||||||
|
c->stop();
|
||||||
|
delete c;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//if(chunked) // technically, if a length was returned, chunked would be ok, but that's not in the cards.
|
||||||
|
// return new ChunkedStream(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doWebGet(const char *hostIp, int port, FS *fs, const char *filename, const char *req, const bool doSSL)
|
||||||
|
{
|
||||||
|
uint32_t respLength=0;
|
||||||
|
WiFiClient *c = doWebGetStream(hostIp, port, req, doSSL, &respLength);
|
||||||
|
if(c==null)
|
||||||
|
return false;
|
||||||
|
uint32_t bytesRead = 0;
|
||||||
|
File f = fs->open(filename, "w");
|
||||||
|
unsigned long now = millis();
|
||||||
|
while((bytesRead < respLength) // this can be removed for chunked encoding support
|
||||||
|
&& (c->connected()||(c->available()>0))
|
||||||
|
&& ((millis()-now)<10000))
|
||||||
|
{
|
||||||
|
if(c->available()>0)
|
||||||
|
{
|
||||||
|
now=millis();
|
||||||
|
uint8_t ch=c->read();
|
||||||
|
logSocketIn(ch); // this is very much socket input!
|
||||||
|
f.write(ch);
|
||||||
|
bytesRead++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
f.flush();
|
||||||
|
f.close();
|
||||||
|
c->stop();
|
||||||
|
delete c;
|
||||||
|
return (respLength == 0) || (bytesRead == respLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doWebGetBytes(const char *hostIp, int port, const char *req, const bool doSSL, uint8_t *buf, int *bufSize)
|
||||||
|
{
|
||||||
|
*bufSize = -1;
|
||||||
|
uint32_t respLength=0;
|
||||||
|
WiFiClient *c = doWebGetStream(hostIp, port, req, doSSL, &respLength);
|
||||||
|
if(c==null)
|
||||||
|
return false;
|
||||||
|
if(((!c->connected())&&(c->available()==0))
|
||||||
|
||(respLength > *bufSize))
|
||||||
|
{
|
||||||
|
c->stop();
|
||||||
|
delete c;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*bufSize = (int)respLength;
|
||||||
|
int index=0;
|
||||||
|
unsigned long now = millis();
|
||||||
|
while((index < respLength) // this can be removed for chunked encoding support
|
||||||
|
&&(c->connected()||(c->available()>0))
|
||||||
|
&& ((millis()-now)<10000))
|
||||||
|
{
|
||||||
|
if(c->available()>0)
|
||||||
|
{
|
||||||
|
uint8_t ch=c->read();
|
||||||
|
now = millis();
|
||||||
|
logSocketIn(ch); // how is this not socket input -- it's coming from a WiFiClient -- that's THE SOCKET!
|
||||||
|
buf[index++] = ch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
*bufSize = index;
|
||||||
|
c->stop();
|
||||||
|
delete c;
|
||||||
|
return (respLength == 0) || (index == respLength);
|
||||||
|
}
|
|
@ -0,0 +1,818 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
/*
|
||||||
|
* K e r m i t File Transfer Utility
|
||||||
|
*
|
||||||
|
* UNIX Kermit, Columbia University, 1981, 1982, 1983
|
||||||
|
* Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
|
||||||
|
*
|
||||||
|
* Also: Jim Guyton, Rand Corporation
|
||||||
|
* Walter Underwood, Ford Aerospace
|
||||||
|
* Lauren Weinstein
|
||||||
|
*
|
||||||
|
* Adapted for Zimodem by Bo Zimmerman
|
||||||
|
*/
|
||||||
|
|
||||||
|
KModem::KModem(FlowControlType commandFlow,
|
||||||
|
int (*recvChar)(ZSerial *ser, int msDelay),
|
||||||
|
void (*sendChar)(ZSerial *ser, char sym),
|
||||||
|
bool (*dataHandler)(File *kfp, unsigned long number, char *buffer, int len),
|
||||||
|
String &errors)
|
||||||
|
{
|
||||||
|
this->errStr = &errors;
|
||||||
|
this->sendChar = sendChar;
|
||||||
|
this->recvChar = recvChar;
|
||||||
|
this->dataHandler = dataHandler;
|
||||||
|
this->kserial.setFlowControlType(FCT_DISABLED);
|
||||||
|
if(commandFlow==FCT_RTSCTS)
|
||||||
|
this->kserial.setFlowControlType(FCT_RTSCTS);
|
||||||
|
this->kserial.setPetsciiMode(false);
|
||||||
|
this->kserial.setXON(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KModem::flushinput()
|
||||||
|
{
|
||||||
|
while(kserial.available()>0)
|
||||||
|
logSerialIn(kserial.read());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KModem::receive()
|
||||||
|
{
|
||||||
|
state = 'R'; /* Receive-Init is the start state */
|
||||||
|
n = 0; /* Initialize message number */
|
||||||
|
numtry = 0; /* Say no tries yet */
|
||||||
|
|
||||||
|
while(TRUE)
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
debugPrintf(" recsw state: %c\n",state);
|
||||||
|
switch(state) /* Do until done */
|
||||||
|
{
|
||||||
|
case 'R':
|
||||||
|
state = rinit();
|
||||||
|
break; /* Receive-Init */
|
||||||
|
case 'F':
|
||||||
|
state = rfile();
|
||||||
|
break; /* Receive-File */
|
||||||
|
case 'D':
|
||||||
|
state = rdata();
|
||||||
|
break; /* Receive-Data */
|
||||||
|
case 'C':
|
||||||
|
kserial.flushAlways();
|
||||||
|
return true; /* Complete state */
|
||||||
|
case 'A':
|
||||||
|
kserial.flushAlways();
|
||||||
|
return false; /* "Abort" state */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool KModem::transmit()
|
||||||
|
{
|
||||||
|
if (gnxtfl() == FALSE) /* No more files go? */
|
||||||
|
{
|
||||||
|
kserial.flushAlways();
|
||||||
|
return false; /* if not, break, EOT, all done */
|
||||||
|
}
|
||||||
|
state = 'S'; /* Send initiate is the start state */
|
||||||
|
n = 0; /* Initialize message number */
|
||||||
|
numtry = 0; /* Say no tries yet */
|
||||||
|
while(ZTRUE) /* Do this as long as necessary */
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
debugPrintf("sendsw state: %c\n",state);
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case 'S':
|
||||||
|
state = sinit();
|
||||||
|
break; /* Send-Init */
|
||||||
|
case 'F':
|
||||||
|
state = sfile();
|
||||||
|
break; /* Send-File */
|
||||||
|
case 'D':
|
||||||
|
state = sdata();
|
||||||
|
break; /* Send-Data */
|
||||||
|
case 'Z':
|
||||||
|
state = seof();
|
||||||
|
break; /* Send-End-of-File */
|
||||||
|
case 'B':
|
||||||
|
state = sbreak();
|
||||||
|
break; /* Send-Break */
|
||||||
|
case 'C':
|
||||||
|
kserial.flushAlways();
|
||||||
|
return true; /* Complete */
|
||||||
|
case 'A':
|
||||||
|
kserial.flushAlways();
|
||||||
|
return false; /* "Abort" */
|
||||||
|
default:
|
||||||
|
kserial.flushAlways();
|
||||||
|
return false; /* Unknown, fail */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* s i n i t
|
||||||
|
*
|
||||||
|
* Send Initiate: send this host's parameters and get other side's back.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char KModem::sinit()
|
||||||
|
{
|
||||||
|
int num, len; /* Packet number, length */
|
||||||
|
|
||||||
|
if (numtry++ > MAXTRY)
|
||||||
|
return('A'); /* If too many tries, give up */
|
||||||
|
spar(packet); /* Fill up init info packet */
|
||||||
|
|
||||||
|
flushinput(); /* Flush pending input */
|
||||||
|
|
||||||
|
spack('S',n,6,packet); /* Send an S packet */
|
||||||
|
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
|
||||||
|
{
|
||||||
|
case 'N':
|
||||||
|
return(state); /* NAK, try it again */
|
||||||
|
|
||||||
|
case 'Y': /* ACK */
|
||||||
|
if (n != num) /* If wrong ACK, stay in S state */
|
||||||
|
return(state); /* and try again */
|
||||||
|
rpar(recpkt); /* Get other side's init info */
|
||||||
|
|
||||||
|
if (eol == 0)
|
||||||
|
eol = '\n'; /* Check and set defaults */
|
||||||
|
if (quote == 0)
|
||||||
|
quote = '#';
|
||||||
|
|
||||||
|
numtry = 0; /* Reset try counter */
|
||||||
|
n = (n+1)%64; /* Bump packet count */
|
||||||
|
return('F'); /* OK, switch state to F */
|
||||||
|
|
||||||
|
case 'E': /* Error packet received */
|
||||||
|
prerrpkt(recpkt); /* Print it out and */
|
||||||
|
return('A'); /* abort */
|
||||||
|
|
||||||
|
case FALSE:
|
||||||
|
return(state); /* Receive failure, try again */
|
||||||
|
|
||||||
|
default:
|
||||||
|
return('A'); /* Anything else, just "abort" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* s f i l e
|
||||||
|
*
|
||||||
|
* Send File Header.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char KModem::sfile()
|
||||||
|
{
|
||||||
|
int num, len; /* Packet number, length */
|
||||||
|
char filnam1[MAX_PATH],/* Converted file name */
|
||||||
|
*newfilnam, /* Pointer to file name to send */
|
||||||
|
*cp; /* char pointer */
|
||||||
|
if (numtry++ > MAXTRY)
|
||||||
|
return('A'); /* If too many tries, give up */
|
||||||
|
|
||||||
|
if (kfpClosed) /* If not already open, */
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
debugPrintf(" Opening %s for sending.\n",filnam);
|
||||||
|
kfp = kfileSystem->open(filnam,"r"); /* open the file to be sent */
|
||||||
|
if (!kfp) /* If bad file pointer, give up */
|
||||||
|
{
|
||||||
|
debugPrintf("Cannot open file %s",filnam);
|
||||||
|
return('A');
|
||||||
|
}
|
||||||
|
kfpClosed=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(filnam1, filnamo); /* Copy file name */
|
||||||
|
newfilnam = cp = filnam1;
|
||||||
|
if (!xflg)
|
||||||
|
while (*cp != '\0') /* Strip off all leading directory */
|
||||||
|
if (*cp++ == '/') /* names (ie. up to the last /). */
|
||||||
|
newfilnam = cp;
|
||||||
|
|
||||||
|
len = strlen(newfilnam); /* Compute length of new filename */
|
||||||
|
|
||||||
|
debugPrintf("Sending %s as %s",filnam,newfilnam);
|
||||||
|
|
||||||
|
spack('F',n,len,newfilnam); /* Send an F packet */
|
||||||
|
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
|
||||||
|
{
|
||||||
|
case 'N': /* NAK, just stay in this state, */
|
||||||
|
num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
|
||||||
|
if (n != num) /* which is just like an ACK for */
|
||||||
|
return(state); /* this packet so fall thru to... */
|
||||||
|
case 'Y': /* ACK */
|
||||||
|
if (n != num)
|
||||||
|
return(state); /* If wrong ACK, stay in F state */
|
||||||
|
numtry = 0; /* Reset try counter */
|
||||||
|
n = (n+1)%64; /* Bump packet count */
|
||||||
|
size = bufill(packet); /* Get first data from file */
|
||||||
|
return('D'); /* Switch state to D */
|
||||||
|
case 'E': /* Error packet received */
|
||||||
|
prerrpkt(recpkt); /* Print it out and */
|
||||||
|
return('A'); /* abort */
|
||||||
|
case FALSE:
|
||||||
|
return(state); /* Receive failure, stay in F state */
|
||||||
|
default:
|
||||||
|
return('A'); /* Something else, just "abort" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* s d a t a
|
||||||
|
*
|
||||||
|
* Send File Data
|
||||||
|
*/
|
||||||
|
|
||||||
|
char KModem::sdata()
|
||||||
|
{
|
||||||
|
int num, len; /* Packet number, length */
|
||||||
|
|
||||||
|
if (numtry++ > MAXTRY)
|
||||||
|
return('A'); /* If too many tries, give up */
|
||||||
|
spack('D',n,size,packet); /* Send a D packet */
|
||||||
|
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
|
||||||
|
{
|
||||||
|
case 'N': /* NAK, just stay in this state, */
|
||||||
|
num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
|
||||||
|
if (n != num) /* which is just like an ACK for */
|
||||||
|
return(state); /* this packet so fall thru to... */
|
||||||
|
case 'Y': /* ACK */
|
||||||
|
if (n != num)
|
||||||
|
return(state); /* If wrong ACK, fail */
|
||||||
|
numtry = 0; /* Reset try counter */
|
||||||
|
n = (n+1)%64; /* Bump packet count */
|
||||||
|
if ((size = bufill(packet)) == EOF) /* Get data from file */
|
||||||
|
return('Z'); /* If EOF set state to that */
|
||||||
|
return('D'); /* Got data, stay in state D */
|
||||||
|
case 'E': /* Error packet received */
|
||||||
|
prerrpkt(recpkt); /* Print it out and */
|
||||||
|
return('A'); /* abort */
|
||||||
|
case FALSE:
|
||||||
|
return(state); /* Receive failure, stay in D */
|
||||||
|
default:
|
||||||
|
return('A'); /* Anything else, "abort" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* s e o f
|
||||||
|
*
|
||||||
|
* Send End-Of-File.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char KModem::seof()
|
||||||
|
{
|
||||||
|
int num, len; /* Packet number, length */
|
||||||
|
if (numtry++ > MAXTRY)
|
||||||
|
return('A'); /* If too many tries, "abort" */
|
||||||
|
|
||||||
|
spack('Z',n,0,packet); /* Send a 'Z' packet */
|
||||||
|
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
|
||||||
|
{
|
||||||
|
case 'N': /* NAK, just stay in this state, */
|
||||||
|
num = (--num<0 ? 63:num); /* unless it's NAK for next packet, */
|
||||||
|
if (n != num) /* which is just like an ACK for */
|
||||||
|
return(state); /* this packet so fall thru to... */
|
||||||
|
case 'Y': /* ACK */
|
||||||
|
if (n != num)
|
||||||
|
return(state); /* If wrong ACK, hold out */
|
||||||
|
numtry = 0; /* Reset try counter */
|
||||||
|
n = (n+1)%64; /* and bump packet count */
|
||||||
|
if (debug)
|
||||||
|
debugPrintf(" Closing input file %s, ",filnam);
|
||||||
|
kfp.close(); /* Close the input file */
|
||||||
|
kfpClosed = true; /* Set flag indicating no file open */
|
||||||
|
if (debug)
|
||||||
|
debugPrintf("looking for next file...\n");
|
||||||
|
if (gnxtfl() == FALSE) /* No more files go? */
|
||||||
|
return('B'); /* if not, break, EOT, all done */
|
||||||
|
if (debug)
|
||||||
|
debugPrintf(" New file is %s\n",filnam);
|
||||||
|
return('F'); /* More files, switch state to F */
|
||||||
|
case 'E': /* Error packet received */
|
||||||
|
prerrpkt(recpkt); /* Print it out and */
|
||||||
|
return('A'); /* abort */
|
||||||
|
case FALSE:
|
||||||
|
return(state); /* Receive failure, stay in Z */
|
||||||
|
default:
|
||||||
|
return('A'); /* Something else, "abort" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* s b r e a k
|
||||||
|
*
|
||||||
|
* Send Break (EOT)
|
||||||
|
*/
|
||||||
|
|
||||||
|
char KModem::sbreak()
|
||||||
|
{
|
||||||
|
int num, len; /* Packet number, length */
|
||||||
|
if (numtry++ > MAXTRY)
|
||||||
|
return('A'); /* If too many tries "abort" */
|
||||||
|
|
||||||
|
spack('B',n,0,packet); /* Send a B packet */
|
||||||
|
switch (rpack(&len,&num,recpkt)) /* What was the reply? */
|
||||||
|
{
|
||||||
|
case 'N': /* NAK, just stay in this state, */
|
||||||
|
num = (--num<0 ? 63:num); /* unless NAK for previous packet, */
|
||||||
|
if (n != num) /* which is just like an ACK for */
|
||||||
|
return(state); /* this packet so fall thru to... */
|
||||||
|
case 'Y': /* ACK */
|
||||||
|
if (n != num)
|
||||||
|
return(state); /* If wrong ACK, fail */
|
||||||
|
numtry = 0; /* Reset try counter */
|
||||||
|
n = (n+1)%64; /* and bump packet count */
|
||||||
|
return('C'); /* Switch state to Complete */
|
||||||
|
case 'E': /* Error packet received */
|
||||||
|
prerrpkt(recpkt); /* Print it out and */
|
||||||
|
return('A'); /* abort */
|
||||||
|
case FALSE:
|
||||||
|
return(state); /* Receive failure, stay in B */
|
||||||
|
default:
|
||||||
|
return ('A'); /* Other, "abort" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r i n i t
|
||||||
|
*
|
||||||
|
* Receive Initialization
|
||||||
|
*/
|
||||||
|
|
||||||
|
char KModem::rinit()
|
||||||
|
{
|
||||||
|
int len, num; /* Packet length, number */
|
||||||
|
|
||||||
|
if (numtry++ > MAXTRY)
|
||||||
|
return('A'); /* If too many tries, "abort" */
|
||||||
|
|
||||||
|
char rs=rpack(&len,&num,packet);
|
||||||
|
if (debug)
|
||||||
|
debugPrintf(" recsw-rinit state: %c\n",rs);
|
||||||
|
switch(rs) /* Get a packet */
|
||||||
|
{
|
||||||
|
case 'S': /* Send-Init */
|
||||||
|
rpar(packet); /* Get the other side's init data */
|
||||||
|
spar(packet); /* Fill up packet with my init info */
|
||||||
|
spack('Y',n,6,packet); /* ACK with my parameters */
|
||||||
|
oldtry = numtry; /* Save old try count */
|
||||||
|
numtry = 0; /* Start a new counter */
|
||||||
|
n = (n+1)%64; /* Bump packet number, mod 64 */
|
||||||
|
return('F'); /* Enter File-Receive state */
|
||||||
|
case 'E': /* Error packet received */
|
||||||
|
prerrpkt(recpkt); /* Print it out and */
|
||||||
|
return('A'); /* abort */
|
||||||
|
case FALSE: /* Didn't get packet */
|
||||||
|
spack('N',n,0,0); /* Return a NAK */
|
||||||
|
return(state); /* Keep trying */
|
||||||
|
default:
|
||||||
|
return('A'); /* Some other packet type, "abort" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r f i l e
|
||||||
|
*
|
||||||
|
* Receive File Header
|
||||||
|
*/
|
||||||
|
|
||||||
|
char KModem::rfile()
|
||||||
|
{
|
||||||
|
int num, len; /* Packet number, length */
|
||||||
|
|
||||||
|
if (numtry++ > MAXTRY)
|
||||||
|
return('A'); /* "abort" if too many tries */
|
||||||
|
|
||||||
|
char rs = rpack(&len,&num,packet);
|
||||||
|
if (debug)
|
||||||
|
debugPrintf(" recsw-rfile state: %c\n",rs);
|
||||||
|
switch(rs) /* Get a packet */
|
||||||
|
{
|
||||||
|
case 'S': /* Send-Init, maybe our ACK lost */
|
||||||
|
if (oldtry++ > MAXTRY)
|
||||||
|
return('A'); /* If too many tries abort */
|
||||||
|
if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
|
||||||
|
{ /* Yes, ACK it again with */
|
||||||
|
spar(packet); /* our Send-Init parameters */
|
||||||
|
spack('Y',num,6,packet);
|
||||||
|
numtry = 0; /* Reset try counter */
|
||||||
|
return(state); /* Stay in this state */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return('A'); /* Not previous packet, "abort" */
|
||||||
|
case 'Z': /* End-Of-File */
|
||||||
|
if (oldtry++ > MAXTRY)
|
||||||
|
return('A');
|
||||||
|
if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
|
||||||
|
{ /* Yes, ACK it again. */
|
||||||
|
spack('Y',num,0,0);
|
||||||
|
numtry = 0;
|
||||||
|
return(state); /* Stay in this state */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return('A'); /* Not previous packet, "abort" */
|
||||||
|
case 'F': /* File Header (just what we want) */
|
||||||
|
if (num != n)
|
||||||
|
return('A'); /* The packet number must be right */
|
||||||
|
{
|
||||||
|
char filnam1[MAX_PATH]; /* Holds the converted file name */
|
||||||
|
char *subNam=filnam1;
|
||||||
|
if(rootpath.length()>0)
|
||||||
|
{
|
||||||
|
strcpy(filnam1, rootpath.c_str());
|
||||||
|
subNam += rootpath.length();
|
||||||
|
if(filnam1[strlen(filnam1)-1]!='/')
|
||||||
|
{
|
||||||
|
filnam1[strlen(filnam1)]='/';
|
||||||
|
filnam1[strlen(filnam1)+1]=0;
|
||||||
|
subNam++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strcpy(subNam, packet); /* Copy the file name */
|
||||||
|
kfp = kfileSystem->open(filnam1,FILE_WRITE);
|
||||||
|
if (!kfp) /* Try to open a new file */
|
||||||
|
{
|
||||||
|
if(errStr != 0)
|
||||||
|
(*errStr) += ("Cannot create %s\n",filnam1); /* Give up if can't */
|
||||||
|
return('A');
|
||||||
|
}
|
||||||
|
else /* OK, give message */
|
||||||
|
{
|
||||||
|
debugPrintf("Receiving %s as %s\n",packet,filnam1);
|
||||||
|
kfpClosed=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spack('Y',n,0,0); /* Acknowledge the file header */
|
||||||
|
oldtry = numtry; /* Reset try counters */
|
||||||
|
numtry = 0; /* ... */
|
||||||
|
n = (n+1)%64; /* Bump packet number, mod 64 */
|
||||||
|
return('D'); /* Switch to Data state */
|
||||||
|
case 'B': /* Break transmission (EOT) */
|
||||||
|
if (num != n)
|
||||||
|
return ('A'); /* Need right packet number here */
|
||||||
|
spack('Y',n,0,0); /* Say OK */
|
||||||
|
return('C'); /* Go to complete state */
|
||||||
|
case 'E': /* Error packet received */
|
||||||
|
prerrpkt(recpkt); /* Print it out and */
|
||||||
|
return('A'); /* abort */
|
||||||
|
case FALSE: /* Didn't get packet */
|
||||||
|
spack('N',n,0,0); /* Return a NAK */
|
||||||
|
return(state); /* Keep trying */
|
||||||
|
default:
|
||||||
|
return ('A'); /* Some other packet, "abort" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r d a t a
|
||||||
|
*
|
||||||
|
* Receive Data
|
||||||
|
*/
|
||||||
|
|
||||||
|
char KModem::rdata()
|
||||||
|
{
|
||||||
|
int num, len; /* Packet number, length */
|
||||||
|
if (numtry++ > MAXTRY)
|
||||||
|
return('A'); /* "abort" if too many tries */
|
||||||
|
|
||||||
|
char rs=rpack(&len,&num,packet);
|
||||||
|
if (debug)
|
||||||
|
debugPrintf(" recsw-rdata state: %c\n",rs);
|
||||||
|
switch(rs) /* Get packet */
|
||||||
|
{
|
||||||
|
case 'D': /* Got Data packet */
|
||||||
|
if (num != n) /* Right packet? */
|
||||||
|
{ /* No */
|
||||||
|
if (oldtry++ > MAXTRY)
|
||||||
|
return('A'); /* If too many tries, abort */
|
||||||
|
if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
|
||||||
|
{ /* Previous packet again? */
|
||||||
|
spack('Y',num,6,packet); /* Yes, re-ACK it */
|
||||||
|
numtry = 0; /* Reset try counter */
|
||||||
|
return(state); /* Don't write out data! */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return('A'); /* sorry, wrong number */
|
||||||
|
}
|
||||||
|
/* Got data with right packet number */
|
||||||
|
bufemp(packet,len); /* Write the data to the file */
|
||||||
|
spack('Y',n,0,0); /* Acknowledge the packet */
|
||||||
|
oldtry = numtry; /* Reset the try counters */
|
||||||
|
numtry = 0; /* ... */
|
||||||
|
n = (n+1)%64; /* Bump packet number, mod 64 */
|
||||||
|
return('D'); /* Remain in data state */
|
||||||
|
case 'F': /* Got a File Header */
|
||||||
|
if (oldtry++ > MAXTRY)
|
||||||
|
return('A'); /* If too many tries, "abort" */
|
||||||
|
if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
|
||||||
|
{ /* It was the previous one */
|
||||||
|
spack('Y',num,0,0); /* ACK it again */
|
||||||
|
numtry = 0; /* Reset try counter */
|
||||||
|
return(state); /* Stay in Data state */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return('A'); /* Not previous packet, "abort" */
|
||||||
|
case 'Z': /* End-Of-File */
|
||||||
|
if (num != n)
|
||||||
|
return('A'); /* Must have right packet number */
|
||||||
|
spack('Y',n,0,0); /* OK, ACK it. */
|
||||||
|
kfp.close(); /* Close the file */
|
||||||
|
kfpClosed=true;
|
||||||
|
n = (n+1)%64; /* Bump packet number */
|
||||||
|
return('F'); /* Go back to Receive File state */
|
||||||
|
case 'E': /* Error packet received */
|
||||||
|
prerrpkt(recpkt); /* Print it out and */
|
||||||
|
return('A'); /* abort */
|
||||||
|
case FALSE: /* Didn't get packet */
|
||||||
|
spack('N',n,0,0); /* Return a NAK */
|
||||||
|
return(state); /* Keep trying */
|
||||||
|
default:
|
||||||
|
return('A'); /* Some other packet, "abort" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* s p a c k
|
||||||
|
*
|
||||||
|
* Send a Packet
|
||||||
|
*/
|
||||||
|
|
||||||
|
int KModem::spack(char type, int num, int len, char *data)
|
||||||
|
{
|
||||||
|
int i; /* Character loop counter */
|
||||||
|
char chksum, buffer[100]; /* Checksum, packet buffer */
|
||||||
|
char *bufp; /* Buffer pointer */
|
||||||
|
|
||||||
|
if (debug>1) /* Display outgoing packet */
|
||||||
|
{
|
||||||
|
if (data != NULL)
|
||||||
|
data[len] = '\0'; /* Null-terminate data to print it */
|
||||||
|
debugPrintf("\n spack type: %c\n",type);
|
||||||
|
debugPrintf(" num: %d\n",num);
|
||||||
|
debugPrintf(" len: %d\n",len);
|
||||||
|
if (data != NULL)
|
||||||
|
debugPrintf(" data: \"%s\"\n",data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bufp = buffer; /* Set up buffer pointer */
|
||||||
|
for (i=1; i<=pad; i++)
|
||||||
|
sendChar(&kserial,padchar); /* Issue any padding */
|
||||||
|
|
||||||
|
*bufp++ = SOH; /* Packet marker, ASCII 1 (SOH) */
|
||||||
|
*bufp++ = (len+3+' '); /* Send the character count */
|
||||||
|
chksum = (len+3+' '); /* Initialize the checksum */
|
||||||
|
*bufp++ = (num+' '); /* Packet number */
|
||||||
|
chksum += (num+' '); /* Update checksum */
|
||||||
|
*bufp++ = type; /* Packet type */
|
||||||
|
chksum += type; /* Update checksum */
|
||||||
|
|
||||||
|
for (i=0; i<len; i++) /* Loop for all data characters */
|
||||||
|
{
|
||||||
|
*bufp++ = data[i]; /* Get a character */
|
||||||
|
chksum += data[i]; /* Update checksum */
|
||||||
|
}
|
||||||
|
chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
|
||||||
|
*bufp++ = (chksum+' '); /* Put it in the packet */
|
||||||
|
if ( mflg )
|
||||||
|
*bufp++ = eol; /* MacKermit needs this */
|
||||||
|
*bufp = eol; /* Extra-packet line terminator */
|
||||||
|
for(i=0;i<bufp-buffer+1;i++) /* Send the packet */
|
||||||
|
sendChar(&kserial,buffer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r p a c k
|
||||||
|
*
|
||||||
|
* Read a Packet
|
||||||
|
*/
|
||||||
|
|
||||||
|
int KModem::rpack(int *len, int *num, char *data)
|
||||||
|
{
|
||||||
|
int i, done; /* Data character number, loop exit */
|
||||||
|
char t, /* Current input character */
|
||||||
|
type, /* Packet type */
|
||||||
|
cchksum, /* Our (computed) checksum */
|
||||||
|
rchksum; /* Checksum received from other host */
|
||||||
|
|
||||||
|
if ((timint > MAXTIM) || (timint < MINTIM))
|
||||||
|
timint = MYTIME;
|
||||||
|
|
||||||
|
while (t != SOH) /* Wait for packet header */
|
||||||
|
{
|
||||||
|
if((t=recvChar(&kserial,timint))<0)
|
||||||
|
return('A');
|
||||||
|
t &= 0177; /* Handle parity */
|
||||||
|
}
|
||||||
|
|
||||||
|
done = FALSE; /* Got SOH, init loop */
|
||||||
|
while (!done) /* Loop to get a packet */
|
||||||
|
{
|
||||||
|
if((t=recvChar(&kserial,timint))<0)
|
||||||
|
return('A');
|
||||||
|
if (!image)
|
||||||
|
t &= 0177; /* Handle parity */
|
||||||
|
if (t == SOH)
|
||||||
|
continue; /* Resynchronize if SOH */
|
||||||
|
cchksum = t; /* Start the checksum */
|
||||||
|
*len = (t-' ')-3; /* Character count */
|
||||||
|
|
||||||
|
if((t=recvChar(&kserial,timint))<0)
|
||||||
|
return('A');
|
||||||
|
if (!image)
|
||||||
|
t &= 0177; /* Handle parity */
|
||||||
|
if (t == SOH)
|
||||||
|
continue; /* Resynchronize if SOH */
|
||||||
|
cchksum = cchksum + t; /* Update checksum */
|
||||||
|
*num = (t-' '); /* Packet number */
|
||||||
|
|
||||||
|
if((t=recvChar(&kserial,timint))<0)
|
||||||
|
return('A');
|
||||||
|
if (!image)
|
||||||
|
t &= 0177; /* Handle parity */
|
||||||
|
if (t == SOH)
|
||||||
|
continue; /* Resynchronize if SOH */
|
||||||
|
cchksum = cchksum + t; /* Update checksum */
|
||||||
|
type = t; /* Packet type */
|
||||||
|
|
||||||
|
for (i=0; i<*len; i++) /* The data itself, if any */
|
||||||
|
{ /* Loop for character count */
|
||||||
|
if((t=recvChar(&kserial,timint))<0)
|
||||||
|
return('A');
|
||||||
|
if (!image)
|
||||||
|
t &= 0177; /* Handle parity */
|
||||||
|
if (t == SOH)
|
||||||
|
continue; /* Resynch if SOH */
|
||||||
|
cchksum = cchksum + t; /* Update checksum */
|
||||||
|
data[i] = t; /* Put it in the data buffer */
|
||||||
|
}
|
||||||
|
data[*len] = 0; /* Mark the end of the data */
|
||||||
|
|
||||||
|
if((t=recvChar(&kserial,timint))<0)
|
||||||
|
return('A');
|
||||||
|
rchksum = (t-' '); /* Convert to numeric */
|
||||||
|
if((t=recvChar(&kserial,timint))<0)
|
||||||
|
return('A');
|
||||||
|
if (!image)
|
||||||
|
t &= 0177; /* Handle parity */
|
||||||
|
if (t == SOH)
|
||||||
|
continue; /* Resynchronize if SOH */
|
||||||
|
done = TRUE; /* Got checksum, done */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug>1) /* Display incoming packet */
|
||||||
|
{
|
||||||
|
if (data != NULL)
|
||||||
|
data[*len] = '\0'; /* Null-terminate data to print it */
|
||||||
|
debugPrintf("\n rpack type: %c\n",type);
|
||||||
|
debugPrintf(" num: %d\n",*num);
|
||||||
|
debugPrintf(" len: %d\n",*len);
|
||||||
|
if (data != NULL)
|
||||||
|
debugPrintf(" data: \"%s\"\n",data);
|
||||||
|
}
|
||||||
|
/* Fold in bits 7,8 to compute */
|
||||||
|
cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
|
||||||
|
|
||||||
|
if (cchksum != rchksum)
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
return(type); /* All OK, return packet type */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* b u f i l l
|
||||||
|
*
|
||||||
|
* Get a bufferful of data from the file that's being sent.
|
||||||
|
* Only control-quoting is done; 8-bit & repeat count prefixes are
|
||||||
|
* not handled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int KModem::bufill(char buffer[])
|
||||||
|
{
|
||||||
|
int i; /* Loop index */
|
||||||
|
char t; /* Char read from file */
|
||||||
|
char t7; /* 7-bit version of above */
|
||||||
|
|
||||||
|
i = 0; /* Init data buffer pointer */
|
||||||
|
while(dataHandler(&kfp,0,&t,1)) /* Get the next character */
|
||||||
|
{
|
||||||
|
t7 = t & 0177; /* Get low order 7 bits */
|
||||||
|
if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
|
||||||
|
{ /* special handling? */
|
||||||
|
if (t=='\n' && !image)
|
||||||
|
{ /* Do LF->CRLF mapping if !image */
|
||||||
|
buffer[i++] = quote;
|
||||||
|
buffer[i++] = '\r' ^ 64;
|
||||||
|
}
|
||||||
|
buffer[i++] = quote; /* Quote the character */
|
||||||
|
if (t7 != quote)
|
||||||
|
{
|
||||||
|
t = (t ^ 64); /* and uncontrolify */
|
||||||
|
t7 = (t7 ^ 64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (image)
|
||||||
|
buffer[i++] = t; /* Deposit the character itself */
|
||||||
|
else
|
||||||
|
buffer[i++] = t7;
|
||||||
|
if (i >= spsiz-8)
|
||||||
|
return(i); /* Check length */
|
||||||
|
}
|
||||||
|
if (i==0)
|
||||||
|
return(EOF); /* Wind up here only on EOF */
|
||||||
|
return(i); /* Handle partial buffer */
|
||||||
|
}
|
||||||
|
|
||||||
|
void KModem::bufemp(char buffer[], int len)
|
||||||
|
{
|
||||||
|
int i; /* Counter */
|
||||||
|
char t; /* Character holder */
|
||||||
|
|
||||||
|
for (i=0; i<len; i++) /* Loop thru the data field */
|
||||||
|
{
|
||||||
|
t = buffer[i]; /* Get character */
|
||||||
|
if (t == MYQUOTE) /* Control quote? */
|
||||||
|
{ /* Yes */
|
||||||
|
t = buffer[++i]; /* Get the quoted character */
|
||||||
|
if ((t & 0177) != MYQUOTE) /* Low order bits match quote char? */
|
||||||
|
t = t ^ 64; /* No, uncontrollify it */
|
||||||
|
}
|
||||||
|
if (t==CR && !image) /* Don't pass CR if in image mode */
|
||||||
|
continue;
|
||||||
|
dataHandler(&kfp,0,&t,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int KModem::gnxtfl()
|
||||||
|
{
|
||||||
|
if (filecount-- == 0)
|
||||||
|
return FALSE; /* If no more, fail */
|
||||||
|
filnam = (char *)filelist[filenum++]->c_str();
|
||||||
|
filnamo = filnam;
|
||||||
|
if (debug)
|
||||||
|
debugPrintf(" gnxtfl: filelist = \"%s\"\n",filnam);
|
||||||
|
return TRUE; /* else succeed */
|
||||||
|
}
|
||||||
|
|
||||||
|
void KModem::spar(char data[])
|
||||||
|
{
|
||||||
|
data[0] = (MAXPACKSIZ + ' '); /* Biggest packet I can receive */
|
||||||
|
data[1] = (MYTIME + ' '); /* When I want to be timed out */
|
||||||
|
data[2] = (MYPAD + ' '); /* How much padding I need */
|
||||||
|
data[3] = (MYPCHAR ^ 64); /* Padding character I want */
|
||||||
|
data[4] = (MYEOL + ' '); /* End-Of-Line character I want */
|
||||||
|
data[5] = MYQUOTE; /* Control-Quote character I send */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KModem::setTransmitList(String **fileList, int numFiles)
|
||||||
|
{
|
||||||
|
filelist = fileList;
|
||||||
|
filecount = numFiles;
|
||||||
|
filenum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* r p a r
|
||||||
|
*
|
||||||
|
* Get the other host's send-init parameters
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void KModem::rpar(char data[])
|
||||||
|
{
|
||||||
|
spsiz = (data[0]- ' '); /* Maximum send packet size */
|
||||||
|
timint = (data[1]- ' '); /* When I should time out */
|
||||||
|
pad = (data[2]- ' '); /* Number of pads to send */
|
||||||
|
padchar = (data[3] ^ 64); /* Padding character to send */
|
||||||
|
eol = (data[4]- ' '); /* EOL character I must send */
|
||||||
|
quote = data[5]; /* Incoming data quote character */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* p r e r r p k t
|
||||||
|
*
|
||||||
|
* Print contents of error packet received from remote host.
|
||||||
|
*/
|
||||||
|
void KModem::prerrpkt(char *msg)
|
||||||
|
{
|
||||||
|
if(errStr != 0)
|
||||||
|
{
|
||||||
|
(*errStr)+=msg;
|
||||||
|
debugPrintf("kermit: %s\n",msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,90 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef INCLUDE_PING
|
||||||
|
/*
|
||||||
|
Copyright 2023-2023 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#include "lwip/netdb.h"
|
||||||
|
#include "lwip/sockets.h"
|
||||||
|
#include "lwip/ip.h"
|
||||||
|
#include "lwip/icmp.h"
|
||||||
|
#include "lwip/inet_chksum.h"
|
||||||
|
#include "lwip/inet.h"
|
||||||
|
|
||||||
|
static int ping(char *host)
|
||||||
|
{
|
||||||
|
IPAddress hostIp((uint32_t)0);
|
||||||
|
if(!WiFiGenericClass::hostByName(host, hostIp)){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int socketfd = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP);
|
||||||
|
if(socketfd < 0)
|
||||||
|
return socketfd;
|
||||||
|
|
||||||
|
const size_t pingpktLen = 10 + sizeof(struct icmp_echo_hdr);
|
||||||
|
struct icmp_echo_hdr *pingpkt = (struct icmp_echo_hdr *)malloc(pingpktLen);
|
||||||
|
ICMPH_TYPE_SET(pingpkt, ICMP_ECHO);
|
||||||
|
ICMPH_CODE_SET(pingpkt, 0);
|
||||||
|
pingpkt->id = 65535;
|
||||||
|
pingpkt->seqno = htons(1);
|
||||||
|
pingpkt->chksum = 0;
|
||||||
|
pingpkt->chksum = inet_chksum(pingpkt, pingpktLen);
|
||||||
|
|
||||||
|
ip4_addr_t outaddr;
|
||||||
|
outaddr.addr = hostIp;
|
||||||
|
|
||||||
|
struct sockaddr_in sockout;
|
||||||
|
sockout.sin_len = sizeof(sockout);
|
||||||
|
sockout.sin_family = AF_INET;
|
||||||
|
inet_addr_from_ip4addr(&sockout.sin_addr, &outaddr);
|
||||||
|
int ok = sendto(socketfd, pingpkt, pingpktLen, 0, (struct sockaddr*)&sockout, sizeof(sockout));
|
||||||
|
free(pingpkt);
|
||||||
|
if (ok == 0)
|
||||||
|
{
|
||||||
|
closesocket(socketfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval timev;
|
||||||
|
timev.tv_sec = 5;
|
||||||
|
timev.tv_usec = 0;
|
||||||
|
if(setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev)) < 0)
|
||||||
|
{
|
||||||
|
closesocket(socketfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t recvBuf[256];
|
||||||
|
struct sockaddr_in inaddr;
|
||||||
|
socklen_t inlen = 0;
|
||||||
|
unsigned long time = millis();
|
||||||
|
|
||||||
|
if(recvfrom(socketfd, recvBuf, 256, 0, (struct sockaddr*)&inaddr, &inlen) > 0)
|
||||||
|
{
|
||||||
|
unsigned long now = millis();
|
||||||
|
if(now > time)
|
||||||
|
time = now - time;
|
||||||
|
else
|
||||||
|
time = now;
|
||||||
|
if(time > 65536)
|
||||||
|
time = 65536;
|
||||||
|
} else {
|
||||||
|
closesocket(socketfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
closesocket(socketfd);
|
||||||
|
return (int)time;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,364 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2018-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
|
||||||
|
XModem::XModem(File &f,
|
||||||
|
FlowControlType commandFlow,
|
||||||
|
int (*recvChar)(ZSerial *ser, int msDelay),
|
||||||
|
void (*sendChar)(ZSerial *ser, char sym),
|
||||||
|
bool (*dataHandler)(File *xfile, unsigned long number, char *buffer, int len))
|
||||||
|
{
|
||||||
|
this->xfile = &f;
|
||||||
|
this->sendChar = sendChar;
|
||||||
|
this->recvChar = recvChar;
|
||||||
|
this->dataHandler = dataHandler;
|
||||||
|
this->xserial.setFlowControlType(FCT_DISABLED);
|
||||||
|
if(commandFlow==FCT_RTSCTS)
|
||||||
|
this->xserial.setFlowControlType(FCT_RTSCTS);
|
||||||
|
this->xserial.setPetsciiMode(false);
|
||||||
|
this->xserial.setXON(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::dataAvail(int delay)
|
||||||
|
{
|
||||||
|
if (this->byte != -1)
|
||||||
|
return true;
|
||||||
|
if ((this->byte = this->recvChar(&xserial,delay)) != -1)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XModem::dataRead(int delay)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
if(this->byte != -1)
|
||||||
|
{
|
||||||
|
b = this->byte;
|
||||||
|
this->byte = -1;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
return this->recvChar(&xserial,delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void XModem::dataWrite(char symbol)
|
||||||
|
{
|
||||||
|
this->sendChar(&xserial,symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::receiveFrameNo()
|
||||||
|
{
|
||||||
|
unsigned char num = (unsigned char)this->dataRead(XModem::receiveDelay);
|
||||||
|
unsigned char invnum = (unsigned char)this-> dataRead(XModem::receiveDelay);
|
||||||
|
this->repeatedBlock = false;
|
||||||
|
//check for repeated block
|
||||||
|
if (invnum == (255-num) && num == this->blockNo-1) {
|
||||||
|
this->repeatedBlock = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num != this-> blockNo || invnum != (255-num))
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::receiveData()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 128; i++) {
|
||||||
|
int byte = this->dataRead(XModem::receiveDelay);
|
||||||
|
if(byte != -1)
|
||||||
|
this->buffer[i] = (unsigned char)byte;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::checkCrc()
|
||||||
|
{
|
||||||
|
unsigned short frame_crc = ((unsigned char)this->dataRead(XModem::receiveDelay)) << 8;
|
||||||
|
|
||||||
|
frame_crc |= (unsigned char)this->dataRead(XModem::receiveDelay);
|
||||||
|
//now calculate crc on data
|
||||||
|
unsigned short crc = this->crc16_ccitt(this->buffer, 128);
|
||||||
|
|
||||||
|
if(frame_crc != crc)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::checkChkSum()
|
||||||
|
{
|
||||||
|
unsigned char frame_chksum = (unsigned char)this->dataRead(XModem::receiveDelay);
|
||||||
|
//calculate chksum
|
||||||
|
unsigned char chksum = 0;
|
||||||
|
for(int i = 0; i< 128; i++) {
|
||||||
|
chksum += this->buffer[i];
|
||||||
|
}
|
||||||
|
if(frame_chksum == chksum)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::sendNack()
|
||||||
|
{
|
||||||
|
this->dataWrite(XModem::XMO_NACK);
|
||||||
|
this->retries++;
|
||||||
|
if(this->retries < XModem::rcvRetryLimit)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::receiveFrames(transfer_t transfer)
|
||||||
|
{
|
||||||
|
this->blockNo = 1;
|
||||||
|
this->blockNoExt = 1;
|
||||||
|
this->retries = 0;
|
||||||
|
while (1) {
|
||||||
|
char cmd = this->dataRead(1000);
|
||||||
|
switch(cmd){
|
||||||
|
case XModem::XMO_SOH:
|
||||||
|
if (!this->receiveFrameNo()) {
|
||||||
|
if (this->sendNack())
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this->receiveData()) {
|
||||||
|
if (this->sendNack())
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if (transfer == Crc) {
|
||||||
|
if (!this->checkCrc()) {
|
||||||
|
if (this->sendNack())
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(!this->checkChkSum()) {
|
||||||
|
if (this->sendNack())
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//callback
|
||||||
|
if(this->dataHandler != NULL && this->repeatedBlock == false)
|
||||||
|
if(!this->dataHandler(xfile,this->blockNoExt, this->buffer, 128)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//ack
|
||||||
|
this->dataWrite(XModem::XMO_ACK);
|
||||||
|
if(this->repeatedBlock == false)
|
||||||
|
{
|
||||||
|
this->blockNo++;
|
||||||
|
this->blockNoExt++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XModem::XMO_EOT:
|
||||||
|
this->dataWrite(XModem::XMO_ACK);
|
||||||
|
return true;
|
||||||
|
case XModem::XMO_CAN:
|
||||||
|
//wait second CAN
|
||||||
|
if(this->dataRead(XModem::receiveDelay) ==XModem::XMO_CAN)
|
||||||
|
{
|
||||||
|
this->dataWrite(XModem::XMO_ACK);
|
||||||
|
//this->flushInput();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//something wrong
|
||||||
|
this->dataWrite(XModem::XMO_CAN);
|
||||||
|
this->dataWrite(XModem::XMO_CAN);
|
||||||
|
this->dataWrite(XModem::XMO_CAN);
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
//something wrong
|
||||||
|
this->dataWrite(XModem::XMO_CAN);
|
||||||
|
this->dataWrite(XModem::XMO_CAN);
|
||||||
|
this->dataWrite(XModem::XMO_CAN);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XModem::init()
|
||||||
|
{
|
||||||
|
//set preread byte
|
||||||
|
this->byte = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::receive()
|
||||||
|
{
|
||||||
|
this->init();
|
||||||
|
|
||||||
|
for (int i =0; i < 16; i++)
|
||||||
|
{
|
||||||
|
this->dataWrite('C');
|
||||||
|
if (this->dataAvail(1500))
|
||||||
|
{
|
||||||
|
bool ok = receiveFrames(Crc);
|
||||||
|
xserial.flushAlways();
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for (int i =0; i < 16; i++)
|
||||||
|
{
|
||||||
|
this->dataWrite(XModem::XMO_NACK);
|
||||||
|
if (this->dataAvail(1500))
|
||||||
|
{
|
||||||
|
bool ok = receiveFrames(ChkSum);
|
||||||
|
xserial.flushAlways();
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short XModem::crc16_ccitt(char *buf, int size)
|
||||||
|
{
|
||||||
|
unsigned short crc = 0;
|
||||||
|
while (--size >= 0) {
|
||||||
|
int i;
|
||||||
|
crc ^= (unsigned short) *buf++ << 8;
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
if (crc & 0x8000)
|
||||||
|
crc = crc << 1 ^ 0x1021;
|
||||||
|
else
|
||||||
|
crc <<= 1;
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char XModem::generateChkSum(void)
|
||||||
|
{
|
||||||
|
//calculate chksum
|
||||||
|
unsigned char chksum = 0;
|
||||||
|
for(int i = 0; i< 128; i++) {
|
||||||
|
chksum += this->buffer[i];
|
||||||
|
}
|
||||||
|
return chksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::transmitFrames(transfer_t transfer)
|
||||||
|
{
|
||||||
|
this->blockNo = 1;
|
||||||
|
this->blockNoExt = 1;
|
||||||
|
// use this only in unit tetsing
|
||||||
|
//memset(this->buffer, 'A', 128);
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
//get data
|
||||||
|
if (this->dataHandler != NULL)
|
||||||
|
{
|
||||||
|
if( false == this->dataHandler(xfile,this->blockNoExt, this->buffer, 128))
|
||||||
|
{
|
||||||
|
//end of transfer
|
||||||
|
this->sendChar(&xserial,XModem::XMO_EOT);
|
||||||
|
//wait ACK
|
||||||
|
if (this->dataRead(XModem::receiveDelay) == XModem::XMO_ACK)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//cancel transfer - send CAN twice
|
||||||
|
this->sendChar(&xserial,XModem::XMO_CAN);
|
||||||
|
this->sendChar(&xserial,XModem::XMO_CAN);
|
||||||
|
//wait ACK
|
||||||
|
if (this->dataRead(XModem::receiveDelay) == XModem::XMO_ACK)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//send SOH
|
||||||
|
this->sendChar(&xserial,XModem::XMO_SOH);
|
||||||
|
//send frame number
|
||||||
|
this->sendChar(&xserial,this->blockNo);
|
||||||
|
//send inv frame number
|
||||||
|
this->sendChar(&xserial,(unsigned char)(255-(this->blockNo)));
|
||||||
|
//send data
|
||||||
|
for(int i = 0; i <128; i++)
|
||||||
|
this->sendChar(&xserial,this->buffer[i]);
|
||||||
|
//send checksum or crc
|
||||||
|
if (transfer == ChkSum) {
|
||||||
|
this->sendChar(&xserial,this->generateChkSum());
|
||||||
|
} else {
|
||||||
|
unsigned short crc;
|
||||||
|
crc = this->crc16_ccitt(this->buffer, 128);
|
||||||
|
|
||||||
|
this->sendChar(&xserial,(unsigned char)(crc >> 8));
|
||||||
|
this->sendChar(&xserial,(unsigned char)(crc));
|
||||||
|
|
||||||
|
}
|
||||||
|
//TO DO - wait NACK or CAN or ACK
|
||||||
|
int ret = this->dataRead(XModem::receiveDelay);
|
||||||
|
switch(ret)
|
||||||
|
{
|
||||||
|
case XModem::XMO_ACK: //data is ok - go to next chunk
|
||||||
|
this->blockNo++;
|
||||||
|
this->blockNoExt++;
|
||||||
|
continue;
|
||||||
|
case XModem::XMO_NACK: //resend data
|
||||||
|
continue;
|
||||||
|
case XModem::XMO_CAN: //abort transmision
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XModem::transmit()
|
||||||
|
{
|
||||||
|
int retry = 0;
|
||||||
|
int sym;
|
||||||
|
this->init();
|
||||||
|
|
||||||
|
//wait for CRC transfer
|
||||||
|
while(retry < 32)
|
||||||
|
{
|
||||||
|
if(this->dataAvail(1000))
|
||||||
|
{
|
||||||
|
sym = this->dataRead(1); //data is here - no delay
|
||||||
|
if(sym == 'C')
|
||||||
|
{
|
||||||
|
bool ok = this->transmitFrames(Crc);
|
||||||
|
xserial.flushAlways();
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
if(sym == XModem::XMO_NACK)
|
||||||
|
{
|
||||||
|
bool ok = this->transmitFrames(ChkSum);
|
||||||
|
xserial.flushAlways();
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retry++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,703 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#include <math.h>
|
||||||
|
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
|
||||||
|
((x)<< 8 & 0x00FF0000UL) | \
|
||||||
|
((x)>> 8 & 0x0000FF00UL) | \
|
||||||
|
((x)>>24 & 0x000000FFUL) )
|
||||||
|
|
||||||
|
const int NTP_PACKET_SIZE = 48;
|
||||||
|
|
||||||
|
uint8_t DAYS_IN_MONTH[13] PROGMEM = {
|
||||||
|
31,28,31,30,31,30,31,31,30,31,30,31
|
||||||
|
};
|
||||||
|
|
||||||
|
char *uintToStr( const uint64_t num, char *str )
|
||||||
|
{
|
||||||
|
uint8_t i = 0;
|
||||||
|
uint64_t n = num;
|
||||||
|
do
|
||||||
|
i++;
|
||||||
|
while ( n /= 10 );
|
||||||
|
str[i] = '\0';
|
||||||
|
n = num;
|
||||||
|
do
|
||||||
|
str[--i] = ( n % 10 ) + '0';
|
||||||
|
while ( n /= 10 );
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTimeClock::DateTimeClock() : DateTimeClock(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DateTimeClock::DateTimeClock(uint32_t epochSecs)
|
||||||
|
{
|
||||||
|
setByUnixEpoch(epochSecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTimeClock::DateTimeClock(int y, int m, int d, int h, int mn, int s, int mi)
|
||||||
|
{
|
||||||
|
year=y;
|
||||||
|
month=m;
|
||||||
|
day=d;
|
||||||
|
hour=h;
|
||||||
|
min=mn;
|
||||||
|
sec=s;
|
||||||
|
milsec=mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
RealTimeClock::RealTimeClock(uint32_t epochSecs) : DateTimeClock(epochSecs)
|
||||||
|
{
|
||||||
|
lastMillis = millis();
|
||||||
|
nextNTPMillis = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
RealTimeClock::RealTimeClock() : DateTimeClock()
|
||||||
|
{
|
||||||
|
lastMillis = millis();
|
||||||
|
nextNTPMillis = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
RealTimeClock::RealTimeClock(int y, int m, int d, int h, int mn, int s, int mi) :
|
||||||
|
DateTimeClock(y,m,d,h,mn,s,mi)
|
||||||
|
{
|
||||||
|
lastMillis = millis();
|
||||||
|
nextNTPMillis = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealTimeClock::startUdp()
|
||||||
|
{
|
||||||
|
if(!udpStarted)
|
||||||
|
{
|
||||||
|
udpStarted=udp.begin(2390);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealTimeClock::tick()
|
||||||
|
{
|
||||||
|
if(disabled)
|
||||||
|
return;
|
||||||
|
if(udpStarted)
|
||||||
|
{
|
||||||
|
int cb = udp.parsePacket();
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
// adapted from code by by Michael Margolis, Tom Igoe, and Ivan Grokhotkov
|
||||||
|
//debugPrint("Packet received, length=%d\n\r",cb);
|
||||||
|
byte packetBuffer[ NTP_PACKET_SIZE];
|
||||||
|
udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
|
||||||
|
// combine the four bytes (two words) into a long integer
|
||||||
|
// this is NTP time (seconds since Jan 1 1900):
|
||||||
|
uint32_t secsSince1900 = htonl(*((uint32_t *)(packetBuffer + 40)));
|
||||||
|
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
|
||||||
|
const uint32_t seventyYears = 2208988800UL;
|
||||||
|
// subtract seventy years:
|
||||||
|
uint32_t epoch = secsSince1900 - seventyYears;
|
||||||
|
lastMillis = millis();
|
||||||
|
// now to apply the timezone. Ugh;
|
||||||
|
setByUnixEpoch(epoch);
|
||||||
|
String tz="";
|
||||||
|
{
|
||||||
|
char s=0;
|
||||||
|
char c=pgm_read_byte_near(&(TimeZones[tzCode][1][s]));
|
||||||
|
while(c != 0)
|
||||||
|
{
|
||||||
|
tz += c;
|
||||||
|
c=pgm_read_byte_near(&(TimeZones[tzCode][1][++s]));
|
||||||
|
}
|
||||||
|
String otz=tz;
|
||||||
|
int x=tz.indexOf("/");
|
||||||
|
if(x > 0)
|
||||||
|
{
|
||||||
|
if(isInStandardTime())
|
||||||
|
tz = tz.substring(0,x);
|
||||||
|
else
|
||||||
|
tz = tz.substring(x+1);
|
||||||
|
}
|
||||||
|
x=tz.indexOf(":");
|
||||||
|
int mm=0;
|
||||||
|
if(x > 0)
|
||||||
|
{
|
||||||
|
mm = atoi(tz.substring(x+1).c_str());
|
||||||
|
tz = tz.substring(0,x);
|
||||||
|
}
|
||||||
|
uint32_t echg = (atoi(tz.c_str()) * 3600);
|
||||||
|
echg += ((echg < 0)?(-(mm * 60)):(mm * 60));
|
||||||
|
setByUnixEpoch(epoch + echg);
|
||||||
|
debugPrintf("Received NTP: %d/%d/%d %d:%d:%d\n\r",(int)getMonth(),(int)getDay(),(int)getYear(),(int)getHour(),(int)getMinute(),(int)getSecond());
|
||||||
|
}
|
||||||
|
nextNTPMillis = millis() + ntpPeriodLongMillis; // one hour
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t now=millis();
|
||||||
|
if(nextNTPMillis >= now)
|
||||||
|
{
|
||||||
|
if(((nextNTPMillis - now) > ntpPeriodLongMillis)
|
||||||
|
||(nextNTPMillis == now))
|
||||||
|
forceUpdate();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((now - nextNTPMillis) > ntpPeriodLongMillis)
|
||||||
|
forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealTimeClock::forceUpdate()
|
||||||
|
{
|
||||||
|
if(!disabled)
|
||||||
|
{
|
||||||
|
nextNTPMillis = millis() + ntpPeriodMillis;
|
||||||
|
startUdp();
|
||||||
|
sendTimeRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealTimeClock::isTimeSet()
|
||||||
|
{
|
||||||
|
return (year > 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealTimeClock::reset()
|
||||||
|
{
|
||||||
|
year=0;
|
||||||
|
month=0;
|
||||||
|
day=0;
|
||||||
|
hour=0;
|
||||||
|
min=0;
|
||||||
|
sec=0;
|
||||||
|
milsec=0;
|
||||||
|
lastMillis = millis();
|
||||||
|
nextNTPMillis = millis();
|
||||||
|
tzCode = 0;
|
||||||
|
format="%M/%d/%yyyy %h:%mm:%ss%aa %z";
|
||||||
|
ntpServerName = "time.nist.gov";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DateTimeClock::getYear()
|
||||||
|
{
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::setYear(int y)
|
||||||
|
{
|
||||||
|
year=y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::addYear(uint32_t y)
|
||||||
|
{
|
||||||
|
year+=y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DateTimeClock::getMonth()
|
||||||
|
{
|
||||||
|
return month + 1; // because 0 based
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::setMonth(int m)
|
||||||
|
{
|
||||||
|
month = m % 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::addMonth(uint32_t m)
|
||||||
|
{
|
||||||
|
m = month + m;
|
||||||
|
if(m > 11)
|
||||||
|
addYear(floor(m / 12));
|
||||||
|
setMonth(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DateTimeClock::getDay()
|
||||||
|
{
|
||||||
|
return day + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::setDay(int d)
|
||||||
|
{
|
||||||
|
day = d % getDaysInThisMonth();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::addDay(uint32_t d)
|
||||||
|
{
|
||||||
|
d = day + d;
|
||||||
|
if(d >= getDaysInThisMonth())
|
||||||
|
{
|
||||||
|
while(d > (isLeapYear()?366:365))
|
||||||
|
{
|
||||||
|
d=d-(isLeapYear()?366:365);
|
||||||
|
addYear(1);
|
||||||
|
}
|
||||||
|
while(d >= getDaysInThisMonth())
|
||||||
|
{
|
||||||
|
d=d-getDaysInThisMonth();
|
||||||
|
addMonth(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setDay(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DateTimeClock::getHour()
|
||||||
|
{
|
||||||
|
return hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::setHour(int h)
|
||||||
|
{
|
||||||
|
hour=h % 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::addHour(uint32_t h)
|
||||||
|
{
|
||||||
|
h=hour + h;
|
||||||
|
if(h > 23)
|
||||||
|
addDay(floor(h / 24));
|
||||||
|
setHour(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DateTimeClock::getMinute()
|
||||||
|
{
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::setMinute(int mm)
|
||||||
|
{
|
||||||
|
min=mm % 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::addMinute(uint32_t mm)
|
||||||
|
{
|
||||||
|
mm = min+mm;
|
||||||
|
if(mm > 59)
|
||||||
|
addHour(floor(mm / 60));
|
||||||
|
setMinute(mm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DateTimeClock::getSecond()
|
||||||
|
{
|
||||||
|
return sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::setSecond(int s)
|
||||||
|
{
|
||||||
|
sec=s % 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::addSecond(uint32_t s)
|
||||||
|
{
|
||||||
|
s = sec + s;
|
||||||
|
if(s > 59)
|
||||||
|
addMinute(floor(s / 60));
|
||||||
|
setSecond(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DateTimeClock::getMillis()
|
||||||
|
{
|
||||||
|
return milsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::setMillis(int s)
|
||||||
|
{
|
||||||
|
milsec=s % 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::addMillis(uint64_t s)
|
||||||
|
{
|
||||||
|
s = milsec+s;
|
||||||
|
if(s > 999)
|
||||||
|
addSecond(floor(s / 1000));
|
||||||
|
setMillis(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DateTimeClock::isLeapYear()
|
||||||
|
{
|
||||||
|
if(year % 4 == 0)
|
||||||
|
{
|
||||||
|
if(year % 100 == 0)
|
||||||
|
{
|
||||||
|
if(year % 400 == 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DateTimeClock::getDaysInThisMonth()
|
||||||
|
{
|
||||||
|
if(month != 1) // feb exception
|
||||||
|
return pgm_read_byte_near(DAYS_IN_MONTH + month);
|
||||||
|
return (isLeapYear() ? 29 : 28);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeClock::setTime(DateTimeClock &clock)
|
||||||
|
{
|
||||||
|
year=clock.year;
|
||||||
|
month=clock.month;
|
||||||
|
day=clock.day;
|
||||||
|
hour=clock.hour;
|
||||||
|
min=clock.min;
|
||||||
|
sec=clock.sec;
|
||||||
|
milsec=clock.milsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DateTimeClock &RealTimeClock::getCurrentTime()
|
||||||
|
{
|
||||||
|
adjClock.setTime(*this);
|
||||||
|
uint32_t now=millis();
|
||||||
|
if(lastMillis <= now)
|
||||||
|
adjClock.addMillis(now - lastMillis);
|
||||||
|
else
|
||||||
|
adjClock.addMillis(now + (0xffffffff - lastMillis));
|
||||||
|
return adjClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DateTimeClock::setByUnixEpoch(uint32_t unisex)
|
||||||
|
{
|
||||||
|
setYear(1970);
|
||||||
|
setMonth(0);
|
||||||
|
setDay(0);
|
||||||
|
setHour(0);
|
||||||
|
setMinute(0);
|
||||||
|
setSecond(0);
|
||||||
|
setMillis(0);
|
||||||
|
uint64_t ms = unisex;
|
||||||
|
ms *= 1000L;
|
||||||
|
addMillis(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DateTimeClock::getUnixEpoch()
|
||||||
|
{
|
||||||
|
if(year < 1970)
|
||||||
|
return 0;
|
||||||
|
uint32_t val = sec + (min * 60) + (hour * 60 * 60);
|
||||||
|
//TODO:
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealTimeClock::sendTimeRequest()
|
||||||
|
{
|
||||||
|
if((WiFi.status() == WL_CONNECTED)&&(udpStarted))
|
||||||
|
{
|
||||||
|
// adapted from code by by Michael Margolis, Tom Igoe, and Ivan Grokhotkov
|
||||||
|
debugPrintf("Sending NTP Packet...");
|
||||||
|
byte packetBuffer[ NTP_PACKET_SIZE];
|
||||||
|
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
||||||
|
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||||
|
packetBuffer[1] = 0; // Stratum, or type of clock
|
||||||
|
packetBuffer[2] = 6; // Polling Interval
|
||||||
|
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||||
|
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||||
|
packetBuffer[12] = 49;
|
||||||
|
packetBuffer[13] = 0x4E;
|
||||||
|
packetBuffer[14] = 49;
|
||||||
|
packetBuffer[15] = 52;
|
||||||
|
IPAddress timeServerIP;
|
||||||
|
String host = ntpServerName;
|
||||||
|
int port=123;
|
||||||
|
int pi=host.indexOf(':');
|
||||||
|
if(pi>0)
|
||||||
|
{
|
||||||
|
port=atoi(host.substring(pi+1).c_str());
|
||||||
|
host = host.substring(0,pi);
|
||||||
|
}
|
||||||
|
WiFi.hostByName(ntpServerName.c_str(), timeServerIP);
|
||||||
|
udp.beginPacket(timeServerIP, port); //NTP requests are to port 123
|
||||||
|
udp.write(packetBuffer, NTP_PACKET_SIZE);
|
||||||
|
udp.endPacket();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DateTimeClock::getDoWNumber()
|
||||||
|
{
|
||||||
|
uint16_t x= (getMonth() + 9) % 12;
|
||||||
|
uint16_t y = getYear() - x/10;
|
||||||
|
uint32_t z= 365*y + y/4 - y/100 + y/400 + (x*306 + 5)/10 + (getDay() - 1);
|
||||||
|
z=z%7;
|
||||||
|
if(z>3)
|
||||||
|
return z-4;
|
||||||
|
else
|
||||||
|
return z+3;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *DateTimeClock::getDoW()
|
||||||
|
{
|
||||||
|
int num=getDoWNumber();
|
||||||
|
switch(num)
|
||||||
|
{
|
||||||
|
case 0:return "Sunday";
|
||||||
|
case 1:return "Monday";
|
||||||
|
case 2:return "Tuesday";
|
||||||
|
case 3:return "Wednesday";
|
||||||
|
case 4:return "Thursday";
|
||||||
|
case 5:return "Friday";
|
||||||
|
case 6:return "Saturday";
|
||||||
|
default: return "Broken";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DateTimeClock::isInStandardTime()
|
||||||
|
{
|
||||||
|
uint8_t m=getMonth();
|
||||||
|
if(m<3)
|
||||||
|
return true;
|
||||||
|
if(m==3)
|
||||||
|
{
|
||||||
|
uint8_t d=getDay();
|
||||||
|
uint8_t dow=getDoWNumber();
|
||||||
|
while(dow-- > 0)
|
||||||
|
d--;
|
||||||
|
if(d<14)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if((m>3)&&(m<11))
|
||||||
|
return false;
|
||||||
|
if(m==11)
|
||||||
|
{
|
||||||
|
uint8_t d=getDay();
|
||||||
|
uint8_t dow=getDoWNumber();
|
||||||
|
while(dow-- > 0)
|
||||||
|
d--;
|
||||||
|
if(d<7)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DateTimeClock::isInDaylightSavingsTime()
|
||||||
|
{
|
||||||
|
return !isInStandardTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
int RealTimeClock::getTimeZoneCode()
|
||||||
|
{
|
||||||
|
return tzCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealTimeClock::setTimeZoneCode(int val)
|
||||||
|
{
|
||||||
|
if((tzCode >= 0)&&(tzCode < 243))
|
||||||
|
{
|
||||||
|
tzCode = val;
|
||||||
|
forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealTimeClock::setTimeZone(String str)
|
||||||
|
{
|
||||||
|
str.toUpperCase();
|
||||||
|
if(str.length()==0)
|
||||||
|
return false;
|
||||||
|
for(int i=0;i<243;i++)
|
||||||
|
{
|
||||||
|
for(int s=0;s<=str.length();s++)
|
||||||
|
{
|
||||||
|
char c=pgm_read_byte_near(&(TimeZones[i][0][s]));
|
||||||
|
if(s==str.length())
|
||||||
|
{
|
||||||
|
if(c==0)
|
||||||
|
{
|
||||||
|
tzCode = i;
|
||||||
|
forceUpdate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((c==0)||(c != str[s]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String RealTimeClock::getFormat()
|
||||||
|
{
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealTimeClock::setFormat(String fmt)
|
||||||
|
{
|
||||||
|
fmt.replace(',','.');
|
||||||
|
format = fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealTimeClock::isDisabled()
|
||||||
|
{
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealTimeClock::setDisabled(bool tf)
|
||||||
|
{
|
||||||
|
disabled=tf;
|
||||||
|
}
|
||||||
|
|
||||||
|
String RealTimeClock::getCurrentTimeFormatted()
|
||||||
|
{
|
||||||
|
//String format="%M/%D/%YYYY %h:%mm:%ss%a"
|
||||||
|
DateTimeClock c = getCurrentTime();
|
||||||
|
String f=format;
|
||||||
|
if(f.indexOf("%yyyy")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%04d",(int)c.getYear());
|
||||||
|
f.replace("%yyyy",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%yy")>=0)
|
||||||
|
{
|
||||||
|
int y=c.getYear();
|
||||||
|
y -= (floor(y/100)*100);
|
||||||
|
sprintf(str,"%02d",y);
|
||||||
|
f.replace("%yy",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%y")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%d",(int)c.getYear());
|
||||||
|
f.replace("%y",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%MM")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%02d",(int)c.getMonth());
|
||||||
|
f.replace("%MM",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%M")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%d",(int)c.getMonth());
|
||||||
|
f.replace("%M",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%dd")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%02d",(int)c.getDay());
|
||||||
|
f.replace("%dd",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%d")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%d",(int)c.getDay());
|
||||||
|
f.replace("%d",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%ee")>=0)
|
||||||
|
{
|
||||||
|
f.replace("%ee",c.getDoW());
|
||||||
|
}
|
||||||
|
if(f.indexOf("%e")>=0)
|
||||||
|
{
|
||||||
|
String dow=c.getDoW();
|
||||||
|
dow = dow.substring(0,3);
|
||||||
|
sprintf(str,"%d",dow.c_str());
|
||||||
|
f.replace("%e",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%HH")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%02d",(int)c.getHour());
|
||||||
|
f.replace("%HH",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%H")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%d",(int)c.getHour());
|
||||||
|
f.replace("%H",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%hh")>=0)
|
||||||
|
{
|
||||||
|
if((c.getHour()%12)==0)
|
||||||
|
strcpy(str,"12");
|
||||||
|
else
|
||||||
|
sprintf(str,"%02d",c.getHour()%12);
|
||||||
|
f.replace("%hh",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%h")>=0)
|
||||||
|
{
|
||||||
|
if((c.getHour()%12)==0)
|
||||||
|
strcpy(str,"12");
|
||||||
|
else
|
||||||
|
sprintf(str,"%d",(int)(c.getHour() % 12));
|
||||||
|
f.replace("%h",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%mm")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%02d",(int)c.getMinute());
|
||||||
|
f.replace("%mm",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%m")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%d",(int)c.getMinute());
|
||||||
|
f.replace("%m",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%ss")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%02d",(int)c.getSecond());
|
||||||
|
f.replace("%ss",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%s")>=0)
|
||||||
|
{
|
||||||
|
sprintf(str,"%d",(int)c.getSecond());
|
||||||
|
f.replace("%s",str);
|
||||||
|
}
|
||||||
|
if(f.indexOf("%AA")>=0)
|
||||||
|
f.replace("%AA",(c.getHour()<12)?"AM":"PM");
|
||||||
|
if(f.indexOf("%aa")>=0)
|
||||||
|
f.replace("%aa",(c.getHour()<12)?"am":"pm");
|
||||||
|
if(f.indexOf("%A")>=0)
|
||||||
|
f.replace("%A",(c.getHour()<12)?"A":"P");
|
||||||
|
if(f.indexOf("%a")>=0)
|
||||||
|
f.replace("%a",(c.getHour()<12)?"a":"p");
|
||||||
|
if(f.indexOf("%z")>=0)
|
||||||
|
{
|
||||||
|
String z="";
|
||||||
|
char s=0;
|
||||||
|
char c=pgm_read_byte_near(&(TimeZones[tzCode][0][s]));
|
||||||
|
while(c != 0)
|
||||||
|
{
|
||||||
|
z += c;
|
||||||
|
c=pgm_read_byte_near(&(TimeZones[tzCode][0][++s]));
|
||||||
|
}
|
||||||
|
z.toLowerCase();
|
||||||
|
f.replace("%z",z.c_str());
|
||||||
|
}
|
||||||
|
if(f.indexOf("%Z")>=0)
|
||||||
|
{
|
||||||
|
String z="";
|
||||||
|
char s=0;
|
||||||
|
char c=pgm_read_byte_near(&(TimeZones[tzCode][0][s]));
|
||||||
|
while(c != 0)
|
||||||
|
{
|
||||||
|
z += c;
|
||||||
|
c=pgm_read_byte_near(&(TimeZones[tzCode][0][++s]));
|
||||||
|
}
|
||||||
|
f.replace("%Z",z.c_str());
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
String RealTimeClock::getNtpServerHost()
|
||||||
|
{
|
||||||
|
return ntpServerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealTimeClock::setNtpServerHost(String newHost)
|
||||||
|
{
|
||||||
|
newHost.replace(',','.');
|
||||||
|
ntpServerName = newHost;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,455 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
static void serialDirectWrite(uint8_t c)
|
||||||
|
{
|
||||||
|
HWSerial.write(c);
|
||||||
|
if(serialDelayMs > 0)
|
||||||
|
delay(serialDelayMs);
|
||||||
|
logSerialOut(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hwSerialFlush()
|
||||||
|
{
|
||||||
|
#ifdef ZIMODEM_ESP8266
|
||||||
|
HWSerial.flush();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serialOutDeque()
|
||||||
|
{
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
while((TBUFhead != TBUFtail)
|
||||||
|
&&((SER_BUFSIZE - HWSerial.availableForWrite())<dequeSize))
|
||||||
|
#else
|
||||||
|
if((TBUFhead != TBUFtail)
|
||||||
|
&&(HWSerial.availableForWrite()>=SER_BUFSIZE)) // necessary for esp8266 flow control
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
serialDirectWrite(TBUF[TBUFhead]);
|
||||||
|
TBUFhead++;
|
||||||
|
if(TBUFhead >= SER_WRITE_BUFSIZE)
|
||||||
|
TBUFhead = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serialOutBufferBytesRemaining()
|
||||||
|
{
|
||||||
|
if(TBUFtail == TBUFhead)
|
||||||
|
return SER_WRITE_BUFSIZE-1;
|
||||||
|
else
|
||||||
|
if(TBUFtail > TBUFhead)
|
||||||
|
{
|
||||||
|
int used = TBUFtail - TBUFhead;
|
||||||
|
return SER_WRITE_BUFSIZE - used -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return TBUFhead - TBUFtail - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enqueSerialOut(uint8_t c)
|
||||||
|
{
|
||||||
|
TBUF[TBUFtail] = c;
|
||||||
|
TBUFtail++;
|
||||||
|
if(TBUFtail >= SER_WRITE_BUFSIZE)
|
||||||
|
TBUFtail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clearSerialOutBuffer()
|
||||||
|
{
|
||||||
|
TBUFtail=TBUFhead;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ensureSerialBytes(int num)
|
||||||
|
{
|
||||||
|
if(serialOutBufferBytesRemaining()<1)
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
while(serialOutBufferBytesRemaining()<1)
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flushSerial()
|
||||||
|
{
|
||||||
|
while(TBUFtail != TBUFhead)
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
hwSerialFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSerial::ZSerial()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::setPetsciiMode(bool petscii)
|
||||||
|
{
|
||||||
|
petsciiMode = petscii;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZSerial::isPetsciiMode()
|
||||||
|
{
|
||||||
|
return petsciiMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::setFlowControlType(FlowControlType type)
|
||||||
|
{
|
||||||
|
flowControlType = type;
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
if(flowControlType == FCT_RTSCTS)
|
||||||
|
{
|
||||||
|
uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_DISABLE,0);
|
||||||
|
uint32_t invertMask = 0;
|
||||||
|
if(pinSupport[pinCTS])
|
||||||
|
{
|
||||||
|
uart_set_pin(UART_NUM_2, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, /*cts_io_num*/pinCTS);
|
||||||
|
// cts is input to me, output to true RS232
|
||||||
|
if(ctsActive == HIGH)
|
||||||
|
# ifdef UART_INVERSE_CTS
|
||||||
|
invertMask = invertMask | UART_INVERSE_CTS;
|
||||||
|
# else
|
||||||
|
invertMask = invertMask | UART_SIGNAL_CTS_INV;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
if(pinSupport[pinRTS])
|
||||||
|
{
|
||||||
|
uart_set_pin(UART_NUM_2, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, /*rts_io_num*/ pinRTS, UART_PIN_NO_CHANGE);
|
||||||
|
s_pinWrite(pinRTS, rtsActive);
|
||||||
|
// rts is output to me, input to true RS232
|
||||||
|
if(rtsActive == HIGH)
|
||||||
|
# ifdef UART_INVERSE_RTS
|
||||||
|
invertMask = invertMask | UART_INVERSE_RTS;
|
||||||
|
# else
|
||||||
|
invertMask = invertMask | UART_SIGNAL_RTS_INV;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
//debugPrintf("invert = %d magic values = %d %d, RTS_HIGH=%d, RTS_LOW=%d HIGHHIGH=%d LOWLOW=%d\n",invertMask,ctsActive,rtsActive, DEFAULT_RTS_HIGH, DEFAULT_RTS_LOW, HIGH, LOW);
|
||||||
|
if(invertMask != 0)
|
||||||
|
uart_set_line_inverse(UART_NUM_2, invertMask);
|
||||||
|
const int CUTOFF = 100;
|
||||||
|
if(pinSupport[pinRTS])
|
||||||
|
{
|
||||||
|
if(pinSupport[pinCTS])
|
||||||
|
uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_CTS_RTS,CUTOFF);
|
||||||
|
else
|
||||||
|
uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_CTS_RTS,CUTOFF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(pinSupport[pinCTS])
|
||||||
|
uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_CTS_RTS,CUTOFF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_DISABLE,0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowControlType ZSerial::getFlowControlType()
|
||||||
|
{
|
||||||
|
return flowControlType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::setXON(bool isXON)
|
||||||
|
{
|
||||||
|
XON_STATE = isXON;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ZSerial::getConfigFlagBitmap()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(isPetsciiMode()?FLAG_PETSCII:0)
|
||||||
|
|((getFlowControlType()==FCT_RTSCTS)?FLAG_RTSCTS:0)
|
||||||
|
|((getFlowControlType()==FCT_NORMAL)?FLAG_XONXOFF:0)
|
||||||
|
|((getFlowControlType()==FCT_AUTOOFF)?FLAG_XONXOFF:0)
|
||||||
|
|((getFlowControlType()==FCT_MANUAL)?FLAG_XONXOFF:0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZSerial::isXON()
|
||||||
|
{
|
||||||
|
return XON_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZSerial::isSerialOut()
|
||||||
|
{
|
||||||
|
switch(flowControlType)
|
||||||
|
{
|
||||||
|
case FCT_RTSCTS:
|
||||||
|
if(pinSupport[pinCTS])
|
||||||
|
{
|
||||||
|
//debugPrintf("CTS: pin %d (%d == %d)\n",pinCTS,digitalRead(pinCTS),ctsActive);
|
||||||
|
return (digitalRead(pinCTS) == ctsActive);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case FCT_NORMAL:
|
||||||
|
case FCT_AUTOOFF:
|
||||||
|
case FCT_MANUAL:
|
||||||
|
break;
|
||||||
|
case FCT_DISABLED:
|
||||||
|
return true;
|
||||||
|
case FCT_INVALID:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return XON_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZSerial::isSerialCancelled()
|
||||||
|
{
|
||||||
|
if(flowControlType == FCT_RTSCTS)
|
||||||
|
{
|
||||||
|
if(pinSupport[pinCTS])
|
||||||
|
{
|
||||||
|
//debugPrintf("CTS: pin %d (%d == %d)\n",pinCTS,digitalRead(pinCTS),ctsActive);
|
||||||
|
return (digitalRead(pinCTS) == ctsInactive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZSerial::isSerialHalted()
|
||||||
|
{
|
||||||
|
return !isSerialOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::enqueByte(uint8_t c)
|
||||||
|
{
|
||||||
|
if(TBUFtail == TBUFhead)
|
||||||
|
{
|
||||||
|
switch(flowControlType)
|
||||||
|
{
|
||||||
|
case FCT_DISABLED:
|
||||||
|
case FCT_INVALID:
|
||||||
|
#ifndef ZIMODEM_ESP32
|
||||||
|
if((HWSerial.availableForWrite() > 0)
|
||||||
|
&&(HWSerial.available() == 0))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
serialDirectWrite(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FCT_RTSCTS:
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
if(isSerialOut())
|
||||||
|
#else
|
||||||
|
if((HWSerial.availableForWrite() >= SER_BUFSIZE) // necessary for esp8266 flow control
|
||||||
|
&&(isSerialOut()))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
serialDirectWrite(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FCT_NORMAL:
|
||||||
|
case FCT_AUTOOFF:
|
||||||
|
case FCT_MANUAL:
|
||||||
|
if((HWSerial.availableForWrite() >= SER_BUFSIZE)
|
||||||
|
&&(HWSerial.available() == 0)
|
||||||
|
&&(XON_STATE))
|
||||||
|
{
|
||||||
|
serialDirectWrite(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the car jam of blocked bytes stops HERE
|
||||||
|
//debugPrintf("%d\n",serialOutBufferBytesRemaining());
|
||||||
|
while(serialOutBufferBytesRemaining()<1)
|
||||||
|
{
|
||||||
|
if(!isSerialOut())
|
||||||
|
delay(1);
|
||||||
|
else
|
||||||
|
serialOutDeque();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
enqueSerialOut(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::prints(const char *expr)
|
||||||
|
{
|
||||||
|
if(!petsciiMode)
|
||||||
|
{
|
||||||
|
for(int i=0;expr[i]!=0;i++)
|
||||||
|
{
|
||||||
|
enqueByte(expr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(int i=0;expr[i]!=0;i++)
|
||||||
|
{
|
||||||
|
enqueByte(ascToPetcii(expr[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::printi(int i)
|
||||||
|
{
|
||||||
|
char buf[12];
|
||||||
|
prints(itoa(i, buf, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::printd(double f)
|
||||||
|
{
|
||||||
|
char buf[12];
|
||||||
|
prints(dtostrf(f, 2, 2, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::printc(const char c)
|
||||||
|
{
|
||||||
|
if(!petsciiMode)
|
||||||
|
enqueByte(c);
|
||||||
|
else
|
||||||
|
enqueByte(ascToPetcii(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::printc(uint8_t c)
|
||||||
|
{
|
||||||
|
if(!petsciiMode)
|
||||||
|
enqueByte(c);
|
||||||
|
else
|
||||||
|
enqueByte(ascToPetcii(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::printb(uint8_t c)
|
||||||
|
{
|
||||||
|
enqueByte(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSerial::write(uint8_t c)
|
||||||
|
{
|
||||||
|
enqueByte(c);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSerial::write(uint8_t *buf, int bufSz)
|
||||||
|
{
|
||||||
|
for(int i=0;i<bufSz;i++)
|
||||||
|
enqueByte(buf[i]);
|
||||||
|
return bufSz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::prints(String str)
|
||||||
|
{
|
||||||
|
prints(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ZSerial::printf(const char* format, ...)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
va_list arglist;
|
||||||
|
va_start(arglist, format);
|
||||||
|
vsnprintf(FBUF, sizeof(FBUF), format, arglist);
|
||||||
|
prints(FBUF);
|
||||||
|
va_end(arglist);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::flushAlways()
|
||||||
|
{
|
||||||
|
while(TBUFtail != TBUFhead)
|
||||||
|
{
|
||||||
|
hwSerialFlush();
|
||||||
|
serialOutDeque();
|
||||||
|
yield();
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
hwSerialFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSerial::flush()
|
||||||
|
{
|
||||||
|
while((TBUFtail != TBUFhead) && (isSerialOut()))
|
||||||
|
{
|
||||||
|
hwSerialFlush();
|
||||||
|
serialOutDeque();
|
||||||
|
yield();
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
hwSerialFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ZSerial::availableForWrite()
|
||||||
|
{
|
||||||
|
return serialOutBufferBytesRemaining();
|
||||||
|
}
|
||||||
|
|
||||||
|
char ZSerial::drainForXonXoff()
|
||||||
|
{
|
||||||
|
char ch = '\0';
|
||||||
|
while(HWSerial.available()>0)
|
||||||
|
{
|
||||||
|
ch=HWSerial.read();
|
||||||
|
logSerialIn(ch);
|
||||||
|
if(ch == 3)
|
||||||
|
break;
|
||||||
|
switch(flowControlType)
|
||||||
|
{
|
||||||
|
case FCT_NORMAL:
|
||||||
|
if((!XON_STATE) && (ch == 17))
|
||||||
|
XON_STATE=true;
|
||||||
|
else
|
||||||
|
if((XON_STATE) && (ch == 19))
|
||||||
|
XON_STATE=false;
|
||||||
|
break;
|
||||||
|
case FCT_AUTOOFF:
|
||||||
|
case FCT_MANUAL:
|
||||||
|
if((!XON_STATE) && (ch == 17))
|
||||||
|
XON_STATE=true;
|
||||||
|
else
|
||||||
|
XON_STATE=false;
|
||||||
|
break;
|
||||||
|
case FCT_INVALID:
|
||||||
|
break;
|
||||||
|
case FCT_RTSCTS:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ZSerial::available()
|
||||||
|
{
|
||||||
|
int avail = HWSerial.available();
|
||||||
|
if(avail == 0)
|
||||||
|
{
|
||||||
|
if((TBUFtail != TBUFhead) && isSerialOut())
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
return avail;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ZSerial::read()
|
||||||
|
{
|
||||||
|
int c=HWSerial.read();
|
||||||
|
if(c == -1)
|
||||||
|
{
|
||||||
|
if((TBUFtail != TBUFhead) && isSerialOut())
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logSerialIn(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ZSerial::peek()
|
||||||
|
{
|
||||||
|
return HWSerial.peek();
|
||||||
|
}
|
|
@ -0,0 +1,506 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void WiFiClientNode::finishConnectionLink()
|
||||||
|
{
|
||||||
|
wasConnected=true;
|
||||||
|
if(conns == null)
|
||||||
|
conns = this;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WiFiClientNode *last = conns;
|
||||||
|
while(last->next != null)
|
||||||
|
last = last->next;
|
||||||
|
last->next = this;
|
||||||
|
}
|
||||||
|
checkOpenConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::constructNode()
|
||||||
|
{
|
||||||
|
id=++WiFiNextClientId;
|
||||||
|
setCharArray(&delimiters,"");
|
||||||
|
setCharArray(&maskOuts,"");
|
||||||
|
setCharArray(&stateMachine,"");
|
||||||
|
machineState = stateMachine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::constructNode(char *hostIp, int newport, int flagsBitmap, int ringDelay)
|
||||||
|
{
|
||||||
|
constructNode();
|
||||||
|
port=newport;
|
||||||
|
host=new char[strlen(hostIp)+1];
|
||||||
|
strcpy(host,hostIp);
|
||||||
|
this->flagsBitmap = flagsBitmap;
|
||||||
|
answered=(ringDelay == 0);
|
||||||
|
if(ringDelay > 0)
|
||||||
|
{
|
||||||
|
ringsRemain = ringDelay;
|
||||||
|
nextRingMillis = millis() + 3000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::constructNode(char *hostIp, int newport, char *username, char *password, int flagsBitmap, int ringDelay)
|
||||||
|
{
|
||||||
|
constructNode(hostIp, newport, flagsBitmap, ringDelay);
|
||||||
|
# ifdef INCLUDE_SSH
|
||||||
|
if(((flagsBitmap&FLAG_SECURE)==FLAG_SECURE)
|
||||||
|
&& (username != 0))
|
||||||
|
{
|
||||||
|
WiFiSSHClient *c = new WiFiSSHClient();
|
||||||
|
c->setLogin(username, password);
|
||||||
|
clientPtr = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
clientPtr = createWiFiClient((flagsBitmap&FLAG_SECURE)==FLAG_SECURE);
|
||||||
|
client = *clientPtr;
|
||||||
|
if(!clientPtr->connect(hostIp, newport))
|
||||||
|
{
|
||||||
|
// deleted when it returns and is deleted
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clientPtr->setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
finishConnectionLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientNode::WiFiClientNode(char *hostIp, int newport, char *username, char *password, int flagsBitmap)
|
||||||
|
{
|
||||||
|
constructNode(hostIp, newport, username, password, flagsBitmap, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientNode::WiFiClientNode(char *hostIp, int newport, int flagsBitmap)
|
||||||
|
{
|
||||||
|
constructNode(hostIp, newport, 0, 0, flagsBitmap, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode:: setNoDelay(bool tf)
|
||||||
|
{
|
||||||
|
if(clientPtr != 0)
|
||||||
|
clientPtr->setNoDelay(tf);
|
||||||
|
else
|
||||||
|
client.setNoDelay(tf);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientNode::WiFiClientNode(WiFiClient newClient, int flagsBitmap, int ringDelay)
|
||||||
|
{
|
||||||
|
constructNode();
|
||||||
|
this->flagsBitmap = flagsBitmap;
|
||||||
|
clientPtr=null;
|
||||||
|
newClient.setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
port=newClient.localPort();
|
||||||
|
String remoteIPStr = newClient.remoteIP().toString();
|
||||||
|
const char *remoteIP=remoteIPStr.c_str();
|
||||||
|
host=new char[remoteIPStr.length()+1];
|
||||||
|
strcpy(host,remoteIP);
|
||||||
|
client = newClient;
|
||||||
|
answered=(ringDelay == 0);
|
||||||
|
if(ringDelay > 0)
|
||||||
|
{
|
||||||
|
ringsRemain = ringDelay;
|
||||||
|
nextRingMillis = millis() + 3000;
|
||||||
|
}
|
||||||
|
finishConnectionLink();
|
||||||
|
serverClient=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientNode::~WiFiClientNode()
|
||||||
|
{
|
||||||
|
lastPacket[0].len=0;
|
||||||
|
lastPacket[1].len=0;
|
||||||
|
if(host!=null)
|
||||||
|
{
|
||||||
|
if(clientPtr != null)
|
||||||
|
clientPtr->stop();
|
||||||
|
else
|
||||||
|
client.stop();
|
||||||
|
delete host;
|
||||||
|
host=null;
|
||||||
|
}
|
||||||
|
if(clientPtr != null)
|
||||||
|
{
|
||||||
|
delete clientPtr;
|
||||||
|
clientPtr = null;
|
||||||
|
}
|
||||||
|
if(conns == this)
|
||||||
|
conns = next;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WiFiClientNode *last = conns;
|
||||||
|
while((last != null) && (last->next != this)) // don't change this!
|
||||||
|
last = last->next;
|
||||||
|
if(last != null)
|
||||||
|
last->next = next;
|
||||||
|
}
|
||||||
|
if(commandMode.current == this)
|
||||||
|
commandMode.current = conns;
|
||||||
|
if(commandMode.nextConn == this)
|
||||||
|
commandMode.nextConn = conns;
|
||||||
|
//underflowBuf.len = 0;
|
||||||
|
freeCharArray(&delimiters);
|
||||||
|
freeCharArray(&maskOuts);
|
||||||
|
freeCharArray(&stateMachine);
|
||||||
|
machineState = NULL;
|
||||||
|
next=null;
|
||||||
|
checkOpenConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiClientNode::isConnected()
|
||||||
|
{
|
||||||
|
return (host != null) && (clientPtr != null) && clientPtr->connected();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiClientNode::isPETSCII()
|
||||||
|
{
|
||||||
|
return (flagsBitmap & FLAG_PETSCII) == FLAG_PETSCII;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiClientNode::isEcho()
|
||||||
|
{
|
||||||
|
return (flagsBitmap & FLAG_ECHO) == FLAG_ECHO;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowControlType WiFiClientNode::getFlowControl()
|
||||||
|
{
|
||||||
|
if((flagsBitmap & FLAG_RTSCTS) == FLAG_RTSCTS)
|
||||||
|
return FCT_RTSCTS;
|
||||||
|
if((flagsBitmap & FLAG_XONXOFF) == FLAG_XONXOFF)
|
||||||
|
return FCT_NORMAL;
|
||||||
|
return FCT_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiClientNode::isTelnet()
|
||||||
|
{
|
||||||
|
return (flagsBitmap & FLAG_TELNET) == FLAG_TELNET;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiClientNode::isDisconnectedOnStreamExit()
|
||||||
|
{
|
||||||
|
return (flagsBitmap & FLAG_DISCONNECT_ON_EXIT) == FLAG_DISCONNECT_ON_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::setDisconnectOnStreamExit(bool tf)
|
||||||
|
{
|
||||||
|
if(tf)
|
||||||
|
flagsBitmap = flagsBitmap | FLAG_DISCONNECT_ON_EXIT;
|
||||||
|
else
|
||||||
|
flagsBitmap = flagsBitmap & ~FLAG_DISCONNECT_ON_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::fillUnderflowBuf()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
//underflow buf is deprecated
|
||||||
|
int newAvail = client.available();
|
||||||
|
if(newAvail > 0)
|
||||||
|
{
|
||||||
|
int maxBufAvail = PACKET_BUF_SIZE-underflowBuf.len;
|
||||||
|
if(newAvail>maxBufAvail)
|
||||||
|
newAvail=maxBufAvail;
|
||||||
|
if(newAvail > 0)
|
||||||
|
underflowBuf.len += client.read(underflowBuf.buf+underflowBuf.len, newAvail);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiClientNode::read()
|
||||||
|
{
|
||||||
|
if((host == null)||(!answered))
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
// underflow buf is no longer needed
|
||||||
|
if(underflowBuf.len > 0)
|
||||||
|
{
|
||||||
|
int b = underflowBuf.buf[0];
|
||||||
|
memcpy(underflowBuf.buf,underflowBuf.buf+1,--underflowBuf.len);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
int c;
|
||||||
|
if(clientPtr != null)
|
||||||
|
c = clientPtr->read();
|
||||||
|
else
|
||||||
|
c= client.read();
|
||||||
|
//fillUnderflowBuf();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiClientNode::peek()
|
||||||
|
{
|
||||||
|
if((host == null)||(!answered))
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
// underflow buf is no longer needed
|
||||||
|
if(underflowBuf.len > 0)
|
||||||
|
return underflowBuf.buf[0];
|
||||||
|
*/
|
||||||
|
if(clientPtr != null)
|
||||||
|
return clientPtr->peek();
|
||||||
|
else
|
||||||
|
return client.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::flush()
|
||||||
|
{
|
||||||
|
if((host != null)&&(clientPtr != null) && (clientPtr->available()==0))
|
||||||
|
flushAlways();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::flushAlways()
|
||||||
|
{
|
||||||
|
if(host != null)
|
||||||
|
{
|
||||||
|
flushOverflowBuffer();
|
||||||
|
if(clientPtr != null)
|
||||||
|
clientPtr->flush();
|
||||||
|
else
|
||||||
|
client.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiClientNode::available()
|
||||||
|
{
|
||||||
|
if((host == null)||(!answered))
|
||||||
|
return 0;
|
||||||
|
if(clientPtr != null)
|
||||||
|
return clientPtr->available();
|
||||||
|
else
|
||||||
|
return client.available(); // +underflowBuf.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiClientNode::read(uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
if((host == null)||(!answered))
|
||||||
|
return 0;
|
||||||
|
// this whole underflow buf len thing is to get around yet another
|
||||||
|
// problem in the underlying library where a socket disconnection
|
||||||
|
// eats away any stray available bytes in their buffers.
|
||||||
|
/*
|
||||||
|
// this was changed to be handled a different, so underBuf is also deprecated;
|
||||||
|
int previouslyRead = 0;
|
||||||
|
if(underflowBuf.len > 0)
|
||||||
|
{
|
||||||
|
if(underflowBuf.len <= size)
|
||||||
|
{
|
||||||
|
previouslyRead += underflowBuf.len;
|
||||||
|
memcpy(buf,underflowBuf.buf,underflowBuf.len);
|
||||||
|
size -= underflowBuf.len;
|
||||||
|
underflowBuf.len = 0;
|
||||||
|
buf += previouslyRead;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(buf,underflowBuf.buf,size);
|
||||||
|
underflowBuf.len -= size;
|
||||||
|
memcpy(underflowBuf.buf,underflowBuf.buf+size,underflowBuf.len);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(size == 0)
|
||||||
|
return previouslyRead;
|
||||||
|
*/
|
||||||
|
|
||||||
|
int bytesRead;
|
||||||
|
if(clientPtr != null)
|
||||||
|
bytesRead = clientPtr->read(buf,size);
|
||||||
|
else
|
||||||
|
bytesRead = client.read(buf,size);
|
||||||
|
//fillUnderflowBuf();
|
||||||
|
return bytesRead;// + previouslyRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiClientNode::flushOverflowBuffer()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* I've never gotten any of this to trigger, and could use those
|
||||||
|
* extra 260 bytes per connection
|
||||||
|
if(overflowBufLen > 0)
|
||||||
|
{
|
||||||
|
// because overflowBuf is not a const char* for some reason
|
||||||
|
// we need to explicitly declare that we want one
|
||||||
|
// The simplest thing to do is pin down the first character of the
|
||||||
|
// array and call it a day.
|
||||||
|
// This avoids client.write<T>(buffer, length) from being seen by the
|
||||||
|
// compiler as a better way to poke at it.
|
||||||
|
const uint8_t* overflowbuf_ptr = &overflowBuf[0];
|
||||||
|
int bufWrite=client.write(overflowbuf_ptr,overflowBufLen);
|
||||||
|
if(bufWrite >= overflowBufLen)
|
||||||
|
{
|
||||||
|
overflowBufLen = 0;
|
||||||
|
s_pinWrite(pinRTS,rtsActive);
|
||||||
|
// fall-through
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(bufWrite > 0)
|
||||||
|
{
|
||||||
|
for(int i=bufWrite;i<overflowBufLen;i++)
|
||||||
|
overflowBuf[i-bufWrite]=overflowBuf[i];
|
||||||
|
overflowBufLen -= bufWrite;
|
||||||
|
}
|
||||||
|
s_pinWrite(pinRTS,rtsInactive);
|
||||||
|
return bufWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WiFiClientNode::write(const uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
int written = 0;
|
||||||
|
/* overflow buf is pretty much useless now
|
||||||
|
if(host == null)
|
||||||
|
{
|
||||||
|
if(overflowBufLen>0)
|
||||||
|
{
|
||||||
|
s_pinWrite(pinRTS,rtsActive);
|
||||||
|
}
|
||||||
|
overflowBufLen=0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
written += flushOverflowBuffer();
|
||||||
|
if(written > 0)
|
||||||
|
{
|
||||||
|
for(int i=0;i<size && overflowBufLen<OVERFLOW_BUF_SIZE;i++,overflowBufLen++)
|
||||||
|
overflowBuf[overflowBufLen]=buf[i];
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if(clientPtr != null)
|
||||||
|
written += clientPtr->write(buf, size);
|
||||||
|
else
|
||||||
|
written += client.write(buf, size);
|
||||||
|
/*
|
||||||
|
if(written < size)
|
||||||
|
{
|
||||||
|
for(int i=written;i<size && overflowBufLen<OVERFLOW_BUF_SIZE;i++,overflowBufLen++)
|
||||||
|
overflowBuf[overflowBufLen]=buf[i];
|
||||||
|
s_pinWrite(pinRTS,rtsInactive);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::print(String s)
|
||||||
|
{
|
||||||
|
int size=s.length();
|
||||||
|
write((const uint8_t *)s.c_str(),size);
|
||||||
|
}
|
||||||
|
|
||||||
|
String WiFiClientNode::readLine(unsigned int timeout)
|
||||||
|
{
|
||||||
|
unsigned long now=millis();
|
||||||
|
String line = "";
|
||||||
|
while(((millis()-now < timeout) || (available()>0)))
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
if(available()>0)
|
||||||
|
{
|
||||||
|
char c=read();
|
||||||
|
if((c=='\n')||(c=='\r'))
|
||||||
|
{
|
||||||
|
if(line.length()>0)
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((c >= 32 ) && (c <= 127))
|
||||||
|
line += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::answer()
|
||||||
|
{
|
||||||
|
answered=true;
|
||||||
|
ringsRemain=0;
|
||||||
|
nextRingMillis=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiClientNode::isAnswered()
|
||||||
|
{
|
||||||
|
return answered;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiClientNode::ringsRemaining(int delta)
|
||||||
|
{
|
||||||
|
ringsRemain += delta;
|
||||||
|
return ringsRemain;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long WiFiClientNode::nextRingTime(long delta)
|
||||||
|
{
|
||||||
|
nextRingMillis += delta;
|
||||||
|
return nextRingMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WiFiClientNode::write(uint8_t c)
|
||||||
|
{
|
||||||
|
const uint8_t one[] = {c};
|
||||||
|
write(one,1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiClientNode::getNumOpenWiFiConnections()
|
||||||
|
{
|
||||||
|
int num = 0;
|
||||||
|
WiFiClientNode *conn = conns;
|
||||||
|
while(conn != null)
|
||||||
|
{
|
||||||
|
WiFiClientNode *chkConn = conn;
|
||||||
|
conn = conn->next;
|
||||||
|
if((chkConn->nextDisconnect != 0)
|
||||||
|
&&(millis() > chkConn->nextDisconnect))
|
||||||
|
delete(chkConn);
|
||||||
|
else
|
||||||
|
if((chkConn->isConnected()
|
||||||
|
||(chkConn->available()>0)
|
||||||
|
||((chkConn == conns)
|
||||||
|
&&((serialOutBufferBytesRemaining() <SER_WRITE_BUFSIZE-1)
|
||||||
|
||(HWSerial.availableForWrite()<SER_BUFSIZE))))
|
||||||
|
&& chkConn->isAnswered())
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::markForDisconnect()
|
||||||
|
{
|
||||||
|
if(nextDisconnect == 0)
|
||||||
|
nextDisconnect = millis() + 5000; // 5 sec
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiClientNode::isMarkedForDisconnect()
|
||||||
|
{
|
||||||
|
return nextDisconnect != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientNode::checkForAutoDisconnections()
|
||||||
|
{
|
||||||
|
WiFiClientNode *conn = conns;
|
||||||
|
while(conn != null)
|
||||||
|
{
|
||||||
|
WiFiClientNode *chkConn = conn;
|
||||||
|
conn = conn->next;
|
||||||
|
if((chkConn->nextDisconnect != 0)
|
||||||
|
&&(millis() > chkConn->nextDisconnect))
|
||||||
|
delete(chkConn);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,291 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
WiFiServerSpec::WiFiServerSpec()
|
||||||
|
{
|
||||||
|
setCharArray(&delimiters,"");
|
||||||
|
setCharArray(&maskOuts,"");
|
||||||
|
setCharArray(&stateMachine,"");
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiServerSpec::~WiFiServerSpec()
|
||||||
|
{
|
||||||
|
freeCharArray(&delimiters);
|
||||||
|
freeCharArray(&maskOuts);
|
||||||
|
freeCharArray(&stateMachine);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiServerSpec::WiFiServerSpec(WiFiServerSpec ©)
|
||||||
|
{
|
||||||
|
port=copy.port;
|
||||||
|
flagsBitmap = copy.flagsBitmap;
|
||||||
|
setCharArray(&delimiters,copy.delimiters);
|
||||||
|
setCharArray(&maskOuts,copy.maskOuts);
|
||||||
|
setCharArray(&stateMachine,copy.stateMachine);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiServerSpec& WiFiServerSpec::operator=(const WiFiServerSpec ©)
|
||||||
|
{
|
||||||
|
if(this != ©)
|
||||||
|
{
|
||||||
|
port=copy.port;
|
||||||
|
flagsBitmap = copy.flagsBitmap;
|
||||||
|
setCharArray(&delimiters,copy.delimiters);
|
||||||
|
setCharArray(&maskOuts,copy.maskOuts);
|
||||||
|
setCharArray(&stateMachine,copy.stateMachine);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiServerNode::WiFiServerNode(int newport, int flagsBitmap)
|
||||||
|
{
|
||||||
|
id=++WiFiNextClientId;
|
||||||
|
port=newport;
|
||||||
|
this->flagsBitmap = flagsBitmap;
|
||||||
|
server = new WiFiServer((uint16_t)newport);
|
||||||
|
//BZ:server->setNoDelay(DEFAULT_NO_DELAY);
|
||||||
|
server->begin();
|
||||||
|
if(servs==null)
|
||||||
|
servs=this;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WiFiServerNode *s=servs;
|
||||||
|
while(s->next != null)
|
||||||
|
s=s->next;
|
||||||
|
s->next=this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiServerNode::~WiFiServerNode()
|
||||||
|
{
|
||||||
|
if(server != null)
|
||||||
|
{
|
||||||
|
server->stop();
|
||||||
|
server->close();
|
||||||
|
delete server;
|
||||||
|
}
|
||||||
|
if(servs == this)
|
||||||
|
servs = next;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WiFiServerNode *last = servs;
|
||||||
|
while((last != null) && (last->next != this)) // don't change this!
|
||||||
|
last = last->next;
|
||||||
|
if(last != null)
|
||||||
|
last->next = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiServerNode::hasClient()
|
||||||
|
{
|
||||||
|
if(server != null)
|
||||||
|
return server->hasClient();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiServerNode::ReadWiFiServer(File &f, WiFiServerSpec &node)
|
||||||
|
{
|
||||||
|
if(f.available()>0)
|
||||||
|
{
|
||||||
|
String str="";
|
||||||
|
char c=f.read();
|
||||||
|
while((c != ',') && (f.available()>0))
|
||||||
|
{
|
||||||
|
str += c;
|
||||||
|
c=f.read();
|
||||||
|
}
|
||||||
|
if(str.length()==0)
|
||||||
|
return false;
|
||||||
|
node.port = atoi(str.c_str());
|
||||||
|
str = "";
|
||||||
|
c=f.read();
|
||||||
|
while((c != '\n') && (f.available()>0))
|
||||||
|
{
|
||||||
|
str += c;
|
||||||
|
c=f.read();
|
||||||
|
}
|
||||||
|
if(str.length()==0)
|
||||||
|
return false;
|
||||||
|
node.flagsBitmap = atoi(str.c_str());
|
||||||
|
str = "";
|
||||||
|
c=f.read();
|
||||||
|
while((c != ',') && (f.available()>0))
|
||||||
|
{
|
||||||
|
str += c;
|
||||||
|
c=f.read();
|
||||||
|
}
|
||||||
|
if(str.length()==0)
|
||||||
|
return false;
|
||||||
|
int chars=atoi(str.c_str());
|
||||||
|
str = "";
|
||||||
|
for(int i=0;i<chars && f.available()>0;i++)
|
||||||
|
{
|
||||||
|
c=f.read();
|
||||||
|
str += c;
|
||||||
|
}
|
||||||
|
setCharArray(&node.maskOuts,str.c_str());
|
||||||
|
if(f.available()<=0 || f.read()!='\n')
|
||||||
|
return false;
|
||||||
|
str = "";
|
||||||
|
c=f.read();
|
||||||
|
while((c != ',') && (f.available()>0))
|
||||||
|
{
|
||||||
|
str += c;
|
||||||
|
c=f.read();
|
||||||
|
}
|
||||||
|
if(str.length()==0)
|
||||||
|
return false;
|
||||||
|
chars=atoi(str.c_str());
|
||||||
|
str = "";
|
||||||
|
for(int i=0;i<chars && f.available()>0;i++)
|
||||||
|
{
|
||||||
|
c=f.read();
|
||||||
|
str += c;
|
||||||
|
}
|
||||||
|
setCharArray(&node.delimiters,str.c_str());
|
||||||
|
if(f.available()<=0 || f.read()!='\n')
|
||||||
|
return true;
|
||||||
|
str = "";
|
||||||
|
c=f.read();
|
||||||
|
while((c != ',') && (f.available()>0))
|
||||||
|
{
|
||||||
|
str += c;
|
||||||
|
c=f.read();
|
||||||
|
}
|
||||||
|
if(str.length()==0)
|
||||||
|
return false;
|
||||||
|
chars=atoi(str.c_str());
|
||||||
|
str = "";
|
||||||
|
for(int i=0;i<chars && f.available()>0;i++)
|
||||||
|
{
|
||||||
|
str += c;
|
||||||
|
c=f.read();
|
||||||
|
}
|
||||||
|
setCharArray(&node.stateMachine,str.c_str());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiServerNode::SaveWiFiServers()
|
||||||
|
{
|
||||||
|
SPIFFS.remove("/zlisteners.txt");
|
||||||
|
delay(500);
|
||||||
|
File f = SPIFFS.open("/zlisteners.txt", "w");
|
||||||
|
int ct=0;
|
||||||
|
WiFiServerNode *serv = servs;
|
||||||
|
while(serv != null)
|
||||||
|
{
|
||||||
|
f.printf("%d,%d\n",serv->port,serv->flagsBitmap);
|
||||||
|
if(serv->maskOuts == NULL)
|
||||||
|
f.printf("0,\n");
|
||||||
|
else
|
||||||
|
f.printf("%d,%s\n",strlen(serv->maskOuts),serv->maskOuts);
|
||||||
|
if(serv->delimiters == NULL)
|
||||||
|
f.printf("0,\n");
|
||||||
|
else
|
||||||
|
f.printf("%d,%s\n",strlen(serv->delimiters),serv->delimiters);
|
||||||
|
if(serv->stateMachine == NULL)
|
||||||
|
f.printf("0,\n");
|
||||||
|
else
|
||||||
|
f.printf("%d,%s\n",strlen(serv->stateMachine),serv->stateMachine);
|
||||||
|
ct++;
|
||||||
|
serv=serv->next;
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
delay(500);
|
||||||
|
if(SPIFFS.exists("/zlisteners.txt"))
|
||||||
|
{
|
||||||
|
File f = SPIFFS.open("/zlisteners.txt", "r");
|
||||||
|
bool fail=false;
|
||||||
|
while(f.available()>5)
|
||||||
|
{
|
||||||
|
WiFiServerSpec snode;
|
||||||
|
if(!ReadWiFiServer(f,snode))
|
||||||
|
{
|
||||||
|
fail=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
if(fail)
|
||||||
|
{
|
||||||
|
delay(100);
|
||||||
|
SaveWiFiServers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiServerNode::DestroyAllServers()
|
||||||
|
{
|
||||||
|
while(servs != null)
|
||||||
|
{
|
||||||
|
WiFiServerNode *s=servs;
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiServerNode *WiFiServerNode::FindServer(int port)
|
||||||
|
{
|
||||||
|
WiFiServerNode *s=servs;
|
||||||
|
while(s != null)
|
||||||
|
{
|
||||||
|
if(s->port == port)
|
||||||
|
return s;
|
||||||
|
s=s->next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WiFiServerNode::RestoreWiFiServers()
|
||||||
|
{
|
||||||
|
if(SPIFFS.exists("/zlisteners.txt"))
|
||||||
|
{
|
||||||
|
File f = SPIFFS.open("/zlisteners.txt", "r");
|
||||||
|
bool fail=false;
|
||||||
|
while(f.available()>0)
|
||||||
|
{
|
||||||
|
WiFiServerSpec snode;
|
||||||
|
if(!ReadWiFiServer(f,snode))
|
||||||
|
{
|
||||||
|
debugPrintf("Server: FAIL\n");
|
||||||
|
fail=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
WiFiServerNode *s=servs;
|
||||||
|
while(s != null)
|
||||||
|
{
|
||||||
|
if(s->port == snode.port)
|
||||||
|
break;
|
||||||
|
s=s->next;
|
||||||
|
}
|
||||||
|
if(s==null)
|
||||||
|
{
|
||||||
|
WiFiServerNode *node = new WiFiServerNode(snode.port, snode.flagsBitmap);
|
||||||
|
setCharArray(&node->delimiters,snode.delimiters);
|
||||||
|
setCharArray(&node->maskOuts,snode.maskOuts);
|
||||||
|
setCharArray(&node->stateMachine,snode.stateMachine);
|
||||||
|
debugPrintf("Server: %d, %d: '%s' '%s'\n",node->port,node->flagsBitmap,node->delimiters,node->maskOuts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debugPrintf("Server: DUP %d\n",snode.port);
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,302 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef INCLUDE_SSH
|
||||||
|
/*
|
||||||
|
Copyright 2023-2023 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
WiFiSSHClient::WiFiSSHClient()
|
||||||
|
{
|
||||||
|
libssh2_init(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiSSHClient::~WiFiSSHClient()
|
||||||
|
{
|
||||||
|
closeSSH();
|
||||||
|
libssh2_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiSSHClient::closeSSH()
|
||||||
|
{
|
||||||
|
if(channel) {
|
||||||
|
libssh2_channel_send_eof(channel);
|
||||||
|
libssh2_channel_close(channel);
|
||||||
|
libssh2_channel_free(channel);
|
||||||
|
channel = null;
|
||||||
|
}
|
||||||
|
if(session) {
|
||||||
|
libssh2_session_disconnect(session, "exit");
|
||||||
|
libssh2_session_free(session);
|
||||||
|
session = null;
|
||||||
|
}
|
||||||
|
if(sock) {
|
||||||
|
close(sock);
|
||||||
|
sock = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiSSHClient &WiFiSSHClient::operator=(const WiFiSSHClient &other)
|
||||||
|
{
|
||||||
|
_username = other._username;
|
||||||
|
_password = other._password;
|
||||||
|
sock = other.sock;
|
||||||
|
session = other.session;
|
||||||
|
channel = other.channel;
|
||||||
|
ibufSz = other.ibufSz;
|
||||||
|
memcpy(ibuf, other.ibuf, INTERNAL_BUF_SIZE);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiSSHClient::stop()
|
||||||
|
{
|
||||||
|
closeSSH();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int WiFiSSHClient::connect(IPAddress ip, uint16_t port)
|
||||||
|
{
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = htons(port);
|
||||||
|
sin.sin_addr.s_addr = ip;
|
||||||
|
if(::connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0)
|
||||||
|
return false;
|
||||||
|
session = libssh2_session_init();
|
||||||
|
if(libssh2_session_handshake(session, sock))
|
||||||
|
{
|
||||||
|
debugPrintf("wifisshclient: failed handshake\n\r");
|
||||||
|
closeSSH();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!finishLogin())
|
||||||
|
{
|
||||||
|
debugPrintf("wifisshclient: failed login\n\r");
|
||||||
|
closeSSH();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
channel = libssh2_channel_open_session(session);
|
||||||
|
if(!channel)
|
||||||
|
{
|
||||||
|
debugPrintf("wifisshclient: failed session\n\r");
|
||||||
|
closeSSH();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(libssh2_channel_request_pty(channel, "vanilla"))
|
||||||
|
{
|
||||||
|
debugPrintf("wifisshclient: failed pty\n\r");
|
||||||
|
closeSSH();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(libssh2_channel_shell(channel)) {
|
||||||
|
debugPrintf("wifisshclient: failed shell\n\r");
|
||||||
|
closeSSH();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ssize_t err = libssh2_channel_read(channel, ibuf, INTERNAL_BUF_SIZE);
|
||||||
|
if((err > 0) && (err != LIBSSH2_ERROR_EAGAIN)) {
|
||||||
|
ibufSz += err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int WiFiSSHClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms)
|
||||||
|
{
|
||||||
|
return connect(ip, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiSSHClient::connect(const char *host, uint16_t port)
|
||||||
|
{
|
||||||
|
if(host == null)
|
||||||
|
return false;
|
||||||
|
IPAddress hostIp((uint32_t)0);
|
||||||
|
if(!WiFiGenericClass::hostByName(host, hostIp))
|
||||||
|
return false;
|
||||||
|
return connect(hostIp, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiSSHClient::connect(const char *host, uint16_t port, int32_t timeout_ms)
|
||||||
|
{
|
||||||
|
return connect(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char _secret[256];
|
||||||
|
static void kbd_callback(const char *name, int name_len, const char *instruction, int instruction_len,
|
||||||
|
int num_prompts, const struct _LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
|
||||||
|
struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract)
|
||||||
|
{
|
||||||
|
(void)name;
|
||||||
|
(void)name_len;
|
||||||
|
(void)instruction;
|
||||||
|
(void)instruction_len;
|
||||||
|
if(num_prompts == 1) {
|
||||||
|
responses[0].text = strdup(_secret);
|
||||||
|
responses[0].length = strlen(_secret);
|
||||||
|
}
|
||||||
|
(void)prompts;
|
||||||
|
(void)abstract;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiSSHClient::finishLogin()
|
||||||
|
{
|
||||||
|
if(_username.length()==0)
|
||||||
|
return true;
|
||||||
|
char *userauthlist;
|
||||||
|
/* check what authentication methods are available */
|
||||||
|
userauthlist = libssh2_userauth_list(session, _username.c_str(), strlen(_username.c_str()));
|
||||||
|
if(strstr(userauthlist, "password") != NULL)
|
||||||
|
{
|
||||||
|
if(libssh2_userauth_password(session, _username.c_str(), _password.c_str()))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(strstr(userauthlist, "keyboard-interactive") != NULL)
|
||||||
|
{
|
||||||
|
strcpy(_secret,_password.c_str());
|
||||||
|
if(libssh2_userauth_keyboard_interactive(session, _username.c_str(), &kbd_callback) )
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(strstr(userauthlist, "publickey") != NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
size_t fn1sz, fn2sz;
|
||||||
|
char *fn1, *fn2;
|
||||||
|
char const *h = getenv("HOME");
|
||||||
|
if(!h || !*h)
|
||||||
|
h = ".";
|
||||||
|
fn1sz = strlen(h) + strlen(keyfile1) + 2;
|
||||||
|
fn2sz = strlen(h) + strlen(keyfile2) + 2;
|
||||||
|
fn1 = (char *)malloc(fn1sz);
|
||||||
|
fn2 = (char *)malloc(fn2sz);
|
||||||
|
// Using asprintf() here would be much cleaner, but less portable
|
||||||
|
snprintf(fn1, fn1sz, "%s/%s", h, keyfile1);
|
||||||
|
snprintf(fn2, fn2sz, "%s/%s", h, keyfile2);
|
||||||
|
|
||||||
|
if(libssh2_userauth_publickey_fromfile(session, username, fn1,
|
||||||
|
fn2, password)) {
|
||||||
|
free(fn2);
|
||||||
|
free(fn1);
|
||||||
|
return false;
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
free(fn2);
|
||||||
|
free(fn1);
|
||||||
|
return true;
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiSSHClient::setLogin(String username, String password)
|
||||||
|
{
|
||||||
|
_username = username;
|
||||||
|
_password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiSSHClient::intern_buffer_fill()
|
||||||
|
{
|
||||||
|
if((session != null) && (channel != null))
|
||||||
|
{
|
||||||
|
const size_t bufRemain = INTERNAL_BUF_SIZE - ibufSz;
|
||||||
|
if(bufRemain > 0)
|
||||||
|
{
|
||||||
|
libssh2_session_set_blocking(session, 0);
|
||||||
|
ssize_t err = libssh2_channel_read(channel, ibuf + ibufSz, bufRemain);
|
||||||
|
libssh2_session_set_blocking(session, 1);
|
||||||
|
if((err > 0) && (err != LIBSSH2_ERROR_EAGAIN)) {
|
||||||
|
ibufSz += err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiSSHClient::peek()
|
||||||
|
{
|
||||||
|
intern_buffer_fill();
|
||||||
|
if(ibufSz > 0)
|
||||||
|
return ibuf[0];
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WiFiSSHClient::write(uint8_t data)
|
||||||
|
{
|
||||||
|
return write(&data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiSSHClient::read()
|
||||||
|
{
|
||||||
|
uint8_t b[1];
|
||||||
|
size_t num = read(b, 1);
|
||||||
|
if(num > 0)
|
||||||
|
return b[0];
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WiFiSSHClient::write(const uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
if(channel != null)
|
||||||
|
return libssh2_channel_write(channel, (const char *)buf, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiSSHClient::read(uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
size_t bytesRead = 0;
|
||||||
|
while(bytesRead < size)
|
||||||
|
{
|
||||||
|
intern_buffer_fill();
|
||||||
|
if(ibufSz == 0)
|
||||||
|
break;
|
||||||
|
size_t bytesToTake = size - bytesRead;
|
||||||
|
if(bytesToTake > ibufSz)
|
||||||
|
bytesToTake = ibufSz;
|
||||||
|
memcpy(buf, ibuf, bytesToTake);
|
||||||
|
if(ibufSz > bytesToTake) // if there are still buffer bytes remaining
|
||||||
|
memcpy(ibuf, ibuf + bytesToTake, ibufSz - bytesToTake);
|
||||||
|
ibufSz -= bytesToTake;
|
||||||
|
bytesRead += bytesToTake;
|
||||||
|
}
|
||||||
|
return (int)bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiSSHClient::available()
|
||||||
|
{
|
||||||
|
intern_buffer_fill();
|
||||||
|
return ibufSz;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t WiFiSSHClient::connected()
|
||||||
|
{
|
||||||
|
if(ibufSz > 0)
|
||||||
|
return true;
|
||||||
|
intern_buffer_fill();
|
||||||
|
if(ibufSz > 0)
|
||||||
|
return true;
|
||||||
|
if(channel == null)
|
||||||
|
return false;
|
||||||
|
return !libssh2_channel_eof(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiFiSSHClient::fd() const
|
||||||
|
{
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,875 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ZConfig::switchTo()
|
||||||
|
{
|
||||||
|
currMode=&configMode;
|
||||||
|
serial.setFlowControlType(commandMode.serial.getFlowControlType());
|
||||||
|
serial.setPetsciiMode(commandMode.serial.isPetsciiMode());
|
||||||
|
savedEcho=commandMode.doEcho;
|
||||||
|
newListen=commandMode.preserveListeners;
|
||||||
|
commandMode.doEcho=true;
|
||||||
|
serverSpec.port=6502;
|
||||||
|
serverSpec.flagsBitmap=commandMode.getConfigFlagBitmap() & (~FLAG_ECHO);
|
||||||
|
if(servs)
|
||||||
|
serverSpec = *servs;
|
||||||
|
serial.setXON(true);
|
||||||
|
showMenu=true;
|
||||||
|
EOLN=commandMode.EOLN;
|
||||||
|
EOLNC=EOLN.c_str();
|
||||||
|
currState = ZCFGMENU_MAIN;
|
||||||
|
lastNumber=0;
|
||||||
|
lastAddress="";
|
||||||
|
lastOptions="";
|
||||||
|
settingsChanged=false;
|
||||||
|
lastNumNetworks=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZConfig::serialIncoming()
|
||||||
|
{
|
||||||
|
bool crReceived=commandMode.readSerialStream();
|
||||||
|
commandMode.clearPlusProgress(); // re-check the plus-escape mode
|
||||||
|
if(crReceived)
|
||||||
|
{
|
||||||
|
doModeCommand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZConfig::switchBackToCommandMode()
|
||||||
|
{
|
||||||
|
commandMode.doEcho=savedEcho;
|
||||||
|
currMode = &commandMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZConfig::doModeCommand()
|
||||||
|
{
|
||||||
|
String cmd = commandMode.getNextSerialCommand();
|
||||||
|
char c='?';
|
||||||
|
char sc='?';
|
||||||
|
for(int i=0;i<cmd.length();i++)
|
||||||
|
{
|
||||||
|
if(cmd[i]>32)
|
||||||
|
{
|
||||||
|
c=lc(cmd[i]);
|
||||||
|
if((i<cmd.length()-1)
|
||||||
|
&&(cmd[i+1]>32))
|
||||||
|
sc=lc(cmd[i+1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch(currState)
|
||||||
|
{
|
||||||
|
case ZCFGMENU_MAIN:
|
||||||
|
{
|
||||||
|
if((c=='q')||(cmd.length()==0))
|
||||||
|
{
|
||||||
|
if(settingsChanged)
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_WICONFIRM;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commandMode.showInitMessage();
|
||||||
|
switchBackToCommandMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c=='a') // add to phonebook
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_NUM;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c=='w') // wifi
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_WIMENU;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c=='h') // host
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_NEWHOST;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c=='f') // flow control
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_FLOW;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((c=='p')&&(sc=='e')) // petscii translation toggle
|
||||||
|
{
|
||||||
|
commandMode.serial.setPetsciiMode(!commandMode.serial.isPetsciiMode());
|
||||||
|
serial.setPetsciiMode(commandMode.serial.isPetsciiMode());
|
||||||
|
settingsChanged=true;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((c=='p')&&(sc=='r')) // print spec
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_NEWPRINT;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c=='e') // echo
|
||||||
|
{
|
||||||
|
savedEcho = !savedEcho;
|
||||||
|
settingsChanged=true;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c=='b') // bbs
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_BBSMENU;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c>47 && c<58) // its a phonebook entry!
|
||||||
|
{
|
||||||
|
PhoneBookEntry *pb=PhoneBookEntry::findPhonebookEntry(cmd);
|
||||||
|
if(pb == null)
|
||||||
|
{
|
||||||
|
serial.printf("%s%sPhone number not found: '%s'.%s%s",EOLNC,EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastNumber = pb->number;
|
||||||
|
lastAddress = pb->address;
|
||||||
|
lastOptions = pb->modifiers;
|
||||||
|
lastNotes = pb->notes;
|
||||||
|
currState=ZCFGMENU_ADDRESS;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showMenu=true; // re-show the menu
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_WICONFIRM:
|
||||||
|
{
|
||||||
|
if((cmd.length()==0)||(c=='n'))
|
||||||
|
{
|
||||||
|
commandMode.showInitMessage();
|
||||||
|
switchBackToCommandMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c=='y')
|
||||||
|
{
|
||||||
|
if(newListen != commandMode.preserveListeners)
|
||||||
|
{
|
||||||
|
commandMode.preserveListeners=newListen;
|
||||||
|
if(!newListen)
|
||||||
|
{
|
||||||
|
SPIFFS.remove("/zlisteners.txt");
|
||||||
|
WiFiServerNode::DestroyAllServers();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commandMode.ringCounter=1;
|
||||||
|
commandMode.autoStreamMode=true;
|
||||||
|
WiFiServerNode *s=WiFiServerNode::FindServer(serverSpec.port);
|
||||||
|
if(s != null)
|
||||||
|
delete s;
|
||||||
|
s = new WiFiServerNode(serverSpec.port,serverSpec.flagsBitmap);
|
||||||
|
WiFiServerNode::SaveWiFiServers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(commandMode.preserveListeners)
|
||||||
|
{
|
||||||
|
WiFiServerNode *s = WiFiServerNode::FindServer(serverSpec.port);
|
||||||
|
if( s != null)
|
||||||
|
{
|
||||||
|
if(s->flagsBitmap != serverSpec.flagsBitmap)
|
||||||
|
{
|
||||||
|
s->flagsBitmap = serverSpec.flagsBitmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WiFiServerNode::DestroyAllServers();
|
||||||
|
s = new WiFiServerNode(serverSpec.port,serverSpec.flagsBitmap);
|
||||||
|
WiFiServerNode::SaveWiFiServers();
|
||||||
|
commandMode.updateAutoAnswer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commandMode.reSaveConfig();
|
||||||
|
serial.printf("%sSettings saved.%s",EOLNC,EOLNC);
|
||||||
|
commandMode.showInitMessage();
|
||||||
|
WiFiServerNode::SaveWiFiServers();
|
||||||
|
switchBackToCommandMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NUM:
|
||||||
|
{
|
||||||
|
PhoneBookEntry *pb=PhoneBookEntry::findPhonebookEntry(cmd);
|
||||||
|
if(pb != null)
|
||||||
|
{
|
||||||
|
serial.printf("%s%sNumber already exists '%s'.%s%s",EOLNC,EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(cmd.length()==0)
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastNumber = atol((char *)cmd.c_str());
|
||||||
|
lastAddress = "";
|
||||||
|
ConnSettings flags(commandMode.getConfigFlagBitmap());
|
||||||
|
lastOptions = flags.getFlagString();
|
||||||
|
lastNotes = "";
|
||||||
|
currState=ZCFGMENU_ADDRESS;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NEWPORT:
|
||||||
|
{
|
||||||
|
if(cmd.length()>0)
|
||||||
|
{
|
||||||
|
serverSpec.port = atoi((char *)cmd.c_str());
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
currState=ZCFGMENU_BBSMENU;
|
||||||
|
showMenu=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_ADDRESS:
|
||||||
|
{
|
||||||
|
PhoneBookEntry *entry = PhoneBookEntry::findPhonebookEntry(lastNumber);
|
||||||
|
if(cmd.equalsIgnoreCase("delete") && (entry != null))
|
||||||
|
{
|
||||||
|
delete entry;
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
serial.printf("%sPhonebook entry deleted.%s%s",EOLNC,EOLNC,EOLNC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((cmd.length()==0) && (entry != null))
|
||||||
|
currState=ZCFGMENU_NOTES; // just keep old values
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!validateHostInfo((uint8_t *)cmd.c_str()))
|
||||||
|
serial.printf("%sInvalid address format (hostname:port) or (user:pass@hostname:port) for '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastAddress = cmd;
|
||||||
|
currState=ZCFGMENU_NOTES;
|
||||||
|
if(lastAddress.indexOf("@")>0)
|
||||||
|
{
|
||||||
|
int x = lastOptions.indexOf("S");
|
||||||
|
if(x<0)
|
||||||
|
lastOptions += "S";
|
||||||
|
else
|
||||||
|
lastOptions = lastOptions.substring(0,x) + lastOptions.substring(x+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showMenu=true; // re-show the menu
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_BBSMENU:
|
||||||
|
{
|
||||||
|
if(cmd.length()==0)
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConnSettings flags(serverSpec.flagsBitmap);
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
currState=ZCFGMENU_NEWPORT;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
newListen=false;
|
||||||
|
settingsChanged=true;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
if(newListen)
|
||||||
|
{
|
||||||
|
flags.petscii=!flags.petscii;
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if(newListen)
|
||||||
|
{
|
||||||
|
flags.telnet=!flags.telnet;
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
if(newListen)
|
||||||
|
flags.echo=!flags.echo;
|
||||||
|
else
|
||||||
|
newListen=true;
|
||||||
|
settingsChanged=true;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if(newListen)
|
||||||
|
{
|
||||||
|
if(flags.xonxoff)
|
||||||
|
{
|
||||||
|
flags.xonxoff=false;
|
||||||
|
flags.rtscts=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(flags.rtscts)
|
||||||
|
flags.rtscts=false;
|
||||||
|
else
|
||||||
|
flags.xonxoff=true;
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if(newListen)
|
||||||
|
{
|
||||||
|
flags.secure=!flags.secure;
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
serial.printf("%sInvalid option '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
settingsChanged=true;
|
||||||
|
serverSpec.flagsBitmap = flags.getBitmap();
|
||||||
|
}
|
||||||
|
showMenu=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_SUBNET:
|
||||||
|
{
|
||||||
|
if(cmd.length()==0)
|
||||||
|
currState=ZCFGMENU_NETMENU;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IPAddress *newaddr = ConnSettings::parseIP(cmd.c_str());
|
||||||
|
if(newaddr==null)
|
||||||
|
serial.printf("%sBad address (%s).%s",EOLNC,cmd.c_str(),EOLNC);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_NETMENU;
|
||||||
|
switch(netOpt)
|
||||||
|
{
|
||||||
|
case 'i': lastIP = *newaddr; break;
|
||||||
|
case 'd': lastDNS = *newaddr; break;
|
||||||
|
case 'g': lastGW = *newaddr; break;
|
||||||
|
case 's': lastSN = *newaddr; break;
|
||||||
|
}
|
||||||
|
free(newaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showMenu=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NETMENU:
|
||||||
|
{
|
||||||
|
if(cmd.length()==0)
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
if((staticIP==null)&&(useDHCP))
|
||||||
|
{}
|
||||||
|
else
|
||||||
|
if(useDHCP)
|
||||||
|
{
|
||||||
|
setNewStaticIPs(null,null,null,null);
|
||||||
|
if(!connectWifi(wifiSSI.c_str(),wifiPW.c_str(),staticIP,staticDNS,staticGW,staticSN))
|
||||||
|
serial.printf("%sUnable to connect to %s. :(%s",EOLNC,wifiSSI.c_str(),EOLNC);
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((staticIP==null)
|
||||||
|
||(*staticIP != lastIP)
|
||||||
|
||(*staticDNS != lastDNS)
|
||||||
|
||(*staticGW != lastGW)
|
||||||
|
||(*staticSN != lastSN))
|
||||||
|
{
|
||||||
|
IPAddress *ip=new IPAddress();
|
||||||
|
*ip = lastIP;
|
||||||
|
IPAddress *dns=new IPAddress();
|
||||||
|
*dns = lastDNS;
|
||||||
|
IPAddress *gw=new IPAddress();
|
||||||
|
*gw = lastGW;
|
||||||
|
IPAddress *sn=new IPAddress();
|
||||||
|
*sn = lastSN;
|
||||||
|
setNewStaticIPs(ip,dns,gw,sn);
|
||||||
|
if(!connectWifi(wifiSSI.c_str(),wifiPW.c_str(),staticIP,staticDNS,staticGW,staticSN))
|
||||||
|
serial.printf("%sUnable to connect to %s. :(%s",EOLNC,wifiSSI.c_str(),EOLNC);
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(useDHCP)
|
||||||
|
{
|
||||||
|
if(c=='d')
|
||||||
|
useDHCP=false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case 'e':
|
||||||
|
useDHCP=true;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
case 'd':
|
||||||
|
case 'g':
|
||||||
|
case 's':
|
||||||
|
netOpt=c;
|
||||||
|
currState=ZCFGMENU_SUBNET;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
serial.printf("%sInvalid option '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showMenu=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NOTES:
|
||||||
|
{
|
||||||
|
if(cmd.length()>0)
|
||||||
|
lastNotes=cmd;
|
||||||
|
currState=ZCFGMENU_OPTIONS;
|
||||||
|
showMenu=true; // re-show the menu
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_OPTIONS:
|
||||||
|
{
|
||||||
|
if(cmd.length()==0)
|
||||||
|
{
|
||||||
|
PhoneBookEntry *entry = PhoneBookEntry::findPhonebookEntry(lastNumber);
|
||||||
|
if(entry != null)
|
||||||
|
{
|
||||||
|
serial.printf("%sPhonebook entry updated.%s%s",EOLNC,EOLNC,EOLNC);
|
||||||
|
delete entry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
serial.printf("%sPhonebook entry added.%s%s",EOLNC,EOLNC,EOLNC);
|
||||||
|
entry = new PhoneBookEntry(lastNumber,lastAddress.c_str(),lastOptions.c_str(),lastNotes.c_str());
|
||||||
|
PhoneBookEntry::savePhonebook();
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConnSettings flags(lastOptions.c_str());
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case 'p':
|
||||||
|
flags.petscii=!flags.petscii;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
flags.telnet=!flags.telnet;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
flags.echo=!flags.echo;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if(flags.xonxoff)
|
||||||
|
{
|
||||||
|
flags.xonxoff=false;
|
||||||
|
flags.rtscts=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(flags.rtscts)
|
||||||
|
flags.rtscts=false;
|
||||||
|
else
|
||||||
|
flags.xonxoff=true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
flags.secure=!flags.secure;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
serial.printf("%sInvalid toggle option '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lastOptions = flags.getFlagString();
|
||||||
|
}
|
||||||
|
showMenu=true; // re-show the menu
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_WIMENU:
|
||||||
|
{
|
||||||
|
if(cmd.length()==0)
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int num=atoi(cmd.c_str());
|
||||||
|
if((num<=0)||(num>lastNumNetworks))
|
||||||
|
serial.printf("%sInvalid number. Try again.%s",EOLNC,EOLNC);
|
||||||
|
else
|
||||||
|
if(WiFi.encryptionType(num-1) == ENC_TYPE_NONE)
|
||||||
|
{
|
||||||
|
if(!connectWifi(WiFi.SSID(num-1).c_str(),"",null,null,null,null))
|
||||||
|
{
|
||||||
|
serial.printf("%sUnable to connect to %s. :(%s",EOLNC,WiFi.SSID(num-1).c_str(),EOLNC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wifiSSI=WiFi.SSID(num-1);
|
||||||
|
wifiPW="";
|
||||||
|
settingsChanged=true;
|
||||||
|
serial.printf("%sConnected!%s",EOLNC,EOLNC);
|
||||||
|
currState=ZCFGMENU_NETMENU;
|
||||||
|
}
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastNumber=num-1;
|
||||||
|
currState=ZCFGMENU_WIFIPW;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NEWHOST:
|
||||||
|
if(cmd.length()==0)
|
||||||
|
currState=ZCFGMENU_WIMENU;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hostname=cmd;
|
||||||
|
hostname.replace(',','.');
|
||||||
|
if((wifiSSI.length() > 0) && (WiFi.status()==WL_CONNECTED))
|
||||||
|
{
|
||||||
|
if(!connectWifi(wifiSSI.c_str(),wifiPW.c_str(),staticIP,staticDNS,staticGW,staticSN))
|
||||||
|
serial.printf("%sUnable to connect to %s. :(%s",EOLNC,wifiSSI.c_str(),EOLNC);
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZCFGMENU_NEWPRINT:
|
||||||
|
if(cmd.length()>0)
|
||||||
|
{
|
||||||
|
if(!printMode.testPrinterSpec(cmd.c_str(),cmd.length(),commandMode.serial.isPetsciiMode()))
|
||||||
|
{
|
||||||
|
serial.printf("%sBad format. Try ?:<host>:<port>/<path>.%s",EOLNC,EOLNC);
|
||||||
|
serial.printf("? = A)scii P)etscii or R)aw.%s",EOLNC);
|
||||||
|
serial.printf("Example: R:192.168.1.71:631/ipp/printer%s",EOLNC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printMode.setLastPrinterSpec(cmd.c_str());
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
break;
|
||||||
|
case ZCFGMENU_WIFIPW:
|
||||||
|
if(cmd.length()==0)
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_WIMENU;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(int i=0;i<500;i++)
|
||||||
|
{
|
||||||
|
if(serial.isSerialOut())
|
||||||
|
serialOutDeque();
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
if(!connectWifi(WiFi.SSID(lastNumber).c_str(),cmd.c_str(),null,null,null,null))
|
||||||
|
serial.printf("%sUnable to connect to %s.%s",EOLNC,WiFi.SSID(lastNumber).c_str(),EOLNC);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//setNewStaticIPs(null,null,null,null);
|
||||||
|
useDHCP=(staticIP==null);
|
||||||
|
lastIP=(staticIP != null)?*staticIP:WiFi.localIP();
|
||||||
|
lastDNS=(staticDNS != null)?*staticDNS:IPAddress(192,168,0,1);
|
||||||
|
lastGW=(staticGW != null)?*staticGW:IPAddress(192,168,0,1);
|
||||||
|
lastSN=(staticSN != null)?*staticSN:IPAddress(255,255,255,0);
|
||||||
|
wifiSSI=WiFi.SSID(lastNumber);
|
||||||
|
wifiPW=cmd;
|
||||||
|
settingsChanged=true;
|
||||||
|
currState=ZCFGMENU_NETMENU;
|
||||||
|
}
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZCFGMENU_FLOW:
|
||||||
|
if(cmd.length()==0)
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_WIMENU;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currState=ZCFGMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
if(c=='x')
|
||||||
|
commandMode.serial.setFlowControlType(FCT_NORMAL);
|
||||||
|
else
|
||||||
|
if(c=='r')
|
||||||
|
commandMode.serial.setFlowControlType(FCT_RTSCTS);
|
||||||
|
else
|
||||||
|
if(c=='d')
|
||||||
|
commandMode.serial.setFlowControlType(FCT_DISABLED);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serial.printf("%sUnknown flow control type '%s'. Try again.%s",EOLNC,cmd.c_str(),EOLNC);
|
||||||
|
currState=ZCFGMENU_FLOW;
|
||||||
|
}
|
||||||
|
settingsChanged = settingsChanged || (currState ==ZCFGMENU_MAIN);
|
||||||
|
serial.setFlowControlType(commandMode.serial.getFlowControlType());
|
||||||
|
serial.setXON(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZConfig::loop()
|
||||||
|
{
|
||||||
|
if(showMenu)
|
||||||
|
{
|
||||||
|
showMenu=false;
|
||||||
|
switch(currState)
|
||||||
|
{
|
||||||
|
case ZCFGMENU_MAIN:
|
||||||
|
{
|
||||||
|
serial.printf("%sMain Menu%s",EOLNC,EOLNC);
|
||||||
|
serial.printf("[HOST] name: %s%s",hostname.c_str(),EOLNC);
|
||||||
|
serial.printf("[WIFI] connection: %s%s",(WiFi.status() == WL_CONNECTED)?wifiSSI.c_str():"Not connected",EOLNC);
|
||||||
|
String flowName;
|
||||||
|
switch(commandMode.serial.getFlowControlType())
|
||||||
|
{
|
||||||
|
case FCT_NORMAL:
|
||||||
|
flowName = "XON/XOFF";
|
||||||
|
break;
|
||||||
|
case FCT_RTSCTS:
|
||||||
|
flowName = "RTS/CTS";
|
||||||
|
break;
|
||||||
|
case FCT_DISABLED:
|
||||||
|
flowName = "DISABLED";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
flowName = "OTHER";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String bbsMode = "DISABLED";
|
||||||
|
if(newListen)
|
||||||
|
{
|
||||||
|
bbsMode = "Port ";
|
||||||
|
bbsMode += serverSpec.port;
|
||||||
|
}
|
||||||
|
serial.printf("[FLOW] control: %s%s",flowName.c_str(),EOLNC);
|
||||||
|
serial.printf("[ECHO] keystrokes: %s%s",savedEcho?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[BBS] host: %s%s",bbsMode.c_str(),EOLNC);
|
||||||
|
serial.printf("[PRINT] spec: %s%s",printMode.getLastPrinterSpec(),EOLNC);
|
||||||
|
serial.printf("[PETSCII] translation: %s%s",commandMode.serial.isPetsciiMode()?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[ADD] new phonebook entry%s",EOLNC);
|
||||||
|
PhoneBookEntry *p = phonebook;
|
||||||
|
if(p != null)
|
||||||
|
{
|
||||||
|
serial.printf("Phonebook entries:%s",EOLNC);
|
||||||
|
while(p != null)
|
||||||
|
{
|
||||||
|
if(strlen(p->notes)>0)
|
||||||
|
serial.printf(" [%lu] %s (%s)%s",p->number, p->address, p->notes, EOLNC);
|
||||||
|
else
|
||||||
|
serial.printf(" [%lu] %s%s",p->number, p->address, EOLNC);
|
||||||
|
p=p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serial.printf("%sEnter command or entry or ENTER to exit: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NUM:
|
||||||
|
serial.printf("%sEnter a new fake phone number (digits ONLY)%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
case ZCFGMENU_NEWPORT:
|
||||||
|
serial.printf("%sEnter a port number to listen on%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
case ZCFGMENU_ADDRESS:
|
||||||
|
{
|
||||||
|
PhoneBookEntry *lastEntry = PhoneBookEntry::findPhonebookEntry(lastNumber);
|
||||||
|
if(lastEntry == null)
|
||||||
|
serial.printf("%sEnter hostname:port, or user:pass@hostname:port for SSH%s: ",EOLNC,EOLNC);
|
||||||
|
else
|
||||||
|
serial.printf("%sModify address, or enter DELETE (%s)%s: ",EOLNC,lastAddress.c_str(),EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_OPTIONS:
|
||||||
|
{
|
||||||
|
ConnSettings flags(lastOptions.c_str());
|
||||||
|
serial.printf("%sConnection Options:%s",EOLNC,EOLNC);
|
||||||
|
serial.printf("[PETSCII] Translation: %s%s",flags.petscii?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[TELNET] Translation: %s%s",flags.telnet?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[ECHO]: %s%s",flags.echo?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[FLOW] Control: %s%s",flags.xonxoff?"XON/XOFF":flags.rtscts?"RTS/CTS":"DISABLED",EOLNC);
|
||||||
|
serial.printf("[SSH/SSL] Security: %s%s",flags.secure?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("%sEnter option to toggle or ENTER to exit%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NOTES:
|
||||||
|
{
|
||||||
|
serial.printf("%sEnter some notes for this entry (%s)%s: ",EOLNC,lastNotes.c_str(),EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_BBSMENU:
|
||||||
|
{
|
||||||
|
serial.printf("%sBBS host settings:%s",EOLNC,EOLNC);
|
||||||
|
if(newListen)
|
||||||
|
{
|
||||||
|
ConnSettings flags(serverSpec.flagsBitmap);
|
||||||
|
serial.printf("%s[HOST] Listener Port: %d%s",EOLNC,serverSpec.port,EOLNC);
|
||||||
|
serial.printf("[PETSCII] Translation: %s%s",flags.petscii?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[TELNET] Translation: %s%s",flags.telnet?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[ECHO]: %s%s",flags.echo?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[FLOW] Control: %s%s",flags.xonxoff?"XON/XOFF":flags.rtscts?"RTS/CTS":"DISABLED",EOLNC);
|
||||||
|
serial.printf("[DISABLE] BBS host listener%s",EOLNC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
serial.printf("%s[ENABLE] BBS host listener%s",EOLNC,EOLNC);
|
||||||
|
serial.printf("%sEnter option to toggle or ENTER to exit%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_SUBNET:
|
||||||
|
{
|
||||||
|
String str;
|
||||||
|
switch(netOpt)
|
||||||
|
{
|
||||||
|
case 'i':
|
||||||
|
{
|
||||||
|
ConnSettings::IPtoStr(&lastIP,str);
|
||||||
|
serial.printf("%sIP Address (%s)%s: %s",EOLNC,str.c_str(),EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'g':
|
||||||
|
{
|
||||||
|
ConnSettings::IPtoStr(&lastGW,str);
|
||||||
|
serial.printf("%sGateway Address (%s)%s: %s",EOLNC,str.c_str(),EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's':
|
||||||
|
{
|
||||||
|
ConnSettings::IPtoStr(&lastSN,str);
|
||||||
|
serial.printf("%sSubnet Mask Address (%s)%s: %s",EOLNC,str.c_str(),EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
{
|
||||||
|
ConnSettings::IPtoStr(&lastDNS,str);
|
||||||
|
serial.printf("%sDNS Address (%s)%s: %s",EOLNC,str.c_str(),EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NETMENU:
|
||||||
|
{
|
||||||
|
serial.printf("%sNetwork settings:%s",EOLNC,EOLNC);
|
||||||
|
if(!useDHCP)
|
||||||
|
{
|
||||||
|
String str;
|
||||||
|
ConnSettings::IPtoStr(&lastIP,str);
|
||||||
|
serial.printf("%s[IP]: %s%s",EOLNC,str.c_str(),EOLNC);
|
||||||
|
ConnSettings::IPtoStr(&lastSN,str);
|
||||||
|
serial.printf("[SUBNET]: %s%s",str.c_str(),EOLNC);
|
||||||
|
ConnSettings::IPtoStr(&lastGW,str);
|
||||||
|
serial.printf("[GATEWAY]: %s%s",str.c_str(),EOLNC);
|
||||||
|
ConnSettings::IPtoStr(&lastDNS,str);
|
||||||
|
serial.printf("[DNS]: %s%s",str.c_str(),EOLNC);
|
||||||
|
serial.printf("[ENABLE] Enable DHCP%s",EOLNC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
serial.printf("%s[DISABLE] DHCP%s",EOLNC,EOLNC);
|
||||||
|
serial.printf("%sEnter option to toggle or ENTER to exit%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_WIMENU:
|
||||||
|
{
|
||||||
|
int n = WiFi.scanNetworks();
|
||||||
|
if(n>20)
|
||||||
|
n=20;
|
||||||
|
serial.printf("%sWiFi Networks:%s",EOLNC,EOLNC);
|
||||||
|
lastNumNetworks=n;
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
serial.printf("[%d] ",(i+1));
|
||||||
|
serial.prints(WiFi.SSID(i).c_str());
|
||||||
|
serial.prints(" (");
|
||||||
|
serial.printi(WiFi.RSSI(i));
|
||||||
|
serial.prints(")");
|
||||||
|
serial.prints((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*");
|
||||||
|
serial.prints(EOLN.c_str());
|
||||||
|
serial.flush();
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
serial.printf("%sEnter number to connect, or ENTER: ",EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NEWHOST:
|
||||||
|
{
|
||||||
|
serial.printf("%sEnter a new hostname: ",EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_NEWPRINT:
|
||||||
|
{
|
||||||
|
serial.printf("%sEnter ipp printer spec (?:<host>:<port>/path)%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_WIFIPW:
|
||||||
|
{
|
||||||
|
serial.printf("%sEnter your WiFi Password: ",EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_FLOW:
|
||||||
|
{
|
||||||
|
serial.printf("%sEnter RTS/CTS, XON/XOFF, or DISABLE flow control%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZCFGMENU_WICONFIRM:
|
||||||
|
{
|
||||||
|
serial.printf("%sYour setting changed. Save (y/N)?",EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(commandMode.checkPlusEscape())
|
||||||
|
{
|
||||||
|
switchBackToCommandMode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(serial.isSerialOut())
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
#ifdef INCLUDE_HOSTCM
|
||||||
|
void ZHostCMMode::switchBackToCommandMode()
|
||||||
|
{
|
||||||
|
if(proto != 0)
|
||||||
|
delete proto;
|
||||||
|
proto = 0;
|
||||||
|
currMode = &commandMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZHostCMMode::switchTo()
|
||||||
|
{
|
||||||
|
currMode=&hostcmMode;
|
||||||
|
if(proto == 0)
|
||||||
|
proto = new HostCM(&SD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZHostCMMode::serialIncoming()
|
||||||
|
{
|
||||||
|
if(proto != 0)
|
||||||
|
proto->receiveLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZHostCMMode::loop()
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
if((proto != 0) && (proto->isAborted()))
|
||||||
|
switchBackToCommandMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,560 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
//#define TCP_SND_BUF 4 * TCP_MSS
|
||||||
|
#define ZIMODEM_VERSION "4.0.0"
|
||||||
|
const char compile_date[] = __DATE__ " " __TIME__;
|
||||||
|
#define DEFAULT_NO_DELAY true
|
||||||
|
#define null 0
|
||||||
|
#define INCLUDE_IRCC true
|
||||||
|
//# define USE_DEVUPDATER true // only enable this if your name is Bo
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ESP32_DEV
|
||||||
|
# define ZIMODEM_ESP32
|
||||||
|
#elif defined(ESP32)
|
||||||
|
# define ZIMODEM_ESP32
|
||||||
|
#elif defined(ARDUINO_ESP320)
|
||||||
|
# define ZIMODEM_ESP32
|
||||||
|
#elif defined(ARDUINO_NANO32)
|
||||||
|
# define ZIMODEM_ESP32
|
||||||
|
#elif defined(ARDUINO_LoLin32)
|
||||||
|
# define ZIMODEM_ESP32
|
||||||
|
#elif defined(ARDUINO_ESPea32)
|
||||||
|
# define ZIMODEM_ESP32
|
||||||
|
#elif defined(ARDUINO_QUANTUM)
|
||||||
|
# define ZIMODEM_ESP32
|
||||||
|
#else
|
||||||
|
# define ZIMODEM_ESP8266
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SUPPORT_LED_PINS
|
||||||
|
# ifdef GPIO_NUM_0
|
||||||
|
# define DEFAULT_PIN_AA GPIO_NUM_16
|
||||||
|
# define DEFAULT_PIN_HS GPIO_NUM_15
|
||||||
|
# define DEFAULT_PIN_WIFI GPIO_NUM_0
|
||||||
|
# else
|
||||||
|
# define DEFAULT_PIN_AA 16
|
||||||
|
# define DEFAULT_PIN_HS 15
|
||||||
|
# define DEFAULT_PIN_WIFI 0
|
||||||
|
# endif
|
||||||
|
# define DEFAULT_HS_BAUD 38400
|
||||||
|
# define DEFAULT_AA_ACTIVE LOW
|
||||||
|
# define DEFAULT_AA_INACTIVE HIGH
|
||||||
|
# define DEFAULT_HS_ACTIVE LOW
|
||||||
|
# define DEFAULT_HS_INACTIVE HIGH
|
||||||
|
# define DEFAULT_WIFI_ACTIVE LOW
|
||||||
|
# define DEFAULT_WIFI_INACTIVE HIGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
# define PIN_FACTORY_RESET GPIO_NUM_0
|
||||||
|
# define DEFAULT_PIN_DCD GPIO_NUM_14
|
||||||
|
# define DEFAULT_PIN_CTS GPIO_NUM_13
|
||||||
|
# define DEFAULT_PIN_RTS GPIO_NUM_15 // unused
|
||||||
|
# define DEFAULT_PIN_RI GPIO_NUM_32
|
||||||
|
# define DEFAULT_PIN_DSR GPIO_NUM_12
|
||||||
|
# define DEFAULT_PIN_SND GPIO_NUM_25
|
||||||
|
# define DEFAULT_PIN_OTH GPIO_NUM_4
|
||||||
|
# define DEFAULT_PIN_DTR GPIO_NUM_27
|
||||||
|
# define debugPrintf Serial.printf
|
||||||
|
# define INCLUDE_SD_SHELL true
|
||||||
|
# define DEFAULT_FCT FCT_DISABLED
|
||||||
|
# define SerialConfig uint32_t
|
||||||
|
# define UART_CONFIG_MASK 0x8000000
|
||||||
|
# define UART_NB_BIT_MASK 0B00001100 | UART_CONFIG_MASK
|
||||||
|
# define UART_NB_BIT_5 0B00000000 | UART_CONFIG_MASK
|
||||||
|
# define UART_NB_BIT_6 0B00000100 | UART_CONFIG_MASK
|
||||||
|
# define UART_NB_BIT_7 0B00001000 | UART_CONFIG_MASK
|
||||||
|
# define UART_NB_BIT_8 0B00001100 | UART_CONFIG_MASK
|
||||||
|
# define UART_PARITY_MASK 0B00000011
|
||||||
|
# define UART_PARITY_NONE 0B00000000
|
||||||
|
# define UART_NB_STOP_BIT_MASK 0B00110000
|
||||||
|
# define UART_NB_STOP_BIT_0 0B00000000
|
||||||
|
# define UART_NB_STOP_BIT_1 0B00010000
|
||||||
|
# define UART_NB_STOP_BIT_15 0B00100000
|
||||||
|
# define UART_NB_STOP_BIT_2 0B00110000
|
||||||
|
# define preEOLN serial.prints
|
||||||
|
# define echoEOLN serial.write
|
||||||
|
//# define HARD_DCD_HIGH 1
|
||||||
|
//# define HARD_DCD_LOW 1
|
||||||
|
# define INCLUDE_HOSTCM true // safe to remove if you need space
|
||||||
|
# define INCLUDE_PING true
|
||||||
|
# define INCLUDE_SSH true
|
||||||
|
#else // ESP-8266, e.g. ESP-01, ESP-12E, inverted for C64Net WiFi Modem
|
||||||
|
# define DEFAULT_PIN_DSR 13
|
||||||
|
# define DEFAULT_PIN_DTR 12
|
||||||
|
# define DEFAULT_PIN_RI 14
|
||||||
|
# define DEFAULT_PIN_RTS 4
|
||||||
|
# define DEFAULT_PIN_CTS 5 // is 0 for ESP-01, see getDefaultCtsPin() below.
|
||||||
|
# define DEFAULT_PIN_DCD 2
|
||||||
|
# define DEFAULT_FCT FCT_DISABLED
|
||||||
|
# define RS232_INVERTED 1
|
||||||
|
# define debugPrintf doNothing
|
||||||
|
# define preEOLN(...)
|
||||||
|
# define echoEOLN(...) serial.prints(EOLN)
|
||||||
|
#endif
|
||||||
|
#define INCLUDE_SLIP true
|
||||||
|
|
||||||
|
#ifdef RS232_INVERTED
|
||||||
|
# define DEFAULT_DCD_HIGH HIGH
|
||||||
|
# define DEFAULT_DCD_LOW LOW
|
||||||
|
# define DEFAULT_CTS_HIGH HIGH
|
||||||
|
# define DEFAULT_CTS_LOW LOW
|
||||||
|
# define DEFAULT_RTS_HIGH HIGH
|
||||||
|
# define DEFAULT_RTS_LOW LOW
|
||||||
|
# define DEFAULT_RI_HIGH HIGH
|
||||||
|
# define DEFAULT_RI_LOW LOW
|
||||||
|
# define DEFAULT_DSR_HIGH HIGH
|
||||||
|
# define DEFAULT_DSR_LOW LOW
|
||||||
|
# define DEFAULT_DTR_HIGH HIGH
|
||||||
|
# define DEFAULT_DTR_LOW LOW
|
||||||
|
#else
|
||||||
|
# define DEFAULT_DCD_HIGH LOW
|
||||||
|
# define DEFAULT_DCD_LOW HIGH
|
||||||
|
# define DEFAULT_CTS_HIGH LOW
|
||||||
|
# define DEFAULT_CTS_LOW HIGH
|
||||||
|
# define DEFAULT_RTS_HIGH LOW
|
||||||
|
# define DEFAULT_RTS_LOW HIGH
|
||||||
|
# define DEFAULT_RI_HIGH LOW
|
||||||
|
# define DEFAULT_RI_LOW HIGH
|
||||||
|
# define DEFAULT_DSR_HIGH LOW
|
||||||
|
# define DEFAULT_DSR_LOW HIGH
|
||||||
|
# define DEFAULT_DTR_HIGH LOW
|
||||||
|
# define DEFAULT_DTR_LOW HIGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_BAUD_RATE 1200
|
||||||
|
#define DEFAULT_SERIAL_CONFIG SERIAL_8N1
|
||||||
|
#define MAX_PIN_NO 50
|
||||||
|
#define INTERNAL_FLOW_CONTROL_DIV 380
|
||||||
|
#define DEFAULT_RECONNECT_DELAY 60000
|
||||||
|
#define MAX_RECONNECT_DELAY 1800000
|
||||||
|
|
||||||
|
class ZMode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void serialIncoming();
|
||||||
|
virtual void loop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "pet2asc.h"
|
||||||
|
#include "rt_clock.h"
|
||||||
|
#include "filelog.h"
|
||||||
|
#include "serout.h"
|
||||||
|
#include "connSettings.h"
|
||||||
|
#include "wificlientnode.h"
|
||||||
|
#include "stringstream.h"
|
||||||
|
#include "phonebook.h"
|
||||||
|
#include "wifiservernode.h"
|
||||||
|
#include "zstream.h"
|
||||||
|
#include "proto_http.h"
|
||||||
|
#include "proto_ftp.h"
|
||||||
|
#include "zconfigmode.h"
|
||||||
|
#include "zcommand.h"
|
||||||
|
#include "zprint.h"
|
||||||
|
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
# ifdef INCLUDE_HOSTCM
|
||||||
|
# include "zhostcmmode.h"
|
||||||
|
# endif
|
||||||
|
# include "proto_xmodem.h"
|
||||||
|
# include "proto_zmodem.h"
|
||||||
|
# include "proto_kermit.h"
|
||||||
|
# include "zbrowser.h"
|
||||||
|
#endif
|
||||||
|
#ifdef INCLUDE_SLIP
|
||||||
|
# include "zslipmode.h"
|
||||||
|
#endif
|
||||||
|
#ifdef INCLUDE_IRCC
|
||||||
|
# include "zircmode.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static WiFiClientNode *conns = null;
|
||||||
|
static WiFiServerNode *servs = null;
|
||||||
|
static PhoneBookEntry *phonebook = null;
|
||||||
|
static bool pinSupport[MAX_PIN_NO];
|
||||||
|
static String termType = DEFAULT_TERMTYPE;
|
||||||
|
static String busyMsg = DEFAULT_BUSYMSG;
|
||||||
|
|
||||||
|
static ZMode *currMode = null;
|
||||||
|
static ZStream streamMode;
|
||||||
|
//static ZSlip slipMode; // not yet implemented
|
||||||
|
static ZCommand commandMode;
|
||||||
|
static ZPrint printMode;
|
||||||
|
static ZConfig configMode;
|
||||||
|
static RealTimeClock zclock(0);
|
||||||
|
#ifdef INCLUDE_SD_SHELL
|
||||||
|
# ifdef INCLUDE_HOSTCM
|
||||||
|
static ZHostCMMode hostcmMode;
|
||||||
|
# endif
|
||||||
|
static ZBrowser browseMode;
|
||||||
|
#endif
|
||||||
|
#ifdef INCLUDE_SLIP
|
||||||
|
static ZSLIPMode slipMode;
|
||||||
|
#endif
|
||||||
|
#ifdef INCLUDE_IRCC
|
||||||
|
static ZIRCMode ircMode;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum BaudState
|
||||||
|
{
|
||||||
|
BS_NORMAL,
|
||||||
|
BS_SWITCH_TEMP_NEXT,
|
||||||
|
BS_SWITCHED_TEMP,
|
||||||
|
BS_SWITCH_NORMAL_NEXT
|
||||||
|
};
|
||||||
|
|
||||||
|
static String wifiSSI;
|
||||||
|
static String wifiPW;
|
||||||
|
static String hostname;
|
||||||
|
static IPAddress *staticIP = null;
|
||||||
|
static IPAddress *staticDNS = null;
|
||||||
|
static IPAddress *staticGW = null;
|
||||||
|
static IPAddress *staticSN = null;
|
||||||
|
static unsigned long lastConnectAttempt = 0;
|
||||||
|
static unsigned long nextReconnectDelay = 0; // zero means don't attempt reconnects
|
||||||
|
static SerialConfig serialConfig = DEFAULT_SERIAL_CONFIG;
|
||||||
|
static int baudRate=DEFAULT_BAUD_RATE;
|
||||||
|
static int dequeSize=1+(DEFAULT_BAUD_RATE/INTERNAL_FLOW_CONTROL_DIV);
|
||||||
|
static BaudState baudState = BS_NORMAL;
|
||||||
|
static unsigned long resetPushTimer=0;
|
||||||
|
static int tempBaud = -1; // -1 do nothing
|
||||||
|
static int dcdStatus = DEFAULT_DCD_LOW;
|
||||||
|
static int pinDCD = DEFAULT_PIN_DCD;
|
||||||
|
static int pinCTS = DEFAULT_PIN_CTS;
|
||||||
|
static int pinRTS = DEFAULT_PIN_RTS;
|
||||||
|
static int pinDSR = DEFAULT_PIN_DSR;
|
||||||
|
static int pinDTR = DEFAULT_PIN_DTR;
|
||||||
|
static int pinRI = DEFAULT_PIN_RI;
|
||||||
|
static int dcdActive = DEFAULT_DCD_HIGH;
|
||||||
|
static int dcdInactive = DEFAULT_DCD_LOW;
|
||||||
|
static int ctsActive = DEFAULT_CTS_HIGH;
|
||||||
|
static int ctsInactive = DEFAULT_CTS_LOW;
|
||||||
|
static int rtsActive = DEFAULT_RTS_HIGH;
|
||||||
|
static int rtsInactive = DEFAULT_RTS_LOW;
|
||||||
|
static int riActive = DEFAULT_RI_HIGH;
|
||||||
|
static int riInactive = DEFAULT_RI_LOW;
|
||||||
|
static int dtrActive = DEFAULT_DTR_HIGH;
|
||||||
|
static int dtrInactive = DEFAULT_DTR_LOW;
|
||||||
|
static int dsrActive = DEFAULT_DSR_HIGH;
|
||||||
|
static int dsrInactive = DEFAULT_DSR_LOW;
|
||||||
|
|
||||||
|
static int getDefaultCtsPin()
|
||||||
|
{
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
return DEFAULT_PIN_CTS;
|
||||||
|
#else
|
||||||
|
if((ESP.getFlashChipRealSize()/1024)>=4096) // assume this is a striketerm/esp12e
|
||||||
|
return DEFAULT_PIN_CTS;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doNothing(const char* format, ...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void s_pinWrite(uint8_t pinNo, uint8_t value)
|
||||||
|
{
|
||||||
|
if(pinSupport[pinNo])
|
||||||
|
{
|
||||||
|
digitalWrite(pinNo, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setHostName(const char *hname)
|
||||||
|
{
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, hname);
|
||||||
|
#else
|
||||||
|
WiFi.hostname(hname);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setNewStaticIPs(IPAddress *ip, IPAddress *dns, IPAddress *gateWay, IPAddress *subNet)
|
||||||
|
{
|
||||||
|
if(staticIP != null)
|
||||||
|
free(staticIP);
|
||||||
|
staticIP = ip;
|
||||||
|
if(staticDNS != null)
|
||||||
|
free(staticDNS);
|
||||||
|
staticDNS = dns;
|
||||||
|
if(staticGW != null)
|
||||||
|
free(staticGW);
|
||||||
|
staticGW = gateWay;
|
||||||
|
if(staticSN != null)
|
||||||
|
free(staticSN);
|
||||||
|
staticSN = subNet;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool connectWifi(const char* ssid, const char* password, IPAddress *ip, IPAddress *dns, IPAddress *gateWay, IPAddress *subNet)
|
||||||
|
{
|
||||||
|
while(WiFi.status() == WL_CONNECTED)
|
||||||
|
{
|
||||||
|
WiFi.disconnect();
|
||||||
|
delay(100);
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#ifndef ZIMODEM_ESP32
|
||||||
|
if(hostname.length() > 0)
|
||||||
|
setHostName(hostname.c_str());
|
||||||
|
#endif
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
if((ip != null)&&(gateWay != null)&&(dns != null)&&(subNet!=null))
|
||||||
|
{
|
||||||
|
if(!WiFi.config(*ip,*gateWay,*subNet,*dns))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
if(hostname.length() > 0)
|
||||||
|
setHostName(hostname.c_str());
|
||||||
|
bool amConnected = (WiFi.status() == WL_CONNECTED) && (strcmp(WiFi.localIP().toString().c_str(), "0.0.0.0")!=0);
|
||||||
|
int WiFiCounter = 0;
|
||||||
|
while ((!amConnected) && (WiFiCounter < 20))
|
||||||
|
{
|
||||||
|
WiFiCounter++;
|
||||||
|
if(!amConnected)
|
||||||
|
delay(500);
|
||||||
|
amConnected = (WiFi.status() == WL_CONNECTED) && (strcmp(WiFi.localIP().toString().c_str(), "0.0.0.0")!=0);
|
||||||
|
}
|
||||||
|
lastConnectAttempt = millis();
|
||||||
|
if(lastConnectAttempt == 0) // it IS possible for millis() to be 0, but we need to ignore it.
|
||||||
|
lastConnectAttempt = 1; // 0 is a special case, so skip it
|
||||||
|
|
||||||
|
if(!amConnected)
|
||||||
|
{
|
||||||
|
nextReconnectDelay = 0; // assume no retry is desired.. let the caller set it up, as it could be bad PW
|
||||||
|
WiFi.disconnect();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nextReconnectDelay = DEFAULT_RECONNECT_DELAY; // if connected, we always want to try reconns in the future
|
||||||
|
|
||||||
|
#ifdef SUPPORT_LED_PINS
|
||||||
|
s_pinWrite(DEFAULT_PIN_WIFI,(WiFi.status() == WL_CONNECTED)?DEFAULT_WIFI_ACTIVE:DEFAULT_WIFI_INACTIVE);
|
||||||
|
#endif
|
||||||
|
return (WiFi.status() == WL_CONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkBaudChange()
|
||||||
|
{
|
||||||
|
switch(baudState)
|
||||||
|
{
|
||||||
|
case BS_SWITCH_TEMP_NEXT:
|
||||||
|
changeBaudRate(tempBaud);
|
||||||
|
baudState = BS_SWITCHED_TEMP;
|
||||||
|
break;
|
||||||
|
case BS_SWITCH_NORMAL_NEXT:
|
||||||
|
changeBaudRate(baudRate);
|
||||||
|
baudState = BS_NORMAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void changeBaudRate(int baudRate)
|
||||||
|
{
|
||||||
|
flushSerial(); // blocking, but very very necessary
|
||||||
|
delay(500); // give the client half a sec to catch up
|
||||||
|
logPrintfln("Baud change to %d.\n",baudRate);
|
||||||
|
debugPrintf("Baud change to %d.\n",baudRate);
|
||||||
|
dequeSize=1+(baudRate/INTERNAL_FLOW_CONTROL_DIV);
|
||||||
|
debugPrintf("Deque constant now: %d\n",dequeSize);
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
HWSerial.updateBaudRate(baudRate);
|
||||||
|
#else
|
||||||
|
HWSerial.begin(baudRate, serialConfig); //Change baud rate
|
||||||
|
#endif
|
||||||
|
#ifdef SUPPORT_LED_PINS
|
||||||
|
s_pinWrite(DEFAULT_PIN_HS,(baudRate>=DEFAULT_HS_BAUD)?DEFAULT_HS_ACTIVE:DEFAULT_HS_INACTIVE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void changeSerialConfig(SerialConfig conf)
|
||||||
|
{
|
||||||
|
flushSerial(); // blocking, but very very necessary
|
||||||
|
delay(500); // give the client half a sec to catch up
|
||||||
|
debugPrintf("Config changing to %d.\n",(int)conf);
|
||||||
|
dequeSize=1+(baudRate/INTERNAL_FLOW_CONTROL_DIV);
|
||||||
|
debugPrintf("Deque constant now: %d\n",dequeSize);
|
||||||
|
HWSerial.begin(baudRate, conf); //Change baud rate
|
||||||
|
debugPrintf("Config changed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int checkOpenConnections()
|
||||||
|
{
|
||||||
|
int num=WiFiClientNode::getNumOpenWiFiConnections();
|
||||||
|
if(num == 0)
|
||||||
|
{
|
||||||
|
if((dcdStatus == dcdActive)
|
||||||
|
&&(dcdStatus != dcdInactive))
|
||||||
|
{
|
||||||
|
logPrintfln("DCD going inactive.\n");
|
||||||
|
dcdStatus = dcdInactive;
|
||||||
|
s_pinWrite(pinDCD,dcdStatus);
|
||||||
|
if(baudState == BS_SWITCHED_TEMP)
|
||||||
|
baudState = BS_SWITCH_NORMAL_NEXT;
|
||||||
|
if(currMode == &commandMode)
|
||||||
|
clearSerialOutBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if((dcdStatus == dcdInactive)
|
||||||
|
&&(dcdStatus != dcdActive))
|
||||||
|
{
|
||||||
|
logPrintfln("DCD going active.\n");
|
||||||
|
dcdStatus = dcdActive;
|
||||||
|
s_pinWrite(pinDCD,dcdStatus);
|
||||||
|
if((tempBaud > 0) && (baudState == BS_NORMAL))
|
||||||
|
baudState = BS_SWITCH_TEMP_NEXT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
for(int i=0;i<MAX_PIN_NO;i++)
|
||||||
|
pinSupport[i]=false;
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
Serial.begin(115200); //the debug port
|
||||||
|
Serial.setDebugOutput(true);
|
||||||
|
debugPrintf("Debug port open and ready.\n");
|
||||||
|
pinSupport[4]=true;
|
||||||
|
pinSupport[5]=true;
|
||||||
|
for(int i=12;i<=23;i++)
|
||||||
|
pinSupport[i]=true;
|
||||||
|
for(int i=25;i<=27;i++)
|
||||||
|
pinSupport[i]=true;
|
||||||
|
for(int i=32;i<=33;i++)
|
||||||
|
pinSupport[i]=true;
|
||||||
|
#else
|
||||||
|
pinSupport[0]=true;
|
||||||
|
pinSupport[2]=true;
|
||||||
|
if((ESP.getFlashChipRealSize()/1024)>=4096) // assume this is a strykelink/esp12e
|
||||||
|
{
|
||||||
|
pinSupport[4]=true;
|
||||||
|
pinSupport[5]=true;
|
||||||
|
for(int i=9;i<=16;i++)
|
||||||
|
pinSupport[i]=true;
|
||||||
|
pinSupport[11]=false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
initSDShell();
|
||||||
|
currMode = &commandMode;
|
||||||
|
if(!SPIFFS.begin())
|
||||||
|
{
|
||||||
|
SPIFFS.format();
|
||||||
|
SPIFFS.begin();
|
||||||
|
debugPrintf("SPIFFS Formatted.");
|
||||||
|
}
|
||||||
|
HWSerial.begin(DEFAULT_BAUD_RATE, DEFAULT_SERIAL_CONFIG); //Start Serial
|
||||||
|
#ifdef ZIMODEM_ESP8266
|
||||||
|
HWSerial.setRxBufferSize(1024);
|
||||||
|
#endif
|
||||||
|
commandMode.loadConfig();
|
||||||
|
PhoneBookEntry::loadPhonebook();
|
||||||
|
dcdStatus = dcdInactive;
|
||||||
|
s_pinWrite(pinDCD,dcdStatus);
|
||||||
|
flushSerial();
|
||||||
|
#ifdef SUPPORT_LED_PINS
|
||||||
|
s_pinWrite(DEFAULT_PIN_WIFI,(WiFi.status() == WL_CONNECTED)?DEFAULT_WIFI_ACTIVE:DEFAULT_WIFI_INACTIVE);
|
||||||
|
s_pinWrite(DEFAULT_PIN_HS,(baudRate>=DEFAULT_HS_BAUD)?DEFAULT_HS_ACTIVE:DEFAULT_HS_INACTIVE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkReconnect()
|
||||||
|
{
|
||||||
|
if((WiFi.status() != WL_CONNECTED)
|
||||||
|
&&(nextReconnectDelay>0)
|
||||||
|
&&(lastConnectAttempt>0)
|
||||||
|
&&(wifiSSI.length()>0))
|
||||||
|
{
|
||||||
|
unsigned long now=millis();
|
||||||
|
if(lastConnectAttempt > now)
|
||||||
|
lastConnectAttempt=1;
|
||||||
|
if(now > lastConnectAttempt + nextReconnectDelay)
|
||||||
|
{
|
||||||
|
debugPrintf("Attempting Reconnect to %s\n",wifiSSI.c_str());
|
||||||
|
unsigned long oldReconnectDelay = nextReconnectDelay;
|
||||||
|
if(!connectWifi(wifiSSI.c_str(),wifiPW.c_str(),staticIP,staticDNS,staticGW,staticSN))
|
||||||
|
debugPrintf("%sUnable to reconnect to %s.\n",wifiSSI.c_str());
|
||||||
|
nextReconnectDelay = oldReconnectDelay * 2;
|
||||||
|
if(nextReconnectDelay > MAX_RECONNECT_DELAY)
|
||||||
|
nextReconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkFactoryReset()
|
||||||
|
{
|
||||||
|
#ifdef ZIMODEM_ESP32
|
||||||
|
if(!digitalRead(PIN_FACTORY_RESET))
|
||||||
|
{
|
||||||
|
if(resetPushTimer != 1)
|
||||||
|
{
|
||||||
|
if(resetPushTimer==0)
|
||||||
|
{
|
||||||
|
resetPushTimer=millis();
|
||||||
|
if(resetPushTimer==1)
|
||||||
|
resetPushTimer++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((millis() - resetPushTimer) > 5000)
|
||||||
|
{
|
||||||
|
SPIFFS.remove(CONFIG_FILE);
|
||||||
|
SPIFFS.remove(CONFIG_FILE_OLD);
|
||||||
|
SPIFFS.remove("/zphonebook.txt");
|
||||||
|
SPIFFS.remove("/zlisteners.txt");
|
||||||
|
PhoneBookEntry::clearPhonebook();
|
||||||
|
SPIFFS.end();
|
||||||
|
SPIFFS.format();
|
||||||
|
SPIFFS.begin();
|
||||||
|
PhoneBookEntry::clearPhonebook();
|
||||||
|
if(WiFi.status() == WL_CONNECTED)
|
||||||
|
WiFi.disconnect();
|
||||||
|
baudRate = DEFAULT_BAUD_RATE;
|
||||||
|
commandMode.loadConfig();
|
||||||
|
PhoneBookEntry::loadPhonebook();
|
||||||
|
dcdStatus = dcdInactive;
|
||||||
|
s_pinWrite(pinDCD,dcdStatus);
|
||||||
|
wifiSSI="";
|
||||||
|
delay(500);
|
||||||
|
zclock.reset();
|
||||||
|
commandMode.reset();
|
||||||
|
resetPushTimer=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(resetPushTimer != 0)
|
||||||
|
resetPushTimer=0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
checkFactoryReset();
|
||||||
|
checkReconnect();
|
||||||
|
if(HWSerial.available())
|
||||||
|
{
|
||||||
|
currMode->serialIncoming();
|
||||||
|
}
|
||||||
|
currMode->loop();
|
||||||
|
zclock.tick();
|
||||||
|
}
|
|
@ -0,0 +1,539 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
* zircmode.ino
|
||||||
|
*
|
||||||
|
* Created on: May 18, 2022
|
||||||
|
* Author: Bo Zimmerman
|
||||||
|
*/
|
||||||
|
#ifdef INCLUDE_IRCC
|
||||||
|
//https://github.com/bl4de/irc-client/blob/master/irc_client.py
|
||||||
|
void ZIRCMode::switchBackToCommandMode()
|
||||||
|
{
|
||||||
|
serial.println("Back in command mode.");
|
||||||
|
if(current != null)
|
||||||
|
{
|
||||||
|
delete current;
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
currMode = &commandMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZIRCMode::switchTo()
|
||||||
|
{
|
||||||
|
currMode=&ircMode;
|
||||||
|
savedEcho=commandMode.doEcho;
|
||||||
|
commandMode.doEcho=true;
|
||||||
|
serial.setFlowControlType(commandMode.serial.getFlowControlType());
|
||||||
|
serial.setPetsciiMode(commandMode.serial.isPetsciiMode());
|
||||||
|
showMenu=true;
|
||||||
|
EOLN=commandMode.EOLN;
|
||||||
|
EOLNC=EOLN.c_str();
|
||||||
|
currState=ZIRCMENU_MAIN;
|
||||||
|
lastNumber=0;
|
||||||
|
lastAddress="";
|
||||||
|
lastOptions="";
|
||||||
|
channelName="";
|
||||||
|
joinReceived=false;
|
||||||
|
if(nick.length()==0)
|
||||||
|
{
|
||||||
|
randomSeed(millis());
|
||||||
|
char tempNick[50];
|
||||||
|
sprintf(tempNick,"ChangeMe#%ld",random(1,999));
|
||||||
|
nick = tempNick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZIRCMode::doIRCCommand()
|
||||||
|
{
|
||||||
|
String cmd = commandMode.getNextSerialCommand();
|
||||||
|
char c='?';
|
||||||
|
while((cmd.length()>0)
|
||||||
|
&&(cmd[0]==32)||(cmd[0]==7))
|
||||||
|
cmd = cmd.substring(1);
|
||||||
|
if(cmd.length()>0)
|
||||||
|
c=lc(cmd[0]);
|
||||||
|
switch(currState)
|
||||||
|
{
|
||||||
|
case ZIRCMENU_MAIN:
|
||||||
|
{
|
||||||
|
if((c=='q')||(cmd.length()==0))
|
||||||
|
{
|
||||||
|
commandMode.showInitMessage();
|
||||||
|
switchBackToCommandMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c=='a') // add to phonebook
|
||||||
|
{
|
||||||
|
currState=ZIRCMENU_NUM;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c=='n') // change nick
|
||||||
|
{
|
||||||
|
currState=ZIRCMENU_NICK;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c>47 && c<58) // its a phonebook entry!
|
||||||
|
{
|
||||||
|
PhoneBookEntry *pb=PhoneBookEntry::findPhonebookEntry(cmd);
|
||||||
|
if(pb == null)
|
||||||
|
{
|
||||||
|
serial.printf("%s%sPhone number not found: '%s'.%s%s",EOLNC,EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
currState=ZIRCMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serial.printf("%s%sConnecting to %s...%s%s",EOLNC,EOLNC,pb->address,EOLNC,EOLNC);
|
||||||
|
String address = pb->address;
|
||||||
|
char vbuf[address.length()+1];
|
||||||
|
strcpy(vbuf,pb->address);
|
||||||
|
char *colon=strstr((char *)vbuf,":");
|
||||||
|
int port=6666;
|
||||||
|
if(colon != null)
|
||||||
|
{
|
||||||
|
(*colon)=0;
|
||||||
|
port=atoi((char *)(++colon));
|
||||||
|
}
|
||||||
|
int flagsBitmap=0;
|
||||||
|
{
|
||||||
|
ConnSettings flags("");
|
||||||
|
flagsBitmap = flags.getBitmap(serial.getFlowControlType());
|
||||||
|
}
|
||||||
|
logPrintfln("Connnecting: %s %d %d",(char *)vbuf,port,flagsBitmap);
|
||||||
|
WiFiClientNode *c = new WiFiClientNode((char *)vbuf,port,flagsBitmap);
|
||||||
|
if(!c->isConnected())
|
||||||
|
{
|
||||||
|
logPrintln("Connnect: FAIL");
|
||||||
|
serial.prints("Connection failed.\n\r"); //TODO: maybe get rid of?
|
||||||
|
currState=ZIRCMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logPrintfln("Connnect: SUCCESS: %d",c->id);
|
||||||
|
serial.prints("Connected.\n\r"); //TODO: maybe get rid of?
|
||||||
|
current=c;
|
||||||
|
buf = "";
|
||||||
|
currState=ZIRCMENU_COMMAND;
|
||||||
|
ircState=ZIRCSTATE_WAIT;
|
||||||
|
timeout=millis()+6000;
|
||||||
|
showMenu=true; // only wait to get it to act
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showMenu=true; // re-show the menu
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_NUM:
|
||||||
|
{
|
||||||
|
PhoneBookEntry *pb=PhoneBookEntry::findPhonebookEntry(cmd);
|
||||||
|
if(pb != null)
|
||||||
|
{
|
||||||
|
serial.printf("%s%sNumber already exists '%s'.%s%s",EOLNC,EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
currState=ZIRCMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(cmd.length()==0)
|
||||||
|
{
|
||||||
|
currState=ZIRCMENU_MAIN;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastNumber = atol((char *)cmd.c_str());
|
||||||
|
lastAddress = "";
|
||||||
|
ConnSettings flags(commandMode.getConfigFlagBitmap());
|
||||||
|
lastOptions = flags.getFlagString();
|
||||||
|
lastNotes = "";
|
||||||
|
currState=ZIRCMENU_ADDRESS;
|
||||||
|
showMenu=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_ADDRESS:
|
||||||
|
{
|
||||||
|
PhoneBookEntry *entry = PhoneBookEntry::findPhonebookEntry(lastNumber);
|
||||||
|
if(cmd.equalsIgnoreCase("delete") && (entry != null))
|
||||||
|
{
|
||||||
|
delete entry;
|
||||||
|
currState=ZIRCMENU_MAIN;
|
||||||
|
serial.printf("%sPhonebook entry deleted.%s%s",EOLNC,EOLNC,EOLNC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((cmd.length()==0) && (entry != null))
|
||||||
|
currState=ZIRCMENU_NOTES; // just keep old values
|
||||||
|
else
|
||||||
|
{
|
||||||
|
boolean fail = cmd.indexOf(',') >= 0;
|
||||||
|
int colonDex=cmd.indexOf(':');
|
||||||
|
fail = fail || (colonDex <= 0) || (colonDex == cmd.length()-1);
|
||||||
|
fail = fail || (colonDex != cmd.lastIndexOf(':'));
|
||||||
|
if(!fail)
|
||||||
|
{
|
||||||
|
for(int i=colonDex+1;i<cmd.length();i++)
|
||||||
|
if(strchr("0123456789",cmd[i])<0)
|
||||||
|
fail=true;
|
||||||
|
}
|
||||||
|
if(fail)
|
||||||
|
{
|
||||||
|
serial.printf("%sInvalid address format (hostname:port) for '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastAddress = cmd;
|
||||||
|
currState=ZIRCMENU_NOTES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showMenu=true; // re-show the menu
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_NOTES:
|
||||||
|
{
|
||||||
|
if(cmd.length()>0)
|
||||||
|
lastNotes=cmd;
|
||||||
|
currState=ZIRCMENU_OPTIONS;
|
||||||
|
showMenu=true; // re-show the menu
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_NICK:
|
||||||
|
{
|
||||||
|
if(cmd.length()>0)
|
||||||
|
nick=cmd;
|
||||||
|
currState=ZIRCMENU_MAIN;
|
||||||
|
showMenu=true; // re-show the menu
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_OPTIONS:
|
||||||
|
{
|
||||||
|
if(cmd.length()==0)
|
||||||
|
{
|
||||||
|
serial.printf("%sPhonebook entry added.%s%s",EOLNC,EOLNC,EOLNC);
|
||||||
|
PhoneBookEntry *entry = new PhoneBookEntry(lastNumber,lastAddress.c_str(),lastOptions.c_str(),lastNotes.c_str());
|
||||||
|
PhoneBookEntry::savePhonebook();
|
||||||
|
currState=ZIRCMENU_MAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConnSettings flags(lastOptions.c_str());
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case 'p':
|
||||||
|
flags.petscii=!flags.petscii;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
flags.telnet=!flags.telnet;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
flags.echo=!flags.echo;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if(flags.xonxoff)
|
||||||
|
{
|
||||||
|
flags.xonxoff=false;
|
||||||
|
flags.rtscts=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(flags.rtscts)
|
||||||
|
flags.rtscts=false;
|
||||||
|
else
|
||||||
|
flags.xonxoff=true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
flags.secure=!flags.secure;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
serial.printf("%sInvalid toggle option '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lastOptions = flags.getFlagString();
|
||||||
|
}
|
||||||
|
showMenu=true; // re-show the menu
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_COMMAND:
|
||||||
|
{
|
||||||
|
if(c=='/')
|
||||||
|
{
|
||||||
|
String lccmd = cmd;
|
||||||
|
lccmd.toLowerCase();
|
||||||
|
if(lccmd.startsWith("/join "))
|
||||||
|
{
|
||||||
|
int cs=5;
|
||||||
|
while((cmd.length()>cs)
|
||||||
|
&&((cmd[cs]==' ')||(cmd[cs]==7)))
|
||||||
|
cs++;
|
||||||
|
if(cs < cmd.length())
|
||||||
|
{
|
||||||
|
if(channelName.length()>0 && joinReceived)
|
||||||
|
{
|
||||||
|
serial.println("* Already in "+channelName+": Not Yet Implemented");
|
||||||
|
// we are already joined somewhere
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
channelName = cmd.substring(cs);
|
||||||
|
if(current != null)
|
||||||
|
current->print("JOIN :"+channelName+"\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
serial.println("* A channel name is required *");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(lccmd.startsWith("/quit"))
|
||||||
|
{
|
||||||
|
if(current != null)
|
||||||
|
{
|
||||||
|
current->print("QUIT Good bye!\r\n");
|
||||||
|
current->flush();
|
||||||
|
delay(1000);
|
||||||
|
current->markForDisconnect();
|
||||||
|
delete current;
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
switchBackToCommandMode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serial.println("* Unknown command: "+lccmd);
|
||||||
|
serial.println("* Try /?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((current != null)
|
||||||
|
&&(joinReceived))
|
||||||
|
current->printf("PRIVMSG %s :%s\r\n",channelName.c_str(),cmd.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZIRCMode::loopMenuMode()
|
||||||
|
{
|
||||||
|
if(showMenu)
|
||||||
|
{
|
||||||
|
showMenu=false;
|
||||||
|
switch(currState)
|
||||||
|
{
|
||||||
|
case ZIRCMENU_MAIN:
|
||||||
|
{
|
||||||
|
if(nick.length()==0)
|
||||||
|
nick = hostname;
|
||||||
|
serial.printf("%sInternet Relay Chat (IRC) Main Menu%s",EOLNC,EOLNC);
|
||||||
|
serial.printf("[NICK] name: %s%s",nick.c_str(),EOLNC);
|
||||||
|
serial.printf("[ADD] new phonebook entry%s",EOLNC);
|
||||||
|
PhoneBookEntry *p = phonebook;
|
||||||
|
if(p != null)
|
||||||
|
{
|
||||||
|
serial.printf("Phonebook entries:%s",EOLNC);
|
||||||
|
while(p != null)
|
||||||
|
{
|
||||||
|
if(strlen(p->notes)>0)
|
||||||
|
serial.printf(" [%lu] %s (%s)%s",p->number, p->address, p->notes, EOLNC);
|
||||||
|
else
|
||||||
|
serial.printf(" [%lu] %s%s",p->number, p->address, EOLNC);
|
||||||
|
p=p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serial.printf("%sEnter command, number to connect to, or ENTER to exit: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_NUM:
|
||||||
|
serial.printf("%sEnter a new fake phone number (digits ONLY)%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
case ZIRCMENU_ADDRESS:
|
||||||
|
{
|
||||||
|
serial.printf("%sEnter a new hostname:port%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_NICK:
|
||||||
|
{
|
||||||
|
serial.printf("%sEnter a new nick-name%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_OPTIONS:
|
||||||
|
{
|
||||||
|
ConnSettings flags(lastOptions.c_str());
|
||||||
|
serial.printf("%sConnection Options:%s",EOLNC,EOLNC);
|
||||||
|
serial.printf("[PETSCII] Translation: %s%s",flags.petscii?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[TELNET] Translation: %s%s",flags.telnet?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[ECHO]: %s%s",flags.echo?"ON":"OFF",EOLNC);
|
||||||
|
serial.printf("[FLOW] Control: %s%s",flags.xonxoff?"XON/XOFF":flags.rtscts?"RTS/CTS":"DISABLED",EOLNC);
|
||||||
|
serial.printf("%sEnter option to toggle or ENTER to exit%s: ",EOLNC,EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_NOTES:
|
||||||
|
{
|
||||||
|
serial.printf("%sEnter some notes for this entry (%s)%s: ",EOLNC,lastNotes.c_str(),EOLNC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCMENU_COMMAND:
|
||||||
|
{
|
||||||
|
showMenu=true; // keep coming back here, over and over and over
|
||||||
|
if((current==null)||(!current->isConnected()))
|
||||||
|
switchBackToCommandMode();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String cmd;
|
||||||
|
while((current->available()>0) && (current->isConnected()))
|
||||||
|
{
|
||||||
|
uint8_t c = current->read();
|
||||||
|
if((c == '\r')||(c == '\n')||(buf.length()>510))
|
||||||
|
{
|
||||||
|
if((c=='\r')||(c=='\n'))
|
||||||
|
{
|
||||||
|
cmd=buf;
|
||||||
|
buf="";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf="";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buf += (char)c;
|
||||||
|
}
|
||||||
|
if(cmd.length()>0)
|
||||||
|
{
|
||||||
|
if(cmd.indexOf("PING :")==0)
|
||||||
|
{
|
||||||
|
int x = cmd.indexOf(':');
|
||||||
|
if(x>0)
|
||||||
|
current->print("PONG "+cmd.substring(x+1)+"\r\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
switch(ircState)
|
||||||
|
{
|
||||||
|
case ZIRCSTATE_WAIT:
|
||||||
|
{
|
||||||
|
if(cmd.indexOf("376")>=0)
|
||||||
|
{
|
||||||
|
ircState = ZIRCSTATE_COMMAND;
|
||||||
|
//TODO: say something?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(cmd.indexOf("No Ident response")>=0)
|
||||||
|
{
|
||||||
|
current->print("NICK "+nick+"\r\n");
|
||||||
|
current->print("USER guest 0 * :"+nick+"\r\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(cmd.indexOf("433")>=0)
|
||||||
|
{
|
||||||
|
if(nick.indexOf("_____")==0)
|
||||||
|
{
|
||||||
|
ircState = ZIRCSTATE_WAIT;
|
||||||
|
delete current;
|
||||||
|
current = null;
|
||||||
|
currState = ZIRCMENU_MAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nick = "_" + nick;
|
||||||
|
current->print("NICK "+nick+"\r\n");
|
||||||
|
current->print("USER guest 0 * :"+nick+"\r\n");
|
||||||
|
// above was user nick * * : nick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(cmd.indexOf(":")==0)
|
||||||
|
{
|
||||||
|
int x = cmd.indexOf(":",1);
|
||||||
|
if(x>1)
|
||||||
|
{
|
||||||
|
serial.prints(cmd.substring(x+1));
|
||||||
|
serial.prints(EOLNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZIRCSTATE_COMMAND:
|
||||||
|
{
|
||||||
|
if((!joinReceived)
|
||||||
|
&& (channelName.length()>0)
|
||||||
|
&& (cmd.indexOf("366")>=0))
|
||||||
|
{
|
||||||
|
joinReceived=true;
|
||||||
|
serial.prints("Channel joined. Enter a message to send, or /quit.");
|
||||||
|
serial.prints(EOLNC);
|
||||||
|
}
|
||||||
|
int x0 = cmd.indexOf(":");
|
||||||
|
int x1 = (x0>=0)?cmd.indexOf(" PRIVMSG ", x0+1):-1;
|
||||||
|
x1 = (x1>0)?cmd.indexOf(":", x1+1):(x0>=0)?cmd.indexOf(":", x0+1):-1;
|
||||||
|
if(x1>0)
|
||||||
|
{
|
||||||
|
String msg2=cmd.substring(x1+1);
|
||||||
|
msg2.trim();
|
||||||
|
String msg1=cmd.substring(x0+1,x1);
|
||||||
|
msg1.trim();
|
||||||
|
int x2=msg1.indexOf("!");
|
||||||
|
if(x2>=0)
|
||||||
|
serial.print("< "+msg1.substring(0,x2)+"> "+msg2);
|
||||||
|
else
|
||||||
|
serial.prints(msg2);
|
||||||
|
serial.prints(EOLNC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
serial.prints("unknown state\n\r");
|
||||||
|
switchBackToCommandMode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(ircState == ZIRCSTATE_WAIT)
|
||||||
|
{
|
||||||
|
if(millis()>timeout)
|
||||||
|
{
|
||||||
|
timeout = millis()+60000;
|
||||||
|
current->print("NICK "+nick+"\r\n");
|
||||||
|
current->print("USER guest 0 * :"+nick+"\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(commandMode.checkPlusEscape())
|
||||||
|
{
|
||||||
|
switchBackToCommandMode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(serial.isSerialOut())
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZIRCMode::serialIncoming()
|
||||||
|
{
|
||||||
|
bool crReceived=commandMode.readSerialStream();
|
||||||
|
commandMode.clearPlusProgress(); // re-check the plus-escape mode
|
||||||
|
if(crReceived)
|
||||||
|
{
|
||||||
|
doIRCCommand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZIRCMode::loop()
|
||||||
|
{
|
||||||
|
loopMenuMode();
|
||||||
|
if(commandMode.checkPlusEscape())
|
||||||
|
{
|
||||||
|
switchBackToCommandMode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(serial.isSerialOut())
|
||||||
|
{
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* INCLUDE_IRCC */
|
|
@ -0,0 +1,417 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
Copyright 2020-2020 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
size_t ZPrint::writeStr(char *s)
|
||||||
|
{
|
||||||
|
if(outStream != null)
|
||||||
|
{
|
||||||
|
int len=strlen(s);
|
||||||
|
outStream->write((uint8_t *)s,len);
|
||||||
|
if(logFileOpen)
|
||||||
|
{
|
||||||
|
for(int i=0;i<len;i++)
|
||||||
|
logSocketOut(s[i]);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ZPrint::getLastPrinterSpec()
|
||||||
|
{
|
||||||
|
if(lastPrinterSpec==0)
|
||||||
|
return "";
|
||||||
|
return lastPrinterSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZPrint::setLastPrinterSpec(const char *spec)
|
||||||
|
{
|
||||||
|
if(lastPrinterSpec != 0)
|
||||||
|
free(lastPrinterSpec);
|
||||||
|
lastPrinterSpec = 0;
|
||||||
|
if((spec != 0) && (*spec != 0))
|
||||||
|
{
|
||||||
|
int newLen = strlen(spec);
|
||||||
|
lastPrinterSpec = (char *)malloc(newLen + 1);
|
||||||
|
strcpy(lastPrinterSpec,spec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ZPrint::getTimeoutDelayMs()
|
||||||
|
{
|
||||||
|
return timeoutDelayMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZPrint::setTimeoutDelayMs(int ms)
|
||||||
|
{
|
||||||
|
if(ms > 50)
|
||||||
|
timeoutDelayMs = ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZPrint::writeChunk(char *s, int len)
|
||||||
|
{
|
||||||
|
char buf[25];
|
||||||
|
sprintf(buf,"%x\r\n",len);
|
||||||
|
writeStr(buf);
|
||||||
|
outStream->write((uint8_t *)s,len);
|
||||||
|
if(logFileOpen)
|
||||||
|
{
|
||||||
|
for(int i=0;i<len;i++)
|
||||||
|
logSocketOut(s[i]);
|
||||||
|
}
|
||||||
|
writeStr("\r\n");
|
||||||
|
return len+strlen(buf)+4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZPrint::announcePrintJob(const char *hostIp, const int port, const char *req)
|
||||||
|
{
|
||||||
|
logPrintfln("Print Request to host=%s, port=%d",hostIp,port);
|
||||||
|
debugPrintf("Print Request to host=%s, port=%d\n",hostIp,port);
|
||||||
|
logPrintfln("Print Request is /%s",req);
|
||||||
|
debugPrintf("Print Request is /%s\n",req);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZResult ZPrint::switchToPostScript(char *prefix)
|
||||||
|
{
|
||||||
|
if((lastPrinterSpec==0)
|
||||||
|
||(strlen(lastPrinterSpec)<=5)
|
||||||
|
||(lastPrinterSpec[1]!=':'))
|
||||||
|
return ZERROR;
|
||||||
|
char *workBuf = (char *)malloc(strlen(lastPrinterSpec) +1);
|
||||||
|
strcpy(workBuf, lastPrinterSpec);
|
||||||
|
char *hostIp;
|
||||||
|
char *req;
|
||||||
|
int port;
|
||||||
|
bool doSSL;
|
||||||
|
if(!parseWebUrl((uint8_t *)workBuf+2,&hostIp,&req,&port,&doSSL))
|
||||||
|
{
|
||||||
|
free(workBuf);
|
||||||
|
return ZERROR;
|
||||||
|
}
|
||||||
|
payloadType = RAW;
|
||||||
|
announcePrintJob(hostIp,port,req);
|
||||||
|
ZResult result;
|
||||||
|
if(pinSupport[pinRTS])
|
||||||
|
s_pinWrite(pinRTS, rtsInactive);
|
||||||
|
yield();
|
||||||
|
wifiSock = new WiFiClientNode(hostIp,port,doSSL?FLAG_SECURE:0);
|
||||||
|
wifiSock->setNoDelay(false); // we want a delay in this case
|
||||||
|
outStream = wifiSock;
|
||||||
|
result = finishSwitchTo(hostIp, req, port, doSSL);
|
||||||
|
if(result == ZERROR)
|
||||||
|
{
|
||||||
|
outStream = null;
|
||||||
|
delete wifiSock;
|
||||||
|
wifiSock = null;
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
if(pinSupport[pinRTS])
|
||||||
|
s_pinWrite(pinRTS, rtsActive);
|
||||||
|
if((result != ZERROR)
|
||||||
|
&&(prefix != 0)
|
||||||
|
&&(strlen(prefix)>0))
|
||||||
|
{
|
||||||
|
writeChunk(prefix,strlen(prefix));
|
||||||
|
serialIncoming();
|
||||||
|
}
|
||||||
|
free(workBuf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZPrint::testPrinterSpec(const char *vbuf, int vlen, bool petscii)
|
||||||
|
{
|
||||||
|
char *workBuf = (char *)malloc(vlen+1);
|
||||||
|
strcpy(workBuf, vbuf);
|
||||||
|
if(petscii)
|
||||||
|
{
|
||||||
|
for(int i=0;i<vlen;i++)
|
||||||
|
workBuf[i] = petToAsc(workBuf[i]);
|
||||||
|
}
|
||||||
|
if((vlen <= 2)||(workBuf[1]!=':'))
|
||||||
|
{
|
||||||
|
free(workBuf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(workBuf[0])
|
||||||
|
{
|
||||||
|
case 'P': case 'p':
|
||||||
|
case 'A': case 'a':
|
||||||
|
case 'R': case 'r':
|
||||||
|
//yay
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
free(workBuf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char *hostIp;
|
||||||
|
char *req;
|
||||||
|
int port;
|
||||||
|
bool doSSL;
|
||||||
|
if(!parseWebUrl((uint8_t *)workBuf+2,&hostIp,&req,&port,&doSSL))
|
||||||
|
{
|
||||||
|
free(workBuf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
free(workBuf);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZResult ZPrint::switchTo(char *vbuf, int vlen, bool petscii)
|
||||||
|
{
|
||||||
|
char *workBuf = (char *)malloc(vlen+1);
|
||||||
|
strcpy(workBuf, vbuf);
|
||||||
|
if(petscii)
|
||||||
|
{
|
||||||
|
for(int i=0;i<vlen;i++)
|
||||||
|
workBuf[i] = petToAsc(workBuf[i]);
|
||||||
|
}
|
||||||
|
bool newUrl = true;
|
||||||
|
if((vlen <= 2)||(workBuf[1]!=':'))
|
||||||
|
{
|
||||||
|
if((lastPrinterSpec==0)
|
||||||
|
||(strlen(lastPrinterSpec)<=5)
|
||||||
|
||(lastPrinterSpec[1]!=':'))
|
||||||
|
{
|
||||||
|
free(workBuf);
|
||||||
|
return ZERROR;
|
||||||
|
}
|
||||||
|
if((vlen == 1)
|
||||||
|
&&(strchr("parPAR",workBuf[0])!=0))
|
||||||
|
lastPrinterSpec[0]=workBuf[0];
|
||||||
|
free(workBuf);
|
||||||
|
workBuf = (char *)malloc(strlen(lastPrinterSpec) +1);
|
||||||
|
strcpy(workBuf, lastPrinterSpec);
|
||||||
|
vlen=strlen(workBuf);
|
||||||
|
newUrl = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(workBuf[0])
|
||||||
|
{
|
||||||
|
case 'P': case 'p':
|
||||||
|
payloadType = PETSCII;
|
||||||
|
break;
|
||||||
|
case 'A': case 'a':
|
||||||
|
payloadType = ASCII;
|
||||||
|
break;
|
||||||
|
case 'R': case 'r':
|
||||||
|
payloadType = RAW;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
free(workBuf);
|
||||||
|
return ZERROR;
|
||||||
|
}
|
||||||
|
char *hostIp;
|
||||||
|
char *req;
|
||||||
|
int port;
|
||||||
|
bool doSSL;
|
||||||
|
if(!parseWebUrl((uint8_t *)workBuf+2,&hostIp,&req,&port,&doSSL))
|
||||||
|
{
|
||||||
|
free(workBuf);
|
||||||
|
return ZERROR;
|
||||||
|
}
|
||||||
|
if(newUrl)
|
||||||
|
setLastPrinterSpec(vbuf);
|
||||||
|
|
||||||
|
wifiSock = new WiFiClientNode(hostIp,port,doSSL?FLAG_SECURE:0);
|
||||||
|
wifiSock->setNoDelay(false); // we want a delay in this case
|
||||||
|
outStream = wifiSock;
|
||||||
|
announcePrintJob(hostIp,port,req);
|
||||||
|
ZResult result = finishSwitchTo(hostIp, req, port, doSSL);
|
||||||
|
free(workBuf);
|
||||||
|
if(result == ZERROR)
|
||||||
|
delete wifiSock;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZResult ZPrint::finishSwitchTo(char *hostIp, char *req, int port, bool doSSL)
|
||||||
|
{
|
||||||
|
if((wifiSock != null) && (!wifiSock->isConnected()))
|
||||||
|
return ZERROR;
|
||||||
|
char portStr[10];
|
||||||
|
sprintf(portStr,"%d",port);
|
||||||
|
// send the request and http headers:
|
||||||
|
sprintf(pbuf,"POST /%s HTTP/1.1\r\n",req);
|
||||||
|
writeStr(pbuf);
|
||||||
|
writeStr("Transfer-Encoding: chunked\r\n");
|
||||||
|
writeStr("Content-Type: application/ipp\r\n");
|
||||||
|
sprintf(pbuf,"Host: %s:%d\r\n",hostIp,port);
|
||||||
|
writeStr(pbuf);
|
||||||
|
writeStr("Connection: Keep-Alive\r\n");
|
||||||
|
writeStr("User-Agent: Zimodem\r\n");
|
||||||
|
writeStr("Accept-Encoding: gzip,deflate\r\n");
|
||||||
|
writeStr("\r\n");
|
||||||
|
outStream->flush();
|
||||||
|
// send the ipp header
|
||||||
|
if((wifiSock != null)&&(!wifiSock->isConnected()))
|
||||||
|
return ZERROR;
|
||||||
|
|
||||||
|
char jobChar1 = '0' + (jobNum / 10);
|
||||||
|
char jobChar2 = '0' + (jobNum % 10);
|
||||||
|
if(++jobNum>94)
|
||||||
|
jobNum=0;
|
||||||
|
// version operatid reqid------------------ attribtabid
|
||||||
|
sprintf(pbuf,"%c%c%c%c%c%c%c%c%c",0x01,0x01,0x00,0x02,0x00,0x00,0x00,jobNum+1,0x01);
|
||||||
|
writeChunk(pbuf,9);
|
||||||
|
sprintf(pbuf,"%c%c%cattributes-charset%c%cutf-8",0x47,0x00,0x12,0x00,0x05);
|
||||||
|
writeChunk(pbuf,28);
|
||||||
|
sprintf(pbuf,"%c%c%cattributes-natural-language%c%cen-us",0x48,0x00,0x1b,0x00,0x05);
|
||||||
|
writeChunk(pbuf,37);
|
||||||
|
|
||||||
|
int urllen = strlen(hostIp) + strlen(req)+ strlen(portStr)+9;
|
||||||
|
sprintf(pbuf,"%c%c%cprinter-uri%c%chttp://%s:%s/%s",0x45,0x00,0x0b,0x00,urllen,hostIp,portStr,req);
|
||||||
|
writeChunk(pbuf,urllen+16);
|
||||||
|
sprintf(pbuf,"%c%c%crequesting-user-name%c%czimodem",0x42,0x00,0x14,0x00,0x07);
|
||||||
|
writeChunk(pbuf,32);
|
||||||
|
sprintf(pbuf,"%c%c%cjob-name%c%czimodem-j%c%c",0x42,0x00,0x08,0x00,0x0b,jobChar1,jobChar2);
|
||||||
|
writeChunk(pbuf,24);
|
||||||
|
sprintf(pbuf,"%c%c%c%ccopies%c%c%c%c%c%c",0x02,0x21,0x00,0x06,0x00,0x04,0x00,0x00,0x00,0x01);
|
||||||
|
writeChunk(pbuf,16);
|
||||||
|
sprintf(pbuf,"%c%c%corientation-requested%c%c%c%c%c%c",0x23,0x00,0x15,0x00,0x04,0x00,0x00,0x00,0x03);
|
||||||
|
writeChunk(pbuf,30);
|
||||||
|
sprintf(pbuf,"%c%c%coutput-mode%c%cmonochrome%c",0x44,0x00,0x0b,0x00,0x0a, 0x03);
|
||||||
|
writeChunk(pbuf,27);
|
||||||
|
outStream->flush();
|
||||||
|
if((wifiSock != null)&&(!wifiSock->isConnected()))
|
||||||
|
return ZERROR;
|
||||||
|
checkOpenConnections();
|
||||||
|
checkBaudChange();
|
||||||
|
pdex=0;
|
||||||
|
coldex=0;
|
||||||
|
lastNonPlusTimeMs = 0;
|
||||||
|
plussesInARow=0;
|
||||||
|
currentExpiresTimeMs = millis()+5000;
|
||||||
|
currMode=&printMode;
|
||||||
|
return ZIGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZPrint::serialIncoming()
|
||||||
|
{
|
||||||
|
if(HWSerial.available() > 0)
|
||||||
|
{
|
||||||
|
while(HWSerial.available() > 0)
|
||||||
|
{
|
||||||
|
uint8_t c=HWSerial.read();
|
||||||
|
logSerialIn(c);
|
||||||
|
if((c==commandMode.EC)
|
||||||
|
&&(plussesInARow<3)
|
||||||
|
&&((plussesInARow>0)||((millis()-lastNonPlusTimeMs)>900)))
|
||||||
|
{
|
||||||
|
plussesInARow++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(plussesInARow > 0)
|
||||||
|
{
|
||||||
|
for(int i=0;i<plussesInARow;i++)
|
||||||
|
pbuf[pdex++]=commandMode.EC;
|
||||||
|
plussesInARow=0;
|
||||||
|
}
|
||||||
|
lastNonPlusTimeMs=millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(payloadType == PETSCII)
|
||||||
|
c=petToAsc(c);
|
||||||
|
if(payloadType != RAW)
|
||||||
|
{
|
||||||
|
if(c==0)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
if(c<32)
|
||||||
|
{
|
||||||
|
if((c=='\r')||(c=='\n'))
|
||||||
|
{
|
||||||
|
coldex=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coldex++;
|
||||||
|
if(coldex > 80)
|
||||||
|
{
|
||||||
|
pbuf[pdex++]='\n';
|
||||||
|
pbuf[pdex++]='\r';
|
||||||
|
coldex=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((lastC == '\n')&&(lastLastC!='\r'))
|
||||||
|
pbuf[pdex++]='\r';
|
||||||
|
else
|
||||||
|
if((lastC == '\r')&&(lastLastC!='\n'))
|
||||||
|
pbuf[pdex++]='\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pbuf[pdex++]=(char)c;
|
||||||
|
lastLastC=lastC;
|
||||||
|
lastC=c;
|
||||||
|
if(pdex>=250)
|
||||||
|
{
|
||||||
|
if(((wifiSock!=null)&&(wifiSock->isConnected()))
|
||||||
|
||((wifiSock==null)&&(outStream!=null)))
|
||||||
|
{
|
||||||
|
writeChunk(pbuf,pdex);
|
||||||
|
//wifiSock->flush();
|
||||||
|
}
|
||||||
|
pdex=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(plussesInARow == 3)
|
||||||
|
currentExpiresTimeMs = millis()+900;
|
||||||
|
else
|
||||||
|
currentExpiresTimeMs = millis()+timeoutDelayMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZPrint::switchBackToCommandMode(bool error)
|
||||||
|
{
|
||||||
|
if((wifiSock != null)||(outStream!=null))
|
||||||
|
{
|
||||||
|
if(error)
|
||||||
|
commandMode.sendOfficialResponse(ZERROR);
|
||||||
|
else
|
||||||
|
commandMode.sendOfficialResponse(ZOK);
|
||||||
|
if(wifiSock != null)
|
||||||
|
delete wifiSock;
|
||||||
|
}
|
||||||
|
wifiSock = null;
|
||||||
|
outStream = null;
|
||||||
|
currMode = &commandMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZPrint::loop()
|
||||||
|
{
|
||||||
|
if(((wifiSock==null)&&(outStream==null))
|
||||||
|
|| ((wifiSock!=null)&&(!wifiSock->isConnected())))
|
||||||
|
{
|
||||||
|
debugPrintf("No printer connection\n");
|
||||||
|
switchBackToCommandMode(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(millis()>currentExpiresTimeMs)
|
||||||
|
{
|
||||||
|
debugPrintf("Time-out in printing\n");
|
||||||
|
if(pdex > 0)
|
||||||
|
writeChunk(pbuf,pdex);
|
||||||
|
writeStr("0\r\n\r\n");
|
||||||
|
outStream->flush();
|
||||||
|
switchBackToCommandMode(false);
|
||||||
|
}
|
||||||
|
checkBaudChange();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
/*
|
||||||
|
* zslipmode.ino
|
||||||
|
*
|
||||||
|
* Created on: May 17, 2022
|
||||||
|
* Author: Bo Zimmerman
|
||||||
|
*/
|
||||||
|
#ifdef INCLUDE_SLIP
|
||||||
|
|
||||||
|
void ZSLIPMode::switchBackToCommandMode()
|
||||||
|
{
|
||||||
|
currMode = &commandMode;
|
||||||
|
//TODO: UNDO THIS: raw_recv(_pcb, &_raw_recv, (void *) _pcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSLIPMode::switchTo()
|
||||||
|
{
|
||||||
|
uint8_t num_slip1 = 0;
|
||||||
|
struct netif slipif1;
|
||||||
|
ip4_addr_t ipaddr_slip1, netmask_slip1, gw_slip1;
|
||||||
|
//LWIP_PORT_INIT_SLIP1_IPADDR(&ipaddr_slip1);
|
||||||
|
//LWIP_PORT_INIT_SLIP1_GW(&gw_slip1);
|
||||||
|
//LWIP_PORT_INIT_SLIP1_NETMASK(&netmask_slip1);
|
||||||
|
//printf("Starting lwIP slipif, local interface IP is %s\n", ip4addr_ntoa(&ipaddr_slip1));
|
||||||
|
|
||||||
|
netif_add(&slipif1, &ipaddr_slip1, &netmask_slip1, &gw_slip1, &num_slip1, slipif_init, ip_input);
|
||||||
|
|
||||||
|
sserial.setFlowControlType(FCT_DISABLED);
|
||||||
|
if(commandMode.getFlowControlType()==FCT_RTSCTS)
|
||||||
|
sserial.setFlowControlType(FCT_RTSCTS);
|
||||||
|
sserial.setPetsciiMode(false);
|
||||||
|
sserial.setXON(true);
|
||||||
|
|
||||||
|
inPacket="";
|
||||||
|
started=false;
|
||||||
|
escaped=false;
|
||||||
|
if(_pcb == 0)
|
||||||
|
{
|
||||||
|
_pcb = raw_new(IP_PROTO_TCP);
|
||||||
|
if(!_pcb){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//_lock = xSemaphoreCreateMutex();
|
||||||
|
raw_recv(_pcb, &_raw_recv, (void *) _pcb);
|
||||||
|
currMode=&slipMode;
|
||||||
|
debugPrintf("Switched to SLIP mode\n\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
static String encodeSLIP(uint8_t *ipPacket, int ipLen)
|
||||||
|
{
|
||||||
|
String slip;
|
||||||
|
slip += ZSLIPMode::SLIP_END;
|
||||||
|
for(int i=0;i<ipLen;i++)
|
||||||
|
{
|
||||||
|
if(ipPacket[i] == ZSLIPMode::SLIP_END)
|
||||||
|
slip += ZSLIPMode::SLIP_ESC + ZSLIPMode::SLIP_ESC_END;
|
||||||
|
else
|
||||||
|
if(ipPacket[i] == ZSLIPMode::SLIP_ESC)
|
||||||
|
slip += ZSLIPMode::SLIP_ESC + ZSLIPMode::SLIP_ESC_ESC;
|
||||||
|
else
|
||||||
|
slip += ipPacket[i];
|
||||||
|
}
|
||||||
|
slip += ZSLIPMode::SLIP_END;
|
||||||
|
return slip;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t _raw_recv(void *arg, raw_pcb *pcb, pbuf *pb, const ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
while(pb != NULL)
|
||||||
|
{
|
||||||
|
pbuf * this_pb = pb;
|
||||||
|
pb = pb->next;
|
||||||
|
this_pb->next = NULL;
|
||||||
|
for(int i=0;i<this_pb->len;i+=4)
|
||||||
|
{
|
||||||
|
String pkt = encodeSLIP((uint8_t *)this_pb->payload, this_pb->len);
|
||||||
|
int plen = pkt.length();
|
||||||
|
if(plen > 0)
|
||||||
|
{
|
||||||
|
if(logFileOpen)
|
||||||
|
logPrintln("SLIP-in packet:");
|
||||||
|
uint8_t *buf = (uint8_t *)pkt.c_str();
|
||||||
|
for(int p=0;p<plen;p++)
|
||||||
|
{
|
||||||
|
if(logFileOpen)
|
||||||
|
logSocketIn(buf[p]);
|
||||||
|
sserial.printb(buf[p]);
|
||||||
|
if(sserial.isSerialOut())
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
if(sserial.isSerialOut())
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//pbuf_free(this_pb); // at this point, there are no refs, so errs out.
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSLIPMode::serialIncoming()
|
||||||
|
{
|
||||||
|
while(HWSerial.available()>0)
|
||||||
|
{
|
||||||
|
uint8_t c = HWSerial.read();
|
||||||
|
if(logFileOpen)
|
||||||
|
logSerialIn(c);
|
||||||
|
if (c == SLIP_END)
|
||||||
|
{
|
||||||
|
if(started)
|
||||||
|
{
|
||||||
|
if(inPacket.length()>0)
|
||||||
|
{
|
||||||
|
if(logFileOpen)
|
||||||
|
logPrintln("SLIP-out packet.");
|
||||||
|
struct pbuf p = { 0 };
|
||||||
|
p.next = NULL;
|
||||||
|
p.payload = (void *)inPacket.c_str();
|
||||||
|
p.len = inPacket.length();
|
||||||
|
p.tot_len = inPacket.length();
|
||||||
|
raw_send(_pcb, &p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
started=true;
|
||||||
|
inPacket="";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c == SLIP_ESC)
|
||||||
|
escaped=true;
|
||||||
|
else
|
||||||
|
if(c == SLIP_ESC_END)
|
||||||
|
{
|
||||||
|
if(escaped)
|
||||||
|
{
|
||||||
|
inPacket += SLIP_END;
|
||||||
|
escaped = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
inPacket += c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(c == SLIP_ESC_ESC)
|
||||||
|
{
|
||||||
|
if(escaped)
|
||||||
|
{
|
||||||
|
inPacket += SLIP_ESC;
|
||||||
|
escaped=false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
inPacket += c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(escaped)
|
||||||
|
{
|
||||||
|
debugPrintf("SLIP Protocol Error\n");
|
||||||
|
if(logFileOpen)
|
||||||
|
logPrintln("SLIP error.");
|
||||||
|
inPacket="";
|
||||||
|
escaped=false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inPacket += c;
|
||||||
|
started=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSLIPMode::loop()
|
||||||
|
{
|
||||||
|
if(sserial.isSerialOut())
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* INCLUDE_SLIP_ */
|
|
@ -0,0 +1,316 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2019 Bo Zimmerman
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ZStream::switchTo(WiFiClientNode *conn)
|
||||||
|
{
|
||||||
|
current = conn;
|
||||||
|
currentExpiresTimeMs = 0;
|
||||||
|
lastNonPlusTimeMs = 0;
|
||||||
|
plussesInARow=0;
|
||||||
|
serial.setXON(true);
|
||||||
|
serial.setPetsciiMode(isPETSCII());
|
||||||
|
serial.setFlowControlType(getFlowControl());
|
||||||
|
currMode=&streamMode;
|
||||||
|
checkBaudChange();
|
||||||
|
if(pinSupport[pinDTR])
|
||||||
|
lastDTR = digitalRead(pinDTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZStream::isPETSCII()
|
||||||
|
{
|
||||||
|
return (current != null) && (current->isPETSCII());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZStream::isEcho()
|
||||||
|
{
|
||||||
|
return (current != null) && (current->isEcho());
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowControlType ZStream::getFlowControl()
|
||||||
|
{
|
||||||
|
return (current != null) ? (current->getFlowControl()) : FCT_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZStream::isTelnet()
|
||||||
|
{
|
||||||
|
return (current != null) && (current->isTelnet());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZStream::isDisconnectedOnStreamExit()
|
||||||
|
{
|
||||||
|
return (current != null) && (current->isDisconnectedOnStreamExit());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZStream::baudDelay()
|
||||||
|
{
|
||||||
|
if(baudRate<1200)
|
||||||
|
delay(5);
|
||||||
|
else
|
||||||
|
if(baudRate==1200)
|
||||||
|
delay(3);
|
||||||
|
else
|
||||||
|
delay(1);
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZStream::serialIncoming()
|
||||||
|
{
|
||||||
|
int bytesAvailable = HWSerial.available();
|
||||||
|
if(bytesAvailable == 0)
|
||||||
|
return;
|
||||||
|
uint8_t escBufDex = 0;
|
||||||
|
while(--bytesAvailable >= 0)
|
||||||
|
{
|
||||||
|
uint8_t c=HWSerial.read();
|
||||||
|
if(((c==27)||(escBufDex>0))
|
||||||
|
&&(!isPETSCII()))
|
||||||
|
{
|
||||||
|
escBuf[escBufDex++] = c;
|
||||||
|
if(((c>='a')&&(c<='z'))
|
||||||
|
||((c>='A')&&(c<='Z'))
|
||||||
|
||(escBufDex>=ZSTREAM_ESC_BUF_MAX)
|
||||||
|
||((escBufDex==2)&&(c!='[')))
|
||||||
|
{
|
||||||
|
logSerialIn(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(bytesAvailable==0)
|
||||||
|
{
|
||||||
|
baudDelay();
|
||||||
|
bytesAvailable=HWSerial.available();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logSerialIn(c);
|
||||||
|
if((c==commandMode.EC)
|
||||||
|
&&((plussesInARow>0)||((millis()-lastNonPlusTimeMs)>800)))
|
||||||
|
plussesInARow++;
|
||||||
|
else
|
||||||
|
if(c!=commandMode.EC)
|
||||||
|
{
|
||||||
|
plussesInARow=0;
|
||||||
|
lastNonPlusTimeMs=millis();
|
||||||
|
}
|
||||||
|
if((c==19)&&(getFlowControl()==FCT_NORMAL))
|
||||||
|
serial.setXON(false);
|
||||||
|
else
|
||||||
|
if((c==17)&&(getFlowControl()==FCT_NORMAL))
|
||||||
|
serial.setXON(true);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(isEcho())
|
||||||
|
serial.printb(c);
|
||||||
|
if(isPETSCII())
|
||||||
|
c = petToAsc(c);
|
||||||
|
if(escBufDex==0)
|
||||||
|
socketWrite(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(escBufDex>0)
|
||||||
|
socketWrite(escBuf,escBufDex);
|
||||||
|
currentExpiresTimeMs = 0;
|
||||||
|
if(plussesInARow==3)
|
||||||
|
currentExpiresTimeMs=millis()+800;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZStream::switchBackToCommandMode(bool logout)
|
||||||
|
{
|
||||||
|
if(logout && (current != null) && isDisconnectedOnStreamExit())
|
||||||
|
{
|
||||||
|
if(!commandMode.suppressResponses)
|
||||||
|
{
|
||||||
|
if(commandMode.numericResponses)
|
||||||
|
{
|
||||||
|
preEOLN(commandMode.EOLN);
|
||||||
|
serial.prints("3");
|
||||||
|
serial.prints(commandMode.EOLN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(current->isAnswered())
|
||||||
|
{
|
||||||
|
preEOLN(commandMode.EOLN);
|
||||||
|
serial.prints("NO CARRIER");
|
||||||
|
serial.prints(commandMode.EOLN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete current;
|
||||||
|
}
|
||||||
|
current = null;
|
||||||
|
currMode = &commandMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZStream::socketWrite(uint8_t *buf, uint8_t len)
|
||||||
|
{
|
||||||
|
if(current->isConnected())
|
||||||
|
{
|
||||||
|
uint8_t escapedBuf[len*2];
|
||||||
|
if(isTelnet())
|
||||||
|
{
|
||||||
|
int eDex=0;
|
||||||
|
for(int i=0;i<len;i++)
|
||||||
|
{
|
||||||
|
escapedBuf[eDex++] = buf[i];
|
||||||
|
if(buf[i]==0xff)
|
||||||
|
escapedBuf[eDex++] = buf[i];
|
||||||
|
}
|
||||||
|
buf=escapedBuf;
|
||||||
|
len=eDex;
|
||||||
|
}
|
||||||
|
for(int i=0;i<len;i++)
|
||||||
|
logSocketOut(buf[i]);
|
||||||
|
current->write(buf,len);
|
||||||
|
nextFlushMs=millis()+250;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZStream::socketWrite(uint8_t c)
|
||||||
|
{
|
||||||
|
if(current->isConnected())
|
||||||
|
{
|
||||||
|
if(c == 0xFF && isTelnet())
|
||||||
|
current->write(c);
|
||||||
|
current->write(c);
|
||||||
|
logSocketOut(c);
|
||||||
|
nextFlushMs=millis()+250;
|
||||||
|
//current->flush(); // rendered safe by available check
|
||||||
|
//delay(0);
|
||||||
|
//yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZStream::loop()
|
||||||
|
{
|
||||||
|
WiFiServerNode *serv = servs;
|
||||||
|
while(serv != null)
|
||||||
|
{
|
||||||
|
if(serv->hasClient())
|
||||||
|
{
|
||||||
|
WiFiClient newClient = serv->server->available();
|
||||||
|
if(newClient.connected())
|
||||||
|
{
|
||||||
|
int port=newClient.localPort();
|
||||||
|
String remoteIPStr = newClient.remoteIP().toString();
|
||||||
|
const char *remoteIP=remoteIPStr.c_str();
|
||||||
|
bool found=false;
|
||||||
|
WiFiClientNode *c=conns;
|
||||||
|
while(c!=null)
|
||||||
|
{
|
||||||
|
if((c->isConnected())
|
||||||
|
&&(c->port==port)
|
||||||
|
&&(strcmp(remoteIP,c->host)==0))
|
||||||
|
found=true;
|
||||||
|
c=c->next;
|
||||||
|
}
|
||||||
|
if(!found)
|
||||||
|
new WiFiClientNode(newClient, serv->flagsBitmap, 5); // constructing is enough
|
||||||
|
// else // auto disconnect when from same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serv=serv->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientNode *conn = conns;
|
||||||
|
unsigned long now=millis();
|
||||||
|
while(conn != null)
|
||||||
|
{
|
||||||
|
WiFiClientNode *nextConn = conn->next;
|
||||||
|
if((!conn->isAnswered())
|
||||||
|
&&(conn->isConnected())
|
||||||
|
&&(conn!=current)
|
||||||
|
&&(!conn->isMarkedForDisconnect()))
|
||||||
|
{
|
||||||
|
conn->write((uint8_t *)busyMsg.c_str(), busyMsg.length());
|
||||||
|
conn->flushAlways();
|
||||||
|
conn->markForDisconnect();
|
||||||
|
}
|
||||||
|
conn = nextConn;
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientNode::checkForAutoDisconnections();
|
||||||
|
|
||||||
|
if(pinSupport[pinDTR])
|
||||||
|
{
|
||||||
|
if(lastDTR==dtrActive)
|
||||||
|
{
|
||||||
|
lastDTR = digitalRead(pinDTR);
|
||||||
|
if((lastDTR==dtrInactive)
|
||||||
|
&&(dtrInactive != dtrActive))
|
||||||
|
{
|
||||||
|
if(current != null)
|
||||||
|
current->setDisconnectOnStreamExit(true);
|
||||||
|
switchBackToCommandMode(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastDTR = digitalRead(pinDTR);
|
||||||
|
}
|
||||||
|
if((current==null)||(!current->isConnected()))
|
||||||
|
{
|
||||||
|
switchBackToCommandMode(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if((currentExpiresTimeMs > 0) && (millis() > currentExpiresTimeMs))
|
||||||
|
{
|
||||||
|
currentExpiresTimeMs = 0;
|
||||||
|
if(plussesInARow == 3)
|
||||||
|
{
|
||||||
|
plussesInARow=0;
|
||||||
|
if(current != 0)
|
||||||
|
{
|
||||||
|
commandMode.sendOfficialResponse(ZOK);
|
||||||
|
switchBackToCommandMode(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(serial.isSerialOut())
|
||||||
|
{
|
||||||
|
if(current->available()>0)
|
||||||
|
//&&(current->isConnected()) // not a requirement to have available bytes to read
|
||||||
|
{
|
||||||
|
int bufferRemaining=serialOutBufferBytesRemaining();
|
||||||
|
if(bufferRemaining > 0)
|
||||||
|
{
|
||||||
|
int bytesAvailable = current->available();
|
||||||
|
if(bytesAvailable > bufferRemaining)
|
||||||
|
bytesAvailable = bufferRemaining;
|
||||||
|
if(bytesAvailable>0)
|
||||||
|
{
|
||||||
|
for(int i=0;(i<bytesAvailable) && (current->available()>0);i++)
|
||||||
|
{
|
||||||
|
if(serial.isSerialCancelled())
|
||||||
|
break;
|
||||||
|
uint8_t c=current->read();
|
||||||
|
logSocketIn(c);
|
||||||
|
if((!isTelnet() || handleAsciiIAC((char *)&c,current))
|
||||||
|
&& (!isPETSCII() || ascToPet((char *)&c,current)))
|
||||||
|
serial.printb(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(serial.isSerialOut())
|
||||||
|
{
|
||||||
|
if((nextFlushMs > 0) && (millis() > nextFlushMs))
|
||||||
|
{
|
||||||
|
nextFlushMs = 0;
|
||||||
|
serial.flush();
|
||||||
|
}
|
||||||
|
serialOutDeque();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkBaudChange();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
Loading…
Reference in New Issue