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_outputline(connection_t
*connection
, char* line
)
62 write_socket(connection
->fd
, line
, strlen(line
));
63 return write_socket(connection
->fd
, "\r\n\0", 3);
66 int telnet_output(struct command_context_s
*cmd_ctx
, char* line
)
68 connection_t
*connection
= cmd_ctx
->output_handler_priv
;
70 write_socket(connection
->fd
, line
, strlen(line
));
71 write_socket(connection
->fd
, "\r\n\0", 3);
76 void telnet_log_callback(void *privData
, const char *file
, int line
,
77 const char *function
, const char *format
, va_list args
)
79 connection_t
*connection
= (connection_t
*)privData
;
80 char *t
= allocPrintf(format
, args
);
84 telnet_outputline(connection
, t
);
89 int telnet_target_callback_event_handler(struct target_s
*target
, enum target_event event
, void *priv
)
91 struct command_context_s
*cmd_ctx
= priv
;
92 connection_t
*connection
= cmd_ctx
->output_handler_priv
;
93 telnet_connection_t
*t_con
= connection
->priv
;
98 case TARGET_EVENT_HALTED
:
99 command_print(cmd_ctx
, "Target %i halted", get_num_by_target(target
));
100 target
->type
->arch_state(target
, buffer
, 512);
102 command_print(cmd_ctx
, "%s", buffer
);
103 if (!t_con
->suppress_prompt
)
104 telnet_prompt(connection
);
106 case TARGET_EVENT_RESUMED
:
107 command_print(cmd_ctx
, "Target %i resumed", get_num_by_target(target
));
108 if (!t_con
->suppress_prompt
)
109 telnet_prompt(connection
);
118 int telnet_new_connection(connection_t
*connection
)
120 telnet_connection_t
*telnet_connection
= malloc(sizeof(telnet_connection_t
));
121 telnet_service_t
*telnet_service
= connection
->service
->priv
;
124 connection
->priv
= telnet_connection
;
126 /* initialize telnet connection information */
127 telnet_connection
->line_size
= 0;
128 telnet_connection
->line_cursor
= 0;
129 telnet_connection
->option_size
= 0;
130 telnet_connection
->prompt
= strdup("> ");
131 telnet_connection
->suppress_prompt
= 0;
132 telnet_connection
->state
= TELNET_STATE_DATA
;
134 /* output goes through telnet connection */
135 command_set_output_handler(connection
->cmd_ctx
, telnet_output
, connection
);
137 /* negotiate telnet options */
138 write_socket(connection
->fd
, negotiate
, strlen(negotiate
));
140 /* print connection banner */
141 if (telnet_service
->banner
)
143 write_socket(connection
->fd
, telnet_service
->banner
, strlen(telnet_service
->banner
));
144 write_socket(connection
->fd
, "\r\n\0", 3);
147 telnet_prompt(connection
);
149 /* initialize history */
150 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
152 telnet_connection
->history
[i
] = NULL
;
154 telnet_connection
->next_history
= 0;
155 telnet_connection
->current_history
= 0;
157 target_register_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
162 void telnet_clear_line(connection_t
*connection
, telnet_connection_t
*t_con
)
164 /* move to end of line */
165 if (t_con
->line_cursor
< t_con
->line_size
)
167 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
170 /* backspace, overwrite with space, backspace */
171 while (t_con
->line_size
> 0)
173 write_socket(connection
->fd
, "\b \b", 3);
176 t_con
->line_cursor
= 0;
179 int telnet_input(connection_t
*connection
)
182 char buffer
[TELNET_BUFFER_SIZE
];
184 telnet_connection_t
*t_con
= connection
->priv
;
185 command_context_t
*command_context
= connection
->cmd_ctx
;
187 bytes_read
= read_socket(connection
->fd
, buffer
, TELNET_BUFFER_SIZE
);
190 return ERROR_SERVER_REMOTE_CLOSED
;
191 else if (bytes_read
== -1)
193 ERROR("error during read: %s", strerror(errno
));
194 return ERROR_SERVER_REMOTE_CLOSED
;
200 switch (t_con
->state
)
202 case TELNET_STATE_DATA
:
203 if (*buf_p
== '\xff')
205 t_con
->state
= TELNET_STATE_IAC
;
209 if (isprint(*buf_p
)) /* printable character */
211 write_socket(connection
->fd
, buf_p
, 1);
212 if (t_con
->line_cursor
== t_con
->line_size
)
214 t_con
->line
[t_con
->line_size
++] = *buf_p
;
215 t_con
->line_cursor
++;
220 memmove(t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
221 t_con
->line
[t_con
->line_cursor
++] = *buf_p
;
223 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
224 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
226 write_socket(connection
->fd
, "\b", 1);
230 else /* non-printable */
232 if (*buf_p
== 0x1b) /* escape */
234 t_con
->state
= TELNET_STATE_ESCAPE
;
235 t_con
->last_escape
= '\x00';
237 else if ((*buf_p
== 0xd) || (*buf_p
== 0xa)) /* CR/LF */
241 /* skip over combinations with CR/LF + NUL */
242 if (((*(buf_p
+ 1) == 0xa) || (*(buf_p
+ 1) == 0xd)) && (bytes_read
> 1))
247 if ((*(buf_p
+ 1) == 0) && (bytes_read
> 1))
252 t_con
->line
[t_con
->line_size
] = 0;
254 write_socket(connection
->fd
, "\r\n\x00", 3);
256 if (strcmp(t_con
->line
, "history") == 0)
259 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
261 if (t_con
->history
[i
])
263 write_socket(connection
->fd
, t_con
->history
[i
], strlen(t_con
->history
[i
]));
264 write_socket(connection
->fd
, "\r\n\x00", 3);
267 telnet_prompt(connection
);
268 t_con
->line_size
= 0;
269 t_con
->line_cursor
= 0;
273 log_setCallback(telnet_log_callback
, connection
);
274 t_con
->suppress_prompt
= 1;
276 if ((retval
= command_run_line(command_context
, t_con
->line
)) != ERROR_OK
)
278 if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
280 return ERROR_SERVER_REMOTE_CLOSED
;
284 t_con
->suppress_prompt
= 0;
286 /* Save only non-blank lines in the history */
287 if (t_con
->line_size
> 0)
289 /* if the history slot is already taken, free it */
290 if (t_con
->history
[t_con
->next_history
])
292 free(t_con
->history
[t_con
->next_history
]);
295 /* add line to history */
296 t_con
->history
[t_con
->next_history
] = strdup(t_con
->line
);
298 /* wrap history at TELNET_LINE_HISTORY_SIZE */
299 t_con
->next_history
= (t_con
->next_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
301 /* current history line starts at the new entry */
302 t_con
->current_history
= t_con
->next_history
;
304 if (t_con
->history
[t_con
->current_history
])
306 free(t_con
->history
[t_con
->current_history
]);
308 t_con
->history
[t_con
->current_history
] = strdup("");
311 /* output prompt after command */
312 telnet_prompt(connection
);
314 t_con
->line_size
= 0;
315 t_con
->line_cursor
= 0;
317 else if ((*buf_p
== 0x7f) || (*buf_p
== 0x8)) /* delete character */
319 if (t_con
->line_cursor
> 0)
321 if (t_con
->line_cursor
!= t_con
->line_size
)
324 write_socket(connection
->fd
, "\b", 1);
325 t_con
->line_cursor
--;
327 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
329 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
330 write_socket(connection
->fd
, " \b", 2);
331 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
333 write_socket(connection
->fd
, "\b", 1);
339 t_con
->line_cursor
--;
340 /* back space: move the 'printer' head one char back, overwrite with space, move back again */
341 write_socket(connection
->fd
, "\b \b", 3);
345 else if (*buf_p
== 0x15) /* clear line */
347 telnet_clear_line(connection
, t_con
);
349 else if (*buf_p
== CTRL('B')) /* cursor left */
351 if (t_con
->line_cursor
> 0)
353 write_socket(connection
->fd
, "\b", 1);
354 t_con
->line_cursor
--;
356 t_con
->state
= TELNET_STATE_DATA
;
358 else if (*buf_p
== CTRL('F')) /* cursor right */
360 if (t_con
->line_cursor
< t_con
->line_size
)
362 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
++, 1);
364 t_con
->state
= TELNET_STATE_DATA
;
368 DEBUG("unhandled nonprintable: %2.2x", *buf_p
);
373 case TELNET_STATE_IAC
:
377 t_con
->state
= TELNET_STATE_DONT
;
380 t_con
->state
= TELNET_STATE_DO
;
383 t_con
->state
= TELNET_STATE_WONT
;
386 t_con
->state
= TELNET_STATE_WILL
;
390 case TELNET_STATE_SB
:
392 case TELNET_STATE_SE
:
394 case TELNET_STATE_WILL
:
395 case TELNET_STATE_WONT
:
396 case TELNET_STATE_DO
:
397 case TELNET_STATE_DONT
:
398 t_con
->state
= TELNET_STATE_DATA
;
400 case TELNET_STATE_ESCAPE
:
401 if (t_con
->last_escape
== '[')
403 if (*buf_p
== 'D') /* cursor left */
405 if (t_con
->line_cursor
> 0)
407 write_socket(connection
->fd
, "\b", 1);
408 t_con
->line_cursor
--;
410 t_con
->state
= TELNET_STATE_DATA
;
412 else if (*buf_p
== 'C') /* cursor right */
414 if (t_con
->line_cursor
< t_con
->line_size
)
416 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
++, 1);
418 t_con
->state
= TELNET_STATE_DATA
;
420 else if (*buf_p
== 'A') /* cursor up */
422 int last_history
= (t_con
->current_history
> 0) ? t_con
->current_history
- 1 : TELNET_LINE_HISTORY_SIZE
-1;
423 if (t_con
->history
[last_history
])
425 telnet_clear_line(connection
, t_con
);
426 t_con
->line_size
= strlen(t_con
->history
[last_history
]);
427 t_con
->line_cursor
= t_con
->line_size
;
428 memcpy(t_con
->line
, t_con
->history
[last_history
], t_con
->line_size
+ 1);
429 write_socket(connection
->fd
, t_con
->line
, t_con
->line_size
);
430 t_con
->current_history
= last_history
;
432 t_con
->state
= TELNET_STATE_DATA
;
434 else if (*buf_p
== 'B') /* cursor down */
436 int next_history
= (t_con
->current_history
+ 1) % TELNET_LINE_HISTORY_SIZE
;
437 if (t_con
->history
[next_history
])
439 telnet_clear_line(connection
, t_con
);
440 t_con
->line_size
= strlen(t_con
->history
[next_history
]);
441 t_con
->line_cursor
= t_con
->line_size
;
442 memcpy(t_con
->line
, t_con
->history
[next_history
], t_con
->line_size
+ 1);
443 write_socket(connection
->fd
, t_con
->line
, t_con
->line_size
);
444 t_con
->current_history
= next_history
;
446 t_con
->state
= TELNET_STATE_DATA
;
448 else if (*buf_p
== '3')
450 t_con
->last_escape
= *buf_p
;
454 t_con
->state
= TELNET_STATE_DATA
;
457 else if (t_con
->last_escape
== '3')
459 /* Remove character */
462 if (t_con
->line_cursor
< t_con
->line_size
)
466 /* remove char from line buffer */
467 memmove(t_con
->line
+ t_con
->line_cursor
, t_con
->line
+ t_con
->line_cursor
+ 1, t_con
->line_size
- t_con
->line_cursor
);
469 /* print remainder of buffer */
470 write_socket(connection
->fd
, t_con
->line
+ t_con
->line_cursor
, t_con
->line_size
- t_con
->line_cursor
);
471 /* overwrite last char with whitespace */
472 write_socket(connection
->fd
, " \b", 2);
474 /* move back to cursor position*/
475 for (i
= t_con
->line_cursor
; i
< t_con
->line_size
; i
++)
477 write_socket(connection
->fd
, "\b", 1);
481 t_con
->state
= TELNET_STATE_DATA
;
485 t_con
->state
= TELNET_STATE_DATA
;
488 else if (t_con
->last_escape
== '\x00')
492 t_con
->last_escape
= *buf_p
;
496 t_con
->state
= TELNET_STATE_DATA
;
501 ERROR("BUG: unexpected value in t_con->last_escape");
502 t_con
->state
= TELNET_STATE_DATA
;
507 ERROR("unknown telnet state");
518 int telnet_connection_closed(connection_t
*connection
)
520 telnet_connection_t
*t_con
= connection
->priv
;
526 t_con
->prompt
= NULL
;
529 for (i
= 0; i
< TELNET_LINE_HISTORY_SIZE
; i
++)
531 if (t_con
->history
[i
])
533 free(t_con
->history
[i
]);
534 t_con
->history
[i
] = NULL
;
538 /* if this connection registered a debug-message receiver delete it */
539 delete_debug_msg_receiver(connection
->cmd_ctx
, NULL
);
541 if (connection
->priv
)
543 free(connection
->priv
);
544 connection
->priv
= NULL
;
548 ERROR("BUG: connection->priv == NULL");
551 target_unregister_event_callback(telnet_target_callback_event_handler
, connection
->cmd_ctx
);
556 int telnet_set_prompt(connection_t
*connection
, char *prompt
)
558 telnet_connection_t
*t_con
= connection
->priv
;
560 t_con
->prompt
= strdup(prompt
);
565 int telnet_init(char *banner
)
567 telnet_service_t
*telnet_service
= malloc(sizeof(telnet_service_t
));
569 if (telnet_port
== 0)
571 WARNING("no telnet port specified, using default port 4444");
575 telnet_service
->banner
= banner
;
577 add_service("telnet", CONNECTION_TELNET
, telnet_port
, 1, telnet_new_connection
, telnet_input
, telnet_connection_closed
, telnet_service
);
582 int telnet_register_commands(command_context_t
*command_context
)
584 register_command(command_context
, NULL
, "exit", handle_exit_command
,
585 COMMAND_EXEC
, "exit telnet session");
587 register_command(command_context
, NULL
, "telnet_port", handle_telnet_port_command
,
593 /* daemon configuration command telnet_port */
594 int handle_telnet_port_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
599 /* only if the port wasn't overwritten by cmdline */
600 if (telnet_port
== 0)
601 telnet_port
= strtoul(args
[0], NULL
, 0);
606 int handle_exit_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
608 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)