415 lines
6.8 KiB
C++
415 lines
6.8 KiB
C++
|
|
#include "ddconfig.h"
|
|
|
|
#include <stdio.h>
|
|
#if defined HAVE_SYS_SOCKET_H
|
|
# include <sys/socket.h>
|
|
# include <sys/select.h>
|
|
# include <netinet/in.h>
|
|
# include <arpa/inet.h>
|
|
#endif
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "utils.h"
|
|
|
|
#include "fuiocl.h"
|
|
|
|
|
|
cl_f *dd= NULL;
|
|
|
|
void deb(const char *format, ...)
|
|
{
|
|
return;
|
|
if (dd==NULL)
|
|
{
|
|
dd= mk_io(/*cchars("/dev/pts/2"),cchars("w")*/"","");
|
|
dd->file_id= open("/dev/pts/4", O_WRONLY);
|
|
//dd->init();
|
|
}
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
//dd->vprintf(format, ap);
|
|
//vdprintf(dd->file_id, format, ap);
|
|
{
|
|
char *buf= vformat_string(format, ap);
|
|
/*dd->*/write(dd->file_id, buf, strlen(buf));
|
|
free(buf);
|
|
}
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
cl_io::cl_io(): cl_f()
|
|
{
|
|
}
|
|
|
|
cl_io::cl_io(chars fn, chars mode): cl_f(fn, mode)
|
|
{
|
|
}
|
|
|
|
cl_io::cl_io(int the_server_port): cl_f(the_server_port)
|
|
{
|
|
}
|
|
|
|
int
|
|
cl_io::close(void)
|
|
{
|
|
int i= 0;
|
|
|
|
deb("fuio close fid=%d\n", file_id);
|
|
if ((type == F_SOCKET) ||
|
|
(type == F_LISTENER))
|
|
{
|
|
restore_attributes();
|
|
shutdown(file_id, 2/*SHUT_RDWR*/);
|
|
}
|
|
/*
|
|
if (file_f)
|
|
{
|
|
restore_attributes();
|
|
i= fclose(file_f);
|
|
}
|
|
else*/ if (file_id >= 0)
|
|
{
|
|
restore_attributes();
|
|
i= ::close(file_id);
|
|
}
|
|
|
|
//file_f= NULL;
|
|
file_id= -1;
|
|
own= false;
|
|
file_name= 0;
|
|
file_mode= 0;
|
|
|
|
changed();
|
|
return i;
|
|
}
|
|
|
|
cl_io::~cl_io(void)
|
|
{
|
|
deb("~cl_uio fid=%d\n", file_id);
|
|
restore_attributes();
|
|
if (echo_of != NULL)
|
|
echo_of->echo(NULL);
|
|
if (/*file_f*/file_id>=0)
|
|
{
|
|
if (own)
|
|
close();
|
|
else
|
|
stop_use();
|
|
}
|
|
}
|
|
|
|
void
|
|
cl_io::changed(void)
|
|
{
|
|
//printf("fuio changed fid=%d\n", file_id);
|
|
if (file_id < 0)
|
|
{
|
|
type= F_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
type= determine_type();
|
|
if (type == F_SOCKET) tty= true;
|
|
}
|
|
}
|
|
|
|
enum file_type
|
|
cl_io::determine_type(void)
|
|
{
|
|
int i;
|
|
struct stat s;
|
|
|
|
if (file_id < 0)
|
|
return F_UNKNOWN;
|
|
i= fstat(file_id, &s);
|
|
if (i < 0)
|
|
return F_UNKNOWN;
|
|
|
|
if (S_ISDIR(s.st_mode) ||
|
|
S_ISLNK(s.st_mode))
|
|
return F_UNKNOWN;
|
|
if (S_ISCHR(s.st_mode))
|
|
return F_CHAR;
|
|
if (S_ISFIFO(s.st_mode))
|
|
return F_PIPE;
|
|
if (S_ISBLK(s.st_mode) ||
|
|
S_ISREG(s.st_mode))
|
|
return F_FILE;
|
|
if (S_ISSOCK(s.st_mode))
|
|
return F_SOCKET;
|
|
return F_UNKNOWN;
|
|
}
|
|
|
|
int
|
|
cl_io::check_dev(void)
|
|
{
|
|
struct timeval tv= { 0, 0 };
|
|
fd_set s;
|
|
int i;
|
|
|
|
if (file_id<0)
|
|
{
|
|
return 0;
|
|
}
|
|
switch (type)
|
|
{
|
|
case F_UNKNOWN:
|
|
case F_CONSOLE:
|
|
case F_SERIAL:
|
|
return false;
|
|
break;
|
|
case F_FILE:
|
|
pick();
|
|
return last_used != first_free;
|
|
break;
|
|
case F_CHAR:
|
|
case F_SOCKET:
|
|
case F_LISTENER:
|
|
case F_PIPE:
|
|
FD_ZERO(&s);
|
|
FD_SET(file_id, &s);
|
|
i= select(file_id+1, &s, NULL, NULL, &tv);
|
|
if (i >= 0)
|
|
{
|
|
int ret= FD_ISSET(file_id, &s);
|
|
if (type == F_LISTENER)
|
|
return ret;
|
|
if (ret)
|
|
{
|
|
pick();
|
|
}
|
|
return last_used != first_free;
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
cl_io::prepare_terminal()
|
|
{
|
|
if (type == F_SOCKET)
|
|
{
|
|
// assume telnet client
|
|
char s[7];
|
|
//deb("preparing TELNET %d\n", file_id);
|
|
sprintf(s, "%c%c%c%c%c%c", 0xff, 0xfb, 1, 0xff, 0xfb, 3 );
|
|
write(s, 7);
|
|
}
|
|
else if (tty)
|
|
{
|
|
struct termios tattr;
|
|
//deb("preparing TTY %d\n", file_id);
|
|
tcgetattr(file_id, &tattr);
|
|
tattr.c_iflag&= ~IXON;
|
|
tattr.c_lflag&= ~ICANON;
|
|
tattr.c_lflag&= ~ECHO;
|
|
tattr.c_cc[VMIN] = 1;
|
|
tattr.c_cc[VTIME]= 0;
|
|
tcsetattr(file_id, TCSAFLUSH, &tattr);
|
|
}
|
|
}
|
|
|
|
void
|
|
cl_io::save_attributes()
|
|
{
|
|
if ((tty) &&
|
|
!attributes_saved)
|
|
{
|
|
tcgetattr(file_id, &saved_attributes);
|
|
attributes_saved= 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
cl_io::restore_attributes()
|
|
{
|
|
if (attributes_saved)
|
|
{
|
|
saved_attributes.c_lflag|= ICANON|ECHO;
|
|
tcsetattr(file_id, TCSAFLUSH, &saved_attributes);
|
|
attributes_saved= 0;
|
|
}
|
|
}
|
|
|
|
int
|
|
mk_srv_socket(int port)
|
|
{
|
|
int sock, i;
|
|
struct sockaddr_in name;
|
|
|
|
/* Create the socket. */
|
|
sock= socket(PF_INET, SOCK_STREAM, 0);
|
|
if (sock < 0)
|
|
{
|
|
perror("socket");
|
|
return(0);
|
|
}
|
|
|
|
/* Give the socket a name. */
|
|
i= 1;
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof(i)) < 0)
|
|
{
|
|
perror("setsockopt");
|
|
}
|
|
name.sin_family = AF_INET;
|
|
name.sin_port = htons(port);
|
|
name.sin_addr.s_addr= htonl(INADDR_ANY);
|
|
if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0)
|
|
{
|
|
perror("bind");
|
|
return(0);
|
|
}
|
|
|
|
return(sock);
|
|
}
|
|
|
|
|
|
class cl_f *
|
|
mk_io(chars fn, chars mode)
|
|
{
|
|
class cl_io *io;
|
|
|
|
if (fn.empty())
|
|
{
|
|
io= new cl_io();
|
|
io->init();
|
|
return io;
|
|
}
|
|
else if (strcmp(fn, "-") == 0)
|
|
{
|
|
if (strcmp(mode, "r") == 0)
|
|
return cp_io(fileno(stdin), mode);
|
|
else if (strcmp(mode, "w") == 0)
|
|
return cp_io(fileno(stdout), mode);
|
|
}
|
|
io= new cl_io(fn, mode);
|
|
io->init();
|
|
return io;
|
|
}
|
|
|
|
class cl_f *
|
|
cp_io(/*FILE *f*/int file_id, chars mode)
|
|
{
|
|
class cl_io *io;
|
|
|
|
io= new cl_io();
|
|
if (/*f*/file_id>=0)
|
|
io->use_opened(/*fileno(f)*/file_id, mode);
|
|
return io;
|
|
}
|
|
|
|
class cl_f *
|
|
mk_srv(int server_port)
|
|
{
|
|
class cl_io *io;
|
|
|
|
io= new cl_io(server_port);
|
|
io->init();
|
|
io->type= F_LISTENER;
|
|
return io;
|
|
}
|
|
|
|
|
|
int
|
|
srv_accept(class cl_f *listen_io,
|
|
class cl_f **fin, class cl_f **fout)
|
|
{
|
|
class cl_io *io;
|
|
//ACCEPT_SOCKLEN_T size;
|
|
//struct sockaddr_in sock_addr;
|
|
int new_sock;
|
|
|
|
//size= sizeof(struct sockaddr);
|
|
new_sock= accept(listen_io->file_id, /*(struct sockaddr *)sock_addr*/NULL, /*&size*/NULL);
|
|
|
|
if (fin)
|
|
{
|
|
io= new cl_io(listen_io->server_port);
|
|
if (new_sock > 0)
|
|
{
|
|
io->own_opened(new_sock, cchars("r"));
|
|
}
|
|
*fin= io;
|
|
}
|
|
|
|
if (fout)
|
|
{
|
|
io= new cl_io(listen_io->server_port);
|
|
if (new_sock > 0)
|
|
{
|
|
io->use_opened(new_sock, cchars("w"));
|
|
}
|
|
*fout= io;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
check_inputs(class cl_list *active, class cl_list *avail)
|
|
{
|
|
int i;
|
|
bool ret= false;
|
|
|
|
if (!active)
|
|
return false;
|
|
|
|
if (avail)
|
|
avail->disconn_all();
|
|
|
|
for (i= 0; i < active->count; i++)
|
|
{
|
|
class cl_f *fio= (class cl_f *)active->at(i);
|
|
//deb("checking fid=%d\n", fio->file_id);
|
|
if (fio->check_dev() ||
|
|
fio->eof())
|
|
{
|
|
deb("found dev input on fid=%d\n", fio->file_id);
|
|
if (avail)
|
|
avail->add(fio);
|
|
ret= true;
|
|
}
|
|
else
|
|
;//deb("no dev input on fid=%d\n", fio->file_id);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
msleep(int msec)
|
|
{
|
|
struct timespec t;
|
|
|
|
t.tv_sec= msec/1000;
|
|
t.tv_nsec= (msec%1000)*1000000;
|
|
nanosleep(&t, NULL);
|
|
}
|
|
|
|
void
|
|
loop_delay()
|
|
{
|
|
msleep(100);
|
|
}
|
|
|
|
|
|
void
|
|
sigpipe_off()
|
|
{
|
|
struct sigaction sa;
|
|
sa.sa_handler= SIG_IGN;
|
|
sigaction(SIGPIPE, &sa, NULL);
|
|
}
|
|
|
|
/* End of fuio.cc */
|