- this is enabled by new command line option option --pipe. git-svn-id: svn://svn.berlios.de/openocd/trunk@1242 b42882b7-edfa-0310-969c-e2dbd0fdcd60tags/v0.1.0
@@ -15,7 +15,7 @@ | |||
@itemize @bullet | |||
@item Copyright @copyright{} 2008 The OpenOCD Project | |||
@item Copyright @copyright{} 2007-2008 Spen @email{spen@@spen-soft.co.uk} | |||
@item Copyright @copyright{} 2007-2008 Spencer Oliver @email{spen@@spen-soft.co.uk} | |||
@item Copyright @copyright{} 2008 Oyvind Harboe @email{oyvind.harboe@@zylin.com} | |||
@item Copyright @copyright{} 2008 Duane Ellis @email{openocd@@duaneellis.com} | |||
@end itemize | |||
@@ -411,9 +411,10 @@ bash$ openocd --help | |||
--debug | -d set debug level <0-3> | |||
--log_output | -l redirect log output to file <name> | |||
--command | -c run <command> | |||
--pipe | -p use pipes when talking to gdb | |||
@end verbatim | |||
By default openocd reads the file configuration file ``openocd.cfg'' | |||
By default OpenOCD reads the file configuration file ``openocd.cfg'' | |||
in the current directory. To specify a different (or multiple) | |||
configuration file, you can use the ``-f'' option. For example: | |||
@@ -445,6 +446,9 @@ Search paths for config/script files can be added to OpenOCD by using | |||
the @option{-s <search>} switch. The current directory and the OpenOCD | |||
target library is in the search path by default. | |||
For details on the @option{-p} option. @xref{Connecting to GDB}. | |||
Option @option{-p} is not currently supported under native win32. | |||
Note! OpenOCD will launch the GDB & telnet server even if it can not | |||
establish a connection with the target. In general, it is possible for | |||
the JTAG controller to be unresponsive until the target is set up | |||
@@ -455,7 +459,7 @@ correctly via e.g. GDB monitor commands in a GDB init script. | |||
@cindex configuration | |||
@section Outline | |||
There are 4 basic ways of ``configurating'' openocd to run, they are: | |||
There are 4 basic ways of ``configurating'' OpenOCD to run, they are: | |||
@enumerate | |||
@item A small openocd.cfg file which ``sources'' other configuration files | |||
@@ -671,7 +675,7 @@ tap identifier dotted name. | |||
every chip. If the @t{-expected-id} is nonzero, OpenOCD attempts | |||
to verify the tap id number verses configuration file and may issue an | |||
error or warning like this. The hope is this will help pin point | |||
problem openocd configurations. | |||
problem OpenOCD configurations. | |||
@example | |||
Info: JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3) | |||
@@ -904,7 +908,7 @@ command interpretor today (28/nov/2008) is a mixture of (newer) | |||
JIM-Tcl commands, and (older) the orginal command interpretor. | |||
@item @b{Commands} | |||
@* At the openocd telnet command line (or via the GDB mon command) one | |||
@* At the OpenOCD telnet command line (or via the GDB mon command) one | |||
can type a Tcl for() loop, set variables, etc. | |||
@item @b{Historical Note} | |||
@@ -1145,7 +1149,7 @@ if compiled with FTD2XX support. | |||
@b{TODO:} Confirm the following: On windows the name needs to end with | |||
a ``space A''? Or not? It has to do with the FTD2xx driver. When must | |||
this be added and when must it not be added? Why can't the code in the | |||
interface or in openocd automatically add this if needed? -- Duane. | |||
interface or in OpenOCD automatically add this if needed? -- Duane. | |||
@item @b{ft2232_serial} <@var{serial-number}> | |||
@cindex ft2232_serial | |||
@@ -1527,7 +1531,7 @@ then ``bypass'' the tap, the tap is completely removed from the | |||
circuit and skipped. | |||
From OpenOCDs view point, a JTAG TAP is in one of 3 states: | |||
From OpenOCD's view point, a JTAG TAP is in one of 3 states: | |||
@itemize @bullet | |||
@item @b{Enabled - Not In ByPass} and has a variable bit length | |||
@@ -1640,7 +1644,7 @@ configure it like this: | |||
puts [format "The button is %s" $x] | |||
@end example | |||
In OpenOCDs terms, the ``target'' is an object just like a Tcl/Tk | |||
In OpenOCD's terms, the ``target'' is an object just like a Tcl/Tk | |||
button. Commands avaialble as a ``target object'' are: | |||
@comment START targetobj commands. | |||
@@ -1841,7 +1845,7 @@ via the configure option or to query the target via cget. | |||
@item @b{-work-area-size [ADDRESS]} specify/set the work area | |||
@item @b{-work-area-backup [0|1]} does the work area get backed up | |||
@item @b{-endian [big|little]} | |||
@item @b{-variant [NAME]} some chips have varients openocd needs to know about | |||
@item @b{-variant [NAME]} some chips have varients OpenOCD needs to know about | |||
@item @b{-chain-position DOTTED.NAME} the tap name this target refers to. | |||
@end itemize | |||
Example: | |||
@@ -1870,7 +1874,7 @@ cores. | |||
@* None (this is also used as the ARM946) | |||
@item @b{cortex_m3} | |||
@* use variant <@var{-variant lm3s}> when debugging luminary lm3s targets. This will cause | |||
openocd to use a software reset rather than asserting SRST to avoid a issue with clearing | |||
OpenOCD to use a software reset rather than asserting SRST to avoid a issue with clearing | |||
the debug registers. This is fixed in Fury Rev B, DustDevil Rev B, Tempest, these revisions will | |||
be detected and the normal reset behaviour used. | |||
@item @b{xscale} | |||
@@ -1880,9 +1884,9 @@ be detected and the normal reset behaviour used. | |||
@item @b{mips_m4k} | |||
@* Use variant @option{ejtag_srst} when debugging targets that do not | |||
provide a functional SRST line on the EJTAG connector. This causes | |||
openocd to instead use an EJTAG software reset command to reset the | |||
OpenOCD to instead use an EJTAG software reset command to reset the | |||
processor. You still need to enable @option{srst} on the reset | |||
configuration command to enable openocd hardware reset functionality. | |||
configuration command to enable OpenOCD hardware reset functionality. | |||
@comment END varients | |||
@end itemize | |||
@section working_area - Command Removed | |||
@@ -2004,7 +2008,7 @@ to a <@var{file}>. | |||
@end itemize | |||
@section flash bank command | |||
The @b{flash bank} command is used to configure one or more flash chips (or banks in openocd terms) | |||
The @b{flash bank} command is used to configure one or more flash chips (or banks in OpenOCD terms) | |||
@example | |||
@b{flash bank} <@var{driver}> <@var{base}> <@var{size}> <@var{chip_width}> | |||
@@ -2170,7 +2174,7 @@ erase the device. | |||
@end itemize | |||
Note: Before using the str9xpec driver here is some background info to help | |||
you better understand how the drivers works. Openocd has two flash drivers for | |||
you better understand how the drivers works. OpenOCD has two flash drivers for | |||
the str9. | |||
@enumerate | |||
@item | |||
@@ -2793,41 +2797,52 @@ openocd -f interface/parport.cfg -f target/at91r40008.cfg -c init -c reset | |||
OpenOCD complies with the remote gdbserver protocol, and as such can be used | |||
to debug remote targets. | |||
@section Connecting to gdb | |||
@cindex Connecting to gdb | |||
@section Connecting to GDB | |||
@cindex Connecting to GDB | |||
@anchor{Connecting to GDB} | |||
Use GDB 6.7 or newer with OpenOCD if you run into trouble. For | |||
instance 6.3 has a known bug where it produces bogus memory access | |||
errors, which has since been fixed: look up 1836 in | |||
@url{http://sourceware.org/cgi-bin/gnatsweb.pl?database=gdb} | |||
A connection is typically started as follows: | |||
@*OpenOCD can communicate with GDB in two ways: | |||
@enumerate | |||
@item | |||
A socket (tcp) connection is typically started as follows: | |||
@example | |||
target remote localhost:3333 | |||
@end example | |||
This would cause gdb to connect to the gdbserver on the local pc using port 3333. | |||
This would cause GDB to connect to the gdbserver on the local pc using port 3333. | |||
@item | |||
A pipe connection is typically started as follows: | |||
@example | |||
target remote openocd --pipe | |||
@end example | |||
This would cause GDB to run OpenOCD and communicate using pipes (stdin/stdout). | |||
Using this method has the advantage of GDB starting/stopping OpenOCD for debug session. | |||
@end enumerate | |||
To see a list of available OpenOCD commands type @option{monitor help} on the | |||
gdb commandline. | |||
@*To see a list of available OpenOCD commands type @option{monitor help} on the | |||
GDB commandline. | |||
OpenOCD supports the gdb @option{qSupported} packet, this enables information | |||
to be sent by the gdb server (openocd) to gdb. Typical information includes | |||
to be sent by the gdb server (OpenOCD) to GDB. Typical information includes | |||
packet size and device memory map. | |||
Previous versions of OpenOCD required the following gdb options to increase | |||
the packet size and speed up gdb communication. | |||
Previous versions of OpenOCD required the following GDB options to increase | |||
the packet size and speed up GDB communication. | |||
@example | |||
set remote memory-write-packet-size 1024 | |||
set remote memory-write-packet-size fixed | |||
set remote memory-read-packet-size 1024 | |||
set remote memory-read-packet-size fixed | |||
@end example | |||
This is now handled in the @option{qSupported} PacketSize. | |||
This is now handled in the @option{qSupported} PacketSize and should not be required. | |||
@section Programming using gdb | |||
@cindex Programming using gdb | |||
@section Programming using GDB | |||
@cindex Programming using GDB | |||
By default the target memory map is sent to gdb, this can be disabled by | |||
By default the target memory map is sent to GDB, this can be disabled by | |||
the following OpenOCD config option: | |||
@example | |||
gdb_memory_map disable | |||
@@ -2836,34 +2851,34 @@ For this to function correctly a valid flash config must also be configured | |||
in OpenOCD. For faster performance you should also configure a valid | |||
working area. | |||
Informing gdb of the memory map of the target will enable gdb to protect any | |||
Informing GDB of the memory map of the target will enable GDB to protect any | |||
flash area of the target and use hardware breakpoints by default. This means | |||
that the OpenOCD option @option{gdb_breakpoint_override} is not required when | |||
using a memory map. @xref{gdb_breakpoint_override}. | |||
To view the configured memory map in gdb, use the gdb command @option{info mem} | |||
All other unasigned addresses within gdb are treated as RAM. | |||
To view the configured memory map in GDB, use the gdb command @option{info mem} | |||
All other unasigned addresses within GDB are treated as RAM. | |||
GDB 6.8 and higher set any memory area not in the memory map as inaccessible, | |||
this can be changed to the old behaviour by using the following gdb command. | |||
this can be changed to the old behaviour by using the following GDB command. | |||
@example | |||
set mem inaccessible-by-default off | |||
@end example | |||
If @option{gdb_flash_program enable} is also used, gdb will be able to | |||
If @option{gdb_flash_program enable} is also used, GDB will be able to | |||
program any flash memory using the vFlash interface. | |||
gdb will look at the target memory map when a load command is given, if any | |||
GDB will look at the target memory map when a load command is given, if any | |||
areas to be programmed lie within the target flash area the vFlash packets | |||
will be used. | |||
If the target needs configuring before gdb programming, an event | |||
If the target needs configuring before GDB programming, an event | |||
script can be executed. | |||
@example | |||
$_TARGETNAME configure -event EVENTNAME BODY | |||
@end example | |||
To verify any flash programming the gdb command @option{compare-sections} | |||
To verify any flash programming the GDB command @option{compare-sections} | |||
can be used. | |||
@node TCL scripting API | |||
@@ -3598,7 +3613,7 @@ foreach who @{A B C D E@} | |||
OpenOCD comes with a target configuration script library. These scripts can be | |||
used as-is or serve as a starting point. | |||
The target library is published together with the openocd executable and | |||
The target library is published together with the OpenOCD executable and | |||
the path to the target library is in the OpenOCD script search path. | |||
Similarly there are example scripts for configuring the JTAG interface. | |||
@@ -1,4 +1,4 @@ | |||
INCLUDES = -I$(top_srcdir)/src $(all_includes) -I$(top_srcdir)/src/target | |||
INCLUDES = -I$(top_srcdir)/src $(all_includes) -I$(top_srcdir)/src/target -I$(top_srcdir)/src/server | |||
METASOURCES = AUTO | |||
AM_CPPFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" -DPKGLIBDIR=\"$(pkglibdir)\" @CPPFLAGS@ | |||
noinst_LIBRARIES = libhelper.a | |||
@@ -31,6 +31,7 @@ | |||
#include "configuration.h" | |||
#include "time_support.h" | |||
#include "command.h" | |||
#include "server.h" | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
@@ -108,9 +109,11 @@ static void log_puts(enum log_levels level, const char *file, int line, const ch | |||
#endif | |||
string); | |||
} | |||
else | |||
else if(server_use_pipes == 0) | |||
{ | |||
if (strcmp(string, "\n")!=0) | |||
/* if we are using gdb through pipes then we do not want any output | |||
* to the pipe otherwise we get repeated strings */ | |||
if (strcmp(string, "\n") != 0) | |||
{ | |||
/* print human readable output - but skip empty lines */ | |||
fprintf(log_output, "%s%s", | |||
@@ -203,6 +206,18 @@ int handle_debug_level_command(struct command_context_s *cmd_ctx, char *cmd, cha | |||
if (debug_level > 3) | |||
debug_level = 3; | |||
if (debug_level >= LOG_LVL_DEBUG && server_use_pipes == 1) | |||
{ | |||
/* if we are enabling debug info then we need to write to a log file | |||
* otherwise the pipe will get full and cause issues with gdb */ | |||
FILE* file = fopen("openocd.log", "w"); | |||
if (file) | |||
{ | |||
log_output = file; | |||
LOG_WARNING("enabling log output as we are using pipes"); | |||
} | |||
} | |||
return ERROR_OK; | |||
} | |||
@@ -24,10 +24,13 @@ | |||
#include "config.h" | |||
#endif | |||
#include "replacements.h" | |||
#include "types.h" | |||
#include "command.h" | |||
#include "configuration.h" | |||
#include "log.h" | |||
#include "server.h" | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
@@ -43,8 +46,9 @@ static struct option long_options[] = | |||
{"debug", optional_argument, 0, 'd'}, | |||
{"file", required_argument, 0, 'f'}, | |||
{"search", required_argument, 0, 's'}, | |||
{"log_output", required_argument, 0, 'l'}, | |||
{"log_output", required_argument, 0, 'l'}, | |||
{"command", required_argument, 0, 'c'}, | |||
{"pipe", no_argument, 0, 'p'}, | |||
{0, 0, 0, 0} | |||
}; | |||
@@ -95,7 +99,7 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[] | |||
/* getopt_long stores the option index here. */ | |||
int option_index = 0; | |||
c = getopt_long(argc, argv, "hvd::l:f:s:c:", long_options, &option_index); | |||
c = getopt_long(argc, argv, "hvd::l:f:s:c:p", long_options, &option_index); | |||
/* Detect the end of the options. */ | |||
if (c == -1) | |||
@@ -140,7 +144,20 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[] | |||
add_config_command(optarg); | |||
} | |||
break; | |||
case 'p': /* --pipe | -p */ | |||
#if BUILD_ECOSBOARD == 1 | |||
/* pipes unsupported on hosted platforms */ | |||
LOG_WARNING("pipes not supported on this platform"); | |||
#else | |||
#ifdef IS_MINGW | |||
/* pipes currently unsupported on win32 */ | |||
LOG_WARNING("pipes currently unsupported on win32"); | |||
exit(1); | |||
#else | |||
server_use_pipes = 1; | |||
#endif | |||
#endif | |||
break; | |||
} | |||
} | |||
@@ -154,6 +171,7 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[] | |||
LOG_OUTPUT("--debug | -d\tset debug level <0-3>\n"); | |||
LOG_OUTPUT("--log_output | -l\tredirect log output to file <name>\n"); | |||
LOG_OUTPUT("--command | -c\trun <command>\n"); | |||
LOG_OUTPUT("--pipe | -p\tuse pipes for gdb communication\n"); | |||
exit(-1); | |||
} | |||
@@ -161,7 +179,7 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[] | |||
{ | |||
/* Nothing to do, version gets printed automatically. */ | |||
exit(-1); | |||
} | |||
} | |||
return ERROR_OK; | |||
} |
@@ -169,10 +169,18 @@ int gdb_get_char(connection_t *connection, int* next_char) | |||
for (;;) | |||
{ | |||
retval=check_pending(connection, 1, NULL); | |||
if (retval!=ERROR_OK) | |||
return retval; | |||
gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); | |||
if (connection->service->type == CONNECTION_PIPE) | |||
{ | |||
gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); | |||
} | |||
else | |||
{ | |||
retval = check_pending(connection, 1, NULL); | |||
if (retval != ERROR_OK) | |||
return retval; | |||
gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); | |||
} | |||
if (gdb_con->buf_cnt > 0) | |||
{ | |||
break; | |||
@@ -268,10 +276,21 @@ int gdb_write(connection_t *connection, void *data, int len) | |||
gdb_connection_t *gdb_con = connection->priv; | |||
if (gdb_con->closed) | |||
return ERROR_SERVER_REMOTE_CLOSED; | |||
if (write_socket(connection->fd, data, len) == len) | |||
if (connection->service->type == CONNECTION_PIPE) | |||
{ | |||
return ERROR_OK; | |||
/* write to stdout */ | |||
if (write(STDOUT_FILENO, data, len) == len) | |||
{ | |||
return ERROR_OK; | |||
} | |||
} | |||
else | |||
{ | |||
if (write_socket(connection->fd, data, len) == len) | |||
{ | |||
return ERROR_OK; | |||
} | |||
} | |||
gdb_con->closed = 1; | |||
return ERROR_SERVER_REMOTE_CLOSED; | |||
@@ -2158,7 +2177,7 @@ int gdb_input(connection_t *connection) | |||
if (retval == ERROR_SERVER_REMOTE_CLOSED) | |||
return retval; | |||
/* logging does not propagate the error, yet can set th gdb_con->closed flag */ | |||
/* logging does not propagate the error, yet can set the gdb_con->closed flag */ | |||
if (gdb_con->closed) | |||
return ERROR_SERVER_REMOTE_CLOSED; | |||
@@ -2177,34 +2196,37 @@ int gdb_init(void) | |||
return ERROR_OK; | |||
} | |||
if (gdb_port == 0) | |||
if (gdb_port == 0 && server_use_pipes == 0) | |||
{ | |||
LOG_WARNING("no gdb port specified, using default port 3333"); | |||
gdb_port = 3333; | |||
} | |||
while (target) | |||
if (server_use_pipes) | |||
{ | |||
char service_name[8]; | |||
snprintf(service_name, 8, "gdb-%2.2i", target->target_number); | |||
/* only a single gdb connection when using a pipe */ | |||
gdb_service = malloc(sizeof(gdb_service_t)); | |||
gdb_service->target = target; | |||
add_service("gdb", CONNECTION_GDB, | |||
gdb_port + target->target_number, | |||
1, gdb_new_connection, gdb_input, | |||
gdb_connection_closed, | |||
gdb_service); | |||
LOG_DEBUG("gdb service for target %s at port %i", | |||
target->type->name, | |||
gdb_port + target->target_number); | |||
add_service("gdb", CONNECTION_PIPE, 0, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service); | |||
target = target->next; | |||
LOG_DEBUG("gdb service for target %s using pipes", target->type->name); | |||
} | |||
else | |||
{ | |||
while (target) | |||
{ | |||
gdb_service = malloc(sizeof(gdb_service_t)); | |||
gdb_service->target = target; | |||
add_service("gdb", CONNECTION_TCP, gdb_port + target->target_number, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service); | |||
LOG_DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + target->target_number); | |||
target = target->next; | |||
} | |||
} | |||
return ERROR_OK; | |||
} | |||
@@ -53,6 +53,9 @@ service_t *services = NULL; | |||
static int shutdown_openocd = 0; | |||
int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); | |||
/* set when using pipes rather than tcp */ | |||
int server_use_pipes = 0; | |||
int add_connection(service_t *service, command_context_t *cmd_ctx) | |||
{ | |||
unsigned int address_size; | |||
@@ -69,28 +72,44 @@ int add_connection(service_t *service, command_context_t *cmd_ctx) | |||
c->priv = NULL; | |||
c->next = NULL; | |||
address_size = sizeof(c->sin); | |||
c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); | |||
/* This increases performance dramatically for e.g. GDB load which | |||
* does not have a sliding window protocol. */ | |||
retval=setsockopt(c->fd, /* socket affected */ | |||
IPPROTO_TCP, /* set option at TCP level */ | |||
TCP_NODELAY, /* name of option */ | |||
(char *)&flag, /* the cast is historical cruft */ | |||
sizeof(int)); /* length of option value */ | |||
LOG_INFO("accepting '%s' connection from %i", service->name, c->sin.sin_port); | |||
if ((retval = service->new_connection(c)) == ERROR_OK) | |||
if (service->type == CONNECTION_TCP) | |||
{ | |||
address_size = sizeof(c->sin); | |||
c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); | |||
/* This increases performance dramatically for e.g. GDB load which | |||
* does not have a sliding window protocol. */ | |||
retval=setsockopt(c->fd, /* socket affected */ | |||
IPPROTO_TCP, /* set option at TCP level */ | |||
TCP_NODELAY, /* name of option */ | |||
(char *)&flag, /* the cast is historical cruft */ | |||
sizeof(int)); /* length of option value */ | |||
LOG_INFO("accepting '%s' connection from %i", service->name, c->sin.sin_port); | |||
if ((retval = service->new_connection(c)) != ERROR_OK) | |||
{ | |||
close_socket(c->fd); | |||
LOG_ERROR("attempted '%s' connection rejected", service->name); | |||
free(c); | |||
return retval; | |||
} | |||
} | |||
else | |||
else if (service->type == CONNECTION_PIPE) | |||
{ | |||
close_socket(c->fd); | |||
LOG_ERROR("attempted '%s' connection rejected", service->name); | |||
free(c); | |||
return retval; | |||
#ifndef _WIN32 | |||
c->fd = service->fd; | |||
/* do not check for new connections again on stdin */ | |||
service->fd = -1; | |||
#endif | |||
LOG_INFO("accepting '%s' connection from pipe", service->name); | |||
if ((retval = service->new_connection(c)) != ERROR_OK) | |||
{ | |||
LOG_ERROR("attempted '%s' connection rejected", service->name); | |||
free(c); | |||
return retval; | |||
} | |||
} | |||
/* add to the end of linked list */ | |||
@@ -113,7 +132,8 @@ int remove_connection(service_t *service, connection_t *connection) | |||
if (c->fd == connection->fd) | |||
{ | |||
service->connection_closed(c); | |||
close_socket(c->fd); | |||
if (service->type == CONNECTION_TCP) | |||
close_socket(c->fd); | |||
command_done(c->cmd_ctx); | |||
/* delete connection */ | |||
@@ -150,44 +170,67 @@ int add_service(char *name, enum connection_type type, unsigned short port, int | |||
c->priv = priv; | |||
c->next = NULL; | |||
if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) | |||
{ | |||
LOG_ERROR("error creating socket: %s", strerror(errno)); | |||
exit(-1); | |||
} | |||
setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int)); | |||
socket_nonblock(c->fd); | |||
memset(&c->sin, 0, sizeof(c->sin)); | |||
c->sin.sin_family = AF_INET; | |||
c->sin.sin_addr.s_addr = INADDR_ANY; | |||
c->sin.sin_port = htons(port); | |||
if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) | |||
if (type == CONNECTION_TCP) | |||
{ | |||
LOG_ERROR("couldn't bind to socket: %s", strerror(errno)); | |||
exit(-1); | |||
} | |||
if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) | |||
{ | |||
LOG_ERROR("error creating socket: %s", strerror(errno)); | |||
exit(-1); | |||
} | |||
setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int)); | |||
socket_nonblock(c->fd); | |||
memset(&c->sin, 0, sizeof(c->sin)); | |||
c->sin.sin_family = AF_INET; | |||
c->sin.sin_addr.s_addr = INADDR_ANY; | |||
c->sin.sin_port = htons(port); | |||
if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) | |||
{ | |||
LOG_ERROR("couldn't bind to socket: %s", strerror(errno)); | |||
exit(-1); | |||
} | |||
#ifndef _WIN32 | |||
int segsize=65536; | |||
setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int)); | |||
int segsize=65536; | |||
setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int)); | |||
#endif | |||
int window_size = 128 * 1024; | |||
/* These setsockopt()s must happen before the listen() */ | |||
setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF, | |||
(char *)&window_size, sizeof(window_size)); | |||
setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF, | |||
(char *)&window_size, sizeof(window_size)); | |||
int window_size = 128 * 1024; | |||
if (listen(c->fd, 1) == -1) | |||
/* These setsockopt()s must happen before the listen() */ | |||
setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF, | |||
(char *)&window_size, sizeof(window_size)); | |||
setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF, | |||
(char *)&window_size, sizeof(window_size)); | |||
if (listen(c->fd, 1) == -1) | |||
{ | |||
LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); | |||
exit(-1); | |||
} | |||
} | |||
else if (type == CONNECTION_PIPE) | |||
{ | |||
LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); | |||
exit(-1); | |||
/* use stdin */ | |||
c->fd = STDIN_FILENO; | |||
#ifdef _WIN32 | |||
/* for win32 set stdin/stdout to binary mode */ | |||
if (_setmode(_fileno(stdout), _O_BINARY) < 0) | |||
LOG_WARNING("cannot change stdout mode to binary"); | |||
if (_setmode(_fileno(stdin), _O_BINARY) < 0) | |||
LOG_WARNING("cannot change stdin mode to binary"); | |||
#else | |||
socket_nonblock(c->fd); | |||
#endif | |||
} | |||
else | |||
{ | |||
LOG_ERROR("unknown connection type: %d", type); | |||
exit(1); | |||
} | |||
/* add to the end of linked list */ | |||
@@ -310,14 +353,18 @@ int server_loop(command_context_t *command_context) | |||
#ifndef _WIN32 | |||
#if BUILD_ECOSBOARD == 0 | |||
/* add STDIN to read_fds */ | |||
FD_SET(fileno(stdin), &read_fds); | |||
if (server_use_pipes == 0) | |||
{ | |||
/* add STDIN to read_fds */ | |||
FD_SET(fileno(stdin), &read_fds); | |||
} | |||
#endif | |||
#endif | |||
openocd_sleep_prelude(); | |||
kept_alive(); | |||
// Only while we're sleeping we'll let others run | |||
/* Only while we're sleeping we'll let others run */ | |||
retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv); | |||
openocd_sleep_postlude(); | |||
@@ -371,11 +418,14 @@ int server_loop(command_context_t *command_context) | |||
} | |||
else | |||
{ | |||
struct sockaddr_in sin; | |||
unsigned int address_size = sizeof(sin); | |||
int tmp_fd; | |||
tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); | |||
close_socket(tmp_fd); | |||
if (service->type != CONNECTION_PIPE) | |||
{ | |||
struct sockaddr_in sin; | |||
unsigned int address_size = sizeof(sin); | |||
int tmp_fd; | |||
tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); | |||
close_socket(tmp_fd); | |||
} | |||
LOG_INFO("rejected '%s' connection, no more connections allowed", service->name); | |||
} | |||
} | |||
@@ -389,11 +439,16 @@ int server_loop(command_context_t *command_context) | |||
{ | |||
if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) | |||
{ | |||
if (service->input(c) != ERROR_OK) | |||
if ((retval = service->input(c)) != ERROR_OK) | |||
{ | |||
connection_t *next = c->next; | |||
if (service->type == CONNECTION_PIPE) | |||
{ | |||
/* if connection uses a pipe then shutdown openocd on error */ | |||
shutdown_openocd = 1; | |||
} | |||
remove_connection(service, c); | |||
LOG_INFO("dropped '%s' connection", service->name); | |||
LOG_INFO("dropped '%s' connection - error %d", service->name, retval); | |||
c = next; | |||
continue; | |||
} | |||
@@ -405,11 +460,15 @@ int server_loop(command_context_t *command_context) | |||
#ifndef _WIN32 | |||
#if BUILD_ECOSBOARD == 0 | |||
if (FD_ISSET(fileno(stdin), &read_fds)) | |||
/* check for data on stdin if not using pipes */ | |||
if (server_use_pipes == 0) | |||
{ | |||
if (getc(stdin) == 'x') | |||
if (FD_ISSET(fileno(stdin), &read_fds)) | |||
{ | |||
shutdown_openocd = 1; | |||
if (getc(stdin) == 'x') | |||
{ | |||
shutdown_openocd = 1; | |||
} | |||
} | |||
} | |||
#endif | |||
@@ -459,7 +518,6 @@ int server_init(void) | |||
signal(SIGBREAK, sig_handler); | |||
signal(SIGABRT, sig_handler); | |||
#endif | |||
return ERROR_OK; | |||
} | |||
@@ -34,9 +34,8 @@ | |||
enum connection_type | |||
{ | |||
CONNECTION_GDB, | |||
CONNECTION_TELNET, | |||
CONNECTION_TCL, | |||
CONNECTION_TCP, | |||
CONNECTION_PIPE | |||
}; | |||
typedef struct connection_s | |||
@@ -76,6 +75,8 @@ extern int server_quit(void); | |||
extern int server_loop(command_context_t *command_context); | |||
extern int server_register_commands(command_context_t *context); | |||
extern int server_use_pipes; | |||
#define ERROR_SERVER_REMOTE_CLOSED (-400) | |||
#define ERROR_CONNECTION_REJECTED (-401) | |||
@@ -179,7 +179,7 @@ int tcl_init(void) | |||
tcl_port = 6666; | |||
} | |||
retval = add_service("tcl", CONNECTION_TCL, tcl_port, 1, tcl_new_connection, tcl_input, tcl_closed, NULL); | |||
retval = add_service("tcl", CONNECTION_TCP, tcl_port, 1, tcl_new_connection, tcl_input, tcl_closed, NULL); | |||
return retval; | |||
} | |||
@@ -615,7 +615,7 @@ int telnet_init(char *banner) | |||
telnet_service->banner = banner; | |||
add_service("telnet", CONNECTION_TELNET, telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service); | |||
add_service("telnet", CONNECTION_TCP, telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service); | |||
return ERROR_OK; | |||
} | |||
@@ -232,7 +232,6 @@ const Jim_Nvp nvp_target_debug_reason [] = { | |||
{ .name = NULL, .value = -1 }, | |||
}; | |||
const Jim_Nvp nvp_target_endian[] = { | |||
{ .name = "big", .value = TARGET_BIG_ENDIAN }, | |||
{ .name = "little", .value = TARGET_LITTLE_ENDIAN }, | |||
@@ -249,8 +248,7 @@ const Jim_Nvp nvp_reset_modes[] = { | |||
{ .name = NULL , .value = -1 }, | |||
}; | |||
static int | |||
max_target_number( void ) | |||
static int max_target_number(void) | |||
{ | |||
target_t *t; | |||
int x; | |||
@@ -267,8 +265,7 @@ max_target_number( void ) | |||
} | |||
/* determine the number of the new target */ | |||
static int | |||
new_target_number( void ) | |||
static int new_target_number(void) | |||
{ | |||
target_t *t; | |||
int x; | |||