mirror of
https://github.com/eddyem/tty_term.git
synced 2026-01-31 20:35:15 +03:00
Add sockets support & dump to file
This commit is contained in:
parent
c03d11e7b6
commit
c8028d6156
@ -1,19 +1,18 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
set(PROJ tty_term)
|
set(PROJ tty_term)
|
||||||
set(MINOR_VERSION "1")
|
set(MINOR_VERSION "0")
|
||||||
set(MID_VERSION "0")
|
set(MID_VERSION "1")
|
||||||
set(MAJOR_VERSION "0")
|
set(MAJOR_VERSION "0")
|
||||||
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
|
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
|
||||||
|
|
||||||
project(${PROJ} VERSION ${PROJ_VERSION} LANGUAGES C)
|
project(${PROJ} VERSION ${VERSION} LANGUAGES C)
|
||||||
#enable_language(C)
|
|
||||||
|
|
||||||
message("VER: ${VERSION}")
|
message("VER: ${VERSION}")
|
||||||
|
|
||||||
# default flags
|
# default flags
|
||||||
set(CMAKE_C_FLAGS_RELEASE "")
|
set(CMAKE_C_FLAGS_RELEASE "")
|
||||||
set(CMAKE_C_FLAGS_DEBUG "")
|
set(CMAKE_C_FLAGS_DEBUG "")
|
||||||
set(CMAKE_C_FLAGS "-O2 -std=gnu99")
|
set(CMAKE_C_FLAGS "-O3 -std=gnu99")
|
||||||
|
|
||||||
set(CMAKE_COLOR_MAKEFILE ON)
|
set(CMAKE_COLOR_MAKEFILE ON)
|
||||||
|
|
||||||
|
|||||||
@ -20,8 +20,9 @@
|
|||||||
#include <assert.h> // assert
|
#include <assert.h> // assert
|
||||||
#include <stdio.h> // printf
|
#include <stdio.h> // printf
|
||||||
#include <string.h> // memcpy
|
#include <string.h> // memcpy
|
||||||
#include <usefull_macros.h>
|
|
||||||
#include "cmdlnopts.h"
|
#include "cmdlnopts.h"
|
||||||
|
#include "dbg.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* here are global parameters initialisation
|
* here are global parameters initialisation
|
||||||
@ -33,7 +34,6 @@ static glob_pars G;
|
|||||||
// default global parameters
|
// default global parameters
|
||||||
glob_pars const Gdefault = {
|
glob_pars const Gdefault = {
|
||||||
.speed = 9600,
|
.speed = 9600,
|
||||||
.ttyname = "/dev/ttyUSB0",
|
|
||||||
.eol = "n",
|
.eol = "n",
|
||||||
.tmoutms = 100,
|
.tmoutms = 100,
|
||||||
};
|
};
|
||||||
@ -46,9 +46,12 @@ static myoption cmdlnopts[] = {
|
|||||||
// set 1 to param despite of its repeating number:
|
// set 1 to param despite of its repeating number:
|
||||||
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")},
|
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")},
|
||||||
{"speed", NEED_ARG, NULL, 's', arg_int, APTR(&G.speed), _("baudrate (default: 9600)")},
|
{"speed", NEED_ARG, NULL, 's', arg_int, APTR(&G.speed), _("baudrate (default: 9600)")},
|
||||||
{"devname", NEED_ARG, NULL, 'd', arg_string, APTR(&G.ttyname), _("serial device name")},
|
{"name", NEED_ARG, NULL, 'n', arg_string, APTR(&G.ttyname), _("serial device path or server name/IP")},
|
||||||
{"eol", NEED_ARG, NULL, 'e', arg_string, APTR(&G.eol), _("end of line: n (default), r, nr or rn")},
|
{"eol", NEED_ARG, NULL, 'e', arg_string, APTR(&G.eol), _("end of line: n (default), r, nr or rn")},
|
||||||
{"timeout", NEED_ARG, NULL, 't', arg_int, APTR(&G.tmoutms), _("timeout for select() in ms (default: 100)")},
|
{"timeout", NEED_ARG, NULL, 't', arg_int, APTR(&G.tmoutms), _("timeout for select() in ms (default: 100)")},
|
||||||
|
{"port", NEED_ARG, NULL, 'p', arg_string, APTR(&G.port), _("socket port (none for UNIX)")},
|
||||||
|
{"socket", NO_ARGS, NULL, 'S', arg_int, APTR(&G.socket), _("open socket")},
|
||||||
|
{"dumpfile",NEED_ARG, NULL, 'd', arg_string, APTR(&G.dumpfile), _("dump data to this file")},
|
||||||
end_option
|
end_option
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -26,8 +26,11 @@
|
|||||||
typedef struct{
|
typedef struct{
|
||||||
int speed; // baudrate
|
int speed; // baudrate
|
||||||
int tmoutms; // timeout for select() in ms
|
int tmoutms; // timeout for select() in ms
|
||||||
|
int socket; // open socket
|
||||||
|
char *dumpfile; // file to save dump
|
||||||
char *ttyname; // device name
|
char *ttyname; // device name
|
||||||
char *eol; // end of line: \r (CR), \rn (CR+LF) or \n (LF): "r", "rn", "n"
|
char *eol; // end of line: \r (CR), \rn (CR+LF) or \n (LF): "r", "rn", "n"
|
||||||
|
char *port; // socket port
|
||||||
} glob_pars;
|
} glob_pars;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
41
dbg.h
Normal file
41
dbg.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the ttyterm project.
|
||||||
|
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef DBG_H__
|
||||||
|
#define DBG_H__
|
||||||
|
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#ifdef EBUG
|
||||||
|
#undef DBG
|
||||||
|
#undef FNAME
|
||||||
|
#undef ERR
|
||||||
|
#undef ERRX
|
||||||
|
//#undef WARN
|
||||||
|
#undef WARNX
|
||||||
|
#define FNAME() do{LOGDBG("%s (%s, line %d)", __func__, __FILE__, __LINE__);}while(0)
|
||||||
|
#define DBG(...) do{LOGDBG("%s (%s, line %d):", __func__, __FILE__, __LINE__); \
|
||||||
|
LOGDBGADD(__VA_ARGS__);} while(0)
|
||||||
|
#define ERR(...) do{LOGERR(__VA_ARGS__); signals(9);}while(0)
|
||||||
|
#define ERRX(...) do{LOGERR(__VA_ARGS__); signals(9);}while(0)
|
||||||
|
//#define WARN(...) do{LOGWARN(__VA_ARGS__);}while(0)
|
||||||
|
#define WARNX(...) do{LOGWARN(__VA_ARGS__);}while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // DBG_H__
|
||||||
82
main.c
82
main.c
@ -19,43 +19,31 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h> // strcmp
|
#include <string.h> // strcmp
|
||||||
#include <usefull_macros.h>
|
|
||||||
#include "cmdlnopts.h"
|
#include "cmdlnopts.h"
|
||||||
#include "ncurses_and_readline.h"
|
#include "ncurses_and_readline.h"
|
||||||
#include "tty.h"
|
#include "ttysocket.h"
|
||||||
|
|
||||||
#define BUFLEN 4096
|
#include "dbg.h"
|
||||||
|
|
||||||
static ttyd dtty = {.dev = NULL, .mutex = PTHREAD_MUTEX_INITIALIZER};
|
static chardevice conndev = {.dev = NULL, .mutex = PTHREAD_MUTEX_INITIALIZER, .name = NULL, .type = DEV_TTY};
|
||||||
|
|
||||||
//FILE *fd;
|
|
||||||
|
|
||||||
void signals(int signo){
|
void signals(int signo){
|
||||||
signal(signo, SIG_IGN);
|
signal(signo, SIG_IGN);
|
||||||
if(dtty.dev){
|
closedev(&conndev);
|
||||||
pthread_mutex_unlock(&dtty.mutex);
|
|
||||||
pthread_mutex_trylock(&dtty.mutex);
|
|
||||||
close_tty(&dtty.dev);
|
|
||||||
}
|
|
||||||
//fprintf(fd, "stop\n");
|
|
||||||
//fflush(fd);
|
|
||||||
deinit_ncurses();
|
deinit_ncurses();
|
||||||
deinit_readline();
|
deinit_readline();
|
||||||
|
DBG("Exit");
|
||||||
exit(signo);
|
exit(signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv){
|
||||||
glob_pars *G = NULL; // default parameters see in cmdlnopts.c
|
glob_pars *G = NULL; // default parameters see in cmdlnopts.c
|
||||||
initial_setup();
|
initial_setup();
|
||||||
|
#ifdef EBUG
|
||||||
|
OPENLOG("debug.log", LOGLEVEL_ANY, 1);
|
||||||
|
#endif
|
||||||
G = parse_args(argc, argv);
|
G = parse_args(argc, argv);
|
||||||
if(G->tmoutms < 0) ERRX("Timeout should be >= 0");
|
if(G->tmoutms < 0) ERRX("Timeout should be >= 0");
|
||||||
dtty.dev = new_tty(G->ttyname, G->speed, BUFLEN);
|
|
||||||
if(!dtty.dev || !(dtty.dev = tty_open(dtty.dev, 1))){
|
|
||||||
WARN("Can't open device %s", G->ttyname);
|
|
||||||
signals(1);
|
|
||||||
}
|
|
||||||
//fd = fopen("loglog", "w");
|
|
||||||
//fprintf(fd, "start\n");
|
|
||||||
const char *EOL = "\n", *seol = "\\n";
|
const char *EOL = "\n", *seol = "\\n";
|
||||||
if(strcasecmp(G->eol, "n")){
|
if(strcasecmp(G->eol, "n")){
|
||||||
if(strcasecmp(G->eol, "r") == 0){ EOL = "\r"; seol = "\\r"; }
|
if(strcasecmp(G->eol, "r") == 0){ EOL = "\r"; seol = "\\r"; }
|
||||||
@ -63,10 +51,27 @@ int main(int argc, char **argv){
|
|||||||
else if(strcasecmp(G->eol, "nr") == 0){ EOL = "\n\r"; seol = "\\n\\r"; }
|
else if(strcasecmp(G->eol, "nr") == 0){ EOL = "\n\r"; seol = "\\n\\r"; }
|
||||||
else ERRX("End of line should be \"r\", \"n\" or \"rn\" or \"nr\"");
|
else ERRX("End of line should be \"r\", \"n\" or \"rn\" or \"nr\"");
|
||||||
}
|
}
|
||||||
strcpy(dtty.eol, EOL);
|
strcpy(conndev.eol, EOL);
|
||||||
strcpy(dtty.seol, seol);
|
strcpy(conndev.seol, seol);
|
||||||
int eollen = strlen(EOL);
|
int eollen = strlen(EOL);
|
||||||
dtty.eollen = eollen;
|
conndev.eollen = eollen;
|
||||||
|
DBG("eol: %s, seol: %s", conndev.eol, conndev.seol);
|
||||||
|
if(!G->ttyname){
|
||||||
|
WARNX("You should point name");
|
||||||
|
signals(0);
|
||||||
|
}
|
||||||
|
conndev.name = strdup(G->ttyname);
|
||||||
|
conndev.speed = G->speed;
|
||||||
|
if(G->socket){
|
||||||
|
if(!G->port) conndev.type = DEV_UNIXSOCKET;
|
||||||
|
else{
|
||||||
|
conndev.type = DEV_NETSOCKET;
|
||||||
|
conndev.port = strdup(G->port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!opendev(&conndev, G->dumpfile)){
|
||||||
|
signals(0);
|
||||||
|
}
|
||||||
init_ncurses();
|
init_ncurses();
|
||||||
init_readline();
|
init_readline();
|
||||||
signal(SIGTERM, signals); // kill (-15) - quit
|
signal(SIGTERM, signals); // kill (-15) - quit
|
||||||
@ -75,42 +80,29 @@ int main(int argc, char **argv){
|
|||||||
signal(SIGQUIT, signals); // ctrl+\ - quit
|
signal(SIGQUIT, signals); // ctrl+\ - quit
|
||||||
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
||||||
pthread_t writer;
|
pthread_t writer;
|
||||||
if(pthread_create(&writer, NULL, cmdline, (void*)&dtty)) ERR("pthread_create()");
|
if(pthread_create(&writer, NULL, cmdline, (void*)&conndev)) ERR("pthread_create()");
|
||||||
settimeout(G->tmoutms);
|
settimeout(G->tmoutms);
|
||||||
while(1){
|
while(1){
|
||||||
if(0 == pthread_mutex_lock(&dtty.mutex)){
|
if(0 == pthread_mutex_lock(&conndev.mutex)){
|
||||||
int l = Read_tty(dtty.dev);
|
int l;
|
||||||
if(l > 0){
|
char *buf = ReadData(&conndev, &l);
|
||||||
char *buf = dtty.dev->buf;
|
if(buf && l > 0){
|
||||||
char *eol = NULL, *estr = buf + l;
|
char *eol = NULL, *estr = buf + l;
|
||||||
do{
|
do{
|
||||||
/*eol = strchr(buf, '\n');
|
|
||||||
if(eol){
|
|
||||||
*eol = 0;
|
|
||||||
add_ttydata(buf);
|
|
||||||
buf = eol + 1;
|
|
||||||
}else{
|
|
||||||
add_ttydata(buf);
|
|
||||||
}*/
|
|
||||||
eol = strstr(buf, EOL);
|
eol = strstr(buf, EOL);
|
||||||
if(eol){
|
if(eol){
|
||||||
*eol = 0;
|
*eol = 0;
|
||||||
add_ttydata(buf);
|
ShowData(buf);
|
||||||
buf = eol + eollen;
|
buf = eol + eollen;
|
||||||
}else{
|
}else{
|
||||||
/* char *ptr = buf;
|
ShowData(buf);
|
||||||
while(*ptr){
|
|
||||||
if(*ptr == '\n' || *ptr == '\r'){ *ptr = 0; break;}
|
|
||||||
++ptr;
|
|
||||||
}*/
|
|
||||||
add_ttydata(buf);
|
|
||||||
}
|
}
|
||||||
}while(eol && buf < estr);
|
}while(eol && buf < estr);
|
||||||
}else if(l < 0){
|
}else if(l < 0){
|
||||||
pthread_mutex_unlock(&dtty.mutex);
|
pthread_mutex_unlock(&conndev.mutex);
|
||||||
ERRX("Device disconnected");
|
ERRX("Device disconnected");
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&dtty.mutex);
|
pthread_mutex_unlock(&conndev.mutex);
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "dbg.h"
|
||||||
|
#include "ttysocket.h"
|
||||||
#include "ncurses_and_readline.h"
|
#include "ncurses_and_readline.h"
|
||||||
|
|
||||||
// Keeps track of the terminal mode so we can reset the terminal if needed on errors
|
// Keeps track of the terminal mode so we can reset the terminal if needed on errors
|
||||||
@ -39,7 +41,7 @@ static bool visual_mode = false;
|
|||||||
static bool insert_mode = true;
|
static bool insert_mode = true;
|
||||||
static bool should_exit = false;
|
static bool should_exit = false;
|
||||||
|
|
||||||
static ttyd *dtty = NULL;
|
static chardevice *dtty = NULL;
|
||||||
|
|
||||||
static void fail_exit(const char *msg){
|
static void fail_exit(const char *msg){
|
||||||
// Make sure endwin() is only called in visual mode. As a note, calling it
|
// Make sure endwin() is only called in visual mode. As a note, calling it
|
||||||
@ -136,14 +138,41 @@ static void readline_redisplay(){
|
|||||||
|
|
||||||
static void show_mode(bool for_resize){
|
static void show_mode(bool for_resize){
|
||||||
wclear(sep_win);
|
wclear(sep_win);
|
||||||
if(insert_mode) wprintw(sep_win, "INSERT (TAB to switch, ctrl+D to quit) ENDLINE: %s SPEED: %d", dtty?dtty->seol:"n", dtty?dtty->dev->speed:"NC");
|
char buf[128];
|
||||||
else wprintw(sep_win, "SCROLL (TAB to switch, q to quit) ENDLINE: %s SPEED: %d", dtty?dtty->seol:"n", dtty?dtty->dev->speed:"NC");
|
if(insert_mode){
|
||||||
|
if(dtty){
|
||||||
|
switch(dtty->type){
|
||||||
|
case DEV_NETSOCKET:
|
||||||
|
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) HOST: %s, ENDLINE: %s, PORT: %s",
|
||||||
|
dtty->name, dtty->seol, dtty->port);
|
||||||
|
break;
|
||||||
|
case DEV_UNIXSOCKET:
|
||||||
|
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) HOST: %s, ENDLINE: %s, PATH: %s",
|
||||||
|
dtty->name, dtty->seol, dtty->port);
|
||||||
|
break;
|
||||||
|
case DEV_TTY:
|
||||||
|
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) DEV: %s, ENDLINE: %s, SPEED: %d",
|
||||||
|
dtty->name, dtty->seol, dtty->speed);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}}else{
|
||||||
|
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) NOT INITIALIZED");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
snprintf(buf, 127, "SCROLL (TAB to switch, q to quit) ENDLINE: %s", dtty?dtty->seol:"n");
|
||||||
|
}
|
||||||
|
wprintw(sep_win, "%s", buf);
|
||||||
if(for_resize) wnoutrefresh(sep_win);
|
if(for_resize) wnoutrefresh(sep_win);
|
||||||
else wrefresh(sep_win);
|
else wrefresh(sep_win);
|
||||||
cmd_win_redisplay(for_resize);
|
cmd_win_redisplay(for_resize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_ttydata(const char *text){
|
/**
|
||||||
|
* @brief ShowData - show string on display
|
||||||
|
* @param text - text string
|
||||||
|
*/
|
||||||
|
void ShowData(const char *text){
|
||||||
if(!text) return;
|
if(!text) return;
|
||||||
if(!*text) text = " "; // empty string
|
if(!*text) text = " "; // empty string
|
||||||
Line *lp = malloc(sizeof(Line));
|
Line *lp = malloc(sizeof(Line));
|
||||||
@ -213,8 +242,9 @@ void init_ncurses(){
|
|||||||
if(has_colors()){
|
if(has_colors()){
|
||||||
init_pair(1, COLOR_WHITE, COLOR_BLUE);
|
init_pair(1, COLOR_WHITE, COLOR_BLUE);
|
||||||
wbkgd(sep_win, COLOR_PAIR(1));
|
wbkgd(sep_win, COLOR_PAIR(1));
|
||||||
}else
|
}else{
|
||||||
wbkgd(sep_win, A_STANDOUT);
|
wbkgd(sep_win, A_STANDOUT);
|
||||||
|
}
|
||||||
show_mode(false);
|
show_mode(false);
|
||||||
mousemask(BUTTON4_PRESSED|BUTTON5_PRESSED, NULL);
|
mousemask(BUTTON4_PRESSED|BUTTON5_PRESSED, NULL);
|
||||||
}
|
}
|
||||||
@ -228,21 +258,15 @@ void deinit_ncurses(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void got_command(char *line){
|
static void got_command(char *line){
|
||||||
bool err = false;
|
|
||||||
if(!line) // Ctrl-D pressed on empty line
|
if(!line) // Ctrl-D pressed on empty line
|
||||||
should_exit = true;
|
should_exit = true;
|
||||||
else{
|
else{
|
||||||
if(!*line) return; // zero length
|
if(!*line) return; // zero length
|
||||||
add_history(line);
|
add_history(line);
|
||||||
if(dtty && dtty->dev){
|
if(SendData(dtty, line) == -1){
|
||||||
if(0 == pthread_mutex_lock(&dtty->mutex)){
|
ERRX("Device disconnected");
|
||||||
if(write_tty(dtty->dev->comfd, line, strlen(line))) err = true;
|
|
||||||
else if(write_tty(dtty->dev->comfd, dtty->eol, dtty->eollen)) err = true;
|
|
||||||
pthread_mutex_unlock(&dtty->mutex);
|
|
||||||
if(err) ERRX("Device disconnected");
|
|
||||||
}
|
}
|
||||||
}
|
FREE(line);
|
||||||
free(line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,9 +300,14 @@ static void rollup(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief cmdline - console reading process; runs as separate thread
|
||||||
|
* @param arg - tty/socket device to write strings entered by user
|
||||||
|
* @return NULL
|
||||||
|
*/
|
||||||
void *cmdline(void* arg){
|
void *cmdline(void* arg){
|
||||||
MEVENT event;
|
MEVENT event;
|
||||||
dtty = (ttyd*)arg;
|
dtty = (chardevice*)arg;
|
||||||
show_mode(false);
|
show_mode(false);
|
||||||
do{
|
do{
|
||||||
int c = wgetch(cmd_win);
|
int c = wgetch(cmd_win);
|
||||||
|
|||||||
@ -19,22 +19,14 @@
|
|||||||
#ifndef NCURSES_AND_READLINE_H__
|
#ifndef NCURSES_AND_READLINE_H__
|
||||||
#define NCURSES_AND_READLINE_H__
|
#define NCURSES_AND_READLINE_H__
|
||||||
|
|
||||||
#include <pthread.h>
|
#include "dbg.h"
|
||||||
#include <usefull_macros.h>
|
#include "ttysocket.h"
|
||||||
|
|
||||||
typedef struct{
|
|
||||||
TTY_descr *dev;
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
char eol[3];
|
|
||||||
char seol[5];
|
|
||||||
int eollen;
|
|
||||||
} ttyd;
|
|
||||||
|
|
||||||
void init_readline();
|
void init_readline();
|
||||||
void deinit_readline();
|
void deinit_readline();
|
||||||
void init_ncurses();
|
void init_ncurses();
|
||||||
void deinit_ncurses();
|
void deinit_ncurses();
|
||||||
void *cmdline(void* arg);
|
void *cmdline(void* arg);
|
||||||
void add_ttydata(const char *text);
|
void ShowData(const char *text);
|
||||||
|
|
||||||
#endif // NCURSES_AND_READLINE_H__
|
#endif // NCURSES_AND_READLINE_H__
|
||||||
|
|||||||
318
ttysocket.c
Normal file
318
ttysocket.c
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the ttyterm project.
|
||||||
|
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h> // getchar
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h> // unix socket
|
||||||
|
|
||||||
|
#include "dbg.h"
|
||||||
|
#include "ttysocket.h"
|
||||||
|
|
||||||
|
static int sec = 0, usec = 100; // timeout
|
||||||
|
static FILE *dupfile = NULL; // file for output
|
||||||
|
// TODO: if unix socket name starts with \0 translate it as \\0 to d->name!
|
||||||
|
|
||||||
|
// set Read_tty timeout in milliseconds
|
||||||
|
void settimeout(int tmout){
|
||||||
|
sec = 0;
|
||||||
|
if(tmout > 999){
|
||||||
|
sec = tmout / 1000;
|
||||||
|
tmout -= sec * 1000;
|
||||||
|
}
|
||||||
|
usec = tmout * 1000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wait for answer from socket
|
||||||
|
* @param sock - socket fd
|
||||||
|
* @return 0 in case of timeout, 1 in case of socket ready, -1 if error
|
||||||
|
*/
|
||||||
|
static int waittoread(int fd){
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = sec;
|
||||||
|
timeout.tv_usec = usec;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(fd, &fds);
|
||||||
|
do{
|
||||||
|
int rc = select(fd+1, &fds, NULL, NULL, &timeout);
|
||||||
|
if(rc < 0){
|
||||||
|
if(errno != EINTR){
|
||||||
|
WARN("select()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}while(1);
|
||||||
|
if(FD_ISSET(fd, &fds)){
|
||||||
|
DBG("FD_ISSET");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get data drom TTY
|
||||||
|
static char *getttydata(TTY_descr *D, int *len){
|
||||||
|
if(!D || D->comfd < 0) return NULL;
|
||||||
|
size_t L = 0;
|
||||||
|
size_t length = D->bufsz;
|
||||||
|
char *ptr = D->buf;
|
||||||
|
int s = 0;
|
||||||
|
do{
|
||||||
|
if(!(s = waittoread(D->comfd))) break;
|
||||||
|
if(s < 0){
|
||||||
|
if(len) *len = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ssize_t l = read(D->comfd, ptr, length);
|
||||||
|
if(l < 1){ // disconnected
|
||||||
|
if(len) *len = -1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ptr += l; L += l;
|
||||||
|
length -= l;
|
||||||
|
}while(length);
|
||||||
|
D->buflen = L;
|
||||||
|
D->buf[L] = 0;
|
||||||
|
if(len) *len = L;
|
||||||
|
return D->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *getsockdata(TTY_descr *D, int *len){
|
||||||
|
if(!D || D->comfd < 0) return NULL;
|
||||||
|
char *ptr = NULL;
|
||||||
|
int n = waittoread(D->comfd);
|
||||||
|
if(n == 1){
|
||||||
|
n = read(D->comfd, D->buf, D->bufsz-1);
|
||||||
|
if(n > 0){
|
||||||
|
ptr = D->buf;
|
||||||
|
ptr[n] = 0;
|
||||||
|
DBG("got %d: %s", n, ptr);
|
||||||
|
}else{
|
||||||
|
DBG("Got nothing");
|
||||||
|
n = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(len) *len = n;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ReadData - get data from serial device or socket
|
||||||
|
* @param d - device
|
||||||
|
* @param len (o) - length of data read (-1 if device disconnected)
|
||||||
|
* @return NULL or string
|
||||||
|
*/
|
||||||
|
char *ReadData(chardevice *d, int *len){
|
||||||
|
if(!d || !d->dev) return NULL;
|
||||||
|
if(len) *len = -1;
|
||||||
|
char *r = NULL;
|
||||||
|
switch(d->type){
|
||||||
|
case DEV_TTY:
|
||||||
|
if(!d || !d->dev) return NULL;
|
||||||
|
r = getttydata(d->dev, len);
|
||||||
|
break;
|
||||||
|
case DEV_NETSOCKET:
|
||||||
|
case DEV_UNIXSOCKET:
|
||||||
|
r = getsockdata(d->dev, len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(r && dupfile){
|
||||||
|
fprintf(dupfile, "< %s", r);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SendData - send data to tty or socket
|
||||||
|
* @param d - device
|
||||||
|
* @param str - text string
|
||||||
|
* @return 0 if error, -1 if disconnected
|
||||||
|
*/
|
||||||
|
int SendData(chardevice *d, char *str){
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
if(!d) return -1;
|
||||||
|
DBG("send %s", str);
|
||||||
|
if(!str) return 0;
|
||||||
|
int ret = 0;
|
||||||
|
if(0 == pthread_mutex_lock(&d->mutex)){
|
||||||
|
int l = strlen(str), lplus = l + d->eollen + 1;
|
||||||
|
if(l < 1) return 0;
|
||||||
|
if(lplus > BUFSIZ-1) lplus = BUFSIZ-1;
|
||||||
|
snprintf(buf, lplus+1, "%s%s", str, d->eol);
|
||||||
|
switch(d->type){
|
||||||
|
case DEV_TTY:
|
||||||
|
if(write_tty(d->dev->comfd, buf, lplus)) ret = 0;
|
||||||
|
else ret = l;
|
||||||
|
break;
|
||||||
|
case DEV_NETSOCKET:
|
||||||
|
case DEV_UNIXSOCKET:
|
||||||
|
if(lplus != send(d->dev->comfd, buf, lplus, 0)) ret = 0;
|
||||||
|
else ret = l;
|
||||||
|
pthread_mutex_unlock(&d->mutex);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(str && dupfile){
|
||||||
|
fprintf(dupfile, "> %s", buf);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&d->mutex);
|
||||||
|
}else ret = -1;
|
||||||
|
DBG("ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int socktypes[] = {SOCK_STREAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, SOCK_DCCP, SOCK_PACKET, SOCK_DGRAM, 0};
|
||||||
|
|
||||||
|
static TTY_descr* opensocket(chardevice *d){
|
||||||
|
if(!d) return FALSE;
|
||||||
|
TTY_descr *descr = MALLOC(TTY_descr, 1); // only for `buf` and bufsz/buflen
|
||||||
|
descr->buf = MALLOC(char, BUFSIZ);
|
||||||
|
descr->bufsz = BUFSIZ;
|
||||||
|
// now try to open a socket
|
||||||
|
descr->comfd = -1;
|
||||||
|
struct hostent *host;
|
||||||
|
struct sockaddr_in addr = {0};
|
||||||
|
struct sockaddr_un saddr = {0};
|
||||||
|
struct sockaddr *sa = NULL;
|
||||||
|
socklen_t addrlen = 0;
|
||||||
|
int domain = -1;
|
||||||
|
if(d->type == DEV_NETSOCKET){
|
||||||
|
DBG("NETSOCK to %s", d->name);
|
||||||
|
sa = (struct sockaddr*) &addr;
|
||||||
|
addrlen = sizeof(addr);
|
||||||
|
if((host = gethostbyname(d->name)) == NULL ){
|
||||||
|
WARN("gethostbyname()");
|
||||||
|
FREE(descr->buf);
|
||||||
|
FREE(descr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct in_addr *ia = (struct in_addr*)host->h_addr_list[0];
|
||||||
|
DBG("addr: %s", inet_ntoa(*ia));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
int p = atoi(d->port); DBG("PORT: %s - %d", d->port, p);
|
||||||
|
addr.sin_port = htons(p);
|
||||||
|
//addr.sin_addr.s_addr = *(long*)(host->h_addr);
|
||||||
|
addr.sin_addr.s_addr = ia->s_addr;
|
||||||
|
domain = AF_INET;
|
||||||
|
}else{
|
||||||
|
DBG("UNSOCK");
|
||||||
|
sa = (struct sockaddr*) &saddr;
|
||||||
|
addrlen = sizeof(saddr);
|
||||||
|
saddr.sun_family = AF_UNIX;
|
||||||
|
strncpy(saddr.sun_path, d->name, 107); // if sun_path[0] == 0 then don't create a file
|
||||||
|
domain = AF_UNIX;
|
||||||
|
}
|
||||||
|
const int *type = socktypes;
|
||||||
|
while(*type){
|
||||||
|
DBG("type = %d", *type);
|
||||||
|
if((descr->comfd = socket(domain, *type, 0)) > -1){
|
||||||
|
if(connect(descr->comfd, sa, addrlen) < 0){
|
||||||
|
DBG("CANT connect");
|
||||||
|
close(descr->comfd);
|
||||||
|
}else break;
|
||||||
|
}
|
||||||
|
WARNX("socket()");
|
||||||
|
++type;
|
||||||
|
}
|
||||||
|
if(descr->comfd < 0){
|
||||||
|
DBG("NO types");
|
||||||
|
WARNX("No types can be choosen");
|
||||||
|
FREE(descr->buf);
|
||||||
|
FREE(descr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief opendev - open TTY or socket output device
|
||||||
|
* @param d - device type
|
||||||
|
* @return FALSE if failed
|
||||||
|
*/
|
||||||
|
int opendev(chardevice *d, char *path){
|
||||||
|
if(!d) return FALSE;
|
||||||
|
DBG("Try to open device");
|
||||||
|
switch(d->type){
|
||||||
|
case DEV_TTY:
|
||||||
|
DBG("Serial");
|
||||||
|
d->dev = new_tty(d->name, d->speed, BUFSIZ);
|
||||||
|
if(!d->dev || !(d->dev = tty_open(d->dev, 1))){
|
||||||
|
WARN("Can't open device %s", d->name);
|
||||||
|
DBG("CANT OPEN");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DEV_NETSOCKET:
|
||||||
|
case DEV_UNIXSOCKET:
|
||||||
|
d->dev = opensocket(d);
|
||||||
|
if(!d->dev){
|
||||||
|
WARNX("Can't open socket");
|
||||||
|
DBG("CANT OPEN");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if(path){ // open logging file
|
||||||
|
dupfile = fopen(path, "a");
|
||||||
|
if(!dupfile){
|
||||||
|
WARN("Can't open %s", path);
|
||||||
|
closedev(d);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void closedev(chardevice *d){
|
||||||
|
if(!d) return;
|
||||||
|
pthread_mutex_unlock(&d->mutex);
|
||||||
|
pthread_mutex_trylock(&d->mutex);
|
||||||
|
if(dupfile){
|
||||||
|
fclose(dupfile);
|
||||||
|
dupfile = NULL;
|
||||||
|
}
|
||||||
|
switch(d->type){
|
||||||
|
case DEV_TTY:
|
||||||
|
if(d->dev){
|
||||||
|
close_tty(&d->dev);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DEV_NETSOCKET:
|
||||||
|
if(d->dev){
|
||||||
|
close(d->dev->comfd);
|
||||||
|
FREE(d->dev);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FREE(d->name);
|
||||||
|
}
|
||||||
50
ttysocket.h
Normal file
50
ttysocket.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the ttyterm project.
|
||||||
|
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef TTY_H__
|
||||||
|
#define TTY_H__
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "dbg.h"
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
DEV_TTY,
|
||||||
|
DEV_NETSOCKET,
|
||||||
|
DEV_UNIXSOCKET,
|
||||||
|
} devtype;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
devtype type; // type
|
||||||
|
char *name; // filename (dev or UNIX socket) or server name/IP
|
||||||
|
TTY_descr *dev; // tty serial device
|
||||||
|
char *port; // port to connect
|
||||||
|
int speed; // tty speed
|
||||||
|
pthread_mutex_t mutex; // reading/writing mutex
|
||||||
|
char eol[3]; // end of line
|
||||||
|
char seol[5]; // `eol` with doubled backslash (for print @ screen)
|
||||||
|
int eollen; // length of `eol`
|
||||||
|
} chardevice;
|
||||||
|
|
||||||
|
char *ReadData(chardevice *d, int *l);
|
||||||
|
int SendData(chardevice *d, char *str);
|
||||||
|
void settimeout(int tms);
|
||||||
|
int opendev(chardevice *d, char *path);
|
||||||
|
void closedev(chardevice *d);
|
||||||
|
|
||||||
|
#endif // TTY_H__
|
||||||
Loading…
x
Reference in New Issue
Block a user