OpenVPN / openvpn3

OpenVPN 3 is a C++ class library that implements the functionality of an OpenVPN client, and is protocol-compatible with the OpenVPN 2.x branch.
https://openvpn.net
Other
973 stars 383 forks source link

How to include the library #48

Closed Herz3h closed 6 years ago

Herz3h commented 6 years ago

Hello,

I'm trying to use this library to create an simple openvpn client, however I don't really know how to include it properly into my c++ application.

I have tried with following includepath : -Iopenvpn3/

With above I get a bunch of "Redefinition of X" (ServerEntry, etc...)

So I'm not sure how this library should be used. Should I use the classes inside openvpn3/openvpn/ only ? From what I understand in readme, I should be using the OpenVPNClient interface inside openvpn3/client/

Thanks in advance.

Herz3h commented 6 years ago

Never mind regarding the Redefinition error, I had <client/ovncli.hpp> included two times in different files. But now it tells me OPENVPN_PACKAGE_ID must be defined. And this turns out to be in the Android folder.

I intend to build application for OS X and Windows only, what am I doing wrong ?

ordex commented 6 years ago

we don't know what you are doing therefore it is not easy to guess what's wrong. How about you share how you are compiling the library/binary and what is the exact output with the error?

Herz3h commented 6 years ago

Okay here is the compilation line which Qt generates :

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -c -pipe -stdlib=libc++ -fwhole-program -O3 -Wno-sign-compare -Wno-unused-parameter -arch x86_64 -std=c++11 -stdlib=libc++ -fvisibility=hidden -fvisibility-inlines-hidden -DUSE_MBEDTLS -DUSE_ASIO -DASIO_STANDALONE -DASIO_NO_DEPRECATED -DHAVE_LZ4 -w -g -std=gnu++11 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -mmacosx-version-min=10.10 -Wall -W -fPIC -DQT_QML_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I../VPNGUI-I. -I../VPNGUI/src/ovpn3/core -I../VPNGUI/src/mac/mbedtls/mbedtls-osx/include -I../VPNGUI/src/mac/asio/asio/include -I../VPNGUI/src/mac/lz4/lz4-osx/include -I../../Qt/5.10.1/clang_64/lib/QtWidgets.framework/Headers -I../../Qt/5.10.1/clang_64/lib/QtGui.framework/Headers -I../../Qt/5.10.1/clang_64/lib/QtNetwork.framework/Headers -I../../Qt/5.10.1/clang_64/lib/QtCore.framework/Headers -I. -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks/OpenGL.framework/Headers -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks/AGL.framework/Headers -I../../Qt/5.10.1/clang_64/mkspecs/macx-clang -F/Users/Herz3h/Qt/5.10.1/clang_64/lib -o main.o ../VPNGUI/main.cpp

And here is compilation error:

In file included from ../VPNGUI/src/ovpn3/core/openvpn/options/merge.hpp:36: ../VPNGUI/src/ovpn3/core/openvpn/common/options.hpp:1290:37: error: reference to overloaded function could not be resolved; did you mean to call it? OPENVPN_LOG_NTNL(title << std::endl << render(Option::RENDER_TRUNC_64|Option::RENDER_NUMBER|Option::RENDER_BRACKET|Option::RENDER_UNUSED));

Finally here is the class code that includes openvpn header files:

#ifndef CLIENT_H
#define CLIENT_H

#include <openvpn/options/merge.hpp>
#include <client/ovpncli.cpp>

using namespace openvpn::ClientAPI;

class Client : public OpenVPNClient
{
public:
    Client();
    virtual bool socket_protect(int socket) override;
    virtual bool pause_on_connection_timeout() override;

    // Callback for delivering events during connect() call.
    // Will be called from the thread executing connect().
    virtual void event(const Event&) override;

    // Callback for logging.
    // Will be called from the thread executing connect().
    virtual void log(const LogInfo&) override;

    // External PKI callbacks
    // Will be called from the thread executing connect().
    virtual void external_pki_cert_request(ExternalPKICertRequest&) override;
    virtual void external_pki_sign_request(ExternalPKISignRequest&) override;

private:
//    openvpn::ProfileMerge *profileMerge;
//    Config *config;

};

#endif // CLIENT_H

Note: I have followed compilation guide for mac, then moved the src folder to my project folder and finally added options dans the build script (build cli command) adds when it generates the command.

dsommers commented 6 years ago

Try adding #include <openvpn/common/platform.hpp> first and then move #include <client/ovpncli.cpp> above the openvpn/options/merge.hpp include.

Herz3h commented 6 years ago

