Devious Fish
pianod2 music server
profile for Perette at Stack Overflow, Q&A for professional and enthusiast programmers

Building & Installing pianod

You will need a C++14 or better compiler; in 2020, these are ubiquitous: Clang 41 or later, gcc 52 or later.

Dependencies

libav is not supported. If you lean that direction, use ffmpeg.

All dependencies can be downloaded and set up manually, but most systems have package managers that streamline this process. On macOS/OS X, see MacPorts; on Ubuntu or Debian, see apt-get; Gentoo, emerge; Fedora and RedHat, RPM; FreeBSD, try pkg or pkg_add. For other Linux distributions, check Wikipedia’s list to determine the packaging system used.

Features supported by output devices
Feature libao libsdl avdevices AVFoundation gstreamer
Crossfading Yes No Yes Yes Yes
Pandora Yes Yes Yes Yes Yes
Filesystem Yes Yes Yes Yes Yes
Tone generator Yes Yes Yes No Yes
Source dependencies
Package Pandora Filesystem Tonegen
cURL w/ TLS support Required No No
taglib No Optional† No
gzstream No Optional Optional

† Provides better results than ffmpeg and gstreamer metadata readers; does not improve on AVFoundation. AVFoundation is found on macOS 10.7+.

Building

If you have all of the dependencies listed above, use:

./configure && make

If you’d like to use the unit test to verify it works:

make check

You can run the software directly from the source directory now:

./src/pianod -c "$PWD/html"

To install it issue:

sudo make install

On startup, pianod reads your ~/.config/pianod2/startscript. A sample is found in the contrib directory.

Automatic Build Configuration

If you let configure make the choices, you will get the best supported set of features with the least redundancy:

Manual Build Configuration

Configuring the build has some options:

--disable-sanity (default is --enable-sanity)
When enabled, configure expects a media engine and at least one output or it fails with an error. Disabling sanity reduces this to a warning.
--enable-debug (default is --disable-debug)
When enabled, turns on assertions (self-checks in the software), some additional logging and debug compile (-g). These enlarge and slow the code down slightly, but make debugging much, much easier.
--enable-shadow[=option] or --disable-shadow
When enabled (and it also needs to be enabled with a command-line switch), pianod will allow login with system usernames and passwords, creating pianod accounts on-demand when necessary. option may be pam or passwd to force a validation method.
--with-compression or --without-compression
When included, pianod stores persisted data in compressed form. If omitted, compression is used if required libraries are available at configuration time.
--with-accesscontrol or --without-accesscontrol
When included, new connections are validated with hosts.deny and hosts.allow. See hosts_access(5). If omitted, access control is used if support is available at configuration time.
--with-engine=package
Chooses a media engine package. Packages may be: gstreamer, avfoundation (macOS/OS X), or ffmpeg.
--with-tls[=package] or --without-tls
Forces inclusion or exclusion of TLS support, or chooses a specific TLS package to use. Packages may be: gnutls, libressl, mbedtls, openssl, or securetransport.
--with-taglib or --without-taglib
Forces inclusion or exclusion taglib for reading ID3 data for the filesystem source. If omitted, taglib is included if the ffmpeg media engine is in use and the library is available at configuration time.
--with-pandora or --without-pandora
Forces inclusion or exclusion of Pandora. If omitted, Pandora is included if its dependencies are available.
--with-tonegenerator or --without-tonegenerator
Forces inclusion or exclusion of the tone generator. The tone generator has a 1KHz and 440Hz tones which could be used for setting levels, and is helpful for troubleshooting and testing, but generally it’s not needed. If omitted, the tone generator is included if either libao or libsdl outputs are available. It is not compatible with AVFoundation for output.
--with-filesystem or --without-filesystem
Forces inclusion or exclusion of the filesystem source, which uses media on a local disk or mounted network filesystem.
--with-libao or --without-libao; --with-libsdl or --without-libsdl
Forces inclusion or exclusion of libao or libsdl, two different output libraries. Both work with all sources for ffmpeg, or for the tone generator when using AVFoundation. However, libsdl does not support crossfading. Automatic configuration chooses one; you may choose more, or 0 if you disable sanity.
--with-libavdevices or --without-libavdevices
The third output library. On Linux, there is a good chance you will need to room reconfigure driver alsa id experimental. Test this with the console; after confirming it’s what you need, you can add it to your startscript.

