Porting miniDLNA to OpenBSD

Build

To compile and run minidlna the following libraries are needed. See ./minidlna/INSTALL. So first step is to find and install all the packages which includes these libraries. One way is to do some searching in http://www.openports.se.

I already had a few packages installed on my development machine.

gettext, libiconv, libidn, nano, ruby, wget

So I installed all the dependent packages ...

pkg_add libexif jpeg libid3tag flac libvorbis sqlite3 ffmpeg ossp-uuid

Next I try to compile the miniDLNA. Make complains about missing header files for the installed packages above. The headers aren't included in the packages as those are build to work with prebuilt applications. This means that the packages must be compiled locally from ports.

So next step is to install the ports source code. Get the source code from the install CD's and unpack them.

cd /usr
tar xzf ports.tar.gz
cd /usr/src
tar xzf src.tar.gz
tar xzf xenocara.tar.gz

Because binaries are already installed I would prefer not to recompile everything. First I try to do make fetch to see if headers become available.

cd /usr/ports/graphics/libexif
make fetch
...

I don't think that was needed. The problem is that base include folder for installed packages in OpenBSD is /usr/local/include instead of /usr/include. So the solution is to change that in Makefile and genconfig.sh.

One difficult problem is that sendfile is used. sendfile is not supported on OpenBSD and need to be replaced by read and write in user space.

Another problem is regarding different network specification in Linux and OpenBSD. minidlna/getifaddr.c calls functions that isn't supported in OpenBSD. The following functions needs to be reimplemented in OpenBSD.

This has been done in FreeBSD port and CVS HEAD.

__NR_clock_gettime syscall can be replaced by CLOCK_GETTIME(2)

1.1 branch is now targetting multiple OS support using autoconf. See autoconf and metaauto for more info. 1.1 branch in not stable yet.

To be continued ...

New attempt on minidlna

I tried to download the latest source from source forge. The version is a development version of 1.1.0 (1.0.24+).

http://minidlna.cvs.sourceforge.net/viewvc/minidlna/?view=tar&pathrev=HEAD

Development is now run from github:

https://github.com/glebius/minidlna

Looking at the links below I did my first attempts.

pkg_add autoconf
pkg_add automake
pkg_add libtool

export AUTOMAKE_VERSION=1.11
export AUTOCONF_VERSION=2.68

./autogen.sh
./configure

./configure stumbled on avformat lib which is part of ffmpeg library.

checking for av_open_input_file in -lavformat... no
configure: error: Could not find libavformat - part of ffmpeg

After some time banging the head against a wall (with configure) I didn't know if I should try to skip autotools and try to create a OpenBSD specific makefile (current FreeBSD port of minidlna 1.0.24 use that approach) or try to fix the problems with configure.

Finally I downloaded the complete ports tree to find another port which use autotools and avformat. I finally found Aqualung. So the idea is to copy aqualung port and use as basis for the minidlna port. Browsing the Makefile for aqualung I realized that LDFLAGS and CFLAGS must be specified for configure to work. From /ports/audio/aqualung/Makefile.

CONFIGURE_STYLE=gnu
CONFIGURE_ENV=  LDFLAGS="-pthread -L${LOCALBASE}/lib -L${X11BASE}/lib" \
                CFLAGS="${CFLAGS} -DOSS_DEVICE='\"/dev/audio\"'  \
                -DPTHREAD_MIN_PRIORITY=0 -DPTHREAD_MAX_PRIORITY=31  \
                -I${LOCALBASE}/include"

So I export those environment variables.

# export LDFLAGS="-pthread -L/usr/local/lib -L/usr/X11R6/lib"
# export CFLAGS="-DOSS_DEVICE='\"/dev/audio\"' -DPTHREAD_MIN_PRIORITY=0 -DPTHREAD_MAX_PRIORITY=31 -I/usr/local/include"

After comparing with FreeBSD I could trim the configuration.

# export LDFLAGS="-pthread -L/usr/local/lib"
# export CFLAGS="-I/usr/local/include"

I also downloaded aqualung source to see if I could make that compile. To avoid any missing dependencies I also installed the package to get all depending libs.

pkg_add aqualung

As configure worked I tried the same on minidlna (still having the same environment variables) and, to my pleasant surprise, that worked as well. After ./configure I could build a binary without a problem.

./configure
make

Check possible configure options with -h option.

./configure -h

The minidlna binary even ran without a major problem.

# ./minidlna
[2012/05/25 16:05:26] minidlna.c:786: error: Usage:
        ./minidlna [-d] [-v] [-f config_file]
                [-a listening_ip] [-p port]
                [-s serial] [-m model_number]
                [-t notify_interval] [-P pid_filename]
                [-w url] [-R] [-V] [-h]

Notes:
        Notify interval is in seconds. Default is 895 seconds.
        Default pid file is /var/run/minidlna.pid.
        With -d minidlna will run in debug mode (not daemonize).
        -w sets the presentation url. Default is http address on port 80
        -h displays this text
        -R forces a full rescan
        -L do note create playlists
        -V print the version number

I made some small changes (e.g. specifying a proper media folder) to the default minidlna.conf file and started the server.

./minidlna -R -d -f ./minidlna.conf

Starting "Windows Media Player" I could see the media server and play my favorite OpenBSD release songs over it.

Bug 3538219

When trying some more audio and video files I noticed a bug in minidlna. It's doesn't handle data transmission over socket completely. See more on.

send(res_buf) error - ID: 3538219

It seems that this issue isn't resolved yet in MAIN.

A proposed patch could be as follows.

Original

void
SendResp_upnphttp(struct upnphttp * h)
{
    int n;
    DPRINTF(E_DEBUG, L_HTTP, "HTTP RESPONSE: %.*s\n", h->res_buflen, h->res_buf);
    n = send(h->socket, h->res_buf, h->res_buflen, 0);
    if(n<0)
    {
        DPRINTF(E_ERROR, L_HTTP, "send(res_buf): %s\n", strerror(errno));
    }
    else if(n < h->res_buflen)
    {
        /* TODO : handle correctly this case */
        DPRINTF(E_ERROR, L_HTTP, "send(res_buf): %d bytes sent (out of %d)\n",
                        n, h->res_buflen);
    }
}

Updated version

void
SendResp_upnphttp(struct upnphttp * h)
{
    int n, m = 0;
    DPRINTF(E_DEBUG, L_HTTP, "HTTP RESPONSE: %.*s\n", h->res_buflen, h->res_buf);
    while (m < h->res_buflen)
    {
        n = send(h->socket, h->res_buf + m, h->res_buflen - m, 0);
        if(n<0)
        {
            DPRINTF(E_ERROR, L_HTTP, "send(res_buf): %s\n", strerror(errno));
            break;
        }
        else if(n < h->res_buflen)
        {
            DPRINTF(E_DEBUG, L_HTTP, "send(res_buf): %d bytes sent (out of %d)\n",
                            n, h->res_buflen);
            m += n;
        }
    }
}

I haven't tried this patch yet though.

Port have already been made ...

It seems like Stuart Henderson finalized a port before I had finished mine.

minidlna port

This is using current version 1.0.25 which doesn't use autotools so it requires a lot of patches. I didn't make any patches in my version from HEAD. Great that it is included anyhow. Shall be interesting to compare the autotools version with my initial work. Also don't understand how upnphttp.c problem is avoided in current port.

1.1.0 was released April 4th 2013 which includes improved OS portability support.

DLNA testing

A set up required and optional media formats has been specified by DLNA alliance.

inotify support

As inotify isn't supported on BSD kqueue would be a good replacement on BSD's.

References