/[LeafOK_CVS]/lbbs/src/io.c
ViewVC logotype

Diff of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.62 by sysadm, Tue Nov 4 13:49:51 2025 UTC Revision 1.67 by sysadm, Mon Nov 17 06:41:18 2025 UTC
# Line 3  Line 3 
3   * io   * io
4   *   - basic terminal-based user input / output features   *   - basic terminal-based user input / output features
5   *   *
6   * Copyright (C) 2004-2025 by Leaflet <leaflet@leafok.com>   * Copyright (C) 2004-2025  Leaflet <leaflet@leafok.com>
7   */   */
8    
9    #ifdef HAVE_CONFIG_H
10    #include "config.h"
11    #endif
12    
13  #include "common.h"  #include "common.h"
14  #include "io.h"  #include "io.h"
15  #include "log.h"  #include "log.h"
# Line 16  Line 20 
20  #include <string.h>  #include <string.h>
21  #include <time.h>  #include <time.h>
22  #include <unistd.h>  #include <unistd.h>
 #include <sys/epoll.h>  
23  #include <sys/ioctl.h>  #include <sys/ioctl.h>
24  #include <sys/select.h>  #include <sys/select.h>
25  #include <libssh/callbacks.h>  #include <libssh/callbacks.h>
26  #include <libssh/libssh.h>  #include <libssh/libssh.h>
27  #include <libssh/server.h>  #include <libssh/server.h>
28    
29  char stdio_charset[20] = BBS_DEFAULT_CHARSET;  #ifdef HAVE_SYS_EPOLL_H
30    #include <sys/epoll.h>
31    #else
32    #include <poll.h>
33    #endif
34    
35    const char BBS_default_charset[CHARSET_MAX_LEN + 1] = "UTF-8";
36    char stdio_charset[CHARSET_MAX_LEN + 1] = "UTF-8";
37    
38    #ifdef HAVE_SYS_EPOLL_H
39    // epoll for STDIO
40    static int stdin_epollfd = -1;
41    static int stdout_epollfd = -1;
42    #endif
43    
44    static int stdin_flags = 0;
45    static int stdout_flags = 0;
46    
47  // static input / output buffer  // static input / output buffer
48  static char stdin_buf[LINE_BUFFER_LEN];  static char stdin_buf[LINE_BUFFER_LEN];
# Line 43  static int stdout_conv_offset = 0; Line 62  static int stdout_conv_offset = 0;
62  static iconv_t stdin_cd = NULL;  static iconv_t stdin_cd = NULL;
63  static iconv_t stdout_cd = NULL;  static iconv_t stdout_cd = NULL;
64    
65    int io_init(void)
66    {
67    #ifdef HAVE_SYS_EPOLL_H
68            struct epoll_event ev;
69    
70            if (stdin_epollfd == -1)
71            {
72                    stdin_epollfd = epoll_create1(0);
73                    if (stdin_epollfd == -1)
74                    {
75                            log_error("epoll_create1() error (%d)\n", errno);
76                            return -1;
77                    }
78    
79                    ev.events = EPOLLIN;
80                    ev.data.fd = STDIN_FILENO;
81                    if (epoll_ctl(stdin_epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)
82                    {
83                            log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
84                            if (close(stdin_epollfd) < 0)
85                            {
86                                    log_error("close(stdin_epollfd) error (%d)\n");
87                            }
88                            stdin_epollfd = -1;
89                            return -1;
90                    }
91    
92                    stdin_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
93                    fcntl(STDIN_FILENO, F_SETFL, stdin_flags | O_NONBLOCK);
94            }
95    
96            if (stdout_epollfd == -1)
97            {
98                    stdout_epollfd = epoll_create1(0);
99                    if (stdout_epollfd == -1)
100                    {
101                            log_error("epoll_create1() error (%d)\n", errno);
102                            return -1;
103                    }
104    
105                    ev.events = EPOLLOUT;
106                    ev.data.fd = STDOUT_FILENO;
107                    if (epoll_ctl(stdout_epollfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev) == -1)
108                    {
109                            log_error("epoll_ctl(STDOUT_FILENO) error (%d)\n", errno);
110                            if (close(stdout_epollfd) < 0)
111                            {
112                                    log_error("close(stdout_epollfd) error (%d)\n");
113                            }
114                            stdout_epollfd = -1;
115                            return -1;
116                    }
117    
118                    stdout_flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
119                    fcntl(STDOUT_FILENO, F_SETFL, stdout_flags | O_NONBLOCK);
120            }
121    #else
122            if (stdin_flags == 0)
123            {
124                    stdin_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
125                    fcntl(STDIN_FILENO, F_SETFL, stdin_flags | O_NONBLOCK);
126            }
127    
128            if (stdout_flags == 0)
129            {
130                    stdout_flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
131                    fcntl(STDOUT_FILENO, F_SETFL, stdout_flags | O_NONBLOCK);
132            }
133    #endif
134    
135            return 0;
136    }
137    
138    void io_cleanup(void)
139    {
140    #ifdef HAVE_SYS_EPOLL_H
141            if (stdin_epollfd != -1)
142            {
143                    fcntl(STDIN_FILENO, F_SETFL, stdin_flags);
144                    stdin_flags = 0;
145    
146                    if (close(stdin_epollfd) < 0)
147                    {
148                            log_error("close(stdin_epollfd) error (%d)\n");
149                    }
150                    stdin_epollfd = -1;
151            }
152    
153            if (stdout_epollfd != -1)
154            {
155                    fcntl(STDOUT_FILENO, F_SETFL, stdout_flags);
156                    stdout_flags = 0;
157    
158                    if (close(stdout_epollfd) < 0)
159                    {
160                            log_error("close(stdout_epollfd) error (%d)\n");
161                    }
162                    stdout_epollfd = -1;
163            }
164    #else
165            if (stdin_flags != 0)
166            {
167                    fcntl(STDIN_FILENO, F_SETFL, stdin_flags);
168                    stdin_flags = 0;
169            }
170    
171            if (stdout_flags != 0)
172            {
173                    fcntl(STDOUT_FILENO, F_SETFL, stdout_flags);
174                    stdout_flags = 0;
175            }
176    #endif
177    }
178    
179  int prints(const char *format, ...)  int prints(const char *format, ...)
180  {  {
181          char buf[BUFSIZ];          char buf[BUFSIZ];
# Line 101  int outc(char c) Line 234  int outc(char c)
234    
235  int iflush(void)  int iflush(void)
236  {  {
237          int flags;  #ifdef HAVE_SYS_EPOLL_H
238          struct epoll_event ev, events[MAX_EVENTS];          struct epoll_event events[MAX_EVENTS];
239          int nfds, epollfd;  #else
240            struct pollfd pfds[1];
241    #endif
242    
243            int nfds;
244          int retry;          int retry;
245          int ret = 0;          int ret = 0;
246    
         epollfd = epoll_create1(0);  
         if (epollfd < 0)  
         {  
                 log_error("epoll_create1() error (%d)\n", errno);  
                 return -1;  
         }  
   
         ev.events = EPOLLOUT;  
         ev.data.fd = STDOUT_FILENO;  
         if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev) == -1)  
         {  
                 log_error("epoll_ctl(STDOUT_FILENO) error (%d)\n", errno);  
                 if (close(epollfd) < 0)  
                 {  
                         log_error("close(epoll) error (%d)\n");  
                 }  
                 return -1;  
         }  
   
         // Set STDOUT as non-blocking  
         flags = fcntl(STDOUT_FILENO, F_GETFL, 0);  
         fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);  
   
247          // Retry wait / flush for at most 3 times          // Retry wait / flush for at most 3 times
248          retry = 3;          retry = 3;
249          while (retry > 0 && !SYS_server_exit)          while (retry > 0 && !SYS_server_exit)
250          {          {
251                  retry--;                  retry--;
252    
253                  nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second  #ifdef HAVE_SYS_EPOLL_H
254                    nfds = epoll_wait(stdout_epollfd, events, MAX_EVENTS, 100); // 0.1 second
255                    ret = nfds;
256    #else
257                    pfds[0].fd = STDOUT_FILENO;
258                    pfds[0].events = POLLOUT;
259                    nfds = 1;
260                    ret = poll(pfds, (nfds_t)nfds, 100); // 0.1 second
261    #endif
262    
263                  if (nfds < 0)                  if (ret < 0)
264                  {                  {
265                          if (errno != EINTR)                          if (errno != EINTR)
266                          {                          {
267    #ifdef HAVE_SYS_EPOLL_H
268                                  log_error("epoll_wait() error (%d)\n", errno);                                  log_error("epoll_wait() error (%d)\n", errno);
269    #else
270                                    log_error("poll() error (%d)\n", errno);
271    #endif
272                                  break;                                  break;
273                          }                          }
274                          continue;                          continue;
275                  }                  }
276                  else if (nfds == 0) // timeout                  else if (ret == 0) // timeout
277                  {                  {
278                          continue;                          continue;
279                  }                  }
280    
281                  for (int i = 0; i < nfds; i++)                  for (int i = 0; i < nfds; i++)
282                  {                  {
283    #ifdef HAVE_SYS_EPOLL_H
284                          if (events[i].data.fd == STDOUT_FILENO)                          if (events[i].data.fd == STDOUT_FILENO)
285    #else
286                            if (pfds[i].fd == STDOUT_FILENO && (pfds[i].revents & POLLOUT))
287    #endif
288                          {                          {
289                                  if (stdout_buf_offset < stdout_buf_len)                                  if (stdout_buf_offset < stdout_buf_len)
290                                  {                                  {
# Line 224  int iflush(void) Line 354  int iflush(void)
354                  }                  }
355          }          }
356    
         // Restore STDOUT flags  
         fcntl(STDOUT_FILENO, F_SETFL, flags);  
   
         if (close(epollfd) < 0)  
         {  
                 log_error("close(epoll) error (%d)\n");  
         }  
   
357          return ret;          return ret;
358  }  }
359    
# Line 239  int igetch(int timeout) Line 361  int igetch(int timeout)
361  {  {
362          static int stdin_read_wait = 0;          static int stdin_read_wait = 0;
363    
364          struct epoll_event ev, events[MAX_EVENTS];  #ifdef HAVE_SYS_EPOLL_H
365          int nfds, epollfd;          struct epoll_event events[MAX_EVENTS];
366    #else
367            struct pollfd pfds[1];
368    #endif
369    
370            int nfds;
371          int ret;          int ret;
372          int loop;          int loop;
373    
# Line 250  int igetch(int timeout) Line 377  int igetch(int timeout)
377          int in_ascii = 0;          int in_ascii = 0;
378          int in_control = 0;          int in_control = 0;
379          int i = 0;          int i = 0;
         int flags;  
380    
381          if (stdin_conv_offset >= stdin_conv_len)          if (stdin_conv_offset >= stdin_conv_len)
382          {          {
383                  stdin_conv_len = 0;                  stdin_conv_len = 0;
384                  stdin_conv_offset = 0;                  stdin_conv_offset = 0;
385    
                 epollfd = epoll_create1(0);  
                 if (epollfd < 0)  
                 {  
                         log_error("epoll_create1() error (%d)\n", errno);  
                         return -1;  
                 }  
   
                 ev.events = EPOLLIN;  
                 ev.data.fd = STDIN_FILENO;  
                 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)  
                 {  
                         log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);  
   
                         if (close(epollfd) < 0)  
                         {  
                                 log_error("close(epoll) error (%d)\n");  
                         }  
                         return -1;  
                 }  
   
                 flags = fcntl(STDIN_FILENO, F_GETFL, 0);  
                 fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);  
   
386                  for (loop = 1; loop && stdin_buf_len < sizeof(stdin_buf) && stdin_conv_offset >= stdin_conv_len && !SYS_server_exit;)                  for (loop = 1; loop && stdin_buf_len < sizeof(stdin_buf) && stdin_conv_offset >= stdin_conv_len && !SYS_server_exit;)
387                  {                  {
388                          if (SSH_v2 && ssh_channel_is_closed(SSH_channel))                          if (SSH_v2 && ssh_channel_is_closed(SSH_channel))
# Line 291  int igetch(int timeout) Line 394  int igetch(int timeout)
394    
395                          if (!stdin_read_wait)                          if (!stdin_read_wait)
396                          {                          {
397                                  nfds = epoll_wait(epollfd, events, MAX_EVENTS, timeout);  #ifdef HAVE_SYS_EPOLL_H
398                                    nfds = epoll_wait(stdin_epollfd, events, MAX_EVENTS, timeout);
399                                    ret = nfds;
400    #else
401                                    pfds[0].fd = STDIN_FILENO;
402                                    pfds[0].events = POLLIN;
403                                    nfds = 1;
404                                    ret = poll(pfds, (nfds_t)nfds, timeout);
405    #endif
406    
407                                  if (nfds < 0)                                  if (ret < 0)
408                                  {                                  {
409                                          if (errno != EINTR)                                          if (errno != EINTR)
410                                          {                                          {
411    #ifdef HAVE_SYS_EPOLL_H
412                                                  log_error("epoll_wait() error (%d)\n", errno);                                                  log_error("epoll_wait() error (%d)\n", errno);
413    #else
414                                                    log_error("poll() error (%d)\n", errno);
415    #endif
416                                                  break;                                                  break;
417                                          }                                          }
418                                          continue;                                          continue;
419                                  }                                  }
420                                  else if (nfds == 0) // timeout                                  else if (ret == 0) // timeout
421                                  {                                  {
422                                          out = KEY_TIMEOUT;                                          out = KEY_TIMEOUT;
423                                          break;                                          break;
# Line 310  int igetch(int timeout) Line 425  int igetch(int timeout)
425    
426                                  for (int i = 0; i < nfds; i++)                                  for (int i = 0; i < nfds; i++)
427                                  {                                  {
428    #ifdef HAVE_SYS_EPOLL_H
429                                          if (events[i].data.fd == STDIN_FILENO)                                          if (events[i].data.fd == STDIN_FILENO)
430    #else
431                                            if (pfds[i].fd == STDIN_FILENO && (pfds[i].revents & POLLIN))
432    #endif
433                                          {                                          {
434                                                  stdin_read_wait = 1;                                                  stdin_read_wait = 1;
435                                          }                                          }
# Line 393  int igetch(int timeout) Line 512  int igetch(int timeout)
512  #endif  #endif
513                  }                  }
514    
                 fcntl(STDIN_FILENO, F_SETFL, flags);  
   
                 if (close(epollfd) < 0)  
                 {  
                         log_error("close(epoll) error (%d)\n");  
                 }  
   
515                  if (stdin_buf_offset < stdin_buf_len)                  if (stdin_buf_offset < stdin_buf_len)
516                  {                  {
517                          ret = io_buf_conv(stdin_cd, stdin_buf, &stdin_buf_len, &stdin_buf_offset, stdin_conv, sizeof(stdin_conv), &stdin_conv_len);                          ret = io_buf_conv(stdin_cd, stdin_buf, &stdin_buf_len, &stdin_buf_offset, stdin_conv, sizeof(stdin_conv), &stdin_conv_len);
# Line 1026  int io_buf_conv(iconv_t cd, char *p_buf, Line 1138  int io_buf_conv(iconv_t cd, char *p_buf,
1138    
1139  int io_conv_init(const char *charset)  int io_conv_init(const char *charset)
1140  {  {
1141          char tocode[32];          char tocode[CHARSET_MAX_LEN + 20];
1142    
1143          if (charset == NULL)          if (charset == NULL)
1144          {          {
# Line 1039  int io_conv_init(const char *charset) Line 1151  int io_conv_init(const char *charset)
1151          strncpy(stdio_charset, charset, sizeof(stdio_charset) - 1);          strncpy(stdio_charset, charset, sizeof(stdio_charset) - 1);
1152          stdio_charset[sizeof(stdio_charset) - 1] = '\0';          stdio_charset[sizeof(stdio_charset) - 1] = '\0';
1153    
1154          snprintf(tocode, sizeof(tocode), "%s%s", BBS_DEFAULT_CHARSET,          snprintf(tocode, sizeof(tocode), "%s%s", BBS_default_charset,
1155                           (strcasecmp(stdio_charset, BBS_DEFAULT_CHARSET) == 0 ? "" : "//IGNORE"));                           (strcasecmp(stdio_charset, BBS_default_charset) == 0 ? "" : "//IGNORE"));
1156          stdin_cd = iconv_open(tocode, stdio_charset);          stdin_cd = iconv_open(tocode, stdio_charset);
1157          if (stdin_cd == (iconv_t)(-1))          if (stdin_cd == (iconv_t)(-1))
1158          {          {
# Line 1049  int io_conv_init(const char *charset) Line 1161  int io_conv_init(const char *charset)
1161          }          }
1162    
1163          snprintf(tocode, sizeof(tocode), "%s%s", stdio_charset,          snprintf(tocode, sizeof(tocode), "%s%s", stdio_charset,
1164                           (strcasecmp(BBS_DEFAULT_CHARSET, stdio_charset) == 0 ? "" : "//TRANSLIT"));                           (strcasecmp(BBS_default_charset, stdio_charset) == 0 ? "" : "//TRANSLIT"));
1165          stdout_cd = iconv_open(tocode, BBS_DEFAULT_CHARSET);          stdout_cd = iconv_open(tocode, BBS_default_charset);
1166          if (stdout_cd == (iconv_t)(-1))          if (stdout_cd == (iconv_t)(-1))
1167          {          {
1168                  log_error("iconv_open(%s->%s) error: %d\n", BBS_DEFAULT_CHARSET, tocode, errno);                  log_error("iconv_open(%s->%s) error: %d\n", BBS_default_charset, tocode, errno);
1169                  iconv_close(stdin_cd);                  iconv_close(stdin_cd);
1170                  return -2;                  return -2;
1171          }          }


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1