How can i print a variable from another function? - c

I try to make a ssh remote command with a part of code founded in libssh examples and i try to print output outside executing function like this
in int main();
printf("Server output: %s", nbytes);
int exec_uname(ssh_session session) {
ssh_channel channel;
int rc;
channel = ssh_channel_new(session);
if (channel == NULL) return SSH_ERROR;
rc = ssh_channel_open_session(channel);
if (rc != SSH_OK) {
ssh_channel_free(channel);
return rc;
}
//Once a session is open, you can start the remote command with ssh_channel_request_exec():
rc = ssh_channel_request_exec(channel, "uname -a");
if (rc != SSH_OK) {
ssh_channel_close(channel);
ssh_channel_free(channel);
return rc;
}
//If the remote command displays data, you get them with ssh_channel_read(). This function returns the number of bytes read. If there is no more data to read on the channel, this function returns 0, and you can go to next step. If an error has been encountered, it returns a negative value:
char buffer[256];
int nbytes;
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
while (nbytes > 0) {
if (fwrite(buffer, 1, nbytes, stdout) != nbytes) {
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
}
if (nbytes < 0) {
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
//Once you read the result of the remote command, you send an end-of-file to the channel, close it, and free the memory that it used:
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_OK;
}

You can't access a local variable outside a function. You either declare that in a broader scope, like global, which is a last-resort, or pass it in to be populated.
For example:
int exec_uname(ssh_session session, int* bytes) {
// ... code
// Push back to caller
*bytes = nbytes;
}
So when called:
int nbytes;
int result = exec_uname(session, &nbytes);
printf("Server output: %d", nbytes);
You'll still need to check result to be sure the function terminated properly or the value in nbytes will not be usable.

Related

Changing STDOUT to file in ncat source code

I managed to compile ncat. I am using -k option to keep server open. Instead of accepting data to STDOUT, my goal is to write to files instead. So far I was able to write to a file instead of STDOUT but my goal is to loop through new files on each new connection. Right now it is appending to the same filename_0 and f++ is not incrementing. Here is what I have so far. The original code will be below. The difference is in the else clause, basically if n is actually greater than 0. On each loop, n is 512 bytes until the last chunk. I just want to be able to have new files from each new connection. filename_0, filename_1, filename_3, etc.
MODIFIED CODE:
/* Read from a client socket and write to stdout. Return the number of bytes
read from the socket, or -1 on error. */
int read_socket(int recv_fd)
{
char buf[DEFAULT_TCP_BUF_LEN];
struct fdinfo *fdn;
int nbytes, pending;
int f = 0;
fdn = get_fdinfo(&client_fdlist, recv_fd);
ncat_assert(fdn != NULL);
nbytes = 0;
do {
int n, s;
n = ncat_recv(fdn, buf, 512, &pending);
if (n <= 0) {
if (o.debug)
logdebug("Closing fd %d.\n", recv_fd);
#ifdef HAVE_OPENSSL
if (o.ssl && fdn->ssl) {
if (nbytes == 0)
SSL_shutdown(fdn->ssl);
SSL_free(fdn->ssl);
}
#endif
close(recv_fd);
checked_fd_clr(recv_fd, &master_readfds);
rm_fd(&client_fdlist, recv_fd);
checked_fd_clr(recv_fd, &master_broadcastfds);
rm_fd(&broadcast_fdlist, recv_fd);
conn_inc--;
if (get_conn_count() == 0)
checked_fd_clr(STDIN_FILENO, &master_readfds);
return n;
}
else {
char filename[20];
snprintf(filename, sizeof(char) * 20, "filename_%i", f);
FILE *fp = fopen(filename, "a");
if (fp == NULL)
{
printf("Could not open file");
return 0;
}
//Write(STDOUT_FILENO, buf, n);
s = fwrite(buf, 1, n, fp);
fclose(fp);
f++;
nbytes += n;
}
} while (pending);
return nbytes;
}
ORIGINAL CODE:
int read_socket(int recv_fd)
{
char buf[DEFAULT_TCP_BUF_LEN];
struct fdinfo *fdn;
int nbytes, pending;
fdn = get_fdinfo(&client_fdlist, recv_fd);
ncat_assert(fdn != NULL);
nbytes = 0;
do {
int n;
n = ncat_recv(fdn, buf, sizeof(buf), &pending);
if (n <= 0) {
if (o.debug)
logdebug("Closing fd %d.\n", recv_fd);
#ifdef HAVE_OPENSSL
if (o.ssl && fdn->ssl) {
if (nbytes == 0)
SSL_shutdown(fdn->ssl);
SSL_free(fdn->ssl);
}
#endif
close(recv_fd);
checked_fd_clr(recv_fd, &master_readfds);
rm_fd(&client_fdlist, recv_fd);
checked_fd_clr(recv_fd, &master_broadcastfds);
rm_fd(&broadcast_fdlist, recv_fd);
conn_inc--;
if (get_conn_count() == 0)
checked_fd_clr(STDIN_FILENO, &master_readfds);
return n;
}
else {
Write(STDOUT_FILENO, buf, n);
nbytes += n;
}
} while (pending);
return nbytes;
}
I was able to figure out using the other functions involved. i passed a pointer into this function to write to it. the handler is a function i added the open() file pointer to.

Fail to read/write struct to fifo recursively in C

In an exercise problem, I am required to build a client program (write first) that opens a .txt file, put each line and the total bytes of each line into a struct variable and then send it out to the server program (read first). Right after this is done, the client program will also receive a struct file (similarly only has char * and int attributes) from the server program.
// Below are global variables in both programs
#define BUFSIZE 1024
struct info_pack
{
char line[BUFSIZE]; // the line to receive messages
int bytes; // the bytes of data transferred
};
char fifo_path[] = "./my_fifo";
struct info_pack info_w; // the info_pack for writing each line in text.txt
struct info_pack info_r; // the info_pack for reading feedback info_pack sent from the server program
First is the client program:
// the main() in the client program
int main()
{
int fd;
int i = 0, index = 1, bytes = 0, line_length, fifo_read;
char *file_path = "/home/text.txt";
FILE *fd2;
mkfifo(fifo_path, 0666);
if ((fd2 = fopen(file_path, "r")) < 0)
{
perror("Opening file");
return -1;
}
else
{
printf("Successfully open the target file\n");
while (fgets(info.line, BUFSIZE, fd2) != NULL)
// the "segmentation fault" error appears right after this line
{
info_w.bytes = strlen(line);
fd = open(fifo_path, O_WRONLY);
printf("The %d th line sent out is: %s\n%d bytes are sent\n\n",
index, info_w.line, info_w.bytes);
write(fd, &info_w, sizeof(info_w) + 1);
close(fd);
fd = open(fifo_path, O_RDONLY);
fifo_read = read(fd, &info_r, sizeof(info_r));
close(fd);
if (fifo_read > 0)
{
printf("Feedback: %s\nand %d bytes are returned\n", info_r.line, info_r.bytes);
}
}
printf("All data is successfully transfered\n");
}
return 0;
}
Then is the server program
// the main() in the server program
int main()
{
int fd, fifo_read;
int line_length;
char *feedback = "SUCCESS";
strcpy(info_w.line, feedback);
info_w.bytes = strlen(feedback);
// define a constant info_pack variable to send to the client program
if (mkfifo(fifo_path, 0666) < 0)
{
perror("client end: ");
exit(-1);
}
while (1)
// This server program will wait for any one single client's message
// This server program can only be terminated by manually input signals (like ^\)
{
fd = open(fifo_path, O_RDONLY);
printf("waiting for client's message\n");
fifo_read = read(fd, &info_r, sizeof(info_r));
close(fd);
if (fifo_read > 0)
// if receive the struct variable, print all of its attributes
{
if (info_r == NULL)
printf("Found no lines sent from the client\n");
else
printf("Read from fifo:\n %s\n(in info)%d bytes read (actually)%d bytes read\n", info_r.line, info_r.bytes, fifo_read);
}
else
{
sleep(1);
printf("Fail to read data from the client\n");
}
// Because of the error in client program this server program
// always pause here
fd = open(fifo_path, O_WRONLY);
printf("Now writing feedback to the client\n");
write(fd, info_w, sizeof(info_w));
close(fd);
}
}
Could anyone explain why the segmentation fault error appears in the client program? Then I can test if the both the client and the server can co-op properly.By the way, I read this post already but, in this post, it is a one-time data stream and I cannot find any hints in it.

Read() stuck on trying to read file

I have a checkpoint file that receives a server state. This states represents serialized commands that pass trough my network.
I'm trying to read the file but the it gets stuck on the read while loop.
My read function:
struct message_t *pmanager_readop(int fd){
if (fd < 0) return NULL;
// Variables
char *buffer = NULL;
int result, msg_size;
struct message_t *msg;
// Check if file has data
lseek (fd, 0, SEEK_END);
int size_ckp = lseek(fd, 0, SEEK_CUR);
if (size_ckp <= 0)
return NULL;
// Read message size
result = read_all(fd, (char *) &msg_size, 4);
if (result < 0) {
return NULL;
}
msg_size = ntohl(msg_size);
// ............
My read_all() function:
int read_all(int sock, char *buf, int len){
int bufsize = len;
while(len > 0){
int res = read(sock,buf,len);
if(res < 0){
if (errno == EINTR) continue;
return res;
}
buf += res;
len -= res;
}
return bufsize;
}
I use this same function to read data from my server/client connection with the same serialization and format but with a socket descriptor, and it works perfectly.
You ought to handle the case that read() returns 0, telling you that the other side shut-down the connection if reading from a socket descriptor, or EOF encountered if reading from a file descriptor.

SSH Tunneling with a c library

I am trying to use libssh library to open an SSH tunnel.
Basically, I need to reach a server through a tunnel. First, I would need to SSH to the gateway (I have already done this), then I would need to SSH from that host to the server:
[PC] -- ssh user1#gateway --> [gateway] -- ssh www#server --> [server]
The first ssh needs a password to reach the gateway but the second ssh is of a different user and it doesn't require a password.
I want to reach that server and execute a script, in this case, it's just a command: ls -all
I tried using ssh_channel_open_forward() but I don't know where to specify the 'user' plus it hangs when I use it. There aren't many examples to follow or that much of documentation.
Here is how I tried to reach a server through a bridge/tunnel :
int direct_forwarding(ssh_session session)
{
ssh_channel channel;
int rc = -1;
int nbytes, nwritten;
channel = ssh_channel_new(session);
if (channel == NULL) {
return rc;
}
printf("\n*********channel is created************\n");
rc = ssh_channel_open_forward(channel, "server", 22, "gateway", 22);
if (rc != SSH_OK)
{
ssh_channel_free(channel);
return rc;
}
printf("\n*********channel is opened************\n");
char *command = "ls -all";
nbytes = strlen(command);
nwritten = ssh_channel_write(channel, command, nbytes);
if (nbytes != nwritten)
{
ssh_channel_free(channel);
return SSH_ERROR;
}
printf("\n*********Write command is finished************\n");
char buffer[256];
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
while (nbytes > 0)
{
printf("number of bytes read : %d\n", nbytes);
if (write(1, buffer, nbytes) != (unsigned int)nbytes)
{
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
}
if (nbytes < 0)
{
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
printf("\n*******************no errors*******************\n");
ssh_channel_free(channel);
return SSH_OK;
}
Is this possible in libssh?

C Socket client prints out a strange output

I'm trying to send a .txt file to a Linux socket client from a Linux server client (I use the loopback interface). I tried to a send a string, i.e. "OK", and everything worked fine, but when I try to send a file, the client prints out a strange output. Obviously I've done all the previous steps like socket, connect, accept, listen etc.
This is the server-side code:
printf("Sending file\n);
if ((fp=fopen(filename, "r"))!=NULL){
while ( (nbytes = fread(sendline, sizeof(char), 512, fp) > 0)){
printf("%s\n",sendline);
sent = writen(clientfd, sendline, nbytes);
}
close(fp);
}else
perror("Open file");
The 'writen' function is:
ssize_t writen(int fd, const void *vptr, size_t n){
/* Write "n" bytes to a descriptor. */
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0; /* and call write() again */
else
return(-1); /* error */
}
nleft -= nwritten;
ptr += nwritten;
}
return(n);
}
The client-side code is:
while (fgets(sendline, 10000,stdin) != NULL)
{
sendto(sockfd,sendline,strlen(sendline),0,
(struct sockaddr *)&servaddr,sizeof(servaddr));
read(sockfd,recvline,10000);
fputs(recvline,stdout);
recvline[n]=0;
if((recvline[0]=='-')&&(recvline[1]=='E')&&(recvline[2]=='R')&&(recvline[3]=='R')){
close(sockfd);
exit(1);
}
}
The strange client that I get is in the image.
Client Output
So what's my mistake? Why do I receive this kind of output and how could I fix it?
Couple of issues,
In server code, parenthesis is at incorrect place,
while ( (nbytes = fread(sendline, sizeof(char), 512, fp) > 0)){
should be
while ( (nbytes = fread(sendline, sizeof(char), 512, fp)) > 0){
---------^ parenthesis close here
And in client side, set '\0' in recvline before printing as
n = read(sockfd,recvline,10000);
recvline[n] = '\0'
fputs(recvline,stdout);
You never check how many bytes read returned (or whether it failed). Even if it does return n bytes as you assume, you don't null-terminate the buffer until after you print it, so fputs(recvline,stdout) will print whatever garbage it finds in the uninitialized buffer on the stack.

Resources