libssh - send request multiple times and read answer from channel - c++

I have created one session and one channel. A request (ssh_channel_request_exec) is supposed to be sent about every second and I want to read the answer (ssh_channel_read) to this request. However, I could not find an example on how to make multiple requests, the api only contains an example on how to make a request, read the answer and close the channel.
When I try requesting and reading from the channel twice in sequence, ssh_channel_request_exec returns an error the second time. Is it necessary to open a new channel for each request?
int ret = ssh_channel_request_exec(m_channel, request.c_str());
if (ret != SSH_OK)
{
ssh_channel_close(m_channel);
ssh_channel_free(m_channel);
return false;
}
std::stringstream sstream;
nbytes = ssh_channel_read(m_channel, buffer, sizeof(buffer), 0);
while (nbytes > 0)
{
sstream.write(buffer, nbytes);
nbytes = ssh_channel_read(m_channel, buffer, sizeof(buffer), 0);
}
if (nbytes < 0) // 'nbytes' becomes zero the first time, the channel is not closed the second time!
{
ssh_channel_close(m_channel);
ssh_channel_free(m_channel);
return false;
}
response = sstream.str();
The api also contains a ssh_channel_send_eof function that is used after reading from the channel in an example. What is good for? The api only says "Send an end of file on the channel. This doesn't close the channel. You may still read from it but not write."
A check for ssh_channel_is_eof (api: "Check if remote has sent an EOF") shows that the channel is not eof the first time, but the second time it is.

Yes. Non-interactive exec is intended for a single command to be executed and therefore you can run only on in single channel, as visible in the official documentation.

Related

How to stop a C++ blocking read call

I'm reading CAN-BUS traffic under SocketCAN and C++ in GNU/Linux. I've found that the read call is blocking, and I'm struggling to figure out how to stop my program properly when I don't want to keep reading.
Of course, I could hit Ctrl+C if I've invoked the program from the terminal, but the point is to find a way to do it programmatically when some condition is met (e.g., record for 5 seconds, or when some event happens, like a flag is raised). A timeout could work, or something like a signal, but I don't know how to do it properly.
// Read (blocking)
nbytes = read(s, &frame, sizeof(struct can_frame));
You don't.
Use a method like select or epoll to determine whether the socket has activity before beginning the read. Then it will not actually block.
The select/epoll call is itself blocking, but can be given a timeout so that you always have an escape route (or, in the case of epoll, the lovely epollfd for immediate triggering of a breakout).
Read is always blocking... you want to only read if data is waiting... so consider doing a poll on the socket first to see if data is available and if so THEN read it. You can loop over doing the poll until you no longer want to read anymore...
bool pollIn(int fd)
{
bool returnValue{false};
struct pollfd *pfd;
pfd = calloc(1, sizeof(struct pollfd));
pfd.fd = fd;
pfd.events = POLLIN;
int pollReturn{-1};
pollReturn = poll(pfd, 1, 0);
if (pollReturn > 0)
{
if (pfd.revents & POLLIN)
{
returnValue = true;
}
}
free(pfd);
return(returnValue);
}
The above should return if there is data waiting at the socket file descriptor.
while(!exitCondition)
{
if(pollIn(fd))
{
nbytes = read(fd, &frame, sizeof(struct can_frame));
// other stuff you need to do with your read
}
}

Winsock 2, condensing variables into a string, sending it out, then recieving it and reading it back

