1

i have a problem with preloading a library.

But first I'll explain what I intend to do. I've developed a Blazor web application using the Un4Seen Bass Audio libraries. The application is hosted on the Kestrel Web Server and I wanted to deploy the application as a service (systemd).

The application works flawlessly and is designed to run on both Ubuntu and Windows systems. As I said, it works the way I want it to. Just not as a service.

As already mentioned, the Un4Seen audio libraries are required for execution, which are stored in the project structure as follows.

[AppRoot]
¦
+---....
¦
+---Bass.Net.dll
¦
+---....
¦   
+---libs
    +---unix
    ¦   +---x64
    ¦   ¦       libbass.so
    ¦   ¦       libbassalac.so
    ¦   ¦       libbassenc.so
    ¦   ¦       libbassenc_flac.so
    ¦   ¦       libbassenc_mp3.so
    ¦   ¦       libbassenc_opus.so
    ¦   ¦       libbassflac.so
    ¦   ¦       libbassmix.so
    ¦   ¦       libbassopus.so
    ¦   ¦       libbasswebm.so
    ¦   ¦       libbass_aac.so
    ¦   ¦       libbass_ac3.so
    ¦   ¦       
    ¦   +---x86
    ¦           libbass.so
    ¦           libbassalac.so
    ¦           libbassenc.so
    ¦           libbassenc_flac.so
    ¦           libbassenc_mp3.so
    ¦           libbassenc_opus.so
    ¦           libbassflac.so
    ¦           libbassmix.so
    ¦           libbassopus.so
    ¦           libbasswebm.so
    ¦           libbass_aac.so
    ¦           libbass_ac3.so
    ¦           
    +---Win32NT
        +---x64
        ¦       bass.dll
        ¦       bassalac.dll
        ¦       bassenc.dll
        ¦       bassenc_flac.dll
        ¦       bassenc_mp3.dll
        ¦       bassenc_opus.dll
        ¦       bassflac.dll
        ¦       bassmix.dll
        ¦       bassopus.dll
        ¦       basswebm.dll
        ¦       bass_aac.dll
        ¦       bass_ac3.dll
        ¦       
        +---x86
                bass.dll
                bassalac.dll
                bassenc.dll
                bassenc_flac.dll
                bassenc_mp3.dll
                bassenc_opus.dll
                bassflac.dll
                bassmix.dll
                bassopus.dll
                basswebm.dll
                bass_aac.dll
                bass_ac3.dll

With the following method i initialize the Bass Libraries:

private bool InitializeBassLibrary()
{
    var appPath = new Uri(Assembly.GetEntryAssembly()?.GetName().CodeBase ?? throw new NullReferenceException())
        .LocalPath;
    appPath = Path.GetDirectoryName(appPath);
    if (string.IsNullOrEmpty(appPath))
    {
        return false;
    }

    var librariesPath = appPath;

    var osPlatform = Environment.OSVersion.Platform;

    switch (osPlatform)
    {
        case PlatformID.Win32NT:
        {
            librariesPath += Environment.Is64BitProcess ? "\\libs\\win32nt\\x64\\" : "\\libs\\win32nt\\x86\\";
            break;
        }
        case PlatformID.Unix:
        {
            // Add following paths to search path for libs of your linux distribution.
            // e.g. for Ubuntu
            //      ldconfig /full/path/to/libs/unix/x64
            //      ldconfig /full/path/to/libs/unix/x86
            break;
        }
    }

    BassNet.Registration("mail@domain.dom", "X123456789012345");

    if (osPlatform == PlatformID.Win32NT)
    {
        var libLoadIsOk = Bass.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassAac.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassAc3.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassAlac.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassFlac.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassOpus.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassEnc.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassEnc_Flac.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassEnc_Mp3.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassEnc_Opus.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }

        libLoadIsOk = BassMix.LoadMe(librariesPath);
        if (!libLoadIsOk)
        {
            return false;
        }
    }

    if (osPlatform == PlatformID.Unix)
    {
        // For preloading BASS libs execute creation of fake streams or execute GetVersion() Methods if exists.
        Bass.BASS_GetVersion(4);
        _ = BassAc3.BASS_AC3_StreamCreateFile("", 0, 0, BASSFlag.BASS_DEFAULT);
        _ = BassAlac.BASS_ALAC_StreamCreateFile("", 0, 0, BASSFlag.BASS_DEFAULT);
        _ = BassFlac.BASS_FLAC_StreamCreateFile("", 0, 0, BASSFlag.BASS_DEFAULT);
        _ = BassOpus.BASS_OPUS_StreamCreateFile("", 0, 0, BASSFlag.BASS_DEFAULT);
        BassEnc.BASS_Encode_GetVersion();
        BassEnc_Flac.BASS_Encode_FLAC_GetVersion();
        BassEnc_Mp3.BASS_Encode_MP3_GetVersion();
        BassEnc_Opus.BASS_Encode_OPUS_GetVersion();
        BassMix.BASS_Mixer_GetVersion();
    }
    
    Bass.BASS_Init(AudioDevice, AudioDeviceSamplingRate, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
    if (Bass.BASS_ErrorGetCode() != BASSError.BASS_OK)
    {
        return false;
    }

    return true;
}

