initial import

This commit is contained in:
Kyle Isom 2023-10-03 18:20:30 -07:00
commit 1092c73986
96 changed files with 46170 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.pio

39
include/README Normal file
View File

@ -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

47
include/connSettings.h Normal file
View File

@ -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);
};

48
include/filelog.h Normal file
View File

@ -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);

75
include/pet2asc.h Normal file
View File

@ -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;
}

35
include/phonebook.h Normal file
View File

@ -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);
};

44
include/proto_ftp.h Normal file
View File

@ -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

84
include/proto_hostcm.h Normal file
View File

@ -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

22
include/proto_http.h Normal file
View File

@ -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

155
include/proto_kermit.h Normal file
View File

@ -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;
}

21
include/proto_ping.h Normal file
View File

@ -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

140
include/proto_xmodem.h Normal file
View File

@ -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;
}

504
include/proto_zmodem.h Normal file
View File

@ -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

174
include/rt_clock.h Normal file
View File

@ -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();
};

91
include/serout.h Normal file
View File

@ -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

27
include/stringstream.h Normal file
View File

@ -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_

123
include/wificlientnode.h Normal file
View File

@ -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();
};

52
include/wifiservernode.h Normal file
View File

@ -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 &copy);
~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();
};

79
include/wifisshclient.h Normal file
View File

@ -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

61
include/zbrowser.h Normal file
View File

@ -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

202
include/zcommand.h Normal file
View File

@ -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();
};

67
include/zconfigmode.h Normal file
View File

@ -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();
};

34
include/zhostcmmode.h Normal file
View File

@ -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

54
include/zircmode.h Normal file
View File

@ -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 */

66
include/zprint.h Normal file
View File

@ -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();
};

34
include/zslipmode.h Normal file
View File

@ -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_ */

51
include/zstream.h Normal file
View File

@ -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();
};

46
lib/README Normal file
View File

@ -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

114
lib/libssh2/agent.h Normal file
View File

@ -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

185
lib/libssh2/bcrypt_pbkdf.c Normal file
View File

@ -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

88
lib/libssh2/blf.h Normal file
View File

@ -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

696
lib/libssh2/blowfish.c Normal file
View File

@ -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

2908
lib/libssh2/channel.c Normal file

File diff suppressed because it is too large Load Diff

143
lib/libssh2/channel.h Normal file
View File

@ -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

379
lib/libssh2/comp.c Normal file
View File

@ -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

46
lib/libssh2/comp.h Normal file
View File

@ -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

353
lib/libssh2/crypt.c Normal file
View File

@ -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

338
lib/libssh2/crypto.h Normal file
View File

@ -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

80
lib/libssh2/global.c Normal file
View File

@ -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

1389
lib/libssh2/hostkey.c Normal file

File diff suppressed because it is too large Load Diff

102
lib/libssh2/keepalive.c Normal file
View File

@ -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

4165
lib/libssh2/kex.c Normal file

File diff suppressed because it is too large Load Diff

240
lib/libssh2/libgcrypt.h Normal file
View File

@ -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

1418
lib/libssh2/libssh2.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

1172
lib/libssh2/libssh2_priv.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

353
lib/libssh2/libssh2_sftp.h Normal file
View File

@ -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

416
lib/libssh2/mac.c Normal file
View File

@ -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

68
lib/libssh2/mac.h Normal file
View File

@ -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

1445
lib/libssh2/mbedtls.c Normal file

File diff suppressed because it is too large Load Diff

611
lib/libssh2/mbedtls.h Normal file
View File

@ -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

932
lib/libssh2/misc.c Normal file
View File

@ -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

133
lib/libssh2/misc.h Normal file
View File

@ -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

445
lib/libssh2/openssl.h Normal file
View File

@ -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

1409
lib/libssh2/packet.c Normal file

File diff suppressed because it is too large Load Diff

78
lib/libssh2/packet.h Normal file
View File

@ -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

913
lib/libssh2/pem.c Normal file
View File

@ -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

1860
lib/libssh2/session.c Normal file

File diff suppressed because it is too large Load Diff

95
lib/libssh2/session.h Normal file
View File

@ -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

240
lib/libssh2/sftp.h Normal file
View File

@ -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

933
lib/libssh2/transport.c Normal file
View File

@ -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

88
lib/libssh2/transport.h Normal file
View File

@ -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

2348
lib/libssh2/userauth.c Normal file

File diff suppressed because it is too large Load Diff

53
lib/libssh2/userauth.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

572
lib/missing/slipif.c Normal file
View File

@ -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 */

86
lib/missing/slipif.h Normal file
View File

@ -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 */

15
platformio.ini Normal file
View File

@ -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 =

140
src/connSettings.ino Normal file
View File

@ -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]);
}

284
src/filelog.ino Normal file
View File

@ -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);
}
}

350
src/pet2asc.ino Normal file
View File

@ -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);
}

191
src/phonebook.ino Normal file
View File

@ -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 **)&notes);
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();
}
}

542
src/proto_ftp.ino Normal file
View File

@ -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

691
src/proto_hostcm.ino Normal file
View File

@ -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

399
src/proto_http.ino Normal file
View File

@ -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);
}

818
src/proto_kermit.ino Normal file
View File

@ -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

90
src/proto_ping.ino Normal file
View File

@ -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

364
src/proto_xmodem.ino Normal file
View File

@ -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

2433
src/proto_zmodem.ino Normal file

File diff suppressed because it is too large Load Diff

703
src/rt_clock.ino Normal file
View File

@ -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;
}

455
src/serout.ino Normal file
View File

@ -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();
}

506
src/wificlientnode.ino Normal file
View File

@ -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);
}
}

291
src/wifiservernode.ino Normal file
View File

@ -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 &copy)
{
port=copy.port;
flagsBitmap = copy.flagsBitmap;
setCharArray(&delimiters,copy.delimiters);
setCharArray(&maskOuts,copy.maskOuts);
setCharArray(&stateMachine,copy.stateMachine);
}
WiFiServerSpec& WiFiServerSpec::operator=(const WiFiServerSpec &copy)
{
if(this != &copy)
{
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();
}
}

302
src/wifisshclient.ino Normal file
View File

@ -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

1178
src/zbrowser.ino Normal file

File diff suppressed because it is too large Load Diff

3798
src/zcommand.ino Normal file

File diff suppressed because it is too large Load Diff

875
src/zconfigmode.ino Normal file
View File

@ -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();
}
}

48
src/zhostcmmode.ino Normal file
View File

@ -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

560
src/zimodem.ino Normal file
View File

@ -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();
}

539
src/zircmode.ino Normal file
View File

@ -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 */

417
src/zprint.ino Normal file
View File

@ -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();
}

176
src/zslipmode.ino Normal file
View File

@ -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_ */

316
src/zstream.ino Normal file
View File

@ -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();
}

11
test/README Normal file
View File

@ -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