I am writing some code that involves using an inertia cube tracker, that actively changes its yaw pitch and roll (in degrees) and I need to set up a server that reads that information in order to network the info. So far I have created a client and server, but the problem I am having is either to send the information in one chunck then read it back as three and print it, or to specify which send matches with which recieve.
if( currentTrackerH > 0 )
{
int iSendResult1;
int iSendResult2;
int iSendResult3;
char EulerBuffer0[64];
char EulerBuffer1[64];
char EulerBuffer2[64];
showStationData( currentTrackerH, &TrackerInfo,
&Stations[station-1], &data.Station[station-1],
&StationsHwInfo[currentTrackerH-1][station-1],
showTemp);
//send to the server
do{
sprintf(EulerBuffer0, "%f", data.Station[station-1].Euler[0]);
iSendResult1= send(Connection, EulerBuffer0, sizeof(data.Station[station-1].Euler[0]), NULL);
sprintf(EulerBuffer1, "%f", data.Station[station-1].Euler[1]);
iSendResult2= send(Connection, EulerBuffer1, sizeof(data.Station[station-1].Euler[1]), NULL);
sprintf(EulerBuffer2, "%f", data.Station[station-1].Euler[2]);
iSendResult3= send(Connection, EulerBuffer2, sizeof(data.Station[station-1].Euler[2]), NULL);
}while ((iSendResult1 || iSendResult2 || iSendResult3)>0);
//shutdown the socket when there is no more data to send
iSendResult1 = shutdown(Connection, SD_SEND);
if (iSendResult1 == SOCKET_ERROR)
{
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(Connection);
WSACleanup();
return 1;
}
}
}
This is my client side and here I will put my server side. The networks connect and my tracker code works just fine but sending and recieving is where it all gets wonky.
//begin recieving data
char yaw[256];
char pitch[256];
char roll[256];
int iResult1;
int iResult2;
int iResult3;
float fyaw, fpitch, froll;
do{
do {
iResult1= recv(newConnection, yaw,sizeof(yaw),NULL);
} while( iResult1 == 0 );
fyaw = atof(yaw);
do {
iResult2= recv(newConnection, pitch,sizeof(pitch),NULL);
} while( iResult1 == 0 );
fpitch = atof(pitch);
do {
iResult3= recv(newConnection, roll,sizeof(roll),NULL);
} while( iResult1 == 0 );
froll = atof(roll);
printf("(%f,%f,%f)deg \n",
fyaw, fpitch, froll);
}while(1);
my knowledge of c++ is not fantastic and any help would be lovely. Thanks!
There is all kinds of wrong in your code. Let's try to break down and correct misconceptions (I assume you're using TCP.) You are sending buffers of one size, but recv'ing potentially a buffer of another size. sizeof(yaw) which is a float, is not the same as the size of the string representation of this float.
Calling send/recv for individual item is slow. Ideally you would define a simple protocol. A message in this protocol would be a string containing all the values you wish to transmit. You send that message using a single send() On the receiving side you read in the stream of data, and look for specific markers that tell you when you have received a complete message. You then process that message, splitting out the different components into your yaw/pitch/roll variables.
An example of a string message would be: "{yaw=1.34;pitch=2.45;roll=5.67}"
Then on the client you continually read into a buffer your data until you reach the "}" Then you can process this message and parse out the different components.

Socket Write Failure when sending File

