1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
24 #include "replacements.h"
26 #include "telnet_server.h"
32 #include "target_request.h"
40 static unsigned short telnet_port
= 0;
42 int handle_exit_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
43 int handle_telnet_port_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
45 static char *negotiate
=
46 "\xFF\xFB\x03" /* IAC WILL Suppress Go Ahead */
47 "\xFF\xFB\x01" /* IAC WILL Echo */
48 "\xFF\xFD\x03" /* IAC DO Suppress Go Ahead */
49 "\xFF\xFE\x01"; /* IAC DON'T Echo */
51 #define CTRL(c) (c - '@')
53 /* The only way we can detect that the socket is closed is the first time
54 * we write to it, we will fail. Subsequent write operations will
57 int telnet_write(connection_t
*connection
, void *data
, int len
)
59 telnet_connection_t
*t_con
= connection
->priv
;
61 return ERROR_SERVER_REMOTE_CLOSED
;
63 if (write_socket(connection
->fd
, data
, len
) == len
)
68 return ERROR_SERVER_REMOTE_CLOSED
;
71 int telnet_prompt(connection_t
*connection
)
73 telnet_connection_t
*t_con
= connection
->priv
;
75 return telnet_write(connection
, t_con
->prompt
, strlen(t_con
->prompt
));
78 int telnet_outputline(connection_t
*connection
, char* line
)
80 telnet_write(connection
, line
, strlen(line
));
81 return telnet_write(connection
, "\r\n\0", 3);
84 int telnet_output(struct command_context_s
*cmd_ctx
, char* line
)
86 connection_t
*connection
= cmd_ctx
->output_handler_priv
;
88 return telnet_outputline(connection
, line
);
91 void telnet_log_callback(void *priv
, const char *file
, int line
,
92 const char *function
, const char *format
, va_list args
)
94 connection_t
*connection
= priv
;
95 char *t
= alloc_printf(format
, args
);
103 if ((endline
=strchr(t2
, '\n'))!=NULL
)
107 telnet_outputline(connection
, t2
);
114 int telnet_target_callback_event_handler(struct target_s
*target
, enum target_event event
, void *priv
)
116 struct command_context_s
*cmd_ctx
= priv
;
117 connection_t
*connection
= cmd_ctx
->output_handler_priv
;
118 telnet_connection_t
*t_con
= connection
->priv
;
122 case TARGET_EVENT_HALTED
:
123 target_arch_state(target
);
124 if (!t_con
->suppress_prompt
)
125 telnet_prompt(connection
);
127 case TARGET_EVENT_RESUMED
:
128 if (!t_con
->suppress_prompt
)
129 telnet_prompt(connection
);
138 int telnet_new_connection(connection_t
*connection
)
140 telnet_connection_t
*telnet_connection
= malloc(sizeof(telnet_connection_t
));
141 telnet_service_t
*telnet_service
= connection
->service
->priv
;
144 connection
->priv
= telnet_connection
;
146 /* initialize telnet connection information */
147 telnet_connection
->closed
= 0;
148 telnet_connection
->line_size
= 0;
149 telnet_connection
->line_cursor
= 0;
150 telnet_connection
->option_size
= 0;
151 telnet_connection
->prompt
= strdup("> ");
152 telnet_connection
->suppress_prompt
= 0;
153 telnet_connection
->state
= TELNET_STATE_DATA
;
155 /* output goes through telnet connection */
156 command_set_output_handler(connection
->cmd_ctx
, telnet_output
, connection
);
158 /* negotiate telnet options */
159 telnet_write(connection
, negotiate
, strlen(negotiate
));
161 /* print connection banner */
162 if (telnet_service
->banner
)
164 telnet_write(connection
, telnet_service
->banner
, strlen(telnet_service
->banner
));
165 telnet_write(connection
, "\r\n\0", 3);
168 telnet_prompt(connection
);
170 /* initialize history */
171 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
173 telnet_connection
->history
[i
] = NULL
;
175 telnet_connection
->next_history
= 0;
176 telnet_connection
->current_history
= 0;
178 target_register_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
183 void telnet_clear_line(connection_t
*connection
, telnet_connection_t
*t_con
)
185 /* move to end of line */
186 if (t_con
->line_cursor
< t_con
->line_size
)
188 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
191 /* backspace, overwrite with space, backspace */
192 while (t_con
->line_size
> 0)
194 telnet_write(connection
, "\b \b", 3);
197 t_con
->line_cursor
= 0;
200 int telnet_input(connection_t
*connection
)
203 char buffer
[TELNET_BUFFER_SIZE
];
205 telnet_connection_t
*t_con
= connection
->priv
;
206 command_context_t
*command_context
= connection
->cmd_ctx
;
208 bytes_read
= read_socket(connection
->fd
, buffer
, TELNET_BUFFER_SIZE
);
211 return ERROR_SERVER_REMOTE_CLOSED
;
212 else if (bytes_read
== -1)
214 ERROR("error during read: %s", strerror(errno
));
215 return ERROR_SERVER_REMOTE_CLOSED
;
221 switch (t_con
->state
)
223 case TELNET_STATE_DATA
:
224 if (*buf_p
== '\xff')
226 t_con
->state
= TELNET_STATE_IAC
;
230 if (isprint(*buf_p
)) /* printable character */
232 telnet_write(connection
, buf_p
, 1);
233 if (t_con
->line_cursor
== t_con
->line_size
)
235 t_con
->line
[t_con
->line_size
++] = *buf_p
;
236 t_con
->line_cursor
++;
241 memmove(t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
242 t_con
->line
[t_con
->line_cursor
++] = *buf_p
;
244 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
245 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
247 telnet_write(connection
, "\b", 1);
251 else /* non-printable */
253 if (*buf_p
== 0x1b) /* escape */
255 t_con
->state
= TELNET_STATE_ESCAPE
;
256 t_con
->last_escape
= '\x00';
258 else if ((*buf_p
== 0xd) || (*buf_p
== 0xa)) /* CR/LF */
262 /* skip over combinations with CR/LF + NUL */
263 if (((*(buf_p
+ 1) == 0xa) || (*(buf_p
+ 1) == 0xd)) && (bytes_read
> 1))
268 if ((*(buf_p
+ 1) == 0) && (bytes_read
> 1))
273 t_con
->line
[t_con
->line_size
] = 0;
275 telnet_write(connection
, "\r\n\x00", 3);
277 if (strcmp(t_con
->line
, "history") == 0)
280 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
282 if (t_con
->history
[i
])
284 telnet_write(connection
, t_con
->history
[i
], strlen(t_con
->history
[i
]));
285 telnet_write(connection
, "\r\n\x00", 3);
288 telnet_prompt(connection
);
289 t_con
->line_size
= 0;
290 t_con
->line_cursor
= 0;
294 log_add_callback(telnet_log_callback
, connection
);
295 t_con
->suppress_prompt
= 1;
297 retval
= command_run_line(command_context
, t_con
->line
);
299 log_remove_callback(telnet_log_callback
, connection
);
300 t_con
->suppress_prompt
= 0;
302 if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
304 return ERROR_SERVER_REMOTE_CLOSED
;
307 /* Save only non-blank lines in the history */
308 if (t_con
->line_size
> 0)
310 /* if the history slot is already taken, free it */
311 if (t_con
->history
[t_con
->next_history
])
313 free(t_con
->history
[t_con
->next_history
]);
316 /* add line to history */
317 t_con
->history
[t_con
->next_history
] = strdup(t_con
->line
);
319 /* wrap history at TELNET_LINE_HISTORY_SIZE */
320 t_con
->next_history
= (t_con
->next_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
322 /* current history line starts at the new entry */
323 t_con
->current_history
= t_con
->next_history
;
325 if (t_con
->history
[t_con
->current_history
])
327 free(t_con
->history
[t_con
->current_history
]);
329 t_con
->history
[t_con
->current_history
] = strdup("");
332 int t
= telnet_prompt(connection
);
333 if (t
== ERROR_SERVER_REMOTE_CLOSED
)
336 t_con
->line_size
= 0;
337 t_con
->line_cursor
= 0;
339 else if ((*buf_p
== 0x7f) || (*buf_p
== 0x8)) /* delete character */
341 if (t_con
->line_cursor
> 0)
343 if (t_con
->line_cursor
!= t_con
->line_size
)
346 telnet_write(connection
, "\b", 1);
347 t_con
->line_cursor
--;
349 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
351 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
352 telnet_write(connection
, " \b", 2);
353 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
355 telnet_write(connection
, "\b", 1);
361 t_con
->line_cursor
--;
362 /* back space: move the 'printer' head one char back, overwrite with space, move back again */
363 telnet_write(connection
, "\b \b", 3);
367 else if (*buf_p
== 0x15) /* clear line */
369 telnet_clear_line(connection
, t_con
);
371 else if (*buf_p
== CTRL('B')) /* cursor left */
373 if (t_con
->line_cursor
> 0)
375 telnet_write(connection
, "\b", 1);
376 t_con
->line_cursor
--;
378 t_con
->state
= TELNET_STATE_DATA
;
380 else if (*buf_p
== CTRL('F')) /* cursor right */
382 if (t_con
->line_cursor
< t_con
->line_size
)
384 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
++, 1);
386 t_con
->state
= TELNET_STATE_DATA
;
390 DEBUG("unhandled nonprintable: %2.2x", *buf_p
);
395 case TELNET_STATE_IAC
:
399 t_con
->state
= TELNET_STATE_DONT
;
402 t_con
->state
= TELNET_STATE_DO
;
405 t_con
->state
= TELNET_STATE_WONT
;
408 t_con
->state
= TELNET_STATE_WILL
;
412 case TELNET_STATE_SB
:
414 case TELNET_STATE_SE
:
416 case TELNET_STATE_WILL
:
417 case TELNET_STATE_WONT
:
418 case TELNET_STATE_DO
:
419 case TELNET_STATE_DONT
:
420 t_con
->state
= TELNET_STATE_DATA
;
422 case TELNET_STATE_ESCAPE
:
423 if (t_con
->last_escape
== '[')
425 if (*buf_p
== 'D') /* cursor left */
427 if (t_con
->line_cursor
> 0)
429 telnet_write(connection
, "\b", 1);
430 t_con
->line_cursor
--;
432 t_con
->state
= TELNET_STATE_DATA
;
434 else if (*buf_p
== 'C') /* cursor right */
436 if (t_con
->line_cursor
< t_con
->line_size
)
438 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
++, 1);
440 t_con
->state
= TELNET_STATE_DATA
;
442 else if (*buf_p
== 'A') /* cursor up */
444 int last_history
= (t_con
->current_history
> 0) ? t_con
->current_history
- 1 : TELNET_LINE_HISTORY_SIZE
-1;
445 if (t_con
->history
[last_history
])
447 telnet_clear_line(connection
, t_con
);
448 t_con
->line_size
= strlen(t_con
->history
[last_history
]);
449 t_con
->line_cursor
= t_con
->line_size
;
450 memcpy(t_con
->line
, t_con
->history
[last_history
], t_con
->line_size
+ 1);
451 telnet_write(connection
, t_con
->line
, t_con
->line_size
);
452 t_con
->current_history
= last_history
;
454 t_con
->state
= TELNET_STATE_DATA
;
456 else if (*buf_p
== 'B') /* cursor down */
458 int next_history
= (t_con
->current_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
459 if (t_con
->history
[next_history
])
461 telnet_clear_line(connection
, t_con
);
462 t_con
->line_size
= strlen(t_con
->history
[next_history
]);
463 t_con
->line_cursor
= t_con
->line_size
;
464 memcpy(t_con
->line
, t_con
->history
[next_history
], t_con
->line_size
+ 1);
465 telnet_write(connection
, t_con
->line
, t_con
->line_size
);
466 t_con
->current_history
= next_history
;
468 t_con
->state
= TELNET_STATE_DATA
;
470 else if (*buf_p
== '3')
472 t_con
->last_escape
= *buf_p
;
476 t_con
->state
= TELNET_STATE_DATA
;
479 else if (t_con
->last_escape
== '3')
481 /* Remove character */
484 if (t_con
->line_cursor
< t_con
->line_size
)
488 /* remove char from line buffer */
489 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
491 /* print remainder of buffer */
492 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
493 /* overwrite last char with whitespace */
494 telnet_write(connection
, " \b", 2);
496 /* move back to cursor position*/
497 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
499 telnet_write(connection
, "\b", 1);
503 t_con
->state
= TELNET_STATE_DATA
;
507 t_con
->state
= TELNET_STATE_DATA
;
510 else if (t_con
->last_escape
== '\x00')
514 t_con
->last_escape
= *buf_p
;
518 t_con
->state
= TELNET_STATE_DATA
;
523 ERROR("BUG: unexpected value in t_con->last_escape");
524 t_con
->state
= TELNET_STATE_DATA
;
529 ERROR("unknown telnet state");
540 int telnet_connection_closed(connection_t
*connection
)
542 telnet_connection_t
*t_con
= connection
->priv
;
548 t_con
->prompt
= NULL
;
551 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
553 if (t_con
->history
[i
])
555 free(t_con
->history
[i
]);
556 t_con
->history
[i
] = NULL
;
560 /* if this connection registered a debug-message receiver delete it */
561 delete_debug_msg_receiver(connection
->cmd_ctx
, NULL
);
563 if (connection
->priv
)
565 free(connection
->priv
);
566 connection
->priv
= NULL
;
570 ERROR("BUG: connection->priv == NULL");
573 target_unregister_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
578 int telnet_set_prompt(connection_t
*connection
, char *prompt
)
580 telnet_connection_t
*t_con
= connection
->priv
;
582 t_con
->prompt
= strdup(prompt
);
587 int telnet_init(char *banner
)
589 telnet_service_t
*telnet_service
= malloc(sizeof(telnet_service_t
));
591 if (telnet_port
== 0)
593 WARNING("no telnet port specified, using default port 4444");
597 telnet_service
->banner
= banner
;
599 add_service("telnet", CONNECTION_TELNET
, telnet_port
, 1, telnet_new_connection
, telnet_input
, telnet_connection_closed
, telnet_service
);
604 int telnet_register_commands(command_context_t
*command_context
)
606 register_command(command_context
, NULL
, "exit", handle_exit_command
,
607 COMMAND_EXEC
, "exit telnet session");
609 register_command(command_context
, NULL
, "telnet_port", handle_telnet_port_command
,
615 /* daemon configuration command telnet_port */
616 int handle_telnet_port_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
621 /* only if the port wasn't overwritten by cmdline */
622 if (telnet_port
== 0)
623 telnet_port
= strtoul(args
[0], NULL
, 0);
628 int handle_exit_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
630 return ERROR_COMMAND_CLOSE_CONNECTION
;
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)