telnet.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:8k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* Internet Telnet client
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #ifdef __TURBOC__
  6. #include <io.h>
  7. #include <fcntl.h>
  8. #endif
  9. #include "global.h"
  10. #include "mbuf.h"
  11. #include "socket.h"
  12. #include "telnet.h"
  13. #include "session.h"
  14. #include "proc.h"
  15. #include "tty.h"
  16. #include "commands.h"
  17. #include "internet.h"
  18. #include "netuser.h"
  19. #include "cmdparse.h"
  20. int Refuse_echo = 0;
  21. int Tn_cr_mode = 0;    /* if true turn <cr> to <cr-nul> */
  22. int Topt = 0;
  23. char *T_options[] = {
  24. "Transmit Binary",
  25. "Echo",
  26. "",
  27. "Suppress Go Ahead",
  28. "",
  29. "Status",
  30. "Timing Mark"
  31. };
  32. static int keychar(int c);
  33. int
  34. dotopt(argc,argv,p)
  35. int argc;
  36. char *argv[];
  37. void *p;
  38. {
  39. setbool(&Topt,"Telnet option tracing",argc,argv);
  40. return 0;
  41. }
  42. /* Execute user telnet command */
  43. int
  44. dotelnet(argc,argv,p)
  45. int argc;
  46. char *argv[];
  47. void *p;
  48. {
  49. struct session *sp;
  50. struct sockaddr_in fsocket;
  51. int s;
  52. /* Allocate a session descriptor */
  53. if((sp = newsession(Cmdline,TELNET,1)) == NULL){
  54. printf("Too many sessionsn");
  55. return 1;
  56. }
  57. sp->inproc = keychar; /* Intercept ^C */
  58. fsocket.sin_family = AF_INET;
  59. if(argc < 3)
  60. fsocket.sin_port = IPPORT_TELNET;
  61. else
  62. fsocket.sin_port = atoi(argv[2]);
  63. if(SETSIG(EABORT)){
  64. keywait(NULL,1);
  65. freesession(sp);
  66. return 1;
  67. }
  68. printf("Resolving %s...n",argv[1]);
  69. if((fsocket.sin_addr.s_addr = resolve(argv[1])) == 0){
  70. printf(Badhost,argv[1]);
  71. keywait(NULL,1);
  72. freesession(sp);
  73. return 1;
  74. }
  75. if((s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  76. printf("Can't create socketn");
  77. keywait(NULL,1);
  78. freesession(sp);
  79. return 1;
  80. }
  81. settos(s,LOW_DELAY);
  82. sp->network = fdopen(s,"r+t");
  83. setvbuf(sp->network,NULL,_IOLBF,BUFSIZ);
  84. return tel_connect(sp,(struct sockaddr *)&fsocket,SOCKSIZE);
  85. }
  86. /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
  87. int
  88. tel_connect(sp,fsocket,len)
  89. struct session *sp;
  90. struct sockaddr *fsocket;
  91. int len;
  92. {
  93. struct telnet tn;
  94. memset(&tn,0,sizeof(tn));
  95. tn.eolmode = Tn_cr_mode;
  96. tn.session = sp; /* Upward pointer */
  97. sp->cb.telnet = &tn; /* Downward pointer */
  98. printf("Trying %s...n",psocket(fsocket));
  99. if(connect(fileno(sp->network),fsocket,len) == -1){
  100. perror("connect failed");
  101. keywait(NULL,1);
  102. freesession(sp);
  103. return 1;
  104. }
  105. printf("Connectedn");
  106. sp->inproc = NULL; /* No longer respond to ^C */
  107. tnrecv(&tn);
  108. return 0;
  109. }
  110. /* Telnet input routine, common to both telnet and ttylink */
  111. void
  112. tnrecv(tn)
  113. struct telnet *tn;
  114. {
  115. int c;
  116. struct session *sp;
  117. char *cp;
  118. FILE *network;
  119. sp = tn->session;
  120. network = sp->network;
  121. /* Fork off the transmit process */
  122. sp->proc1 = newproc("tel_out",1024,tel_output,0,tn,NULL,0);
  123. /* Process input on the connection */
  124. while((c = getc(network)) != EOF){
  125. if(c != IAC){
  126. /* Ordinary character */
  127. putchar((char)c);
  128. if(sp->record != NULL)
  129. putc(c,sp->record);
  130. continue;
  131. }
  132. /* IAC received, get command sequence */
  133. c = getc(network);
  134. switch(c){
  135. case WILL:
  136. c = getc(network);
  137. willopt(tn,c);
  138. break;
  139. case WONT:
  140. c = getc(network);
  141. wontopt(tn,c);
  142. break;
  143. case DO:
  144. c = getc(network);
  145. doopt(tn,c);
  146. break;
  147. case DONT:
  148. c = getc(network);
  149. dontopt(tn,c);
  150. break;
  151. case IAC: /* Escaped IAC */
  152. putchar(IAC);
  153. if(sp->record != NULL)
  154. putc(IAC,sp->record);
  155. break;
  156. }
  157. }
  158. quit: /* A close was received from the remote host.
  159.  * Notify the user, kill the output task and wait for a response
  160.  * from the user before freeing the session.
  161.  */
  162. fmode(sp->output,STREAM_ASCII); /* Restore newline translation */
  163. setvbuf(sp->output,NULL,_IOLBF,BUFSIZ);
  164. cp = sockerr(fileno(network));
  165. printf("Closed: %sn", cp != NULL ? cp : "EOF");
  166. killproc(sp->proc1);
  167. sp->proc1 = NULL;
  168. fclose(sp->network);
  169. sp->network = NULL;
  170. keywait(NULL,1);
  171. freesession(sp);
  172. }
  173. /* User telnet output task, started by user telnet command */
  174. void
  175. tel_output(unused,tn1,p)
  176. int unused;
  177. void *tn1;
  178. void *p;
  179. {
  180. struct session *sp;
  181. int c;
  182. struct telnet *tn;
  183. tn = (struct telnet *)tn1;
  184. sp = tn->session;
  185. /* Send whatever's typed on the terminal */
  186. while((c = getc(sp->input)) != EOF){
  187. putc(c,sp->network);
  188. if(!tn->remote[TN_ECHO] && sp->record != NULL)
  189. putc(c,sp->record);
  190. /* By default, output is transparent in remote echo mode.
  191.  * If eolmode is set, turn a cr into cr-null.
  192.  * This can only happen when in remote echo (raw) mode, since
  193.  * the tty driver normally maps r to n in cooked mode.
  194.  */
  195. if(c == 'r' && tn->eolmode)
  196. putc('',sp->network);
  197. if(tn->remote[TN_ECHO])
  198. fflush(sp->network);
  199. }
  200. /* Make sure our parent doesn't try to kill us after we exit */
  201. sp->proc1 = NULL;
  202. }
  203. int
  204. doecho(argc,argv,p)
  205. int argc;
  206. char *argv[];
  207. void *p;
  208. {
  209. if(argc < 2){
  210. if(Refuse_echo)
  211. printf("Refusen");
  212. else
  213. printf("Acceptn");
  214. } else {
  215. if(argv[1][0] == 'r')
  216. Refuse_echo = 1;
  217. else if(argv[1][0] == 'a')
  218. Refuse_echo = 0;
  219. else
  220. return -1;
  221. }
  222. return 0;
  223. }
  224. /* set for unix end of line for remote echo mode telnet */
  225. int
  226. doeol(argc,argv,p)
  227. int argc;
  228. char *argv[];
  229. void *p;
  230. {
  231. if(argc < 2){
  232. if(Tn_cr_mode)
  233. printf("nulln");
  234. else
  235. printf("standardn");
  236. } else {
  237. if(argv[1][0] == 'n')
  238. Tn_cr_mode = 1;
  239. else if(argv[1][0] == 's')
  240. Tn_cr_mode = 0;
  241. else {
  242. printf("Usage: %s [standard|null]n",argv[0]);
  243. return -1;
  244. }
  245. }
  246. return 0;
  247. }
  248. /* The guts of the actual Telnet protocol: negotiating options */
  249. void
  250. willopt(tn,opt)
  251. struct telnet *tn;
  252. int opt;
  253. {
  254. int ack;
  255. if(Topt){
  256. printf("recv: will ");
  257. if(opt <= NOPTIONS)
  258. printf("%sn",T_options[opt]);
  259. else
  260. printf("%un",opt);
  261. }
  262. switch(opt){
  263. case TN_TRANSMIT_BINARY:
  264. case TN_ECHO:
  265. case TN_SUPPRESS_GA:
  266. if(tn->remote[opt] == 1)
  267. return; /* Already set, ignore to prevent loop */
  268. if(opt == TN_ECHO){
  269. if(Refuse_echo){
  270. /* User doesn't want to accept */
  271. ack = DONT;
  272. break;
  273. } else {
  274. /* Put tty into raw mode */
  275. tn->session->ttystate.edit = 0;
  276. tn->session->ttystate.echo = 0;
  277. fmode(tn->session->network,STREAM_BINARY);
  278. setvbuf(tn->session->network,NULL,_IONBF,0);
  279. fmode(stdout,STREAM_BINARY);
  280. setvbuf(stdout,NULL,_IONBF,0);
  281. }
  282. }
  283. tn->remote[opt] = 1;
  284. ack = DO;
  285. break;
  286. default:
  287. ack = DONT; /* We don't know what he's offering; refuse */
  288. }
  289. answer(tn,ack,opt);
  290. }
  291. void
  292. wontopt(tn,opt)
  293. struct telnet *tn;
  294. int opt;
  295. {
  296. if(Topt){
  297. printf("recv: wont ");
  298. if(opt <= NOPTIONS)
  299. printf("%sn",T_options[opt]);
  300. else
  301. printf("%un",opt);
  302. }
  303. if(opt <= NOPTIONS){
  304. if(tn->remote[opt] == 0)
  305. return; /* Already clear, ignore to prevent loop */
  306. tn->remote[opt] = 0;
  307. if(opt == TN_ECHO){
  308. /* Put tty into cooked mode */
  309. tn->session->ttystate.edit = 1;
  310. tn->session->ttystate.echo = 1;
  311. fmode(tn->session->network,STREAM_ASCII);
  312. setvbuf(tn->session->network,NULL,_IOLBF,BUFSIZ);
  313. fmode(stdout,STREAM_ASCII);
  314. setvbuf(stdout,NULL,_IOLBF,BUFSIZ);
  315. }
  316. }
  317. answer(tn,DONT,opt); /* Must always accept */
  318. }
  319. void
  320. doopt(tn,opt)
  321. struct telnet *tn;
  322. int opt;
  323. {
  324. int ack;
  325. if(Topt){
  326. printf("recv: do ");
  327. if(opt <= NOPTIONS)
  328. printf("%sn",T_options[opt]);
  329. else
  330. printf("%un",opt);
  331. }
  332. switch(opt){
  333. case TN_SUPPRESS_GA:
  334. if(tn->local[opt] == 1)
  335. return; /* Already set, ignore to prevent loop */
  336. tn->local[opt] = 1;
  337. ack = WILL;
  338. break;
  339. default:
  340. ack = WONT; /* Don't know what it is */
  341. }
  342. answer(tn,ack,opt);
  343. }
  344. void
  345. dontopt(tn,opt)
  346. struct telnet *tn;
  347. int opt;
  348. {
  349. if(Topt){
  350. printf("recv: dont ");
  351. if(opt <= NOPTIONS)
  352. printf("%sn",T_options[opt]);
  353. else
  354. printf("%un",opt);
  355. }
  356. if(opt <= NOPTIONS){
  357. if(tn->local[opt] == 0){
  358. /* Already clear, ignore to prevent loop */
  359. return;
  360. }
  361. tn->local[opt] = 0;
  362. }
  363. answer(tn,WONT,opt);
  364. }
  365. void
  366. answer(tn,r1,r2)
  367. struct telnet *tn;
  368. int r1,r2;
  369. {
  370. if(Topt){
  371. switch(r1){
  372. case WILL:
  373. printf("sent: will ");
  374. break;
  375. case WONT:
  376. printf("sent: wont ");
  377. break;
  378. case DO:
  379. printf("sent: do ");
  380. break;
  381. case DONT:
  382. printf("sent: dont ");
  383. break;
  384. }
  385. if(r2 <= NOPTIONS)
  386. printf("%sn",T_options[r2]);
  387. else
  388. printf("%un",r2);
  389. }
  390. fprintf(tn->session->network,"%c%c%c",IAC,r1,r2);
  391. fflush(tn->session->network);
  392. }
  393. static int
  394. keychar(c)
  395. int c;
  396. {
  397. if(c != CTLC)
  398. return 1; /* Ignore all but ^C */
  399. fprintf(Current->output,"^Cn");
  400. alert(Current->proc,EABORT);
  401. return 0;
  402. }