The Ubuntu version of the application is released for linux-x64 and is then copied to an Ubuntu machine.

So that the library assignment works correctly under Ubuntu, I created the file /etc/ld.so.conf.d/app_name.conf.

/etc/ld.so.conf.d/app_name.conf

/usr/share/nginx/html/dds-audio-transcoder-service/libs/unix/x64
/usr/share/nginx/html/dds-audio-transcoder-service/libs/unix/x86

This LD configuration file was then successfully applied with sudo ldconfig -v.

Whatever the reason, to get it working I had to preload the libbass.so library with LD_PRELOAD although it already has it in /etc/ld.so.conf.d/app_name.conf should be discoverable. I entered the LD_PRELOAD variable system-wide via /etc/environment and the value /usr/share/nginx/html/app_name/libs/unix/x64/libbass.so set. For those who don't know the bass audio libraries: libbass.so is the main library. The other files are plugins.

If I don't set the LD_PRELOAD variable the application won't start and gives the error: symbol lookup error: /usr/share/nginx/html/dds-audio-transcoder-service/libs/unix/ x64/libbass_ac3.so: undefined symbol: BASS_GetVersion. This is completely misleading because the method is not called at all. At least not on libbass_ac3.so. Took a bit to figure out it's from libbass.so.

If I then start the application with: sudo [app_file_name] --environment [custom_environment] the app works as expected.

Now finally comes the problem

I configured this Kestrel hosted application as a service in systemd. The following service file was created for this purpose.

/etc/systemd/system/app_name.service

[Unit]
Description=DDS-Audio-Transcoder for transcoding audio files to different audio formats

[Service]
WorkingDirectory=/usr/share/nginx/html/app-name
ExecStart=/usr/share/nginx/html/app-name/app-name-start-binary --environment TestInstance3Unix
Restart=always
RestartSec=150
KillSignal=SIGINT
SyslogIdentifier=bit-dds-transcoder
User=www-data
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
Environment="LD_PRELOAD=libbass.so"
Environment="LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/share/nginx/html/dds-transcoder-service/libs/unix/x64:/usr/share/nginx/html/dds-transcoder-service/libs/unix/x86"

[Install]
WantedBy=multi-user.target

The service was enabled with: sudo systemctl enable app_name.service

Then I tried with: sudo systemctl start app_name.service to start the service and nothing happens.

The syslog says the following:

Jul  4 23:04:49 l01-v-s-0081 systemd[1]: app_name.service: Scheduled restart job, restart counter is at 21.
Jul  4 23:04:49 l01-v-s-0081 systemd[1]: Stopped app_name.
Jul  4 23:04:49 l01-v-s-0081 systemd[1]: Started app_name.
Jul  4 23:04:50 l01-v-s-0081 app_name[2241]: /usr/share/nginx/html/app_name/app-name-start-binary: symbol lookup error: /usr/share/nginx/html/dds-audio-transcoder-service/libs/unix/x64/libbass_ac3.so: undefined symbol: BASS_GetVersion
Jul  4 23:04:50 l01-v-s-0081 systemd[1]: dds-audio-transcoder.service: Main process exited, code=exited, status=127/n/a
Jul  4 23:04:50 l01-v-s-0081 systemd[1]: dds-audio-transcoder.service: Failed with result 'exit-code'.

System Informations

esx Virtual Mashine with Ubuntu 20.04 .Net 5.0

What i'm missing or what i have done wrong?

Remember! Without systemd it works fine.

I'm really grateful for every tip.

Many greetings

Marcus

Marcus
  • 654
  • 1
  • 8
  • 19
  • 2
    where i n the service file does it say LD_PRELOAD? – pm100 Jul 04 '22 at 23:28
  • 1
    I don't know exactly what you mean, but by setting the OS environment variable ```LD_PRELOAD``` the operating system will try to load the libraries in the variable in an application. Example: If ```LD_PRELOAD="/usr/share/nginx/html/app_name/libs/unix/x64/libbass.so"``` is set, ```libbass.so``` is tried before running an application to load. This actually happens with every application that is somehow started. I set the variable in ```/etc/environment```. https://man7.org/linux/man-pages/man8/ld.so.8.html#:~:text=as%20shell%20variables!)-,LD_PRELOAD,-A%20list%20of – Marcus Jul 04 '22 at 23:41
  • 1
    But I don't see that set in your service config file. – pm100 Jul 05 '22 at 14:02
  • LD_PRELOAD was set in /etc/environment. Isn't correct? If i remove it from there it will not start enymore from bash shell. – Marcus Jul 05 '22 at 17:48
  • @pm100 you are right. I've updated my question with two Lines. ```LD_PRELOAD=libbass.so``` and ```LD_LIBRARY_PATH=$LD_LIBRARY_PATH:[PathTox64Libs]:[PathTox86Libs]]```. Now it works. – Marcus Jul 05 '22 at 17:56

0 Answers0