在工作中,我们有一个老的C程序,与霍尼韦尔的工业手持terminal一起工作。
该terminal有自己的SSH客户端连接到一个Linux的红帽6.6服务器。 一旦它被连接到Linux机箱(使用某个用户),一个C程序由bash shell用以下参数启动
export TERM=vt200 stty raw icrnl -echo $APLI_EXEC/program param1 param2
所以stream程就像=>客户端ssh – > ssh服务器 – > bash – > c程序
应用程序(或似乎)工作正常,但有时(每周1-3-5次)随机terminal停止从服务器接收数据,但应用程序接收来自它的input。 这就好像你在一个shell中写入Ctrl + S。
使用stracedebugging应用程序和ssh进程我意识到一些奇怪的事情:
应用程序strace是好的
write(1, "1", 7) = 1
但是,ssh进程的strace并不好(我认为…是的,我看到了ioctl no echo参数,但是…)
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 read(3, "\227\316\242\350\261\330)\300e\210\352\367\2VX\24\305\2474\272\371\34\273n{\323p.\211\17H\327"..., 16384) = 48 select(14, [3 9], [11], NULL, {900, 0}) = 1 (out [11], left {899, 999996}) rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(11, "1", 1) = 1 ioctl(11, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0 select(14, [3 9], [], NULL, {900, 0} <<<<
由ssh进程使用的文件描述符:
lr-x------ 1 root root 64 Feb 15 17:12 9 -> pipe:[383586491] lr-x------ 1 root root 64 Feb 15 17:12 8 -> /var/lib/sss/mc/group lrwx------ 1 root root 64 Feb 15 17:12 7 -> socket:[383586484] lrwx------ 1 root root 64 Feb 15 17:12 6 -> socket:[383586478] lrwx------ 1 root root 64 Feb 15 17:12 5 -> socket:[383586458] lrwx------ 1 root root 64 Feb 15 17:12 4 -> socket:[383586457] lrwx------ 1 root root 64 Feb 15 17:12 3 -> socket:[383585929] lrwx------ 1 root root 64 Feb 15 17:12 2 -> /dev/null lrwx------ 1 root root 64 Feb 15 17:12 14 -> /dev/ptmx lrwx------ 1 root root 64 Feb 15 17:12 13 -> /dev/ptmx lrwx------ 1 root root 64 Feb 15 17:12 11 -> /dev/ptmx l-wx------ 1 root root 64 Feb 15 17:12 10 -> pipe:[383586491] lrwx------ 1 root root 64 Feb 15 17:12 1 -> /dev/null lrwx------ 1 root root 64 Feb 15 17:12 0 -> /dev/null
在select通话中,我想念那里的fd#11或fd#13
比较这与另一个电话
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 read(3, "\365\354\354C\10|\336-\4\342\327B0P\275&\213)\367\32\24\333)#\364\355V\3\237\337\33\204"..., 16384) = 52 select(14, [3 9 13], [11], NULL, {900, 0}) = 1 (out [11], left {899, 999997}) rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(11, "a", 1) = 1 ioctl(11, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0 select(14, [3 9 13], [], NULL, {900, 0} <<<
在另一个电话中,fd#13是怎么回事?
C程序是否有可能lockingssh进程的文件描述符?
手持terminal可能会发送一个“挂起”标准输出的Ctrl键组合。
我跑出了想法。 任何人都能把我推向正确的方向吗?
二月二十五号 2016
我有更多关于这方面的信息:
select(14, [3 9 13], [], NULL, {900, 0}) = 1 (in [13], left {899, 998835}) <<- sshd realizes about data in fd #13 from C application read(13, "\33[1;23H1\33[1;24H", 16384) = 15 <<- sshd check data from th fd#13 select(14, [3 9 13], [3], NULL, {900, 0}) = 1 (out [3], left {899, 999998}) <<- sshd sends data to fd#3 (socket) write(3, "\301\236W\250\333\260\r\204\316o]:*1K\203\242\204\257Vb,V\347l\242\352K\341,,\307d\273\277\202.l\32F\2471\257DJt3\36\303\5\256\21K6\27\212\253\326|l\33\270\262S", 64) = 64 (1) <<- sshd encrypts data to be sent select(14, [3 9 13], [3], NULL, {900, 0}) = 1 (out [3], left {899, 999998}) <<-- sshd sends data thru the socket select(14, [3 9 13], [], NULL, {900, 0}) = 1 (in [13], left {899, 998569}) <<- sshd realizes about data in fd #13 from C application read(13, "\7\33[1;16H \33[6;6H_______\33[7;1H -INFORME CANT. RECOGIDA-\33[7;26H", 16384) = 67 <<- sshd check data from th fd#13 select(14, [3 9], [], NULL, {900, 0}) = 1 (in [3], left {892, 12016}) <<- sshd sends data to fd#3 (socket) but... where is fd#13 where sshd has to read it from? read it from?
terminal收到“\ 7 \ 33 [1; 16H”,但其余的string“\ 33 [7; 1H -INFORME CANT。RECOGIDA- \ 33 [7; 26H”
没有收到
为什么?
当应用程序写入它的输出文件描述符(fd#1)时,sshd收到它(fd#13)..但fd#1在这个时候被清除了? 或者是sshd从文件描述符中读取字符char,而它是sendind / encripting数据?
我回答自己说,我刚刚发现了问题,我希望以下帮助任何人
最后,我重新编译了ssh源代码(openssh-5.3p1),在代码中插入了几个“陷阱”,看看那里发生了什么
channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset) { u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); int aux = buffer_len(&c->input); debugtrap("en pre_open c-istate: %d limit %d buffer_len %d c_ostate %d ctl_fd %d\n",c->istate,limit,aux,c->ostate,c->ctl_fd); /* the rest of the function code */
限制variables在开始(默认)是1024 * 1024
在正常情况下,每次调用channe_pre_open函数时,极限variables都会调整其窗口大小(例如使用putty)
En pre_open c-istate: 0 limit 1048576 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1048576 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1048495 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1048495 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1048415 buffer_len 0 c_ostate 0 ctl_fd -1 ...... time later En pre_open c-istate: 0 limit 1002267 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1002267 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1002267 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 998560 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 998560 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1048576 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1048576 buffer_len 0 c_ostate 0 ctl_fd -1
但是,如果我将手持terminal连接到应用程序时比较相同的轨迹,我可以看到缓冲区正在消耗(每次都不重新协商)整个尺寸
En pre_open c-istate: 0 limit 1048576 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1048576 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 1048476 buffer_len 0 c_ostate 0 ctl_fd -1 ...... En pre_open c-istate: 0 limit 985 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 647 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 647 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 647 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 647 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 632 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 322 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 322 buffer_len 0 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 0 buffer_len 16 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 0 buffer_len 16 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 0 buffer_len 16 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 0 buffer_len 16 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 0 buffer_len 16 c_ostate 0 ctl_fd -1 En pre_open c-istate: 0 limit 0 buffer_len 16 c_ostate 0 ctl_fd -1
最后限制variables为0
当它发生fd#10在select呼叫中从readfds中丢失
0.000025 select(11, [3 6 10], [3], NULL, {900, 0}) = 1 (in [10], left {899, 999997}) 0.000025 select(11, [3 6 10], [3], NULL, {900, 0}) = 1 (in [10], left {899, 999994}) 0.000025 select(11, [3 6 10], [3], NULL, {900, 0}) = 1 (in [10], left {899, 999995}) 0.000025 select(11, [3 6], [3], NULL, {900, 0}) = 1 (out [3], left {899, 908736}) 0.000026 select(11, [3 6], [3], NULL, {900, 0}) = 1 (out [3], left {899, 986906}) 0.000025 select(11, [3 6], [3], NULL, {900, 0}) = 1 (out [3], left {899, 992061})
问题是select调用不包含这个文件描述符,因为它被另一端阻塞,直到缓冲区(client < – > sshd)为空(它假设sshd不能向ssh客户端发送更多字节,因为窗口大小为0,所以fd必须被阻止,以防止从壳侧发送更多的信息)
这种行为不会发生,使用腻子客户端,似乎是基于Openssh(不知道版本)的霍尼韦尔手机terminal相关的SSH客户端,
无论如何,我刚刚确认了以下版本:OpenSSH_3.8.1p1,OpenSSL 0.9.7d 2004年3月17日不受影响(在Windows 10上针对RHEL6 ssh-server 5.3.p1进行testing)
纳乔。