macOS (formerly Mac OS X)

You’ll need to install Xcode developer tools found your installation DVD or downloaded from the App store or developer.apple.com. Tools are free. Alternately, on newer macOS versions, open terminal and enter “cc”. A window will pop up allowing you to install the command-line tools, which are much smaller than all of Xcode.

With clang (Apple’s compiler) you will need to set the compiler standard for Objective C:

OBJCXXFLAGS=-std=c++14
./configure

If ./configure fails because the compiler doesn’t support C++11, you will need to install a C++ compiler. gcc 4.8.4 (or later) works, and is easily installed via MacPorts.

After installing the MacPorts base:

sudo port install gcc5
export CC=gcc-mp-5
export CXX=g++-mp-5
./configure

pianod2 is believed viable on macOS 10.7+ without any additional dependencies. For Snow Leopard (OS X 10.6) or earlier, you will need audio support. To install these dependencies:

sudo port -v install libao ffmpeg taglib

To create pianod from a tarball, using MacPorts for dependencies, you will also need these environment variables before invoking ./configure:

export CPPFLAGS=-I/opt/local/include
export LDFLAGS=-L/opt/local/lib

The tarball build will install to /usr/local/bin.

Linux

If launching as root, use ‘pianod -n pi’ to run pianod as the pi’s starter user.

To open audio devices, a process usually needs to belong to the audio group:

usermod --append --groups audio _username_

When launching as root (such as from init.d, systemd or /etc/rc.d files), specify the user to run as:

pianod -r _username_

Build Troubleshooting

Messages may vary slightly by system and compiler.

General Troubles

Mixing C++ Compilers

Linking between C++ code built with different compilers or standards can cause woes. I encountered taglib corrupting the stack; build issues were confirmed via a simple test program (just read and get artist). If you run into troubles, rebuild the C++ dependencies and pianod using the same compiler and standards mode.

Rare Mac Troubles

pianod and all libraries must be built with the same architecture. If the dependency libraries are installed but mismatched, you may override the default with export CFLAGS="-arch x86_64" or export CFLAGS="-arch i386".

TLS Configuration

To use transport layer encryption, you must provide certificate and key files. The script create-pianod-tls-cert in the contrib directory will create the necessary files, the certificate issued by a bogus CA. The certificate is for the current hostname, or another host specified as the first parameter.

Reporting Bugs

Report bugs to perette@deviousfish.com

Reporting a crash or hang

Providing useful and accurate information will help track down issues and get them fixed. If nobody reports things, they will stay broken; some bugs only show up on some operating systems or with certain hardware/software configurations. (Although these are written for pianod2, providing the details outlined here will be helpful to most open-source developers.)

First off, don’t rush to report problems; instead, study it and collect details. Vague and unclear reports may not get fixed. So, can you reproduce it? If so, what makes it happen? Does doing it always make it happen, or is it intermittent? Collect a stack dump if you can (see below).

When you’re ready, submit an e-mail to perette@deviousfish.com with:

If you’re experiencing crashes, it would be helpful to capture a snapshot of what’s going on. Thankfully, there are tools to do this.

Capturing Diagnostics on a Mac

On application crash, a Mac automatically captures and logs the details. Look in ~/Library/Logs/DiagnosticReports; the files will be named pianod_year_mo_da_number_hostname.crash. Attach them to your report.

You can generate a diagnostic report for a stuck process with kill -ABRT <pid>

If you can’t see the Library folder in your home folder, open Finder and Go→Go to Folder and type in/cut-and-paste the above folder name. Find the report in there and mail it in.

Building for debugging

