-2

I'm new to programming, but I'm trying to use C++ to create a TCP server with Winsock which will send a list of all the host's files and directories to the client using dirent. So far the code creates the server, lists all of its directories, and sends the name of only one of them to the client. I can't figure out why only one directory name is being sent, despite all of them being listed on the server's computer.

The 1st code block creates the socket. The issue seems to be in the 2nd block

#include<io.h>
#include<stdio.h>
#include<winsock2.h>
#include <iostream>
#include <dirent.h>
#include <sys/types.h>
#include <string>
#pragma comment(lib,"ws2_32.lib") 
 using namespace std;
 


int main(int argc , char *argv[])
{
    WSADATA wsa;
    SOCKET s , new_socket;
    struct sockaddr_in server , client;
    int c;
    char *message;
 
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        printf("Failed. Error Code : %d",WSAGetLastError());
        return 1;
    }
     
    printf("Initialised.\n");
     
    //Create a socket
    if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
    {
        printf("Could not create socket : %d" , WSAGetLastError());
    }
 
    printf("Socket created.\n");
     
    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 8888 );
     
    //Bind
    if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
    {
        printf("Bind failed with error code : %d" , WSAGetLastError());
    }
     
    puts("Bind done");
 
    //Listen to incoming connections
    listen(s , 3);
     
    //Accept and incoming connection
    puts("Waiting for incoming connections...");
     
    c = sizeof(struct sockaddr_in);
    new_socket = accept(s , (struct sockaddr *)&client, &c);
    if (new_socket == INVALID_SOCKET)
    {
        printf("accept failed with error code : %d" , WSAGetLastError());
    }
     
    puts("Connection accepted");

This is what lists & sends the directories.

//List directory
   DIR *dr;
   struct dirent *en;
   dr = opendir("."); //open all or present directory
   if (dr) {
      while ((en = readdir(dr)) != NULL) {
         printf("%s\n", en->d_name); //print all directory name
      message = ("%s\n", en->d_name); //Problem line?
      }
      closedir(dr); //close all directory
   }

    send(new_socket , message , strlen(message) , 0);
     
    getchar();
 
    closesocket(s);
    WSACleanup();
     
    return 0;
}

I'd really appreciate any help understanding the issue and how to fix it.

Ken White
  • 123,280
  • 14
  • 225
  • 444
Agent.BTZ
  • 1
  • 1
  • 2
    `message = ("%s\n", en->d_name);` doesn't do what you apparently think it does. – πάντα ῥεῖ Jun 05 '21 at 01:20
  • Doesn't ```"%s\n"``` tell the compiler that the following argument will be a string? I'm not too clear on the function of ```en->d_name```, but doesn't ```d_name``` refer to the filename? I'm just confused how ```printf("%s\n", en->d_name);``` will successfully print the whole list, but ```message = ("%s\n", en->d_name);``` won't send it. – Agent.BTZ Jun 05 '21 at 01:27
  • 2
    No, it doesn't. That kind of format strings can be usied in combination with `printf()` alike functions. – πάντα ῥεῖ Jun 05 '21 at 01:29
  • @πάντα ῥεῖ That wasn't covered in my intro to C++ course, so I'll try to research this further. So I better understand what to look up, are you saying that ```%s\n``` is a format string which is compatible with functions like ```printf()```, but can't be used in conjunction with ```message``` and a while loop to send more than one string? Also, thanks for the info! I've been completely stuck on this for days – Agent.BTZ Jun 05 '21 at 02:12
  • 1
    What you're probably looking for is `sprintf()` and pass `message` as output buffer. But that requires that `message` points to some already allocated and available memory. – πάντα ῥεῖ Jun 05 '21 at 07:21
  • @πάνταῥεῖ You pointed me in the right direction, thanks! Using sprintf() and a buffer worked, I really appreciate the help! – Agent.BTZ Jun 08 '21 at 20:06

1 Answers1

0

I edited the 2nd block of code shown above, and this ended up working.

    DIR *dr;
   struct dirent *en;
   dr = opendir("."); //open all or present directory
   if (dr) {
      while ((en = readdir(dr)) != NULL) {
         printf("%s\n", en->d_name);
         char buffer[300];
         sprintf(buffer, "%s\n", en->d_name); //saves info to buffer
        send(new_socket, buffer, strlen(buffer), 0); //sends the buffer as a message
      }
      closedir(dr); //close all directory
   }

    send(new_socket , message , strlen(message) , 0);
     
    getchar();
 
    closesocket(s);
    WSACleanup();
     
    return 0;
}
Agent.BTZ
  • 1
  • 1
  • You don't need to call `strlen` since `sprintf` already calculates it. Just save the return value of `sprintf`. (also you should use `snprintf` to avoid buffer overrun and you should send something that lets the receiver separate the names, like a length prefix or a separator) – Ben Voigt Jun 08 '21 at 20:36