mirror of
https://github.com/eddyem/tty_term.git
synced 2025-12-06 02:25:11 +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)
|
||||
set(PROJ tty_term)
|
||||
set(MINOR_VERSION "1")
|
||||
set(MID_VERSION "0")
|
||||
set(MINOR_VERSION "0")
|
||||
set(MID_VERSION "1")
|
||||
set(MAJOR_VERSION "0")
|
||||
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
|
||||
|
||||
project(${PROJ} VERSION ${PROJ_VERSION} LANGUAGES C)
|
||||
#enable_language(C)
|
||||
project(${PROJ} VERSION ${VERSION} LANGUAGES C)
|
||||
|
||||
message("VER: ${VERSION}")
|
||||
|
||||
# default flags
|
||||
set(CMAKE_C_FLAGS_RELEASE "")
|
||||
set(CMAKE_C_FLAGS_DEBUG "")
|
||||
set(CMAKE_C_FLAGS "-O2 -std=gnu99")
|
||||
set(CMAKE_C_FLAGS "-O3 -std=gnu99")
|
||||
|
||||
set(CMAKE_COLOR_MAKEFILE ON)
|
||||
|
||||
|
||||
@ -20,8 +20,9 @@
|
||||
#include <assert.h> // assert
|
||||
#include <stdio.h> // printf
|
||||
#include <string.h> // memcpy
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "cmdlnopts.h"
|
||||
#include "dbg.h"
|
||||
|
||||
/*
|
||||
* here are global parameters initialisation
|
||||
@ -33,7 +34,6 @@ static glob_pars G;
|
||||
// default global parameters
|
||||
glob_pars const Gdefault = {
|
||||
.speed = 9600,
|
||||
.ttyname = "/dev/ttyUSB0",
|
||||
.eol = "n",
|
||||
.tmoutms = 100,
|
||||
};
|
||||
@ -46,9 +46,12 @@ static myoption cmdlnopts[] = {
|
||||
// set 1 to param despite of its repeating number:
|
||||
{"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)")},
|
||||
{"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")},
|
||||
{"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
|
||||
};
|
||||
|
||||
|
||||
@ -26,8 +26,11 @@
|
||||
typedef struct{
|
||||
int speed; // baudrate
|
||||
int tmoutms; // timeout for select() in ms
|
||||
int socket; // open socket
|
||||
char *dumpfile; // file to save dump
|
||||
char *ttyname; // device name
|
||||
char *eol; // end of line: \r (CR), \rn (CR+LF) or \n (LF): "r", "rn", "n"
|
||||
char *port; // socket port
|
||||
} 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 <stdio.h>
|
||||
#include <string.h> // strcmp
|
||||
#include <usefull_macros.h>
|
||||
#include "cmdlnopts.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};
|
||||
|
||||
//FILE *fd;
|
||||
static chardevice conndev = {.dev = NULL, .mutex = PTHREAD_MUTEX_INITIALIZER, .name = NULL, .type = DEV_TTY};
|
||||
|
||||
void signals(int signo){
|
||||
signal(signo, SIG_IGN);
|
||||
if(dtty.dev){
|
||||
pthread_mutex_unlock(&dtty.mutex);
|
||||
pthread_mutex_trylock(&dtty.mutex);
|
||||
close_tty(&dtty.dev);
|
||||
}
|
||||
//fprintf(fd, "stop\n");
|
||||
//fflush(fd);
|
||||
closedev(&conndev);
|
||||
deinit_ncurses();
|
||||
deinit_readline();
|
||||
DBG("Exit");
|
||||
exit(signo);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
glob_pars *G = NULL; // default parameters see in cmdlnopts.c
|
||||
initial_setup();
|
||||
#ifdef EBUG
|
||||
OPENLOG("debug.log", LOGLEVEL_ANY, 1);
|
||||
#endif
|
||||
G = parse_args(argc, argv);
|
||||
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";
|
||||
if(strcasecmp(G->eol, "n")){
|
||||
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 ERRX("End of line should be \"r\", \"n\" or \"rn\" or \"nr\"");
|
||||
}
|
||||
strcpy(dtty.eol, EOL);
|
||||
strcpy(dtty.seol, seol);
|
||||
strcpy(conndev.eol, EOL);
|
||||
strcpy(conndev.seol, seol);
|
||||
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_readline();
|
||||
signal(SIGTERM, signals); // kill (-15) - quit
|
||||
@ -75,42 +80,29 @@ int main(int argc, char **argv){
|
||||
signal(SIGQUIT, signals); // ctrl+\ - quit
|
||||
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
||||
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);
|
||||
while(1){
|
||||
if(0 == pthread_mutex_lock(&dtty.mutex)){
|
||||
int l = Read_tty(dtty.dev);
|
||||
if(l > 0){
|
||||
char *buf = dtty.dev->buf;
|
||||
if(0 == pthread_mutex_lock(&conndev.mutex)){
|
||||
int l;
|
||||
char *buf = ReadData(&conndev, &l);
|
||||
if(buf && l > 0){
|
||||
char *eol = NULL, *estr = buf + l;
|
||||
do{
|
||||
/*eol = strchr(buf, '\n');
|
||||
if(eol){
|
||||
*eol = 0;
|
||||
add_ttydata(buf);
|
||||
buf = eol + 1;
|
||||
}else{
|
||||
add_ttydata(buf);
|
||||
}*/
|
||||
eol = strstr(buf, EOL);
|
||||
if(eol){
|
||||
*eol = 0;
|
||||
add_ttydata(buf);
|
||||
ShowData(buf);
|
||||
buf = eol + eollen;
|
||||
}else{
|
||||
/* char *ptr = buf;
|
||||
while(*ptr){
|
||||
if(*ptr == '\n' || *ptr == '\r'){ *ptr = 0; break;}
|
||||
++ptr;
|
||||
}*/
|
||||
add_ttydata(buf);
|
||||
ShowData(buf);
|
||||
}
|
||||
}while(eol && buf < estr);
|
||||
}else if(l < 0){
|
||||
pthread_mutex_unlock(&dtty.mutex);
|
||||
pthread_mutex_unlock(&conndev.mutex);
|
||||
ERRX("Device disconnected");
|
||||
}
|
||||
pthread_mutex_unlock(&dtty.mutex);
|
||||
pthread_mutex_unlock(&conndev.mutex);
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbg.h"
|
||||
#include "ttysocket.h"
|
||||
#include "ncurses_and_readline.h"
|
||||
|
||||
// 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 should_exit = false;
|
||||
|
||||
static ttyd *dtty = NULL;
|
||||
static chardevice *dtty = NULL;
|
||||
|
||||
static void fail_exit(const char *msg){
|
||||
// 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){
|
||||
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");
|
||||
else wprintw(sep_win, "SCROLL (TAB to switch, q to quit) ENDLINE: %s SPEED: %d", dtty?dtty->seol:"n", dtty?dtty->dev->speed:"NC");
|
||||
char buf[128];
|
||||
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);
|
||||
else wrefresh(sep_win);
|
||||
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) text = " "; // empty string
|
||||
Line *lp = malloc(sizeof(Line));
|
||||
@ -213,8 +242,9 @@ void init_ncurses(){
|
||||
if(has_colors()){
|
||||
init_pair(1, COLOR_WHITE, COLOR_BLUE);
|
||||
wbkgd(sep_win, COLOR_PAIR(1));
|
||||
}else
|
||||
}else{
|
||||
wbkgd(sep_win, A_STANDOUT);
|
||||
}
|
||||
show_mode(false);
|
||||
mousemask(BUTTON4_PRESSED|BUTTON5_PRESSED, NULL);
|
||||
}
|
||||
@ -228,21 +258,15 @@ void deinit_ncurses(){
|
||||
}
|
||||
|
||||
static void got_command(char *line){
|
||||
bool err = false;
|
||||
if(!line) // Ctrl-D pressed on empty line
|
||||
should_exit = true;
|
||||
else{
|
||||
if(!*line) return; // zero length
|
||||
add_history(line);
|
||||
if(dtty && dtty->dev){
|
||||
if(0 == pthread_mutex_lock(&dtty->mutex)){
|
||||
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");
|
||||
}
|
||||
if(SendData(dtty, line) == -1){
|
||||
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){
|
||||
MEVENT event;
|
||||
dtty = (ttyd*)arg;
|
||||
dtty = (chardevice*)arg;
|
||||
show_mode(false);
|
||||
do{
|
||||
int c = wgetch(cmd_win);
|
||||
|
||||
@ -19,22 +19,14 @@
|
||||
#ifndef NCURSES_AND_READLINE_H__
|
||||
#define NCURSES_AND_READLINE_H__
|
||||
|
||||
#include <pthread.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
typedef struct{
|
||||
TTY_descr *dev;
|
||||
pthread_mutex_t mutex;
|
||||
char eol[3];
|
||||
char seol[5];
|
||||
int eollen;
|
||||
} ttyd;
|
||||
#include "dbg.h"
|
||||
#include "ttysocket.h"
|
||||
|
||||
void init_readline();
|
||||
void deinit_readline();
|
||||
void init_ncurses();
|
||||
void deinit_ncurses();
|
||||
void *cmdline(void* arg);
|
||||
void add_ttydata(const char *text);
|
||||
void ShowData(const char *text);
|
||||
|
||||
#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