If you don’t know how to do this, you may skip this step—but if you compiled and installed your own software, then building a debug-friendly variant is straightforward and makes troubleshooting much easier. Please do it if you can. pianod’s configure script has an –enable-debug option; simply ./configure --enable-debug then make again, and make install if you want to install it.

Capturing a Stack Dump

To capture a stack dump, use gdb, the GNU debugger.

For a hang, attach to an existing process:

ps x | grep pianod
50942   ??  S      8:50.40 /usr/local/bin/pianod
gdb -p 50942

For crashes, start pianod from gdb:

gdb /usr/local/bin/pianod _add your normal pianod options here_
run

When pianod crashes, gdb will report this and give you a command prompt. (If you want to capture a hang this way, press control-C when pianod has hung.)

Now, in the gdb console, do the following: (For more on gdb, see the GDB Cheat sheet.)

info args
info locals
info variables
info threads
info signals
thread apply all where full

Cut-and-paste from the gdb window to your bug report and mail it in.

Security Implications

As with all network server applications, pianod should be considered a security risk out of paranoia: there may be undiscovered bugs or exploits in pianod or any of the libraries on which it is built. To minimize risk should it be compromised, pianod should be run as a unique, low- or non-privileged user account.

Passwords

User passwords are stored using OS-provided, one-way encryption with salt. They cannot be decrypted, although dictionary/brute-force attacks apply as they do to the underlying operating system.

Music service passwords for “remembered” sources, however, are stored in the user data file using a custom symetric encryption algorithm using a per-user key, and are easily decrypted. Users should use a unique password for any music password they register.

For these reasons, limiting access to the user data file (by chmoding the directory, or running pianod with a 077 umask) is recommended.

HTTP Server

The HTTP server does not create files. If a directory is requested, its index.html is provided (or a 404 occurs); directory contents are not listed. Requests to higher-level directories (http://myserver/../../../Documents/myprivatething.txt) are rejected, preventing download of arbitrary data for simple cases.

If canonicalize_file_name or realpath are available, served files are validated to ensure they are contained in the served directory after any symbolic links are resolved. If neither function is available, a well-placed symbolic link (such as myexploit -> /) could open a security hole subsequently used to retrieve arbitrary data.

Starting pianod2

Configuration files location

pianod stores several files in a configuration directory, the configuration of which is set by:

Configuration files

On startup, pianod2 reads its startscript, executing the command therein as a pianod administrator. The file uses the same syntax and commands as the socket interface. A sample startscript is provided in the contrib directory.

pianod also has a user data file, passwd. If the file does not exist, a single user admin (password admin) is created. This user is persisted, so once you create your own administrator account be sure to delete admin.

Launching at boot or login

Unlike older UNIX daemons, pianod does not use fork(2)/exec(2) or daemon(3) on startup. Supplied sample configuration files expect pianod to be installed in /usr/local/bin; if this is not right you will need to revise the files when installing.

If pianod is started as root, after establishing the listener socket, pianod drops root privileges and takes on a user persona, by default the user ‘nobody’. It also adopts the user’s groups. To allow data to be persisted, the configuration directory is (re)assigned to this user. The user can be selected via -n; -n root will allow pianod to retain root privileges. Using -n root may be a useful troubleshooting tool, but running any network-based service as root is risky.

The -g option can be used to specify a comma-separated list of groups instead of nobody’s groups. Some platforms have a group music or audio to which users must belong to be able to open audio ports.

pianod must not be installed setuid. Using a combination of -d and -n options, a malicious user could arbitrarily reassign file ownership.

On OS X:

On Linux with systemd(8):

On systems using /etc/init.d scripts:

For systems that use init without /etc/init.d, you’ll need to edit the inittab file. Add this to /etc/inittab:

pd:23:respawn:su - username -c /usr/local/bin/pianod

On Windows, you are on your own.

Start Options

See the pianod(1) manual page for the full list of command line options.


  1. See C++ Support in Clang. Clang 8 has been tested; I have no empirical data on earlier versions.  ↩︎

  2. See C++ Standards Support in GCC. GCC 6 has been tested; I have no empiricial data on earlier versions.  ↩︎