0

I am trying to build a C++ webserver project using MingW in windows visual studio code. Because I am new to C++, I am learning using VSCODE, the project structure is not so clear with multiple files. is it the file references which I should look out for in this instance or is there a file am missing?

This is the error

> Executing task: C/C++: g++.exe build active file <

Starting build...
C:\msys64\mingw64\bin\g++.exe -fdiagnostics-color=always -g C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles\TcpListener.cpp -o C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles\TcpListener.exe
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\AppData\Local\Temp\ccVz58F5.o: in function `TcpListener::init()':
C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:12: undefined reference to `__imp_WSAStartup'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:19: undefined reference to `__imp_socket'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:22: undefined reference to `__imp_WSAGetLastError'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:28: undefined reference to `__imp_htons'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:29: undefined reference to `__imp_inet_pton'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:31: undefined reference to `__imp_bind'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:33: undefined reference to `__imp_WSAGetLastError'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:37: undefined reference to `__imp_listen'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:39: undefined reference to `__imp_WSAGetLastError'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\AppData\Local\Temp\ccVz58F5.o: in function `TcpListener::run()':
C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:76: undefined reference to `__imp_select'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:88: undefined reference to `__imp_accept'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:101: undefined reference to `__imp_recv'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:107: undefined reference to `__imp_closesocket'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:151: undefined reference to `__imp_closesocket'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:166: undefined reference to `__imp_closesocket'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:170: undefined reference to `__imp_WSACleanup'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Admin\AppData\Local\Temp\ccVz58F5.o: in function `TcpListener::sendToClient(int, char const*, int)':
C:\Users\Admin\Desktop\Projects\WebServer\SourceFiles/TcpListener.cpp:177: undefined reference to `__imp_send'

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/lib/../lib/libmingw32.a(lib64_libmingw32_a-crt0_c.o): in function `main':
C:/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crt0_c.c:18: undefined reference to `WinMain'

collect2.exe: error: ld returned 1 exit status

Build finished with error(s).

Terminal will be reused by tasks, press any key to close it.

and this is my project structure project structure

and my TTcpListener.cpp

#include "../HeaderFiles/TcpListener.h"
#include <iostream>
#include <string>
#include <sstream>

int TcpListener::init()
{
  // Initialze winsock
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);

    int wsOk = WSAStartup(ver, &wsData);
    if (wsOk != 0)
    {
        return wsOk;
    }
    
    // Create a socket
    m_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (m_socket == INVALID_SOCKET)
    {
        return WSAGetLastError();
    }

  // Bind the ip address and port to a socket
    sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(m_port);
  inet_pton(AF_INET, m_ipAddress, &hint.sin_addr);
    
    if (bind(m_socket, (sockaddr*)&hint, sizeof(hint)) == SOCKET_ERROR)
  {
    return WSAGetLastError();
  }

  // Tell Winsock the socket is for listening 
    if (listen(m_socket, SOMAXCONN) == SOCKET_ERROR)
  {
    return WSAGetLastError();
  }

  // Create the master file descriptor set and zero it
    FD_ZERO(&m_master);

    // Add our first socket that we're interested in interacting with; the listening socket!
    // It's important that this socket is added for our server or else we won't 'hear' incoming
    // connections 
    FD_SET(m_socket, &m_master);

  return 0;

}

int TcpListener::run()
{
// this will be changed by the \quit command (see below, bonus not in video!)
    bool running = true; 

    while (running)
    {
        // Make a copy of the master file descriptor set, this is SUPER important because
        // the call to select() is _DESTRUCTIVE_. The copy only contains the sockets that
        // are accepting inbound connection requests OR messages. 

        // E.g. You have a server and it's master file descriptor set contains 5 items;
        // the listening socket and four clients. When you pass this set into select(), 
        // only the sockets that are interacting with the server are returned. Let's say
        // only one client is sending a message at that time. The contents of 'copy' will
        // be one socket. You will have LOST all the other sockets.

        // SO MAKE A COPY OF THE MASTER LIST TO PASS INTO select() !!!

        fd_set copy = m_master;

        // See who's talking to us
        int socketCount = select(0, &copy, nullptr, nullptr, nullptr);

        // Loop through all the current connections / potential connect
        for (int i = 0; i < socketCount; i++)
        {
            // Makes things easy for us doing this assignment
            SOCKET sock = copy.fd_array[i];

            // Is it an inbound communication?
            if (sock == m_socket)
            {
                // Accept a new connection
                SOCKET client = accept(m_socket, nullptr, nullptr);

                // Add the new connection to the list of connected clients
                FD_SET(client, &m_master);

        onClientConnected(client);
            }
            else // It's an inbound message
            {
                char buf[4096];
                ZeroMemory(buf, 4096);
                
                // Receive message
                int bytesIn = recv(sock, buf, 4096, 0);
                if (bytesIn <= 0)
                {
                    // Drop the client
        
          onClientDisconnected(sock);
                    closesocket(sock);
                    FD_CLR(sock, &m_master);
          
                }
                else
                {
          onMessageReceived(sock, buf, bytesIn);
                    // Check to see if it's a command. \quit kills the server
                    // if (buf[0] == '\\')
                    // {
                    //  // Is the command quit? 
                    //  string cmd = string(buf, bytesIn);
                    //  if (cmd == "\\quit")
                    //  {
                    //      running = false;
                    //      break;
                    //  }

                    //  // Unknown command
                    //  continue;
                    // }

                    // Send message to other clients, and definiately NOT the listening socket

                    // for (int i = 0; i < m_master.fd_count; i++)
                    // {
                    //  SOCKET outSock = m_master.fd_array[i];
                    //  if (outSock != m_socket && outSock != sock)
                    //  {
                    //      // ostringstream ss;
                    //      // ss << "SOCKET #" << sock << ": " << buf << "\r\n";
                    //      // string strOut = ss.str();

                    //      // send(outSock, strOut.c_str(), strOut.size() + 1, 0);
                    //  }
                    // }
                }
            }
        }
    }

    // Remove the listening socket from the master file descriptor set and close it
    // to prevent anyone else trying to connect.
    FD_CLR(m_socket, &m_master);
    closesocket(m_socket);
    
    // Message to let users know what's happening.
    // string msg = "Server is shutting down. Goodbye\r\n";

    while (m_master.fd_count > 0)
    {
        // Get the socket number
        SOCKET sock = m_master.fd_array[0];

        // Send the goodbye message
        //send(sock, msg.c_str(), msg.size() + 1, 0);

        // Remove it from the master file list and close the socket
        FD_CLR(sock, &m_master);
        closesocket(sock);
    }

    // Cleanup winsock
    WSACleanup();
  return 0;
}

// Send a message to a client
void TcpListener::sendToClient(int clientSocket, const char* msg, int length)
{
  send(clientSocket, msg, length, 0);
}

// Broadcast a message froma client
void TcpListener::broadcastToClients(int sendingClient, const char* msg, int length)
{
  for (int i = 0; i < m_master.fd_count; i++)
  {
    SOCKET outSock = m_master.fd_array[i];
    if (outSock != m_socket && outSock != sendingClient)
    {
      sendToClient(outSock, msg, length);
    }
  }
}

void TcpListener::onClientConnected(int clientSocket)
{
}

void TcpListener::onClientDisconnected(int clientSocket)
{
}

void TcpListener::onMessageReceived(int clientSocket, const char* msg, int length)
{
}

Would appreciate any suggestion. Thanks you.

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • Most of those look like linker errors. Particularly, it looks like you've included a header file which provides an interface for some classes or functions, but you didn't link against any object (shared object / DLL / etc.) files which provide definitions of those classes or functions. If compiling in VSCode, you'll need to research how to link a library in the IDE. If compiling from the command line / terminal, [this](https://stackoverflow.com/questions/22314120/imp-link-errors-using-g-running-under-mingw) might help you. – Alexander Guyer Jan 15 '22 at 15:53
  • *undefined reference to __imp_WSAGetLastError* -- All of these are Winsock related. So how do you link the Winsock library to your application? Remember that when you build a C++ application, all of those functions you're calling must exist somewhere when the linker builds the program -- the linker is not going to search your drive for these libraries -- you have to tell it which libraries to link. You didn't tell the linker where to find `WSAGetLastError`. Since I do not use MingW, read the documentation on where to find the Winsock library for this build system. – PaulMcKenzie Jan 15 '22 at 16:09
  • BTW, as mentioned, those are *linker* errors. Your program compiled just fine. Now when it's time to take the object code that the compiler produced and make the final executable, the linker has no idea what WSAGetLastError is (and all those other functions), so you need to specify where to find them. That's the quick lesson in how to successfully build a C++ application. – PaulMcKenzie Jan 15 '22 at 16:14
  • Looks like you did not link to `Ws2_32.lib` which is the required library for windows sockets. The help for any of these functions mentions the requirement: [https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsagetlasterror](https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsagetlasterror) – drescherjm Jan 15 '22 at 16:33
  • It seems achieving this with a single .cpp file is direct following this doc by Microsoft https://code.visualstudio.com/docs/cpp/config-msvc. I have multiple files (both .h and .cpp) in 2 different directories, is this library to link the methods same as .csproj in C#? And how would you implement it? Any resources – Godfrey Owidi Jan 15 '22 at 16:46
  • In VSCode when you get to this many files you probably should switch to use CMake and the CMake tools extension for your project. With that said CMake will take you some time to learn. – drescherjm Jan 15 '22 at 16:53
  • If you don't want to do that you can turn off code-runner and edit your tasks.json file. This document describes how to use more than 1 source file with mingw on windows: [https://code.visualstudio.com/docs/cpp/config-mingw#_modifying-tasksjson](https://code.visualstudio.com/docs/cpp/config-mingw#_modifying-tasksjson) it does not however tell you how to link to other libraries. You will have to know your compiler's settings and add additional arguments to the args: part for that. `-l` and `-L` will be used for that when using gcc/g++ clang ... `-L` sets the additional link folder. – drescherjm Jan 15 '22 at 16:57

0 Answers0