I have a new error now :

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -dynamic -arch x86_64 -headerpad_max_install_names -macosx_version_min 10.10.0 -o vpn-bridge.app/Contents/MacOS/vpn-bridge -L/Users/Herz3h/Documents/VPNGUI-WINDOWS/src/mac/mbedtls/mbedtls-osx/library -framework Security -framework CoreFoundation -framework SystemConfiguration -framework IOKit -framework ApplicationServices -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -rpath @executable_path/Frameworks -rpath /Users/Herz3h/Qt/5.10.1/clang_64/lib main.o mainwindow.o client.o qrc_logojpl.o moc_mainwindow.o -lmbedtls /Users/Herz3h/Documents/VPNGUI-WINDOWS/src/mac/lz4/lz4-osx/lib/liblz4.a -framework QtWidgets -framework QtGui -framework QtCore -framework DiskArbitration -framework IOKit -framework QtNetwork -framework OpenGL -framework AGL -lc++ -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.1.0/lib/darwin/libclang_rt.osx.a -F/Users/Herz3h/Qt/5.10.1/clang_64/lib
duplicate symbol __ZN7openvpn9ClientAPI13OpenVPNClient16crypto_self_testEv in:
    main.o
    mainwindow.o
duplicate symbol __ZN7openvpn9ClientAPI13OpenVPNClient9copyrightEv in:
    main.o
    mainwindow.o
duplicate symbol __ZN7openvpn9ClientAPI13OpenVPNClient13on_disconnectEv in:
    main.o
    mainwindow.o

The errors keeps going on, I seem to have 204 duplicated symbols. I made sure I included ovpncli.cpp only once in my .h file

Edit: This was apparently caused because I included ovpncli.cpp in one h file, which is then included in two .cpp files. So I have changed the ovpncli.cpp to ovpncli.hpp

But now I have the same error as my previous post (same file and line and same error).

This is what I have in my .h file :

#ifndef CLIENT_H
#define CLIENT_H

#include <openvpn/common/platform.hpp>
#include <client/ovpncli.hpp>
#include <openvpn/options/merge.hpp>

using namespace openvpn::ClientAPI;

class Client : public OpenVPNClient
{
public:
    Client();
    virtual bool socket_protect(int socket) override;
    virtual bool pause_on_connection_timeout() override;

    // Callback for delivering events during connect() call.
    // Will be called from the thread executing connect().
    virtual void event(const Event&) override;

    // Callback for logging.
    // Will be called from the thread executing connect().
    virtual void log(const LogInfo&) override;

    // External PKI callbacks
    // Will be called from the thread executing connect().
    virtual void external_pki_cert_request(ExternalPKICertRequest&) override;
    virtual void external_pki_sign_request(ExternalPKISignRequest&) override;

private:
//    openvpn::ProfileMerge *profileMerge;
//    Config *config;

}

#endif

Also if I remove the #include <openvpn/options/merge.hpp> the reference to overloaded function ...to call it? OPENVPN_LOG_NTNL(... goes away and I'm back with duplicate symbols. Why is it that I have to include a cpp file (why isn't it ovpncli.hpp) that should be included ? I'm confused here, as the cpp inclusion seems to be the reason for duplicated symbols. I have a typical Qt App:

main.cpp -> includes mainwindow.h
mainwindow.cpp
mainwindow.h -> includes client.h
client.cpp
client.h -> include ovpncli.cpp

And symbols are duplicated in main.o and client.o

Herz3h commented 6 years ago

Is there anything I can do ? The problem once again seems to be that I have to include the .cpp file instead of an .hpp file. But that causes the duplicate symbols error.

dsommers commented 6 years ago

Please have a close look at how the reference client (test/ovpncli/cli.cpp) does things. Another reference point is the openvpn3-linux implementation (openvpn3-service-client, core-client.hpp). These two implementations manages to implement the client without any duplicated symbols.

It is hard to understand what is going wrong without seeing the whole picture as well, so without sharing your project with us, we will just be shooting blindly in the dark.

Herz3h commented 6 years ago

I already looked the cli.cpp before, I've tried having same includes/defines, but same result. I took a quick look at core-client.cpp but it seems they also include the ovpncli.cpp (which seems to be the root cause).

It seems odd to have to include a .cpp file for a library instead of .hpp...

Here is the full compilation log which ends up giving me duplicated symbols: https://pastebin.com/1aLNstpL

dsommers commented 6 years ago

We need the full source code of your implementation too. Plus it would help a lot if all the warnings and errors weren't in French. We are also chasing a ghost here, as the earlier compiler warnings you showed here seems to be from a Mac running XCode, while this pastebin seems to be from a Windows box - which means: Quite different compiler environments.

In regards to the .cpp file inclusion. A file name is a file name, which is the argument given to #include, regardless of the extension. There is nothing special about including a .cpp except of it being a bit unusual. But it needs to be like this for other use cases this library has.

I believe the root cause is wrong order of #include statements. And then you build several object files from .cpp files, where some of the same symbols ends up being in more object files, which then explodes when these objects files are getting linked together. You need to figure out a way to untangle this, as it won't compile as it is now.

