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
= allocPrintf(format
, args
);
103 if ((endline
=strchr(t2
, '\n'))!=NULL
)
107 telnet_outputline(connection
, t2
);
115 int telnet_target_callback_event_handler(struct target_s
*target
, enum target_event event
, void *priv
)
117 struct command_context_s
*cmd_ctx
= priv
;
118 connection_t
*connection
= cmd_ctx
->output_handler_priv
;
119 telnet_connection_t
*t_con
= connection
->priv
;
123 case TARGET_EVENT_HALTED
:
124 command_print(cmd_ctx
, "Target %i halted", get_num_by_target(target
));
125 target_arch_state(target
);
126 if (!t_con
->suppress_prompt
)
127 telnet_prompt(connection
);
129 case TARGET_EVENT_RESUMED
:
130 command_print(cmd_ctx
, "Target %i resumed", get_num_by_target(target
));
131 if (!t_con
->suppress_prompt
)
132 telnet_prompt(connection
);
141 int telnet_new_connection(connection_t
*connection
)
143 telnet_connection_t
*telnet_connection
= malloc(sizeof(telnet_connection_t
));
144 telnet_service_t
*telnet_service
= connection
->service
->priv
;
147 connection
->priv
= telnet_connection
;
149 /* initialize telnet connection information */
150 telnet_connection
->closed
= 0;
151 telnet_connection
->line_size
= 0;
152 telnet_connection
->line_cursor
= 0;
153 telnet_connection
->option_size
= 0;
154 telnet_connection
->prompt
= strdup("> ");
155 telnet_connection
->suppress_prompt
= 0;
156 telnet_connection
->state
= TELNET_STATE_DATA
;
158 /* output goes through telnet connection */
159 command_set_output_handler(connection
->cmd_ctx
, telnet_output
, connection
);
161 /* negotiate telnet options */
162 telnet_write(connection
, negotiate
, strlen(negotiate
));
164 /* print connection banner */
165 if (telnet_service
->banner
)
167 telnet_write(connection
, telnet_service
->banner
, strlen(telnet_service
->banner
));
168 telnet_write(connection
, "\r\n\0", 3);
171 telnet_prompt(connection
);
173 /* initialize history */
174 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
176 telnet_connection
->history
[i
] = NULL
;
178 telnet_connection
->next_history
= 0;
179 telnet_connection
->current_history
= 0;
181 target_register_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
186 void telnet_clear_line(connection_t
*connection
, telnet_connection_t
*t_con
)
188 /* move to end of line */
189 if (t_con
->line_cursor
< t_con
->line_size
)
191 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
194 /* backspace, overwrite with space, backspace */
195 while (t_con
->line_size
> 0)
197 telnet_write(connection
, "\b \b", 3);
200 t_con
->line_cursor
= 0;
203 int telnet_input(connection_t
*connection
)
206 char buffer
[TELNET_BUFFER_SIZE
];
208 telnet_connection_t
*t_con
= connection
->priv
;
209 command_context_t
*command_context
= connection
->cmd_ctx
;
211 bytes_read
= read_socket(connection
->fd
, buffer
, TELNET_BUFFER_SIZE
);
214 return ERROR_SERVER_REMOTE_CLOSED
;
215 else if (bytes_read
== -1)
217 ERROR("error during read: %s", strerror(errno
));
218 return ERROR_SERVER_REMOTE_CLOSED
;
224 switch (t_con
->state
)
226 case TELNET_STATE_DATA
:
227 if (*buf_p
== '\xff')
229 t_con
->state
= TELNET_STATE_IAC
;
233 if (isprint(*buf_p
)) /* printable character */
235 telnet_write(connection
, buf_p
, 1);
236 if (t_con
->line_cursor
== t_con
->line_size
)
238 t_con
->line
[t_con
->line_size
++] = *buf_p
;
239 t_con
->line_cursor
++;
244 memmove(t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
245 t_con
->line
[t_con
->line_cursor
++] = *buf_p
;
247 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
248 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
250 telnet_write(connection
, "\b", 1);
254 else /* non-printable */
256 if (*buf_p
== 0x1b) /* escape */
258 t_con
->state
= TELNET_STATE_ESCAPE
;
259 t_con
->last_escape
= '\x00';
261 else if ((*buf_p
== 0xd) || (*buf_p
== 0xa)) /* CR/LF */
265 /* skip over combinations with CR/LF + NUL */
266 if (((*(buf_p
+ 1) == 0xa) || (*(buf_p
+ 1) == 0xd)) && (bytes_read
> 1))
271 if ((*(buf_p
+ 1) == 0) && (bytes_read
> 1))
276 t_con
->line
[t_con
->line_size
] = 0;
278 telnet_write(connection
, "\r\n\x00", 3);
280 if (strcmp(t_con
->line
, "history") == 0)
283 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
285 if (t_con
->history
[i
])
287 telnet_write(connection
, t_con
->history
[i
], strlen(t_con
->history
[i
]));
288 telnet_write(connection
, "\r\n\x00", 3);
291 telnet_prompt(connection
);
292 t_con
->line_size
= 0;
293 t_con
->line_cursor
= 0;
297 log_setCallback(telnet_log_callback
, connection
);
298 t_con
->suppress_prompt
= 1;
300 if ((retval
= command_run_line(command_context
, t_con
->line
)) != ERROR_OK
)
302 if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
304 return ERROR_SERVER_REMOTE_CLOSED
;
308 t_con
->suppress_prompt
= 0;
310 /* Save only non-blank lines in the history */
311 if (t_con
->line_size
> 0)
313 /* if the history slot is already taken, free it */
314 if (t_con
->history
[t_con
->next_history
])
316 free(t_con
->history
[t_con
->next_history
]);
319 /* add line to history */
320 t_con
->history
[t_con
->next_history
] = strdup(t_con
->line
);
322 /* wrap history at TELNET_LINE_HISTORY_SIZE */
323 t_con
->next_history
= (t_con
->next_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
325 /* current history line starts at the new entry */
326 t_con
->current_history
= t_con
->next_history
;
328 if (t_con
->history
[t_con
->current_history
])
330 free(t_con
->history
[t_con
->current_history
]);
332 t_con
->history
[t_con
->current_history
] = strdup("");
335 int t
= telnet_prompt(connection
);
336 if (t
== ERROR_SERVER_REMOTE_CLOSED
)
339 t_con
->line_size
= 0;
340 t_con
->line_cursor
= 0;
342 else if ((*buf_p
== 0x7f) || (*buf_p
== 0x8)) /* delete character */
344 if (t_con
->line_cursor
> 0)
346 if (t_con
->line_cursor
!= t_con
->line_size
)
349 telnet_write(connection
, "\b", 1);
350 t_con
->line_cursor
--;
352 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
354 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
355 telnet_write(connection
, " \b", 2);
356 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
358 telnet_write(connection
, "\b", 1);
364 t_con
->line_cursor
--;
365 /* back space: move the 'printer' head one char back, overwrite with space, move back again */
366 telnet_write(connection
, "\b \b", 3);
370 else if (*buf_p
== 0x15) /* clear line */
372 telnet_clear_line(connection
, t_con
);
374 else if (*buf_p
== CTRL('B')) /* cursor left */
376 if (t_con
->line_cursor
> 0)
378 telnet_write(connection
, "\b", 1);
379 t_con
->line_cursor
--;
381 t_con
->state
= TELNET_STATE_DATA
;
383 else if (*buf_p
== CTRL('F')) /* cursor right */
385 if (t_con
->line_cursor
< t_con
->line_size
)
387 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
++, 1);
389 t_con
->state
= TELNET_STATE_DATA
;
393 DEBUG("unhandled nonprintable: %2.2x", *buf_p
);
398 case TELNET_STATE_IAC
:
402 t_con
->state
= TELNET_STATE_DONT
;
405 t_con
->state
= TELNET_STATE_DO
;
408 t_con
->state
= TELNET_STATE_WONT
;
411 t_con
->state
= TELNET_STATE_WILL
;
415 case TELNET_STATE_SB
:
417 case TELNET_STATE_SE
:
419 case TELNET_STATE_WILL
:
420 case TELNET_STATE_WONT
:
421 case TELNET_STATE_DO
:
422 case TELNET_STATE_DONT
:
423 t_con
->state
= TELNET_STATE_DATA
;
425 case TELNET_STATE_ESCAPE
:
426 if (t_con
->last_escape
== '[')
428 if (*buf_p
== 'D') /* cursor left */
430 if (t_con
->line_cursor
> 0)
432 telnet_write(connection
, "\b", 1);
433 t_con
->line_cursor
--;
435 t_con
->state
= TELNET_STATE_DATA
;
437 else if (*buf_p
== 'C') /* cursor right */
439 if (t_con
->line_cursor
< t_con
->line_size
)
441 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
++, 1);
443 t_con
->state
= TELNET_STATE_DATA
;
445 else if (*buf_p
== 'A') /* cursor up */
447 int last_history
= (t_con
->current_history
> 0) ? t_con
->current_history
- 1 : TELNET_LINE_HISTORY_SIZE
-1;
448 if (t_con
->history
[last_history
])
450 telnet_clear_line(connection
, t_con
);
451 t_con
->line_size
= strlen(t_con
->history
[last_history
]);
452 t_con
->line_cursor
= t_con
->line_size
;
453 memcpy(t_con
->line
, t_con
->history
[last_history
], t_con
->line_size
+ 1);
454 telnet_write(connection
, t_con
->line
, t_con
->line_size
);
455 t_con
->current_history
= last_history
;
457 t_con
->state
= TELNET_STATE_DATA
;
459 else if (*buf_p
== 'B') /* cursor down */
461 int next_history
= (t_con
->current_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
462 if (t_con
->history
[next_history
])
464 telnet_clear_line(connection
, t_con
);
465 t_con
->line_size
= strlen(t_con
->history
[next_history
]);
466 t_con
->line_cursor
= t_con
->line_size
;
467 memcpy(t_con
->line
, t_con
->history
[next_history
], t_con
->line_size
+ 1);
468 telnet_write(connection
, t_con
->line
, t_con
->line_size
);
469 t_con
->current_history
= next_history
;
471 t_con
->state
= TELNET_STATE_DATA
;
473 else if (*buf_p
== '3')
475 t_con
->last_escape
= *buf_p
;
479 t_con
->state
= TELNET_STATE_DATA
;
482 else if (t_con
->last_escape
== '3')
484 /* Remove character */
487 if (t_con
->line_cursor
< t_con
->line_size
)
491 /* remove char from line buffer */
492 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
494 /* print remainder of buffer */
495 telnet_write(connection
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
496 /* overwrite last char with whitespace */
497 telnet_write(connection
, " \b", 2);
499 /* move back to cursor position*/
500 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
502 telnet_write(connection
, "\b", 1);
506 t_con
->state
= TELNET_STATE_DATA
;
510 t_con
->state
= TELNET_STATE_DATA
;
513 else if (t_con
->last_escape
== '\x00')
517 t_con
->last_escape
= *buf_p
;
521 t_con
->state
= TELNET_STATE_DATA
;
526 ERROR("BUG: unexpected value in t_con->last_escape");
527 t_con
->state
= TELNET_STATE_DATA
;
532 ERROR("unknown telnet state");
543 int telnet_connection_closed(connection_t
*connection
)
545 telnet_connection_t
*t_con
= connection
->priv
;
551 t_con
->prompt
= NULL
;
554 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
556 if (t_con
->history
[i
])
558 free(t_con
->history
[i
]);
559 t_con
->history
[i
] = NULL
;
563 /* if this connection registered a debug-message receiver delete it */
564 delete_debug_msg_receiver(connection
->cmd_ctx
, NULL
);
566 if (connection
->priv
)
568 free(connection
->priv
);
569 connection
->priv
= NULL
;
573 ERROR("BUG: connection->priv == NULL");
576 target_unregister_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
581 int telnet_set_prompt(connection_t
*connection
, char *prompt
)
583 telnet_connection_t
*t_con
= connection
->priv
;
585 t_con
->prompt
= strdup(prompt
);
590 int telnet_init(char *banner
)
592 telnet_service_t
*telnet_service
= malloc(sizeof(telnet_service_t
));
594 if (telnet_port
== 0)
596 WARNING("no telnet port specified, using default port 4444");
600 telnet_service
->banner
= banner
;
602 add_service("telnet", CONNECTION_TELNET
, telnet_port
, 1, telnet_new_connection
, telnet_input
, telnet_connection_closed
, telnet_service
);
607 int telnet_register_commands(command_context_t
*command_context
)
609 register_command(command_context
, NULL
, "exit", handle_exit_command
,
610 COMMAND_EXEC
, "exit telnet session");
612 register_command(command_context
, NULL
, "telnet_port", handle_telnet_port_command
,
618 /* daemon configuration command telnet_port */
619 int handle_telnet_port_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
624 /* only if the port wasn't overwritten by cmdline */
625 if (telnet_port
== 0)
626 telnet_port
= strtoul(args
[0], NULL
, 0);
631 int handle_exit_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
633 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)