Line 55... |
Line 55... |
using std::setw;
|
using std::setw;
|
|
|
// Define RSP_TRACE to turn on tracing of packets sent and received
|
// Define RSP_TRACE to turn on tracing of packets sent and received
|
// #define RSP_TRACE
|
// #define RSP_TRACE
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Constructor when using a port number
|
//! Constructor when using a port number
|
|
|
//! Calls the generic initializer.
|
//! Calls the generic initializer.
|
|
|
Line 69... |
Line 68... |
{
|
{
|
rspInit (_portNum, DEFAULT_RSP_SERVICE);
|
rspInit (_portNum, DEFAULT_RSP_SERVICE);
|
|
|
} // RspConnection ()
|
} // RspConnection ()
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Constructor when using a service
|
//! Constructor when using a service
|
|
|
//! Calls the generic initializer.
|
//! Calls the generic initializer.
|
|
|
Line 84... |
Line 82... |
{
|
{
|
rspInit (0, _serviceName);
|
rspInit (0, _serviceName);
|
|
|
} // RspConnection ()
|
} // RspConnection ()
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Destructor
|
//! Destructor
|
|
|
//! Close the connection if it is still open
|
//! Close the connection if it is still open
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
Line 96... |
Line 93... |
{
|
{
|
this->rspClose (); // Don't confuse with any other close ()
|
this->rspClose (); // Don't confuse with any other close ()
|
|
|
} // ~RspConnection ()
|
} // ~RspConnection ()
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Generic initialization routine specifying both port number and service
|
//! Generic initialization routine specifying both port number and service
|
//! name.
|
//! name.
|
|
|
//! Private, since this is not intended to be called by users. The service
|
//! Private, since this is not intended to be called by users. The service
|
Line 113... |
Line 109... |
|
|
//! @param[in] _portNum The port number to connect to
|
//! @param[in] _portNum The port number to connect to
|
//! @param[in] _serviceName The service name to use (if PortNum == 0).
|
//! @param[in] _serviceName The service name to use (if PortNum == 0).
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
void
|
void
|
RspConnection::rspInit (int _portNum,
|
RspConnection::rspInit(int _portNum, const char *_serviceName)
|
const char *_serviceName)
|
|
{
|
{
|
portNum = _portNum;
|
portNum = _portNum;
|
serviceName = _serviceName;
|
serviceName = _serviceName;
|
clientFd = -1;
|
clientFd = -1;
|
|
|
} // init ()
|
} // init ()
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Get a new client connection.
|
//! Get a new client connection.
|
|
|
//! Blocks until the client connection is available.
|
//! Blocks until the client connection is available.
|
|
|
Line 146... |
Line 140... |
//! The protocol used for communication is specified in OR1KSIM_RSP_PROTOCOL.
|
//! The protocol used for communication is specified in OR1KSIM_RSP_PROTOCOL.
|
|
|
//! @return TRUE if the connection was established or can be retried. FALSE
|
//! @return TRUE if the connection was established or can be retried. FALSE
|
//! if the error was so serious the program must be aborted.
|
//! if the error was so serious the program must be aborted.
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
bool
|
bool RspConnection::rspConnect()
|
RspConnection::rspConnect ()
|
|
{
|
{
|
// 0 is used as the RSP port number to indicate that we should use the
|
// 0 is used as the RSP port number to indicate that we should use the
|
// service name instead.
|
// service name instead.
|
if (0 == portNum)
|
if (0 == portNum) {
|
{
|
|
struct servent *service = getservbyname (serviceName, "tcp");
|
struct servent *service = getservbyname (serviceName, "tcp");
|
|
|
if (NULL == service)
|
if (NULL == service) {
|
{
|
cerr << "ERROR: RSP unable to find service \"" <<
|
cerr << "ERROR: RSP unable to find service \"" << serviceName
|
serviceName << "\": " << strerror(errno) << endl;
|
<< "\": " << strerror (errno) << endl;
|
|
return false;
|
return false;
|
}
|
}
|
|
|
portNum = ntohs (service->s_port);
|
portNum = ntohs (service->s_port);
|
}
|
}
|
|
|
// Open a socket on which we'll listen for clients
|
// Open a socket on which we'll listen for clients
|
int tmpFd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
int tmpFd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
if (tmpFd < 0)
|
if (tmpFd < 0) {
|
{
|
|
cerr << "ERROR: Cannot open RSP socket" << endl;
|
cerr << "ERROR: Cannot open RSP socket" << endl;
|
return false;
|
return false;
|
}
|
}
|
|
|
// Allow rapid reuse of the port on this socket
|
// Allow rapid reuse of the port on this socket
|
int optval = 1;
|
int optval = 1;
|
setsockopt (tmpFd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval,
|
setsockopt (tmpFd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval,
|
sizeof (optval));
|
sizeof (optval));
|
|
|
|
|
|
|
// Bind the port to the socket
|
// Bind the port to the socket
|
struct sockaddr_in sockAddr;
|
struct sockaddr_in sockAddr;
|
sockAddr.sin_family = PF_INET;
|
sockAddr.sin_family = PF_INET;
|
sockAddr.sin_port = htons (portNum);
|
sockAddr.sin_port = htons (portNum);
|
sockAddr.sin_addr.s_addr = INADDR_ANY;
|
sockAddr.sin_addr.s_addr = INADDR_ANY;
|
|
|
if (bind (tmpFd, (struct sockaddr *) &sockAddr, sizeof (sockAddr)))
|
if (bind(tmpFd, (struct sockaddr *)&sockAddr, sizeof(sockAddr))) {
|
{
|
|
cerr << "ERROR: Cannot bind to RSP socket" << endl;
|
cerr << "ERROR: Cannot bind to RSP socket" << endl;
|
return false;
|
return false;
|
}
|
}
|
|
|
// Listen for (at most one) client
|
// Listen for (at most one) client
|
if (listen (tmpFd, 1))
|
if (listen(tmpFd, 1)) {
|
{
|
|
cerr << "ERROR: Cannot listen on RSP socket" << endl;
|
cerr << "ERROR: Cannot listen on RSP socket" << endl;
|
return false;
|
return false;
|
}
|
}
|
|
|
cout << "Listening for RSP on port " << portNum << endl << flush;
|
cout << "Listening for RSP on port " << portNum << endl << flush;
|
|
|
// Accept a client which connects
|
// Accept a client which connects
|
socklen_t len; // Size of the socket address
|
socklen_t len; // Size of the socket address
|
clientFd = accept (tmpFd, (struct sockaddr *)&sockAddr, &len);
|
clientFd = accept (tmpFd, (struct sockaddr *)&sockAddr, &len);
|
|
|
if (-1 == clientFd)
|
if (-1 == clientFd) {
|
{
|
|
cerr << "Warning: Failed to accept RSP client" << endl;
|
cerr << "Warning: Failed to accept RSP client" << endl;
|
return true; // OK to retry
|
return true; // OK to retry
|
}
|
}
|
|
|
// Enable TCP keep alive process
|
// Enable TCP keep alive process
|
optval = 1;
|
optval = 1;
|
setsockopt (clientFd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval,
|
setsockopt (clientFd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval,
|
sizeof (optval));
|
sizeof (optval));
|
|
|
Line 249... |
Line 230... |
the existing code. No "simulation" of blocking behaviour on the
|
the existing code. No "simulation" of blocking behaviour on the
|
non-blocking socket was required (in the event that a read/write throws
|
non-blocking socket was required (in the event that a read/write throws
|
back a EWOULDBLOCK error, as was looked to be the case in the previous
|
back a EWOULDBLOCK error, as was looked to be the case in the previous
|
GDB handling code) -- Julius
|
GDB handling code) -- Julius
|
*/
|
*/
|
if (ioctl(clientFd, FIONBIO, (char *)&optval) > 0 )
|
if (ioctl(clientFd, FIONBIO, (char *)&optval) > 0) {
|
{
|
|
cerr << "RspConnect: ioctl failed, line "<< __LINE__ << endl;
|
cerr << "RspConnect: ioctl failed, line "<< __LINE__ << endl;
|
close(clientFd);
|
close(clientFd);
|
close(tmpFd);
|
close(tmpFd);
|
return false;
|
return false;
|
}
|
}
|
|
|
// Don't delay small packets, for better interactive response (disable
|
// Don't delay small packets, for better interactive response (disable
|
// Nagel's algorithm)
|
// Nagel's algorithm)
|
optval = 1;
|
optval = 1;
|
setsockopt (clientFd, IPPROTO_TCP, TCP_NODELAY, (char *)&optval,
|
setsockopt (clientFd, IPPROTO_TCP, TCP_NODELAY, (char *)&optval,
|
sizeof (optval));
|
sizeof (optval));
|
Line 273... |
Line 252... |
<< endl;
|
<< endl;
|
return true;
|
return true;
|
|
|
} // rspConnect ()
|
} // rspConnect ()
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Close a client connection if it is open
|
//! Close a client connection if it is open
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
void
|
void RspConnection::rspClose()
|
RspConnection::rspClose ()
|
|
{
|
|
if (isConnected ())
|
|
{
|
{
|
|
if (isConnected()) {
|
cout << "Closing connection" << endl;
|
cout << "Closing connection" << endl;
|
close (clientFd);
|
close (clientFd);
|
clientFd = -1;
|
clientFd = -1;
|
}
|
}
|
} // rspClose ()
|
} // rspClose ()
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Report if we are connected to a client.
|
//! Report if we are connected to a client.
|
|
|
//! @return TRUE if we are connected, FALSE otherwise
|
//! @return TRUE if we are connected, FALSE otherwise
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
bool
|
bool RspConnection::isConnected()
|
RspConnection::isConnected ()
|
|
{
|
{
|
return -1 != clientFd;
|
return -1 != clientFd;
|
|
|
} // isConnected ()
|
} // isConnected ()
|
|
|
Line 309... |
Line 283... |
//! Useful for polling for ETX (0x3) chars being sent when GDB wants to
|
//! Useful for polling for ETX (0x3) chars being sent when GDB wants to
|
//! interrupt
|
//! interrupt
|
|
|
//! @return the char we peeked, 0 otherwise
|
//! @return the char we peeked, 0 otherwise
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
char
|
char RspConnection::rspSocketPeek()
|
RspConnection::rspSocketPeek()
|
|
{
|
{
|
char c;
|
char c;
|
int n;
|
int n;
|
// Using recv here instead of read becuase we can pass the MSG_PEEK
|
// Using recv here instead of read becuase we can pass the MSG_PEEK
|
// flag, which lets us look at what's on the socket, without actually
|
// flag, which lets us look at what's on the socket, without actually
|
Line 359... |
Line 332... |
//! @param[in] pkt The packet for storing the result.
|
//! @param[in] pkt The packet for storing the result.
|
|
|
//! @return TRUE to indicate success, FALSE otherwise (means a communications
|
//! @return TRUE to indicate success, FALSE otherwise (means a communications
|
//! failure)
|
//! failure)
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
bool
|
bool RspConnection::getPkt(RspPacket * pkt)
|
RspConnection::getPkt (RspPacket *pkt)
|
|
{
|
{
|
// Keep getting packets, until one is found with a valid checksum
|
// Keep getting packets, until one is found with a valid checksum
|
while (true)
|
while (true) {
|
{
|
|
int bufSize = pkt->getBufSize ();
|
int bufSize = pkt->getBufSize ();
|
unsigned char checksum; // The checksum we have computed
|
unsigned char checksum; // The checksum we have computed
|
int count; // Index into the buffer
|
int count; // Index into the buffer
|
int ch; // Current character
|
int ch; // Current character
|
|
|
|
|
// Wait around for the start character ('$'). Ignore all other
|
// Wait around for the start character ('$'). Ignore all other
|
// characters
|
// characters
|
ch = getRspChar ();
|
ch = getRspChar ();
|
while (ch != '$')
|
while (ch != '$') {
|
{
|
if (-1 == ch) {
|
if (-1 == ch)
|
|
{
|
|
return false; // Connection failed
|
return false; // Connection failed
|
}
|
} else {
|
else
|
|
{
|
|
ch = getRspChar ();
|
ch = getRspChar ();
|
}
|
}
|
}
|
}
|
|
|
// Read until a '#' or end of buffer is found
|
// Read until a '#' or end of buffer is found
|
checksum = 0;
|
checksum = 0;
|
count = 0;
|
count = 0;
|
while (count < bufSize - 1)
|
while (count < bufSize - 1) {
|
{
|
|
ch = getRspChar ();
|
ch = getRspChar ();
|
|
|
if (-1 == ch)
|
if (-1 == ch) {
|
{
|
|
return false; // Connection failed
|
return false; // Connection failed
|
}
|
}
|
|
|
// If we hit a start of line char begin all over again
|
// If we hit a start of line char begin all over again
|
if ('$' == ch)
|
if ('$' == ch) {
|
{
|
|
checksum = 0;
|
checksum = 0;
|
count = 0;
|
count = 0;
|
|
|
continue;
|
continue;
|
}
|
}
|
|
|
// Break out if we get the end of line char
|
// Break out if we get the end of line char
|
if ('#' == ch)
|
if ('#' == ch) {
|
{
|
|
break;
|
break;
|
}
|
}
|
|
|
// Update the checksum and add the char to the buffer
|
// Update the checksum and add the char to the buffer
|
checksum = checksum + (unsigned char)ch;
|
checksum = checksum + (unsigned char)ch;
|
pkt->data[count] = (char)ch;
|
pkt->data[count] = (char)ch;
|
count++;
|
count++;
|
}
|
}
|
Line 426... |
Line 385... |
pkt->data[count] = 0;
|
pkt->data[count] = 0;
|
pkt->setLen (count);
|
pkt->setLen (count);
|
|
|
// If we have a valid end of packet char, validate the checksum. If we
|
// If we have a valid end of packet char, validate the checksum. If we
|
// don't it's because we ran out of buffer in the previous loop.
|
// don't it's because we ran out of buffer in the previous loop.
|
if ('#' == ch)
|
if ('#' == ch) {
|
{
|
|
unsigned char xmitcsum; // The checksum in the packet
|
unsigned char xmitcsum; // The checksum in the packet
|
|
|
ch = getRspChar ();
|
ch = getRspChar ();
|
if (-1 == ch)
|
if (-1 == ch) {
|
{
|
|
return false; // Connection failed
|
return false; // Connection failed
|
}
|
}
|
xmitcsum = Utils::char2Hex (ch) << 4;
|
xmitcsum = Utils::char2Hex (ch) << 4;
|
|
|
ch = getRspChar ();
|
ch = getRspChar ();
|
if (-1 == ch)
|
if (-1 == ch) {
|
{
|
|
return false; // Connection failed
|
return false; // Connection failed
|
}
|
}
|
|
|
xmitcsum += Utils::char2Hex (ch);
|
xmitcsum += Utils::char2Hex (ch);
|
|
|
// If the checksums don't match print a warning, and put the
|
// If the checksums don't match print a warning, and put the
|
// negative ack back to the client. Otherwise put a positive ack.
|
// negative ack back to the client. Otherwise put a positive ack.
|
if (checksum != xmitcsum)
|
if (checksum != xmitcsum) {
|
{
|
|
cerr << "Warning: Bad RSP checksum: Computed 0x"
|
cerr << "Warning: Bad RSP checksum: Computed 0x"
|
<< setw (2) << setfill ('0') << hex
|
<< setw (2) << setfill ('0') << hex
|
<< checksum << ", received 0x" << xmitcsum
|
<< checksum << ", received 0x" << xmitcsum
|
<< setfill (' ') << dec << endl;
|
<< setfill (' ') << dec << endl;
|
if (!putRspChar ('-')) // Failed checksum
|
if (!putRspChar ('-')) // Failed checksum
|
{
|
{
|
return false; // Comms failure
|
return false; // Comms failure
|
}
|
}
|
}
|
} else {
|
else
|
|
{
|
|
if (!putRspChar ('+')) // successful transfer
|
if (!putRspChar ('+')) // successful transfer
|
{
|
{
|
return false; // Comms failure
|
return false; // Comms failure
|
}
|
} else {
|
else
|
|
{
|
|
#ifdef RSP_TRACE
|
#ifdef RSP_TRACE
|
cout << "getPkt: " << *pkt << endl;
|
cout << "getPkt: " << *pkt << endl;
|
#endif
|
#endif
|
return true; // Success
|
return true; // Success
|
}
|
}
|
}
|
}
|
}
|
} else {
|
else
|
|
{
|
|
cerr << "Warning: RSP packet overran buffer" << endl;
|
cerr << "Warning: RSP packet overran buffer" << endl;
|
}
|
}
|
}
|
}
|
|
|
} // getPkt ()
|
} // getPkt ()
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Put the packet out on the RSP connection
|
//! Put the packet out on the RSP connection
|
|
|
//! Modeled on the stub version supplied with GDB. Put out the data preceded
|
//! Modeled on the stub version supplied with GDB. Put out the data preceded
|
//! by a '$', followed by a '#' and a one byte checksum. '$', '#', '*' and '}'
|
//! by a '$', followed by a '#' and a one byte checksum. '$', '#', '*' and '}'
|
Line 498... |
Line 446... |
//! @param[in] pkt The Packet to transmit
|
//! @param[in] pkt The Packet to transmit
|
|
|
//! @return TRUE to indicate success, FALSE otherwise (means a communications
|
//! @return TRUE to indicate success, FALSE otherwise (means a communications
|
//! failure).
|
//! failure).
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
bool
|
bool RspConnection::putPkt(RspPacket * pkt)
|
RspConnection::putPkt (RspPacket *pkt)
|
|
{
|
{
|
int len = pkt->getLen ();
|
int len = pkt->getLen ();
|
int ch; // Ack char
|
int ch; // Ack char
|
|
|
// Construct $<packet info>#<checksum>. Repeat until the GDB client
|
// Construct $<packet info>#<checksum>. Repeat until the GDB client
|
// acknowledges satisfactory receipt.
|
// acknowledges satisfactory receipt.
|
do
|
do {
|
{
|
|
unsigned char checksum = 0; // Computed checksum
|
unsigned char checksum = 0; // Computed checksum
|
int count = 0; // Index into the buffer
|
int count = 0; // Index into the buffer
|
|
|
if (!putRspChar ('$')) // Start char
|
if (!putRspChar ('$')) // Start char
|
{
|
{
|
return false; // Comms failure
|
return false; // Comms failure
|
}
|
}
|
|
|
|
|
// Body of the packet
|
// Body of the packet
|
for (count = 0; count < len; count++)
|
for (count = 0; count < len; count++) {
|
{
|
|
unsigned char ch = pkt->data[count];
|
unsigned char ch = pkt->data[count];
|
|
|
// Check for escaped chars
|
// Check for escaped chars
|
if (('$' == ch) || ('#' == ch) || ('*' == ch) || ('}' == ch))
|
if (('$' == ch) || ('#' == ch) || ('*' == ch)
|
{
|
|| ('}' == ch)) {
|
ch ^= 0x20;
|
ch ^= 0x20;
|
checksum += (unsigned char)'}';
|
checksum += (unsigned char)'}';
|
if (!putRspChar ('}'))
|
if (!putRspChar('}')) {
|
{
|
|
return false; // Comms failure
|
return false; // Comms failure
|
}
|
}
|
|
|
}
|
}
|
|
|
checksum += ch;
|
checksum += ch;
|
if (!putRspChar (ch))
|
if (!putRspChar(ch)) {
|
{
|
|
return false; // Comms failure
|
return false; // Comms failure
|
}
|
}
|
}
|
}
|
|
|
if (!putRspChar ('#')) // End char
|
if (!putRspChar ('#')) // End char
|
{
|
{
|
return false; // Comms failure
|
return false; // Comms failure
|
}
|
}
|
|
|
// Computed checksum
|
// Computed checksum
|
if (!putRspChar (Utils::hex2Char (checksum >> 4)))
|
if (!putRspChar(Utils::hex2Char(checksum >> 4))) {
|
{
|
|
return false; // Comms failure
|
return false; // Comms failure
|
}
|
}
|
if (!putRspChar (Utils::hex2Char (checksum % 16)))
|
if (!putRspChar(Utils::hex2Char(checksum % 16))) {
|
{
|
|
return false; // Comms failure
|
return false; // Comms failure
|
}
|
}
|
|
|
// Check for ack of connection failure
|
// Check for ack of connection failure
|
ch = getRspChar ();
|
ch = getRspChar ();
|
if (-1 == ch)
|
if (-1 == ch) {
|
{
|
|
return false; // Comms failure
|
return false; // Comms failure
|
}
|
}
|
}
|
}
|
while ('+' != ch);
|
while ('+' != ch);
|
|
|
Line 572... |
Line 508... |
#endif
|
#endif
|
return true;
|
return true;
|
|
|
} // putPkt ()
|
} // putPkt ()
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Put a single character out on the RSP connection
|
//! Put a single character out on the RSP connection
|
|
|
//! Utility routine. This should only be called if the client is open, but we
|
//! Utility routine. This should only be called if the client is open, but we
|
//! check for safety.
|
//! check for safety.
|
|
|
//! @param[in] c The character to put out
|
//! @param[in] c The character to put out
|
|
|
//! @return TRUE if char sent OK, FALSE if not (communications failure)
|
//! @return TRUE if char sent OK, FALSE if not (communications failure)
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
bool
|
bool RspConnection::putRspChar(char c)
|
RspConnection::putRspChar (char c)
|
|
{
|
|
if (-1 == clientFd)
|
|
{
|
{
|
|
if (-1 == clientFd) {
|
cerr << "Warning: Attempt to write '" << c
|
cerr << "Warning: Attempt to write '" << c
|
<< "' to unopened RSP client: Ignored" << endl;
|
<< "' to unopened RSP client: Ignored" << endl;
|
return false;
|
return false;
|
}
|
}
|
|
|
// Write until successful (we retry after interrupts) or catastrophic
|
// Write until successful (we retry after interrupts) or catastrophic
|
// failure.
|
// failure.
|
while (true)
|
while (true) {
|
{
|
switch (write(clientFd, &c, sizeof(c))) {
|
switch (write (clientFd, &c, sizeof (c)))
|
|
{
|
|
case -1:
|
case -1:
|
// Error: only allow interrupts or would block
|
// Error: only allow interrupts or would block
|
if ((EAGAIN != errno) && (EINTR != errno))
|
if ((EAGAIN != errno) && (EINTR != errno)) {
|
{
|
cerr <<
|
cerr << "Warning: Failed to write to RSP client: "
|
"Warning: Failed to write to RSP client: "
|
<< "Closing client connection: "
|
<< "Closing client connection: " <<
|
<< strerror (errno) << endl;
|
strerror(errno) << endl;
|
return false;
|
return false;
|
}
|
}
|
|
|
break;
|
break;
|
|
|
Line 620... |
Line 550... |
return true; // Success, we can return
|
return true; // Success, we can return
|
}
|
}
|
}
|
}
|
} // putRspChar ()
|
} // putRspChar ()
|
|
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
//! Get a single character from the RSP connection
|
//! Get a single character from the RSP connection
|
|
|
//! Utility routine. This should only be called if the client is open, but we
|
//! Utility routine. This should only be called if the client is open, but we
|
//! check for safety.
|
//! check for safety.
|
|
|
//! @return The character received or -1 on failure
|
//! @return The character received or -1 on failure
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
int
|
int RspConnection::getRspChar()
|
RspConnection::getRspChar ()
|
|
{
|
|
if (-1 == clientFd)
|
|
{
|
{
|
|
if (-1 == clientFd) {
|
cerr << "Warning: Attempt to read from "
|
cerr << "Warning: Attempt to read from "
|
<< "unopened RSP client: Ignored" << endl;
|
<< "unopened RSP client: Ignored" << endl;
|
return -1;
|
return -1;
|
}
|
}
|
|
|
// Blocking read until successful (we retry after interrupts) or
|
// Blocking read until successful (we retry after interrupts) or
|
// catastrophic failure.
|
// catastrophic failure.
|
while (true)
|
while (true) {
|
{
|
|
unsigned char c;
|
unsigned char c;
|
|
|
switch (read (clientFd, &c, sizeof (c)))
|
switch (read(clientFd, &c, sizeof(c))) {
|
{
|
|
case -1:
|
case -1:
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
continue;
|
continue;
|
// Error: only allow interrupts
|
// Error: only allow interrupts
|
if (EINTR != errno)
|
if (EINTR != errno) {
|
{
|
cerr <<
|
cerr << "Warning: Failed to read from RSP client: "
|
"Warning: Failed to read from RSP client: "
|
<< "Closing client connection: "
|
<< "Closing client connection: " <<
|
<< strerror (errno) << endl;
|
strerror(errno) << endl;
|
return -1;
|
return -1;
|
}
|
}
|
break;
|
break;
|
|
|
case 0:
|
case 0:
|