But since you're playing with Qt, also ensure that you use at least -std=c++11, preferably -std=c++14. Depending on Qt versions, this might or might not work - I don't know how compliant your Qt targets are with those standards.

I'm closing this now, as this seems to be more a local implementation issue and not a bug in the OpenVPN 3 Core library.

Herz3h commented 6 years ago

Here is the fully source of the implementation : VPNClient, I've tried on Windows and Mac, this repository is ready to be compiled on Windows with Qt 5.x (here is the client.h)

dsommers commented 6 years ago

I get "404 This is not the web page you are looking for." on both these URLs.

dsommers commented 6 years ago

Oh, wait ... the URLs are wrong, the "text version" of the URL works.

Herz3h commented 6 years ago

Ok sorry the link is fixed

dsommers commented 6 years ago

You have #include <openvpn/io/io.hpp> on line 6 in client.h. Try moving that one below line 11. But if you have more files including client.h which are built as separate object files, you will still most likely hit the duplicated symbols error. This needs to be resolved differently as well.

dsommers commented 6 years ago

I also see you have: #define OPENVPN_CORE_API_VISIBILITY_HIDEN. There's a typo here. It should say HIDDEN not HIDEN.

Herz3h commented 6 years ago

I've moved the io.hpp include below ovpncli.hpp, and fixed the typo. As for client.h it is included by mainwindow.h which in turn is included by main.cpp (mainwindow.h seems to also be included by moc_mainwindow.h), what do you mean it should be "resolved differently" ?

schwabe commented 6 years ago

Generally OpenVPN3 core is a bit different than most libraries. The whole implementation is header only.

To fix the problem you are seeing I would if possible for you include the openvpn header in only one c/c++ file and make only that file access openvpn3 directly and the rest of your program go that that class/file with function calls. We might fix openvpn3 in the future to be used more like a normal c++ library but at the moment that is the approach you need to take.

Herz3h commented 6 years ago

@schwave So the idea is to include the ovpncli.hpp (instead of ovpncli.cpp) only in one class (that's what I'm doing at the moment) ? Because I have tried that and I get different errors

dsommers commented 6 years ago

No, you must use ovpncli.cpp.

Herz3h commented 6 years ago

So I have a client.h class which include the ovpncli.cpp and makes the implementation. Then mainwindow.cpp uses Client class and not OpenVPNClient class directly, but that's where I was before and had the duplicated symbols, so I'm confused regarding your last message.

dsommers commented 6 years ago

Your duplicated symbols issues is tied to

    duplicate symbol __ZN7openvpn9ClientAPI13OpenVPNClient16crypto_self_testEv in:
    main.o
    mainwindow.o

So both main.cpp and mainwindow.cpp is including the same openvpn3 header file somewhere in the chain. This needs to be decoupled, so that only one of these source files includes ovpncli.cpp.

Or how I understand what @schwabe says, you have your own implementation of the "OpenVPN 3 Client class" where the declaration is exported in a .hpp file, used by both main.cpp and mainwindow.cpp and the implementation is built separately from its own .cpp file. When linking this together, you will only have the needed symbols defined in a single object file.

dsommers commented 6 years ago

And just to clarify an ugly detail in the last paragraph ... the declaration cannot include any openvpn3 header files, those needs to be included in the implementation file only.

Herz3h commented 6 years ago

So if my client.h (Client class) is the one I expose, It should not include any openvpn3 headers files (but rather the client.cpp should include those) right ? I have tried that, and symbols are duplicated still.... I'm sorry but I really don't understand how I should go about this.

I have a my client.h class (inheriting OpenVPNClient) decalaration, the implementation is inside client.cpp (I have tried including openvpn3 headers here too instead of in the client.h), then my mainwindow.h includes the client.h and main.cpp includes mainwindow.h

dsommers commented 6 years ago

You might need to ensure that you do not expose any OpenVPN 3 related symbols at all in client.h.

As I see the current include chain in your current github repository (git master commit eb0c800fb77ce5c889b78daf74219c4ece14b1fa):

 * mainwindow.cpp includes:
    - mainwindow.h  includes:
       -  client.hpp  includes
            - ovpncli.cpp
 * main.cpp includes
       - mainwindow.h includes
            -  client.hpp includes:
                 - ovpncli.cpp

Here you see that ovpncli.cpp gets included twice, via separate .cpp files - which is compiled separately into separate object files, both containing the same symbols from ovpncli.cpp. This is why client.hpp cannot include any openvpn3 source files, otherwise you will have duplicated symbols conflict, all pointing at ovpncli.cpp.

So you need to be sure that your client.h is completely openvpn3 agnostic, only exports its own declarations. And the client.cpp which includes ovpncli.cpp with the needed implementation. This needs to built separately (into it's own client.o object file) and then this object file can be linked together with mainwindow.o and main.o and the end result is your executable client.

Herz3h commented 6 years ago

I understand now, I've got it working.

Thank you very much for the help 👍