1 
2 #include "ddconfig.h"
3 
4 #include <stdio.h>
5 #if defined HAVE_SYS_SOCKET_H
6 # include <sys/socket.h>
7 # include <sys/select.h>
8 # include <netinet/in.h>
9 # include <arpa/inet.h>
10 #endif
11 #include <signal.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <time.h>
17 #include <string.h>
18 #include <stdarg.h>
19 #include <fcntl.h>
20 
21 #include "utils.h"
22 
23 #include "fuiocl.h"
24 
25 
26 cl_f *dd= NULL;
27 
deb(const char * format,...)28 void deb(const char *format, ...)
29 {
30   return;
31   if (dd==NULL)
32     {
33       dd= mk_io(/*cchars("/dev/pts/2"),cchars("w")*/"","");
34       dd->file_id= open("/dev/pts/4", O_WRONLY);
35       //dd->init();
36     }
37   va_list ap;
38   va_start(ap, format);
39   //dd->vprintf(format, ap);
40   //vdprintf(dd->file_id, format, ap);
41   {
42     char *buf= vformat_string(format, ap);
43     /*dd->*/write(dd->file_id, buf, strlen(buf));
44     free(buf);
45   }
46   va_end(ap);
47 }
48 
49 
cl_io()50 cl_io::cl_io(): cl_f()
51 {
52 }
53 
cl_io(chars fn,chars mode)54 cl_io::cl_io(chars fn, chars mode): cl_f(fn, mode)
55 {
56 }
57 
cl_io(int the_server_port)58 cl_io::cl_io(int the_server_port): cl_f(the_server_port)
59 {
60 }
61 
62 int
close(void)63 cl_io::close(void)
64 {
65   int i= 0;
66 
67   deb("fuio close fid=%d\n", file_id);
68   if ((type == F_SOCKET) ||
69       (type == F_LISTENER))
70     {
71       restore_attributes();
72       shutdown(file_id, 2/*SHUT_RDWR*/);
73     }
74   /*
75   if (file_f)
76     {
77       restore_attributes();
78       i= fclose(file_f);
79     }
80     else*/ if (file_id >= 0)
81     {
82       restore_attributes();
83       i= ::close(file_id);
84     }
85 
86   //file_f= NULL;
87   file_id= -1;
88   own= false;
89   file_name= 0;
90   file_mode= 0;
91 
92   changed();
93   return i;
94 }
95 
~cl_io(void)96 cl_io::~cl_io(void)
97 {
98   deb("~cl_uio fid=%d\n", file_id);
99   restore_attributes();
100   if (echo_of != NULL)
101     echo_of->echo(NULL);
102   if (/*file_f*/file_id>=0)
103     {
104       if (own)
105 	close();
106       else
107 	stop_use();
108     }
109 }
110 
111 void
changed(void)112 cl_io::changed(void)
113 {
114   //printf("fuio changed fid=%d\n", file_id);
115   if (file_id < 0)
116     {
117       type= F_UNKNOWN;
118     }
119   else
120     {
121       type= determine_type();
122       if (type == F_SOCKET) tty= true;
123     }
124 }
125 
126 enum file_type
determine_type(void)127 cl_io::determine_type(void)
128 {
129   int i;
130   struct stat s;
131 
132   if (file_id < 0)
133     return F_UNKNOWN;
134   i= fstat(file_id, &s);
135   if (i < 0)
136     return F_UNKNOWN;
137 
138   if (S_ISDIR(s.st_mode) ||
139       S_ISLNK(s.st_mode))
140     return F_UNKNOWN;
141   if (S_ISCHR(s.st_mode))
142     return F_CHAR;
143   if (S_ISFIFO(s.st_mode))
144     return F_PIPE;
145   if (S_ISBLK(s.st_mode) ||
146       S_ISREG(s.st_mode))
147     return F_FILE;
148   if (S_ISSOCK(s.st_mode))
149     return F_SOCKET;
150   return F_UNKNOWN;
151 }
152 
153 int
check_dev(void)154 cl_io::check_dev(void)
155 {
156   struct timeval tv= { 0, 0 };
157   fd_set s;
158   int i;
159 
160   if (file_id<0)
161     {
162       return 0;
163     }
164   switch (type)
165     {
166     case F_UNKNOWN:
167     case F_CONSOLE:
168     case F_SERIAL:
169       return false;
170       break;
171     case F_FILE:
172       pick();
173       return last_used != first_free;
174       break;
175     case F_CHAR:
176     case F_SOCKET:
177     case F_LISTENER:
178     case F_PIPE:
179       FD_ZERO(&s);
180       FD_SET(file_id, &s);
181       i= select(file_id+1, &s, NULL, NULL, &tv);
182       if (i >= 0)
183 	{
184 	  int ret= FD_ISSET(file_id, &s);
185 	  if (type == F_LISTENER)
186 	    return ret;
187 	  if (ret)
188 	    {
189 	      pick();
190 	    }
191 	  return last_used != first_free;
192 	}
193       break;
194     }
195   return 0;
196 }
197 
198 void
prepare_terminal()199 cl_io::prepare_terminal()
200 {
201   if (type == F_SOCKET)
202     {
203       // assume telnet client
204       char s[7];
205       //deb("preparing TELNET %d\n", file_id);
206       sprintf(s, "%c%c%c%c%c%c", 0xff, 0xfb, 1, 0xff, 0xfb, 3 );
207       write(s, 7);
208     }
209   else if (tty)
210     {
211       struct termios tattr;
212       //deb("preparing TTY %d\n", file_id);
213       tcgetattr(file_id, &tattr);
214       tattr.c_iflag&= ~IXON;
215       tattr.c_lflag&= ~ICANON;
216       tattr.c_lflag&= ~ECHO;
217       tattr.c_cc[VMIN] = 1;
218       tattr.c_cc[VTIME]= 0;
219       tcsetattr(file_id, TCSAFLUSH, &tattr);
220     }
221 }
222 
223 void
save_attributes()224 cl_io::save_attributes()
225 {
226   if ((tty) &&
227       !attributes_saved)
228     {
229       tcgetattr(file_id, &saved_attributes);
230       attributes_saved= 1;
231     }
232 }
233 
234 void
restore_attributes()235 cl_io::restore_attributes()
236 {
237   if (attributes_saved)
238     {
239       saved_attributes.c_lflag|= ICANON|ECHO;
240       tcsetattr(file_id, TCSAFLUSH, &saved_attributes);
241       attributes_saved= 0;
242     }
243 }
244 
245 int
mk_srv_socket(int port)246 mk_srv_socket(int port)
247 {
248   int sock, i;
249   struct sockaddr_in name;
250 
251   /* Create the socket. */
252   sock= socket(PF_INET, SOCK_STREAM, 0);
253   if (sock < 0)
254     {
255       perror("socket");
256       return(0);
257     }
258 
259   /* Give the socket a name. */
260   i= 1;
261   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof(i)) < 0)
262     {
263       perror("setsockopt");
264     }
265   name.sin_family     = AF_INET;
266   name.sin_port       = htons(port);
267   name.sin_addr.s_addr= htonl(INADDR_ANY);
268   if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0)
269     {
270       perror("bind");
271       return(0);
272     }
273 
274   return(sock);
275 }
276 
277 
278 class cl_f *
mk_io(chars fn,chars mode)279 mk_io(chars fn, chars mode)
280 {
281   class cl_io *io;
282 
283   if (fn.empty())
284     {
285       io= new cl_io();
286       io->init();
287       return io;
288     }
289   else if (strcmp(fn, "-") == 0)
290     {
291       if (strcmp(mode, "r") == 0)
292 	return cp_io(fileno(stdin), mode);
293       else if (strcmp(mode, "w") == 0)
294 	return cp_io(fileno(stdout), mode);
295     }
296   io= new cl_io(fn, mode);
297   io->init();
298   return io;
299 }
300 
301 class cl_f *
cp_io(int file_id,chars mode)302 cp_io(/*FILE *f*/int file_id, chars mode)
303 {
304   class cl_io *io;
305 
306   io= new cl_io();
307   if (/*f*/file_id>=0)
308     io->use_opened(/*fileno(f)*/file_id, mode);
309   return io;
310 }
311 
312 class cl_f *
mk_srv(int server_port)313 mk_srv(int server_port)
314 {
315   class cl_io *io;
316 
317   io= new cl_io(server_port);
318   io->init();
319   io->type= F_LISTENER;
320   return io;
321 }
322 
323 
324 int
srv_accept(class cl_f * listen_io,class cl_f ** fin,class cl_f ** fout)325 srv_accept(class cl_f *listen_io,
326 	   class cl_f **fin, class cl_f **fout)
327 {
328   class cl_io *io;
329   //ACCEPT_SOCKLEN_T size;
330   //struct sockaddr_in sock_addr;
331   int new_sock;
332 
333   //size= sizeof(struct sockaddr);
334   new_sock= accept(listen_io->file_id, /*(struct sockaddr *)sock_addr*/NULL, /*&size*/NULL);
335 
336   if (fin)
337     {
338       io= new cl_io(listen_io->server_port);
339       if (new_sock > 0)
340 	{
341 	  io->own_opened(new_sock, cchars("r"));
342 	}
343       *fin= io;
344     }
345 
346   if (fout)
347     {
348       io= new cl_io(listen_io->server_port);
349       if (new_sock > 0)
350 	{
351 	  io->use_opened(new_sock, cchars("w"));
352 	}
353       *fout= io;
354     }
355 
356   return 0;
357 }
358 
359 bool
check_inputs(class cl_list * active,class cl_list * avail)360 check_inputs(class cl_list *active, class cl_list *avail)
361 {
362   int i;
363   bool ret= false;
364 
365   if (!active)
366     return false;
367 
368   if (avail)
369     avail->disconn_all();
370 
371   for (i= 0; i < active->count; i++)
372     {
373       class cl_f *fio= (class cl_f *)active->at(i);
374       //deb("checking fid=%d\n", fio->file_id);
375       if (fio->check_dev() ||
376 	  fio->eof())
377 	{
378 	  deb("found dev input on fid=%d\n", fio->file_id);
379 	  if (avail)
380 	    avail->add(fio);
381 	  ret= true;
382 	}
383       else
384 	;//deb("no dev input on fid=%d\n", fio->file_id);
385     }
386   return ret;
387 }
388 
389 void
msleep(int msec)390 msleep(int msec)
391 {
392   struct timespec t;
393 
394   t.tv_sec= msec/1000;
395   t.tv_nsec= (msec%1000)*1000000;
396   nanosleep(&t, NULL);
397 }
398 
399 void
loop_delay()400 loop_delay()
401 {
402   msleep(100);
403 }
404 
405 
406 void
sigpipe_off()407 sigpipe_off()
408 {
409   struct sigaction sa;
410   sa.sa_handler= SIG_IGN;
411   sigaction(SIGPIPE, &sa, NULL);
412 }
413 
414 /* End of fuio.cc */
415