I've been stuck on this issue for awhile where I'm unable to send a file through a socket. I've sent other information just fine using this method, but the problem seems to appear when I try to send a PNG file as a string.
These are the methods I use to to send and receive information:
// Sends a Message to the specified Socket
void Server::sendMessage(int socket, string message)
{
// Write the Message Size to the Socket
send(socket, itoa((message.length() + 1)), sizeof(size_t));
// Wait for Write Confirmation
bool response;
receive(socket, &response, 2);
// Write the Message to the Socket
send(socket, (char*) message.c_str(), message.length() + 1);
// Wait for Write Confirmation
receive(socket, &response, 2);
}
// Receives Message from the specified Socket
string Server::receiveMessage(int socket)
{
// Read the Message Size from the Socket
int size;
receive(socket, &size, sizeof(size_t));
// Send Write Confirmation
send(socket, itoa(true), 2);
// Receive the Message from the Socket
char message[size];
receive(socket, message, size);
// Send Write Confirmation
send(socket, itoa(true), 2);
// Return the Message as a String
string msg(message);
return msg;
}
The send and receive methods are just relays for write and read respectively. I'm only doing error checking in those methods, and it's the send method that's telling me that the write isn't working. In case it matters, this is my send method:
// Sends a Data Packet to the specified Socket
int Server::send(int socket, void* data, int size)
{
// Write the Data to the Socket
int count = write(socket, data, size);
// Make sure the Write Succeeded
if(count == -1)
{
print("$f1Error: $f0Unable to Write to Socket $t1%i$t0\n", socket);
exit(1);
}
return count;
}
I should note that the Server operates as a Thread, therefore the above three functions are static. The Client also contains the same four networking functions.
The command line breaking this happens in a separate static function which I use to handle Clients. Here is the relevant portion of said method:
// Handles each Client with a Thread
void* Server::server_handleClient(void* arg)
{
// Determine the Socket Descriptor
int socket = *((int*) arg);
free(arg);
// Create the Rover
Rover* rover = new Rover();
// Loop Indefinitely
while(true)
{
...
// Take a Picture and Send it
sendMessage(socket, rover -> takePicture());
...
}
// Delete the Rover
delete rover;
// Close the Socket
close(socket);
// Return a Successful Status
return (void*) new int(0);
}
Here you can see that I make use of a method from another class I've created. Here is the takePicture method from the Rover class, which is where I actually grab the picture:
// Takes a Picture and Returns the Photo as a String
inline string Rover::takePicture()
{
// Open the Picture File
ifstream picture;
string filepath = "./Server/Pictures/" + getDirection() + ".png";
picture.open(filepath.c_str());
// Make sure the File Opened
if(!picture.is_open())
return "";
// Read the File into a String Buffer
stringstream buffer;
buffer << picture.rdbuf();
return buffer.str();
}
So in short, the Server gets a picture from the Rover which it then sends to a Client. When I check the contents of the string for the photo, it's all there. All possible photos are reasonable in size (the photo used for testing is 674,962 bytes, and the buffer size sent is 674,963 which is expected).
I've used these methods for sending various messages, and all of that worked fine. I'm able to send strings (Like "Hello World!") and integers just fine.
Is there something that I'm doing wrong? Is the file that I'm trying to send simply too large? Is there some information that I'm missing? I need help...
Edit:
I've made a few changes with a little progress. I made one small change to the sendMessage command. The current problem is that the picture isn't being sent properly.
New sendMessage function:
// Sends a Message to the specified Socket
void Server::sendMessage(int socket, string message, bool data = false)
{
// Write the Message Size to the Socket
send(socket, itoa((message.length() + 1)), sizeof(size_t));
// Wait for Write Confirmation
bool response;
receive(socket, &response, 2);
// Determine the Type of Data to Send
if(data)
{
// Write the Message Data to the Socket
send(socket, (char*) message.data(), message.length() + 1);
}
else
{
// Write the Message to the Socket
send(socket, (char*) message.c_str(), message.length() + 1);
}
// Wait for Write Confirmation
receive(socket, &response, 2);
}
The Client's copy of this function has been updated to match as well.
Now that we're working on getting the PNG file saved, here's the function that deals with that as well:
// Handles each Client with a Thread
void* Client::client_handleServer(void* arg)
{
// Define Socket Variables
int socket = *((int*) arg);
free(arg);
...
// Export the Picture to the Client's Directory
message = receiveMessage(socket);
ofstream picture;
picture.open("./Client/Pictures/Picture.png", std::ifstream::binary);
picture << message;
picture.close();
...
}
Currently you are opening the file in textmode. that means any characters in the files which contain newlines "\n" are converted to new line + carriage returns "\r\n".
Open your file in binary mode, like so
picture.open(filepath.c_str(), std::ifstream::binary);
then it may work.
void Server::sendMessage(int socket, string message)
The problem is right here. Don't use string as a container for binary data. Pass the image around as a byte array. Same applies to this:
string Server::receiveMessage(int socket)
I eventually figured everything out in the long run.
Pictures are binary files, and I was using Strings which use ASCII Characters. The issue with this is that binary data does not always translate to ASCII, and Strings are terminated by null characters, whereas binary data can contain null data within it. Long story short, strings do not work.
To preserve the message handling I had in place, I ended up just converting the binary data to hexadecimal data (0-F) which could be displayed in a String.

