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 void telnet_prompt(connection_t
*connection
)
55 telnet_connection_t
*t_con
= connection
->priv
;
57 write_socket(connection
->fd
, t_con
->prompt
, strlen(t_con
->prompt
));
60 int telnet_output(struct command_context_s
*cmd_ctx
, char* line
)
62 connection_t
*connection
= cmd_ctx
->output_handler_priv
;
64 write_socket(connection
->fd
, line
, strlen(line
));
65 write_socket(connection
->fd
, "\r\n\0", 3);
70 int telnet_target_callback_event_handler(struct target_s
*target
, enum target_event event
, void *priv
)
72 struct command_context_s
*cmd_ctx
= priv
;
77 case TARGET_EVENT_HALTED
:
78 command_print(cmd_ctx
, "Target %i halted", get_num_by_target(target
));
79 target
->type
->arch_state(target
, buffer
, 512);
81 command_print(cmd_ctx
, "%s", buffer
);
83 case TARGET_EVENT_RESUMED
:
84 command_print(cmd_ctx
, "Target %i resumed", get_num_by_target(target
));
93 int telnet_new_connection(connection_t
*connection
)
95 telnet_connection_t
*telnet_connection
= malloc(sizeof(telnet_connection_t
));
96 telnet_service_t
*telnet_service
= connection
->service
->priv
;
99 connection
->priv
= telnet_connection
;
101 /* initialize telnet connection information */
102 telnet_connection
->line_size
= 0;
103 telnet_connection
->line_cursor
= 0;
104 telnet_connection
->option_size
= 0;
105 telnet_connection
->prompt
= strdup("> ");
106 telnet_connection
->state
= TELNET_STATE_DATA
;
108 /* output goes through telnet connection */
109 command_set_output_handler(connection
->cmd_ctx
, telnet_output
, connection
);
111 /* negotiate telnet options */
112 write_socket(connection
->fd
, negotiate
, strlen(negotiate
));
114 /* print connection banner */
115 if (telnet_service
->banner
)
117 write_socket(connection
->fd
, telnet_service
->banner
, strlen(telnet_service
->banner
));
118 write_socket(connection
->fd
, "\r\n\0", 3);
121 telnet_prompt(connection
);
123 /* initialize history */
124 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
126 telnet_connection
->history
[i
] = NULL
;
128 telnet_connection
->next_history
= 0;
129 telnet_connection
->current_history
= 0;
131 target_register_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
136 void telnet_clear_line(connection_t
*connection
, telnet_connection_t
*t_con
)
138 /* move to end of line */
139 if (t_con
->line_cursor
< t_con
->line_size
)
141 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
144 /* backspace, overwrite with space, backspace */
145 while (t_con
->line_size
> 0)
147 write_socket(connection
->fd
, "\b \b", 3);
150 t_con
->line_cursor
= 0;
153 int telnet_input(connection_t
*connection
)
156 char buffer
[TELNET_BUFFER_SIZE
];
158 telnet_connection_t
*t_con
= connection
->priv
;
159 command_context_t
*command_context
= connection
->cmd_ctx
;
161 bytes_read
= read_socket(connection
->fd
, buffer
, TELNET_BUFFER_SIZE
);
164 return ERROR_SERVER_REMOTE_CLOSED
;
165 else if (bytes_read
== -1)
167 ERROR("error during read: %s", strerror(errno
));
168 return ERROR_SERVER_REMOTE_CLOSED
;
174 switch (t_con
->state
)
176 case TELNET_STATE_DATA
:
177 if (*buf_p
== '\xff')
179 t_con
->state
= TELNET_STATE_IAC
;
183 if (isprint(*buf_p
)) /* printable character */
185 write_socket(connection
->fd
, buf_p
, 1);
186 if (t_con
->line_cursor
== t_con
->line_size
)
188 t_con
->line
[t_con
->line_size
++] = *buf_p
;
189 t_con
->line_cursor
++;
194 memmove(t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
195 t_con
->line
[t_con
->line_cursor
++] = *buf_p
;
197 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
198 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
200 write_socket(connection
->fd
, "\b", 1);
204 else /* non-printable */
206 if (*buf_p
== 0x1b) /* escape */
208 t_con
->state
= TELNET_STATE_ESCAPE
;
209 t_con
->last_escape
= '\x00';
211 else if ((*buf_p
== 0xd) || (*buf_p
== 0xa)) /* CR/LF */
215 /* skip over combinations with CR/LF + NUL */
216 if (((*(buf_p
+ 1) == 0xa) || (*(buf_p
+ 1) == 0xd)) && (bytes_read
> 1))
221 if ((*(buf_p
+ 1) == 0) && (bytes_read
> 1))
226 t_con
->line
[t_con
->line_size
] = 0;
228 write_socket(connection
->fd
, "\r\n\x00", 3);
230 if (strcmp(t_con
->line
, "history") == 0)
233 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
235 if (t_con
->history
[i
])
237 write_socket(connection
->fd
, t_con
->history
[i
], strlen(t_con
->history
[i
]));
238 write_socket(connection
->fd
, "\r\n\x00", 3);
241 telnet_prompt(connection
);
242 t_con
->line_size
= 0;
243 t_con
->line_cursor
= 0;
247 if ((retval
= command_run_line(command_context
, t_con
->line
)) != ERROR_OK
)
249 if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
251 return ERROR_SERVER_REMOTE_CLOSED
;
255 /* Save only non-blank lines in the history */
256 if (t_con
->line_size
> 0)
258 /* if the history slot is already taken, free it */
259 if (t_con
->history
[t_con
->next_history
])
261 free(t_con
->history
[t_con
->next_history
]);
264 /* add line to history */
265 t_con
->history
[t_con
->next_history
] = strdup(t_con
->line
);
267 /* wrap history at TELNET_LINE_HISTORY_SIZE */
268 t_con
->next_history
= (t_con
->next_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
270 /* current history line starts at the new entry */
271 t_con
->current_history
= t_con
->next_history
;
273 if (t_con
->history
[t_con
->current_history
])
275 free(t_con
->history
[t_con
->current_history
]);
277 t_con
->history
[t_con
->current_history
] = strdup("");
280 /* output prompt after command */
281 telnet_prompt(connection
);
283 t_con
->line_size
= 0;
284 t_con
->line_cursor
= 0;
286 else if ((*buf_p
== 0x7f) || (*buf_p
== 0x8)) /* delete character */
288 if (t_con
->line_cursor
> 0)
290 if (t_con
->line_cursor
!= t_con
->line_size
)
293 write_socket(connection
->fd
, "\b", 1);
294 t_con
->line_cursor
--;
296 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
298 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
299 write_socket(connection
->fd
, " \b", 2);
300 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
302 write_socket(connection
->fd
, "\b", 1);
308 t_con
->line_cursor
--;
309 /* back space: move the 'printer' head one char back, overwrite with space, move back again */
310 write_socket(connection
->fd
, "\b \b", 3);
314 else if (*buf_p
== 0x15) /* clear line */
316 telnet_clear_line(connection
, t_con
);
318 else if (*buf_p
== CTRL('B')) /* cursor left */
320 if (t_con
->line_cursor
> 0)
322 write_socket(connection
->fd
, "\b", 1);
323 t_con
->line_cursor
--;
325 t_con
->state
= TELNET_STATE_DATA
;
327 else if (*buf_p
== CTRL('F')) /* cursor right */
329 if (t_con
->line_cursor
< t_con
->line_size
)
331 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
++, 1);
333 t_con
->state
= TELNET_STATE_DATA
;
337 DEBUG("unhandled nonprintable: %2.2x", *buf_p
);
342 case TELNET_STATE_IAC
:
346 t_con
->state
= TELNET_STATE_DONT
;
349 t_con
->state
= TELNET_STATE_DO
;
352 t_con
->state
= TELNET_STATE_WONT
;
355 t_con
->state
= TELNET_STATE_WILL
;
359 case TELNET_STATE_SB
:
361 case TELNET_STATE_SE
:
363 case TELNET_STATE_WILL
:
364 case TELNET_STATE_WONT
:
365 case TELNET_STATE_DO
:
366 case TELNET_STATE_DONT
:
367 t_con
->state
= TELNET_STATE_DATA
;
369 case TELNET_STATE_ESCAPE
:
370 if (t_con
->last_escape
== '[')
372 if (*buf_p
== 'D') /* cursor left */
374 if (t_con
->line_cursor
> 0)
376 write_socket(connection
->fd
, "\b", 1);
377 t_con
->line_cursor
--;
379 t_con
->state
= TELNET_STATE_DATA
;
381 else if (*buf_p
== 'C') /* cursor right */
383 if (t_con
->line_cursor
< t_con
->line_size
)
385 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
++, 1);
387 t_con
->state
= TELNET_STATE_DATA
;
389 else if (*buf_p
== 'A') /* cursor up */
391 int last_history
= (t_con
->current_history
> 0) ? t_con
->current_history
- 1 : TELNET_LINE_HISTORY_SIZE
-1;
392 if (t_con
->history
[last_history
])
394 telnet_clear_line(connection
, t_con
);
395 t_con
->line_size
= strlen(t_con
->history
[last_history
]);
396 t_con
->line_cursor
= t_con
->line_size
;
397 memcpy(t_con
->line
, t_con
->history
[last_history
], t_con
->line_size
+ 1);
398 write_socket(connection
->fd
, t_con
->line
, t_con
->line_size
);
399 t_con
->current_history
= last_history
;
401 t_con
->state
= TELNET_STATE_DATA
;
403 else if (*buf_p
== 'B') /* cursor down */
405 int next_history
= (t_con
->current_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
406 if (t_con
->history
[next_history
])
408 telnet_clear_line(connection
, t_con
);
409 t_con
->line_size
= strlen(t_con
->history
[next_history
]);
410 t_con
->line_cursor
= t_con
->line_size
;
411 memcpy(t_con
->line
, t_con
->history
[next_history
], t_con
->line_size
+ 1);
412 write_socket(connection
->fd
, t_con
->line
, t_con
->line_size
);
413 t_con
->current_history
= next_history
;
415 t_con
->state
= TELNET_STATE_DATA
;
417 else if (*buf_p
== '3')
419 t_con
->last_escape
= *buf_p
;
423 t_con
->state
= TELNET_STATE_DATA
;
426 else if (t_con
->last_escape
== '3')
428 /* Remove character */
431 if (t_con
->line_cursor
< t_con
->line_size
)
435 /* remove char from line buffer */
436 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
438 /* print remainder of buffer */
439 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
440 /* overwrite last char with whitespace */
441 write_socket(connection
->fd
, " \b", 2);
443 /* move back to cursor position*/
444 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
446 write_socket(connection
->fd
, "\b", 1);
450 t_con
->state
= TELNET_STATE_DATA
;
454 t_con
->state
= TELNET_STATE_DATA
;
457 else if (t_con
->last_escape
== '\x00')
461 t_con
->last_escape
= *buf_p
;
465 t_con
->state
= TELNET_STATE_DATA
;
470 ERROR("BUG: unexpected value in t_con->last_escape");
471 t_con
->state
= TELNET_STATE_DATA
;
476 ERROR("unknown telnet state");
487 int telnet_connection_closed(connection_t
*connection
)
489 telnet_connection_t
*t_con
= connection
->priv
;
495 t_con
->prompt
= NULL
;
498 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
500 if (t_con
->history
[i
])
502 free(t_con
->history
[i
]);
503 t_con
->history
[i
] = NULL
;
507 /* if this connection registered a debug-message receiver delete it */
508 delete_debug_msg_receiver(connection
->cmd_ctx
, NULL
);
510 if (connection
->priv
)
512 free(connection
->priv
);
513 connection
->priv
= NULL
;
517 ERROR("BUG: connection->priv == NULL");
520 target_unregister_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
525 int telnet_set_prompt(connection_t
*connection
, char *prompt
)
527 telnet_connection_t
*t_con
= connection
->priv
;
529 t_con
->prompt
= strdup(prompt
);
534 int telnet_init(char *banner
)
536 telnet_service_t
*telnet_service
= malloc(sizeof(telnet_service_t
));
538 if (telnet_port
== 0)
540 WARNING("no telnet port specified, using default port 4444");
544 telnet_service
->banner
= banner
;
546 add_service("telnet", CONNECTION_TELNET
, telnet_port
, 1, telnet_new_connection
, telnet_input
, telnet_connection_closed
, telnet_service
);
551 int telnet_register_commands(command_context_t
*command_context
)
553 register_command(command_context
, NULL
, "exit", handle_exit_command
,
554 COMMAND_EXEC
, "exit telnet session");
556 register_command(command_context
, NULL
, "telnet_port", handle_telnet_port_command
,
562 /* daemon configuration command telnet_port */
563 int handle_telnet_port_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
568 /* only if the port wasn't overwritten by cmdline */
569 if (telnet_port
== 0)
570 telnet_port
= strtoul(args
[0], NULL
, 0);
575 int handle_exit_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
577 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)