/* * TINET (TCP/IP Protocol Stack) * * Copyright (C) 2001-2012 by Dep. of Computer Science and Engineering * Tomakomai National College of Technology, JAPAN * * 上記著作権者は,以下の (1)~(4) の条件か,Free Software Foundation * によって公表されている GNU General Public License の Version 2 に記 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア * を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下, * 利用と呼ぶ)することを無償で許諾する. * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー * スコード中に含まれていること. * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 * の無保証規定を掲載すること. * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 * 用できない形で再配布する場合には,次の条件を満たすこと. * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 * 作権表示,この利用条件および下記の無保証規定を掲載すること. * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. * * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない. * * @(#) $Id$ */ /* * ネットワーク化サンプルプログラム(1)の本体 */ #include #include #include "syssvc/syslog.h" #include "syssvc/serial.h" #include "kernel_cfg.h" #include "tinet_cfg.h" #include #include #include "sample1n.h" /* * マクロ定義 */ /* リネームの解除 */ #undef syslog #undef serial_rea_dat #undef serial_ctl_por #define EOF (-1) /* TELNET オプション */ #define TELNET_OPT_SE (240) #define TELNET_OPT_NOP (241) #define TELNET_OPT_DM (242) #define TELNET_OPT_BRK (243) #define TELNET_OPT_IP (244) #define TELNET_OPT_AO (245) #define TELNET_OPT_AYT (246) #define TELNET_OPT_EC (247) #define TELNET_OPT_EL (248) #define TELNET_OPT_GA (249) #define TELNET_OPT_SB (250) #define TELNET_OPT_WILL (251) #define TELNET_OPT_WONT (252) #define TELNET_OPT_DO (253) #define TELNET_OPT_DONT (254) #define TELNET_OPT_IAC (255) /* * 変数 */ /* TCP 送受信ウィンドバッファ */ uint8_t tcp_swbuf[TCP_SWBUF_SIZE]; uint8_t tcp_rwbuf[TCP_RWBUF_SIZE]; bool_t connected = false; /* コネクションの状態 */ bool_t wait_accept = false; /* 接続要求待ち中 */ #ifdef SUPPORT_INET6 T_IPV6EP dst; #else /* of #ifdef SUPPORT_INET6 */ #ifdef SUPPORT_INET4 T_IPV4EP dst; #endif /* of #ifdef SUPPORT_INET4 */ #endif /* of #ifdef SUPPORT_INET6 */ uint8_t *snd_buff = NULL; uint8_t *rcv_buff = NULL; uint_t snd_off = 0; uint_t rcv_off = 0; ER_UINT snd_len = 0; ER_UINT rcv_len = 0; uint_t net_ioctl = IOCTL_NULL; uint8_t addr[sizeof("0123:4567:89ab:cdef:0123:4567:89ab:cdef")]; /* * ネットワーク層の選択 */ #ifdef SUPPORT_INET6 #define TCP_ACP_CEP(c,r,d,t) tcp6_acp_cep(c,r,d,t) #define IP2STR(s,a) ipv62str(s,a) #else /* of #ifdef SUPPORT_INET6 */ #ifdef SUPPORT_INET4 #define TCP_ACP_CEP(c,r,d,t) tcp_acp_cep(c,r,d,t) #define IP2STR(s,a) ip2str(s,a) #endif /* of #ifdef SUPPORT_INET4 */ #endif /* of #ifdef SUPPORT_INET6 */ /* * ノンブロッキングコールのコールバック関数 */ ER callback_nblk_tcp (ID cepid, FN fncd, void *p_parblk) { ER error = E_OK; switch (fncd) { case TFN_TCP_ACP_CEP: IP2STR((char *)addr, &dst.ipaddr); syslog(LOG_NOTICE, "connected: %s.%d", addr, dst.portno); if (*(ER*)p_parblk == E_OK) connected = true; snd_len = snd_off = rcv_len = rcv_off = 0; wait_accept = false; break; case TFN_TCP_CLS_CEP: case TFN_TCP_RCV_BUF: case TFN_TCP_GET_BUF: case TFN_TCP_RCV_DAT: case TFN_TCP_SND_DAT: case TFN_TCP_CON_CEP: case TFN_TCP_SND_OOB: default: error = E_PAR; break; } return error; } /* * コネクションを切断 */ ER disconnecting (void) { ER error = E_OK; if (connected) { syscall(wai_sem(SEM_NET_SEND)); if (snd_off > 0) tcp_snd_buf(TCP_CEPID, snd_off); tcp_sht_cep(TCP_CEPID); tcp_cls_cep(TCP_CEPID, TMO_FEVR); connected = false; syscall(sig_sem(SEM_NET_SEND)); IP2STR((char *)addr, &dst.ipaddr); syslog(LOG_NOTICE, "disconnected: %s.%d", addr, dst.portno); } return error; } /* * 送信バッファのフラッシュ */ void flush_snd_buff (ID cepid) { if (connected) { syscall(wai_sem(SEM_NET_SEND)); if (snd_off > 0) { tcp_snd_buf(cepid, snd_off); snd_len = snd_off = 0; } syscall(sig_sem(SEM_NET_SEND)); } return; } /* * 文字送信 */ void put_char (ID cepid, char ch) { if (connected) { if (ch == '\n' && (net_ioctl & IOCTL_CRLF) != 0) put_char(cepid, '\r'); syscall(wai_sem(SEM_NET_SEND)); if (snd_off >= snd_len) { if (tcp_snd_buf(cepid, snd_off) != E_OK) { syscall(sig_sem(SEM_NET_SEND)); return; } snd_off = 0; if ((snd_len = tcp_get_buf(cepid, (void**)&snd_buff, TMO_FEVR)) <= 0) { syscall(sig_sem(SEM_NET_SEND)); return; } } snd_buff[snd_off ++] = ch; syscall(sig_sem(SEM_NET_SEND)); } } /* * 文字受信(変換なし) */ int_t get_char_raw (ID cepid) { if (connected) { if (rcv_off >= rcv_len) { rcv_off = 0; if (tcp_rel_buf(TCP_CEPID, rcv_len) != E_OK) { disconnecting(); return EOF; } if ((rcv_len = tcp_rcv_buf(TCP_CEPID, (void**)&rcv_buff, TMO_FEVR)) == 0) { disconnecting(); return EOF; } else if (rcv_len < 0) { disconnecting(); return EOF; } } return rcv_buff[rcv_off ++]; } else return EOF; } /* * 文字受信(TELNET オプションをスキップ) */ int_t get_char (ID cepid) { int_t ch, req; while ((ch = get_char_raw(cepid)) == TELNET_OPT_IAC || ch == '\0') { if (ch != '\0') { switch (ch = get_char_raw(cepid)) { case TELNET_OPT_WILL: case TELNET_OPT_WONT: case TELNET_OPT_DO: case TELNET_OPT_DONT: req = get_char_raw(cepid); break; case TELNET_OPT_SB: while ((ch = get_char_raw(cepid)) != EOF && ch != TELNET_OPT_IAC) { if ((ch = get_char_raw(cepid)) == EOF || ch == TELNET_OPT_SE) break; } break; default: break; } } } return ch; } /* * シリアルポートからの読出し */ ER_UINT net_serial_rea_dat (ID portid, char *buf, uint_t len) { T_SERIAL_RPOR rpor; uint_t off; int_t ch; if (!wait_accept && !connected) { wait_accept = true; if (TCP_ACP_CEP(TCP_CEPID, TCP_REPID, &dst, TMO_NBLK) != E_WBLK) return 0; } while (true) { if (connected) { off = 0; while (off < len && (ch = get_char(TCP_CEPID)) != EOF) { *(buf + off ++) = ch; if ((net_ioctl & IOCTL_ECHO) != 0) { put_char(TCP_CEPID, ch); flush_snd_buff(TCP_CEPID); } } return off; } else if (serial_ref_por(portid, &rpor) == E_OK && rpor.reacnt > 0) { return serial_rea_dat(portid, buf, len); } dly_tsk(500000); } return off; } /* * シリアルポートの制御 */ ER net_serial_ctl_por (ID portid, uint_t ioctl) { net_ioctl = ioctl; return serial_ctl_por(portid, ioctl); } /* * もっとも長い整数型 (LONGEST) と符号なし整数型 (ULONGEST) */ #ifdef LONGLONG_TYPE typedef LONGLONG_TYPE LONGEST; typedef unsigned LONGLONG_TYPE ULONGEST; #else /* of #ifdef LONGLONG_TYPE */ #ifdef LONG_TYPE typedef LONG_TYPE LONGEST; typedef unsigned LONG_TYPE ULONGEST; #else /* of #ifdef LONG_TYPE */ typedef int_t LONGEST; typedef uint_t ULONGEST; #endif /* of #ifdef LONG_TYPE */ #endif /* of #ifdef LONGLONG_TYPE */ /* * ログのシミュレーション */ /* 数値変換のための変換表 */ static const char radhex[] = "0123456789abcdef"; static const char radHEX[] = "0123456789ABCDEF"; /* * put_num -- printf の数値変換 */ int_t put_num(ID cepid, ULONGEST val, int_t radix, const char *radchar, int_t width, bool_t minus, char padchar) { char digits[24]; int_t ix, pad, pchars; bool_t left; if (width < 0) { width = -width; left = true; } else left = false; ix = 0; do { digits[ix ++] = radchar[val % radix]; val /= radix; } while (val != 0); if (minus) digits[ix ++] = '-'; if (width > ix) pchars = width; else pchars = ix; pad = ix; if (!left) /* 右詰め */ for ( ; pad < width; pad ++) put_char(cepid, padchar); while (ix -- > 0) put_char(cepid, digits[ix]); if (left) /* 左詰め */ for ( ; pad < width; pad ++) put_char(cepid, padchar); return pchars; } /* * ipv6addr -- IPv6 アドレス出力 */ int_t put_ipv6addr (ID cepid, const T_IN6_ADDR *addr, int_t width) { int_t len = 0, ix; bool_t omit = false, zero = false; if (addr == NULL) { put_char(cepid, '0'); put_char(cepid, ':'); put_char(cepid, ':'); put_char(cepid, '0'); len = 4; } else { for (ix = 0; ix < sizeof(T_IN6_ADDR) / 2; ix ++) { if (omit) { len += put_num(cepid, addr->s6_addr16[ix], 16, radhex, 0, false, ' '); if (ix < 7) { put_char(cepid, ':'); len ++; } } else if (ix > 0 && ix < 7 && addr->s6_addr16[ix] == 0) zero = true; else { if (zero) { omit = true; put_char(cepid, ':'); len ++; } len += put_num(cepid, addr->s6_addr16[ix], 16, radhex, 0, false, ' '); if (ix < 7) { put_char(cepid, ':'); len ++; } } } for ( ; len < width; len ++) put_char(cepid, ' '); } return len; } /* * put_ipv4addr -- IPv4 アドレス出力 */ int_t put_ipv4addr (ID cepid, ULONGEST *addr, int_t width) { int_t len = 3; /* 3 は '.' の文字数 */ #if _NET_CFG_BYTE_ORDER == _NET_CFG_BIG_ENDIAN len += put_num(cepid, (*addr >> 24) & 0xff, 10, radhex, 0, false, ' '); put_char(cepid, '.'); len += put_num(cepid, (*addr >> 16) & 0xff, 10, radhex, 0, false, ' '); put_char(cepid, '.'); len += put_num(cepid, (*addr >> 8) & 0xff, 10, radhex, 0, false, ' '); put_char(cepid, '.'); len += put_num(cepid, *addr & 0xff, 10, radhex, 0, false, ' '); #else /* of #if _NET_CFG_BYTE_ORDER == _NET_CFG_BIG_ENDIAN */ len += put_num(cepid, *addr & 0xff, 10, radhex, 0, false, ' '); put_char(cepid, '.'); len += put_num(cepid, (*addr >> 8) & 0xff, 10, radhex, 0, false, ' '); put_char(cepid, '.'); len += put_num(cepid, (*addr >> 16) & 0xff, 10, radhex, 0, false, ' '); put_char(cepid, '.'); len += put_num(cepid, (*addr >> 24) & 0xff, 10, radhex, 0, false, ' '); #endif /* of #if _NET_CFG_BYTE_ORDER == _NET_CFG_BIG_ENDIAN */ for ( ; len < width; len ++) put_char(cepid, ' '); return len; } /* * put_macaddr -- MAC アドレス出力 */ static int_t put_macaddr (ID cepid, char *mac, int_t width) { int_t oct, len; for (oct = 5; oct -- > 0; ) { put_num(cepid, *mac ++, 16, radhex, 2, false, '0'); put_char(cepid, ':'); } put_num(cepid, *mac, 16, radhex, 2, false, '0'); for (len = 17; len < width; len ++) put_char(cepid, ' '); return len; } /* * 引数を取り出すためのマクロ */ #ifdef LONGLONG_TYPE #ifdef LONG_TYPE #define GET_ARG(ap,lf) ((lf > 1) ? va_arg(ap, LONGLONG_TYPE) \ (lf ? va_arg(ap, LONG_TYPE) \ : va_arg(ap, int_t))) #else /* of #ifdef LONG_TYPE */ #define GET_ARG(ap,lf) ((lf > 1) ? va_arg(ap, LONGLONG_TYPE) \ : va_arg(ap, int_t)) #endif /* of #ifdef LONG_TYPE */ #else /* of #ifdef LONGLONG_TYPE */ #ifdef LONG_TYPE #define GET_ARG(ap,lf) (lf ? va_arg(ap, LONG_TYPE) \ : va_arg(ap, int_t)) #else /* of #ifdef LONG_TYPE */ #define GET_ARG(ap,lf) (va_arg(ap, int_t)) #endif /* of #ifdef LONG_TYPE */ #endif /* of #ifdef LONGLONG_TYPE */ /* * ログ出力 */ void net_syslog (uint_t prio, const char *format, ...) { LONGEST val; SYSLOG log; va_list ap; char padchar, *str; int_t ch, width, longflag, shortflag, left, i, c; if (connected) { syscall(wai_sem(SEM_TCP_SYSLOG)); va_start(ap, format); while ((ch = *format ++) != '\0') { if (ch != '%') { /* 書式指定以外 */ put_char(TCP_CEPID, (char)ch); continue; } width = longflag = shortflag = 0; padchar = ' '; if (ch == '-') { /* 左詰め */ format ++; left = -1; } else left = 1; if ((ch = *format ++) == '0') { /* 上位桁の 0 */ padchar = '0'; ch = *format ++; } while ('0' <= ch && ch <= '9') { /* 出力幅 */ width = width * 10 + ch - '0'; ch = *format ++; } while (ch == 'l') { /* long (long) の指定 */ longflag ++; ch = *format ++; } while (ch == 'h') { /* short の指定 */ shortflag ++; ch = *format ++; } switch (ch) { case 'd': val = GET_ARG(ap, longflag); if (val >= 0) put_num(TCP_CEPID, val, 10, radhex, width * left, false, padchar); else put_num(TCP_CEPID, -val, 10, radhex, width * left, true, padchar); break; case 'u': val = GET_ARG(ap, longflag); put_num(TCP_CEPID, val, 10, radhex, width * left, false, padchar); break; case 'x': val = GET_ARG(ap, longflag); put_num(TCP_CEPID, val, 16, radhex, width * left, false, padchar); break; case 'X': val = GET_ARG(ap, longflag); put_num(TCP_CEPID, val, 16, radHEX, width * left, false, padchar); break; case 'c': ch = va_arg(ap, int_t); put_char(TCP_CEPID, (char)ch); break; case 's': str = va_arg(ap, char*); while ((ch = *str ++) != '\0') { put_char(TCP_CEPID, (char)ch); width --; } while (width -- > 0) put_char(TCP_CEPID, ' '); break; case 'I': if (longflag) { str = va_arg(ap, char*); put_ipv6addr(TCP_CEPID, (T_IN6_ADDR *)str, width); } else if (shortflag) { val = GET_ARG(ap, longflag); put_ipv4addr(TCP_CEPID, (ULONGEST *)val, width); } else { #ifdef SUPPORT_INET6 str = va_arg(ap, char*); put_ipv6addr(TCP_CEPID, (T_IN6_ADDR *)str, width); #else /* of #ifdef SUPPORT_INET6 */ #ifdef SUPPORT_INET4 val = GET_ARG(ap, longflag); put_ipv4addr(TCP_CEPID, (ULONGEST *)val, width); #endif /* of #ifdef SUPPORT_INET4 */ #endif /* of #ifdef SUPPORT_INET6 */ } break; case 'M': str = va_arg(ap, char*); put_macaddr(TCP_CEPID, str, width); break; case '%': put_char(TCP_CEPID, '%'); break; case '0': format --; break; default: break; } } va_end(ap); put_char(TCP_CEPID, '\n'); flush_snd_buff(TCP_CEPID); syscall(sig_sem(SEM_TCP_SYSLOG)); return; } else { log.logtype = LOG_TYPE_COMMENT; log.logpar[0] = (intptr_t)format; i = 1; va_start(ap, format); while ((c = *format++) != '\0' && i < TNUM_LOGPAR) { if (c != '%') { continue; } longflag = 0; c = *format++; while ('0' <= c && c <= '9') { c = *format++; } while (c == 'l') { longflag = 1; c = *format++; } switch (c) { case 'd': if(longflag == 1) { log.logpar[i++] = (intptr_t)va_arg(ap, long_t); } else { log.logpar[i++] = (intptr_t)va_arg(ap, int_t); } break; case 'u': case 'x': case 'X': log.logpar[i++] = (intptr_t)va_arg(ap, uint_t); break; case 'p': log.logpar[i++] = (intptr_t)va_arg(ap, void *); break; case 'c': log.logpar[i++] = (intptr_t)va_arg(ap, int_t); break; case 's': log.logpar[i++] = (intptr_t)va_arg(ap, const char *); break; case '\0': format--; break; default: break; } } va_end(ap); syslog_wri_log(prio, &log); return; } }