Berkeley Socket Send returning 0 on successful non-blocking send

I am writing a non-blocking chat server, so far the server works fine, but I can't figure out how to correct for partial sends if they happen. The send(int, char*, int); function always returns 0 on a success and -1 on a failed send. Every doc/man page I have read says it should return the number of bytes actually feed to the network buffer. I have checked to be sure that I can send to the server and recv back the data repeatedly without problem.
This is the function I use to call the send. I both tried to print the return data to the console first, then tried line breaking on the return ReturnValue; while debugging. Same result, ReturnValue is always 0 or -1;
int Connection::Transmit(string MessageToSend)
{
// check for send attempts on a closed socket
// return if it happens.
if(this->Socket_Filedescriptor == -1)
return -1;
// Send a message to the client on the other end
// note, the last parameter is a flag bit which
// is used for declaring out of bound data transmissions.
ReturnValue = send(Socket_Filedescriptor,
MessageToSend.c_str(),
MessageToSend.length(),
0);
return ReturnValue;
}
Why don't you try to send in a loop? For instance:
int Connection::Transmit(string MessageToSend)
{
// check for send attempts on a closed socket
// return if it happens.
if(this->Socket_Filedescriptor == -1)
return -1;
int expected = MessageToSend.length();
int sent = 0;
// Send a message to the client on the other end
// note, the last parameter is a flag bit which
// is used for declaring out of bound data transmissions.
while(sent < expected) {
ReturnValue = send(Socket_Filedescriptor,
MessageToSend.c_str() + sent, // Send from correct location
MessageToSend.length() - sent, // Update how much remains
0);
if(ReturnValue == -1)
return -1; // Error occurred
sent += ReturnValue;
}
return sent;
}
This way your code will continually try to send all the data until either an error occurs, or all data is sent successfully.

Losing characters in TCP Telnet transmission

I'm using Winsock to send commands through Telnet ; but for some reason when I try to send a string, a few characters get dropped occasionally. I use send:
int SendData(const string & text)
{
send(hSocket,text.c_str(),static_cast<int>(text.size()),0);
Sleep(100);
send(hSocket,"\r",1,0);
Sleep(100);
return 0;
}
Any suggestions?
Update:
I checked and the error still occurs even if all the characters are sent. So I decided to change the Send function so that it sends individual characters and checks if they have been sent:
void SafeSend(const string &text)
{
char char_text[1];
for(size_t i = 0; i <text.size(); ++i)
{
char_text[0] = text[i];
while(send(hSocket,char_text,1,0) != 1);
}
}
Also, it drops characters in a peculiar way ; i.e. in the middle of the sentence. E.g.
set variable [fp]exit_flag = true
is sent as
ariable [fp]exit_flag = true
Or
set variable [fp]app_flag = true
is sent as
setrable [fp]app_flag = true
As mentioned in the comments you absolutely need to check the return value of send as it can return after sending only a part of your buffer.
You nearly always want to call send in a loop similar to the following (not tested as I don't have a Windows development environment available at the moment):
bool SendString(const std::string& text) {
int remaining = text.length();
const char* buf = text.data();
while (remaining > 0) {
int sent = send(hSocket, buf, remaining, 0);
if (sent == SOCKET_ERROR) {
/* Error occurred check WSAGetLastError() */
return false;
}
remaining -= sent;
buf += sent;
}
return true;
}
Update:
This is not relevant for the OP, but calls to recv should also structured in the same way as above.
To debug the problem further, Wireshark (or equivalent software) is excellent in tracking down the source of the problem.
Filter the packets you want to look at (it has lots of options) and check if they include what you think they include.
Also note that telnet is a protocol with numerous RFCs. Most of the time you can get away with just sending raw text, but it's not really guaranteed to work.
You mention that the windows telnet client sends different bytes from you, capture a minimal sequence from both clients and compare them. Use the RFCs to figure out what the other client does different and why. You can use "View -> Packet Bytes" to bring up the data of the packet and can easily inspect and copy/paste the hex dump.