/* * TOPPERS ECHONET Lite Communication Middleware * * Copyright (C) 2017 Cores Co., Ltd. Japan * * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー * スコード中に含まれていること. * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 * の無保証規定を掲載すること. * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ * と. * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 * 作権表示,この利用条件および下記の無保証規定を掲載すること. * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに * 報告すること. * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを * 免責すること. * * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ * の責任を負わない. * * @(#) $Id$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../../musl-1.1.12/include/poll.h" #include "syssvc/serial.h" #include "syssvc/syslog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "ff.h" #include "socket_stub.h" #include "kernel_cfg.h" #define SIO_PORTID 1 #define IO_TYPE_FREE 0 #define IO_TYPE_SIO 1 #define IO_TYPE_FILE 2 #define IO_TYPE_TCP 3 #define IO_TYPE_UDP 4 static struct _IO_FILE fd_table[8 * sizeof(FLGPTN)] = { { 0, IO_TYPE_SIO, 0, stdio_close, stdin_read, stdio_write }, { 1, IO_TYPE_SIO, 0, stdio_close, stdio_read, stdout_write }, { 2, IO_TYPE_SIO, 0, stdio_close, stdio_read, stderr_write }, }; #define fd_table_count (sizeof(fd_table) / sizeof(fd_table[0])) static int new_fd(int type, int id) { for (int fd = 3; fd < fd_table_count; fd++) { struct _IO_FILE *fp = &fd_table[fd]; if (fp->type != IO_TYPE_FREE) continue; fp->fd = fd; fp->type = type; fp->handle = id; return fd; } return -1; } static struct _IO_FILE *id_to_fd(int type, int id) { for (int fd = 3; fd < fd_table_count; fd++) { struct _IO_FILE *fp = &fd_table[fd]; if ((fp->type == type) && (fp->handle == id)) return fp; } return NULL; } static int delete_fd(int type, int id) { struct _IO_FILE *fp = id_to_fd(type, id); if (fp == NULL) return -1; memset(fp, 0, sizeof(struct _IO_FILE)); return 0; } struct _IO_FILE *fd_to_fp(int fd) { if ((fd < 0) || (fd >= fd_table_count)) return NULL; return &fd_table[fd]; } struct _IO_FILE *new_sio_fd(int sioid) { int fd = new_fd(IO_TYPE_SIO, sioid); if ((fd < 0) || (fd >= fd_table_count)) return NULL; struct _IO_FILE *fp = &fd_table[fd]; fp->close = sio_close; fp->read = sio_read; fp->write = sio_write; return fp; } int delete_sio_fd(int sioid) { return delete_fd(IO_TYPE_SIO, sioid); } struct _IO_FILE *sioid_to_fd(int sioid) { return id_to_fd(IO_TYPE_SIO, sioid); } struct _IO_FILE *new_file_fd(int fileid) { int fd = new_fd(IO_TYPE_FILE, fileid); if ((fd < 0) || (fd >= fd_table_count)) return NULL; struct _IO_FILE *fp = &fd_table[fd]; fp->close = file_close; fp->read = file_read; fp->write = file_write; return fp; } int delete_file_fd(int fileid) { return delete_fd(IO_TYPE_FILE, fileid); } struct _IO_FILE *fileid_to_fd(int fileid) { return id_to_fd(IO_TYPE_FILE, fileid); } struct _IO_FILE *new_tcp_fd(int tcpid) { int fd = new_fd(IO_TYPE_TCP, tcpid); if ((fd < 0) || (fd >= fd_table_count)) return NULL; struct _IO_FILE *fp = &fd_table[fd]; fp->close = tcp_fd_close; fp->read = tcp_fd_read; fp->write = tcp_fd_write; return fp; } int delete_tcp_fd(int tcpid) { return delete_fd(IO_TYPE_TCP, tcpid); } struct _IO_FILE *tcpid_to_fd(int tcpid) { return id_to_fd(IO_TYPE_TCP, tcpid); } struct _IO_FILE *new_udp_fd(int udpid) { int fd = new_fd(IO_TYPE_UDP, udpid); if ((fd < 0) || (fd >= fd_table_count)) return NULL; struct _IO_FILE *fp = &fd_table[fd]; fp->close = udp_fd_close; fp->read = udp_fd_read; fp->write = udp_fd_write; return fp; } int delete_udp_fd(int udpid) { return delete_fd(IO_TYPE_UDP, udpid); } struct _IO_FILE *udpid_to_fd(int udpid) { return id_to_fd(IO_TYPE_UDP, udpid); } int shell_isatty(int fd) { if ((fd < 0) || (fd >= fd_table_count)) return 0; struct _IO_FILE *fp = &fd_table[fd]; if (fp->type == IO_TYPE_SIO) return 1; return 0; } struct fd_events { int count; fd_set readfds; fd_set writefds; fd_set errorfds; }; ER shell_get_evts(struct fd_events *evts, TMO tmout); #define TMO_MAX INT_MAX int select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv) { ER ret; TMO tmout = TMO_FEVR; struct fd_events evts; if (tv != NULL) { if (tv->tv_sec < (TMO_MAX / 1000000)) tmout = tv->tv_sec * 1000000 + tv->tv_usec; else tmout = TMO_MAX; } memcpy(&evts.readfds, rfds, sizeof(fd_set)); memcpy(&evts.writefds, wfds, sizeof(fd_set)); memcpy(&evts.errorfds, efds, sizeof(fd_set)); evts.count = 0; ret = shell_get_evts(&evts, tmout); if (ret == E_OK) { memcpy(rfds, &evts.readfds, sizeof(fd_set)); memcpy(wfds, &evts.writefds, sizeof(fd_set)); memcpy(efds, &evts.errorfds, sizeof(fd_set)); return evts.count; } if (ret == E_TMOUT) { memset(rfds, 0, sizeof(fd_set)); memset(wfds, 0, sizeof(fd_set)); memset(efds, 0, sizeof(fd_set)); return 0; } return -1; } int poll(struct pollfd *fds, nfds_t nfds, int timeout) { ER ret; TMO tmout; struct fd_events evts; if(timeout < 0) tmout = TMO_FEVR; else if (timeout < (TMO_MAX / 1000)) tmout = timeout * 1000; else tmout = TMO_MAX; memset(&evts, 0, sizeof(evts)); for (int i = 0; i < nfds; i++) { struct pollfd *pfd = &fds[i]; int fd = pfd->fd; if ((fd < 0) || (fd >= fd_table_count)) continue; if (pfd->events & POLLIN) FD_SET(fd, &evts.readfds); if (pfd->events & POLLOUT) FD_SET(fd, &evts.writefds); if (pfd->events & POLLERR) FD_SET(fd, &evts.errorfds); pfd->revents = 0; } ret = shell_get_evts(&evts, tmout); if (ret == E_OK) { int result = 0; for (int i = 0; i < nfds; i++) { struct pollfd *pfd = &fds[i]; int fd = pfd->fd; if ((fd < 0) || (fd >= fd_table_count)) continue; if (FD_ISSET(fd, &evts.readfds)) pfd->revents |= POLLIN; if (FD_ISSET(fd, &evts.writefds)) pfd->revents |= POLLOUT; if (FD_ISSET(fd, &evts.errorfds)) pfd->revents |= POLLERR; if (pfd->revents != 0) result++; } return result; } if (ret == E_TMOUT) { return 0; } return -1; } void stdio_update_evts() { int fd = STDIN_FILENO; struct _IO_FILE *fp = &fd_table[fd]; T_SERIAL_RPOR rpor; FLGPTN flgptn = 0; ER ret = serial_ref_por(SIO_PORTID, &rpor); if (ret != E_OK) return; if (rpor.reacnt != 0) { if (fp->readevt_w == fp->readevt_r) fp->readevt_w++; FD_SET(fd, (fd_set *)&flgptn); } if (rpor.wricnt != 0) { if (fp->writeevt_w == fp->writeevt_r) fp->writeevt_w++; FD_SET(fd, (fd_set *)&flgptn); } if (flgptn != 0) { set_flg(FLG_SELECT_WAIT, flgptn); } } void stdio_flgptn(FLGPTN *flgptn) { int fd = STDIN_FILENO; struct _IO_FILE *fp = &fd_table[fd]; T_SERIAL_RPOR rpor; *flgptn = 0; ER ret = serial_ref_por(SIO_PORTID, &rpor); if (ret != E_OK) return; if (rpor.reacnt != 0) { if (fp->readevt_w == fp->readevt_r) fp->readevt_w++; FD_SET(fd, (fd_set *)flgptn); } if (rpor.wricnt != 0) { if (fp->writeevt_w == fp->writeevt_r) fp->writeevt_w++; FD_SET(fd, (fd_set *)flgptn); } } ER socket_tcp_callback(ID cepid, FN fncd, void *p_parblk) { struct _IO_FILE *fp = tcpid_to_fd(cepid); FLGPTN flgptn = 0; if (fp == NULL) return E_PAR; int fd = fp->fd; FD_SET(fd, (fd_set *)&flgptn); switch (fncd) { case TFN_TCP_RCV_DAT: if (fp->readevt_w == fp->readevt_r) fp->readevt_w++; set_flg(FLG_SELECT_WAIT, flgptn); return E_OK; case TFN_TCP_SND_DAT: if (fp->writeevt_w == fp->writeevt_r) fp->writeevt_w++; set_flg(FLG_SELECT_WAIT, flgptn); return E_OK; case TFN_TCP_CAN_CEP: if (fp->errorevt_w == fp->errorevt_r) fp->errorevt_w++; set_flg(FLG_SELECT_WAIT, flgptn); return E_OK; case TFN_TCP_DEL_REP: delete_tcp_rep(cepid); return E_OK; case TFN_TCP_DEL_CEP: delete_tcp_fd(cepid); return E_OK; default: return E_OK; } } ER socket_udp_callback(ID cepid, FN fncd, void *p_parblk) { struct _IO_FILE *fp = udpid_to_fd(cepid); FLGPTN flgptn = 0; if (fp == NULL) return E_PAR; int fd = fp->fd; FD_SET(fd, (fd_set *)&flgptn); switch (fncd) { case TFN_UDP_CRE_CEP: case TFN_UDP_RCV_DAT: if (fp->readevt_w == fp->readevt_r) fp->readevt_w++; set_flg(FLG_SELECT_WAIT, flgptn); return E_OK; case TFN_UDP_SND_DAT: if (fp->writeevt_w == fp->writeevt_r) fp->writeevt_w++; set_flg(FLG_SELECT_WAIT, flgptn); return E_OK; case TFN_UDP_CAN_CEP: if (fp->errorevt_w == fp->errorevt_r) fp->errorevt_w++; set_flg(FLG_SELECT_WAIT, flgptn); return E_OK; case TFN_UDP_DEL_CEP: delete_udp_fd(cepid); return E_OK; default: return E_OK; } } ER shell_get_evts(struct fd_events *evts, TMO tmout) { ER ret; FLGPTN waitptn, flgptn = 0; stdio_update_evts(); waitptn = *((FLGPTN *)&evts->readfds) | *((FLGPTN *)&evts->writefds) | *((FLGPTN *)&evts->errorfds); memset(evts, 0, sizeof(*evts)); /* イベント待ち */ ret = twai_flg(FLG_SELECT_WAIT, waitptn, TWF_ORW, &flgptn, tmout); if (ret != E_OK) { if (ret != E_TMOUT) { syslog(LOG_ERROR, "twai_flg => %d", ret); return ret; } stdio_flgptn(&flgptn); if (flgptn == 0) return E_TMOUT; } flgptn &= waitptn; /* 受け取ったフラグのみクリア */ ret = clr_flg(FLG_SELECT_WAIT, ~flgptn); if (ret != E_OK) { syslog(LOG_ERROR, "clr_flg => %d", ret); } struct _IO_FILE *fp = NULL; for (int fd = 0; fd < fd_table_count; fd++) { if (!FD_ISSET(fd, (fd_set *)&flgptn)) continue; fp = &fd_table[fd]; if (fp->readevt_w != fp->readevt_r) { fp->readevt_r++; FD_SET(fd, &evts->readfds); evts->count++; } if (fp->writeevt_w != fp->writeevt_r) { fp->writeevt_r++; FD_SET(fd, &evts->writefds); evts->count++; } if (fp->errorevt_w != fp->errorevt_r) { fp->errorevt_r++; FD_SET(fd, &evts->errorfds); evts->count++; } } return E_OK; } void clean_fd() { struct _IO_FILE *fp = NULL; for (int fd = 3; fd < fd_table_count; fd++) { fp = &fd_table[fd]; if ((fp->type == 0) || (fp->fd == 0)) continue; fp->close(fp); memset(fp, 0, sizeof(*fp)); } }