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"
39 static unsigned short telnet_port
= 0;
41 int handle_exit_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
42 int handle_telnet_port_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
44 static char *negotiate
=
45 "\xFF\xFB\x03" /* IAC WILL Suppress Go Ahead */
46 "\xFF\xFB\x01" /* IAC WILL Echo */
47 "\xFF\xFD\x03" /* IAC DO Suppress Go Ahead */
48 "\xFF\xFE\x01"; /* IAC DON'T Echo */
50 #define CTRL(c) (c - '@')
52 void telnet_prompt(connection_t
*connection
)
54 telnet_connection_t
*t_con
= connection
->priv
;
56 write_socket(connection
->fd
, t_con
->prompt
, strlen(t_con
->prompt
));
59 int telnet_output(struct command_context_s
*cmd_ctx
, char* line
)
61 connection_t
*connection
= cmd_ctx
->output_handler_priv
;
63 write_socket(connection
->fd
, line
, strlen(line
));
64 write_socket(connection
->fd
, "\r\n\0", 3);
69 int telnet_target_callback_event_handler(struct target_s
*target
, enum target_event event
, void *priv
)
71 struct command_context_s
*cmd_ctx
= priv
;
72 connection_t
*connection
= cmd_ctx
->output_handler_priv
;
73 telnet_connection_t
*t_con
= connection
->priv
;
78 case TARGET_EVENT_HALTED
:
79 command_print(cmd_ctx
, "Target %i halted", get_num_by_target(target
));
80 target
->type
->arch_state(target
, buffer
, 512);
82 command_print(cmd_ctx
, "%s", buffer
);
83 telnet_prompt(connection
);
84 t_con
->suppress_prompt
= 1;
86 case TARGET_EVENT_RESUMED
:
87 command_print(cmd_ctx
, "Target %i resumed", get_num_by_target(target
));
88 telnet_prompt(connection
);
89 t_con
->suppress_prompt
= 1;
98 int telnet_new_connection(connection_t
*connection
)
100 telnet_connection_t
*telnet_connection
= malloc(sizeof(telnet_connection_t
));
101 telnet_service_t
*telnet_service
= connection
->service
->priv
;
104 connection
->priv
= telnet_connection
;
106 /* initialize telnet connection information */
107 telnet_connection
->line_size
= 0;
108 telnet_connection
->line_cursor
= 0;
109 telnet_connection
->option_size
= 0;
110 telnet_connection
->prompt
= strdup("> ");
111 telnet_connection
->suppress_prompt
= 0;
112 telnet_connection
->state
= TELNET_STATE_DATA
;
114 /* output goes through telnet connection */
115 command_set_output_handler(connection
->cmd_ctx
, telnet_output
, connection
);
117 /* negotiate telnet options */
118 write_socket(connection
->fd
, negotiate
, strlen(negotiate
));
120 /* print connection banner */
121 if (telnet_service
->banner
)
123 write_socket(connection
->fd
, telnet_service
->banner
, strlen(telnet_service
->banner
));
124 write_socket(connection
->fd
, "\r\n\0", 3);
127 telnet_prompt(connection
);
129 /* initialize history */
130 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
132 telnet_connection
->history
[i
] = NULL
;
134 telnet_connection
->next_history
= 0;
135 telnet_connection
->current_history
= 0;
137 target_register_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
142 void telnet_clear_line(connection_t
*connection
, telnet_connection_t
*t_con
)
144 /* move to end of line */
145 if (t_con
->line_cursor
< t_con
->line_size
)
147 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
150 /* backspace, overwrite with space, backspace */
151 while (t_con
->line_size
> 0)
153 write_socket(connection
->fd
, "\b \b", 3);
156 t_con
->line_cursor
= 0;
159 int telnet_input(connection_t
*connection
)
162 char buffer
[TELNET_BUFFER_SIZE
];
164 telnet_connection_t
*t_con
= connection
->priv
;
165 command_context_t
*command_context
= connection
->cmd_ctx
;
167 bytes_read
= read_socket(connection
->fd
, buffer
, TELNET_BUFFER_SIZE
);
170 return ERROR_SERVER_REMOTE_CLOSED
;
171 else if (bytes_read
== -1)
173 ERROR("error during read: %s", strerror(errno
));
174 return ERROR_SERVER_REMOTE_CLOSED
;
180 switch (t_con
->state
)
182 case TELNET_STATE_DATA
:
183 if (*buf_p
== '\xff')
185 t_con
->state
= TELNET_STATE_IAC
;
189 if (isprint(*buf_p
)) /* printable character */
191 write_socket(connection
->fd
, buf_p
, 1);
192 if (t_con
->line_cursor
== t_con
->line_size
)
194 t_con
->line
[t_con
->line_size
++] = *buf_p
;
195 t_con
->line_cursor
++;
200 memmove(t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
201 t_con
->line
[t_con
->line_cursor
++] = *buf_p
;
203 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
204 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
206 write_socket(connection
->fd
, "\b", 1);
210 else /* non-printable */
212 if (*buf_p
== 0x1b) /* escape */
214 t_con
->state
= TELNET_STATE_ESCAPE
;
215 t_con
->last_escape
= '\x00';
217 else if ((*buf_p
== 0xd) || (*buf_p
== 0xa)) /* CR/LF */
221 /* skip over combinations with CR/LF + NUL */
222 if (((*(buf_p
+ 1) == 0xa) || (*(buf_p
+ 1) == 0xd)) && (bytes_read
> 1))
227 if ((*(buf_p
+ 1) == 0) && (bytes_read
> 1))
232 t_con
->line
[t_con
->line_size
] = 0;
234 write_socket(connection
->fd
, "\r\n\x00", 3);
236 if (strcmp(t_con
->line
, "history") == 0)
239 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
241 if (t_con
->history
[i
])
243 write_socket(connection
->fd
, t_con
->history
[i
], strlen(t_con
->history
[i
]));
244 write_socket(connection
->fd
, "\r\n\x00", 3);
247 telnet_prompt(connection
);
248 t_con
->line_size
= 0;
249 t_con
->line_cursor
= 0;
253 /* we're running a command, so we need a prompt
254 * if the output handler is called, this gets set again */
255 t_con
->suppress_prompt
= 0;
256 if ((retval
= command_run_line(command_context
, t_con
->line
)) != ERROR_OK
)
258 if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
260 return ERROR_SERVER_REMOTE_CLOSED
;
264 /* Save only non-blank lines in the history */
265 if (t_con
->line_size
> 0)
267 /* if the history slot is already taken, free it */
268 if (t_con
->history
[t_con
->next_history
])
270 free(t_con
->history
[t_con
->next_history
]);
273 /* add line to history */
274 t_con
->history
[t_con
->next_history
] = strdup(t_con
->line
);
276 /* wrap history at TELNET_LINE_HISTORY_SIZE */
277 t_con
->next_history
= (t_con
->next_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
279 /* current history line starts at the new entry */
280 t_con
->current_history
= t_con
->next_history
;
282 if (t_con
->history
[t_con
->current_history
])
284 free(t_con
->history
[t_con
->current_history
]);
286 t_con
->history
[t_con
->current_history
] = strdup("");
289 if (!t_con
->suppress_prompt
)
291 telnet_prompt(connection
);
295 t_con
->suppress_prompt
= 0;
298 t_con
->line_size
= 0;
299 t_con
->line_cursor
= 0;
301 else if ((*buf_p
== 0x7f) || (*buf_p
== 0x8)) /* delete character */
303 if (t_con
->line_cursor
> 0)
305 if (t_con
->line_cursor
!= t_con
->line_size
)
308 write_socket(connection
->fd
, "\b", 1);
309 t_con
->line_cursor
--;
311 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
313 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
314 write_socket(connection
->fd
, " \b", 2);
315 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
317 write_socket(connection
->fd
, "\b", 1);
323 t_con
->line_cursor
--;
324 /* back space: move the 'printer' head one char back, overwrite with space, move back again */
325 write_socket(connection
->fd
, "\b \b", 3);
329 else if (*buf_p
== 0x15) /* clear line */
331 telnet_clear_line(connection
, t_con
);
333 else if (*buf_p
== CTRL('B')) /* cursor left */
335 if (t_con
->line_cursor
> 0)
337 write_socket(connection
->fd
, "\b", 1);
338 t_con
->line_cursor
--;
340 t_con
->state
= TELNET_STATE_DATA
;
342 else if (*buf_p
== CTRL('F')) /* cursor right */
344 if (t_con
->line_cursor
< t_con
->line_size
)
346 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
++, 1);
348 t_con
->state
= TELNET_STATE_DATA
;
352 DEBUG("unhandled nonprintable: %2.2x", *buf_p
);
357 case TELNET_STATE_IAC
:
361 t_con
->state
= TELNET_STATE_DONT
;
364 t_con
->state
= TELNET_STATE_DO
;
367 t_con
->state
= TELNET_STATE_WONT
;
370 t_con
->state
= TELNET_STATE_WILL
;
374 case TELNET_STATE_SB
:
376 case TELNET_STATE_SE
:
378 case TELNET_STATE_WILL
:
379 case TELNET_STATE_WONT
:
380 case TELNET_STATE_DO
:
381 case TELNET_STATE_DONT
:
382 t_con
->state
= TELNET_STATE_DATA
;
384 case TELNET_STATE_ESCAPE
:
385 if (t_con
->last_escape
== '[')
387 if (*buf_p
== 'D') /* cursor left */
389 if (t_con
->line_cursor
> 0)
391 write_socket(connection
->fd
, "\b", 1);
392 t_con
->line_cursor
--;
394 t_con
->state
= TELNET_STATE_DATA
;
396 else if (*buf_p
== 'C') /* cursor right */
398 if (t_con
->line_cursor
< t_con
->line_size
)
400 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
++, 1);
402 t_con
->state
= TELNET_STATE_DATA
;
404 else if (*buf_p
== 'A') /* cursor up */
406 int last_history
= (t_con
->current_history
> 0) ? t_con
->current_history
- 1 : TELNET_LINE_HISTORY_SIZE
-1;
407 if (t_con
->history
[last_history
])
409 telnet_clear_line(connection
, t_con
);
410 t_con
->line_size
= strlen(t_con
->history
[last_history
]);
411 t_con
->line_cursor
= t_con
->line_size
;
412 memcpy(t_con
->line
, t_con
->history
[last_history
], t_con
->line_size
+ 1);
413 write_socket(connection
->fd
, t_con
->line
, t_con
->line_size
);
414 t_con
->current_history
= last_history
;
416 t_con
->state
= TELNET_STATE_DATA
;
418 else if (*buf_p
== 'B') /* cursor down */
420 int next_history
= (t_con
->current_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
421 if (t_con
->history
[next_history
])
423 telnet_clear_line(connection
, t_con
);
424 t_con
->line_size
= strlen(t_con
->history
[next_history
]);
425 t_con
->line_cursor
= t_con
->line_size
;
426 memcpy(t_con
->line
, t_con
->history
[next_history
], t_con
->line_size
+ 1);
427 write_socket(connection
->fd
, t_con
->line
, t_con
->line_size
);
428 t_con
->current_history
= next_history
;
430 t_con
->state
= TELNET_STATE_DATA
;
432 else if (*buf_p
== '3')
434 t_con
->last_escape
= *buf_p
;
438 t_con
->state
= TELNET_STATE_DATA
;
441 else if (t_con
->last_escape
== '3')
443 /* Remove character */
446 if (t_con
->line_cursor
< t_con
->line_size
)
450 /* remove char from line buffer */
451 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
453 /* print remainder of buffer */
454 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
455 /* overwrite last char with whitespace */
456 write_socket(connection
->fd
, " \b", 2);
458 /* move back to cursor position*/
459 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
461 write_socket(connection
->fd
, "\b", 1);
465 t_con
->state
= TELNET_STATE_DATA
;
469 t_con
->state
= TELNET_STATE_DATA
;
472 else if (t_con
->last_escape
== '\x00')
476 t_con
->last_escape
= *buf_p
;
480 t_con
->state
= TELNET_STATE_DATA
;
485 ERROR("BUG: unexpected value in t_con->last_escape");
486 t_con
->state
= TELNET_STATE_DATA
;
491 ERROR("unknown telnet state");
502 int telnet_connection_closed(connection_t
*connection
)
504 telnet_connection_t
*t_con
= connection
->priv
;
510 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
512 if (t_con
->history
[i
])
513 free(t_con
->history
[i
]);
516 if (connection
->priv
)
517 free(connection
->priv
);
519 ERROR("BUG: connection->priv == NULL");
521 target_unregister_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
526 int telnet_set_prompt(connection_t
*connection
, char *prompt
)
528 telnet_connection_t
*t_con
= connection
->priv
;
530 t_con
->prompt
= strdup(prompt
);
535 int telnet_init(char *banner
)
537 telnet_service_t
*telnet_service
= malloc(sizeof(telnet_service_t
));
539 if (telnet_port
== 0)
541 WARNING("no telnet port specified, using default port 4444");
545 telnet_service
->banner
= banner
;
547 add_service("telnet", CONNECTION_TELNET
, telnet_port
, 1, telnet_new_connection
, telnet_input
, telnet_connection_closed
, telnet_service
);
552 int telnet_register_commands(command_context_t
*command_context
)
554 register_command(command_context
, NULL
, "exit", handle_exit_command
,
555 COMMAND_EXEC
, "exit telnet session");
557 register_command(command_context
, NULL
, "telnet_port", handle_telnet_port_command
,
563 /* daemon configuration command telnet_port */
564 int handle_telnet_port_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
569 /* only if the port wasn't overwritten by cmdline */
570 if (telnet_port
== 0)
571 telnet_port
= strtoul(args
[0], NULL
, 0);
576 int handle_exit_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
578 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)