Add Meson build system support (#300)

diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..942bbed
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,219 @@
+# Project definition
+project('usrsctplib', 'c',
+    version: '1.0.0',
+    default_options: ['c_std=c99'],
+    meson_version: '>=0.49.0')
+
+# Set compiler warning flags
+compiler = meson.get_compiler('c')
+if compiler.get_argument_syntax() == 'msvc'
+    compiler_args = compiler.get_supported_arguments([
+        '/wd4100', # 'identifier' : unreferenced formal parameter
+        '/wd4127', # conditional expression is constant
+        '/wd4200', # nonstandard extension used : zero-sized array in struct/union
+        '/wd4214', # bit field types other than int
+        '/wd4706', # assignment within conditional expression
+        '/wd4245', # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
+        '/wd4389', # 'operator' : signed/unsigned mismatch
+        '/wd4702', # unreachable code
+        '/wd4701', # Potentially uninitialized local variable 'name' used
+        '/wd4244', # 'conversion' conversion from 'type1' to 'type2', possible loss of data
+    ])
+else
+    compiler_args = compiler.get_supported_arguments([
+        '-pedantic',
+        '-Wall',
+        '-Wextra',
+        '-Wfloat-equal',
+        '-Wshadow',
+        '-Wpointer-arith',
+        '-Winit-self',
+        '-Wno-unused-function',
+        '-Wno-unused-parameter',
+        '-Wno-unreachable-code',
+        '-Wstrict-prototypes',
+    ])
+endif
+add_project_arguments(compiler_args, language: 'c')
+
+# Configuration
+compile_args = []
+
+# Dependency: Threads
+thread_dep = dependency('threads', required: true)
+
+# Dependencies list
+dependencies = [
+    thread_dep,
+]
+
+# Global settings
+add_project_arguments([
+    '-D__Userspace__',
+    '-DSCTP_SIMPLE_ALLOCATOR',
+    '-DSCTP_PROCESS_LEVEL_LOCKS',
+], language: 'c')
+
+# OS-specific settings
+system = host_machine.system()
+if system == 'linux'
+    add_project_arguments([
+        '-D__Userspace_os_Linux',
+        '-D_GNU_SOURCE',
+    ], language: 'c')
+elif system == 'freebsd'
+    add_project_arguments([
+        '-D__Userspace_os_FreeBSD',
+        '-U__FreeBSD__',
+    ] + compiler.get_supported_arguments([
+        '-Wno-address-of-packed-member',
+    ]), language: 'c')
+elif system == 'darwin'
+    add_project_arguments([
+            '-D__Userspace_os_Darwin',
+            '-U__APPLE__',
+            '-D__APPLE_USE_RFC_2292',
+        ] + compiler.get_supported_arguments([
+            '-Wno-address-of-packed-member',
+            '-Wno-deprecated-declarations',
+        ]), language: 'c')
+elif system == 'dragonfly'
+    add_project_arguments([
+        '-D__Userspace_os_DragonFly',
+        '-U__DragonFly__',
+    ], language: 'c')
+elif system == 'netbsd'
+    add_project_arguments([
+        '-D__Userspace_os_NetBSD',
+        '-U__NetBSD__',
+    ], language: 'c')
+elif system == 'openbsd'
+    add_project_arguments([
+        '-D__Userspace_os_OpenBSD',
+        '-U__OpenBSD__',
+    ], language: 'c')
+elif system == 'windows'
+    add_project_arguments('-D__Userspace_os_Windows', language: 'c')
+    dependencies += compiler.find_library('ws2_32', required: true)
+    dependencies += compiler.find_library('iphlpapi', required: true)
+    if compiler.get_id() == 'gcc'
+        add_project_arguments(compiler.get_supported_arguments([
+            '-Wno-format',
+            '-D_WIN32_WINNT=0x601',  # Enables inet_ntop and friends
+        ]), language: 'c')
+    endif
+else
+    error('Unknown system: @0@'.format(system))
+endif
+
+# Feature: sys/queue
+if compiler.has_header('sys/queue.h')
+    add_project_arguments('-DHAVE_SYS_QUEUE_H', language: 'c')
+endif
+
+# Feature: sys/socket, linux/ifaddr, linux/rtnetlink
+if compiler.has_header('sys/socket.h')
+    if compiler.has_header('linux/if_addr.h')
+        add_project_arguments('-DHAVE_LINUX_IF_ADDR_H', language: 'c')
+    endif
+
+    if compiler.has_header('linux/rtnetlink.h')
+        add_project_arguments('-DHAVE_LINUX_RTNETLINK_H', language: 'c')
+    endif
+endif
+
+# Feature: ICMP
+have_sys_types = compiler.has_header('sys/types.h')
+have_netinet_in = compiler.has_header('netinet/in.h')
+have_netinet_ip = compiler.has_header('netinet/ip.h')
+have_netinet_ip_icmp = compiler.has_header('netinet/ip_icmp.h')
+if have_sys_types and have_netinet_in and have_netinet_ip and have_netinet_ip_icmp
+    add_project_arguments('-DHAVE_NETINET_IP_ICMP_H', language: 'c')
+endif
+
+# Feature: stdatomic
+if compiler.has_header('stdatomic.h')
+    add_project_arguments('-DHAVE_STDATOMIC_H', language: 'c')
+endif
+
+# Feature: sockaddr.sa_len
+prefix = '''
+#include <sys/types.h>
+#include <sys/socket.h>
+'''
+have_sa_len = compiler.has_member('struct sockaddr', 'sa_len', prefix: prefix)
+if have_sa_len
+    add_project_arguments('-DHAVE_SA_LEN', language: 'c')
+endif
+
+# Feature: sockaddr_in.sin_len / sockaddr_in6.sin6_len / sockaddr_conn.sconn_len
+prefix = '''
+#include <sys/types.h>
+#include <netinet/in.h>
+'''
+have_sin_len = compiler.has_member('struct sockaddr_in', 'sin_len', prefix: prefix)
+if have_sin_len
+    add_project_arguments('-DHAVE_SIN_LEN', language: 'c')
+endif
+have_sin6_len = compiler.has_member('struct sockaddr_in6', 'sin6_len', prefix: prefix)
+if have_sin6_len
+    add_project_arguments('-DHAVE_SIN6_LEN', language: 'c')
+endif
+have_sconn_len = compiler.has_member('struct sockaddr_conn', 'sconn_len', prefix: '#include "usrsctp.h"')
+if have_sconn_len
+    add_project_arguments('-DHAVE_SCONN_LEN', language: 'c')
+endif
+
+# Options
+if get_option('sctp_invariants')
+    add_project_arguments('-DINVARIANTS', language: 'c')
+endif
+if get_option('sctp_debug')
+    add_project_arguments('-DSCTP_DEBUG', language: 'c')
+    compile_args += '-DSCTP_DEBUG'
+endif
+if get_option('sctp_inet')
+    add_project_arguments('-DINET', language: 'c')
+endif
+if get_option('sctp_inet6')
+    add_project_arguments('-DINET6', language: 'c')
+endif
+
+# Library
+subdir('usrsctplib')
+
+# Build library
+usrsctp = library('usrsctp', sources,
+    dependencies: dependencies,
+    include_directories: include_dirs,
+    install: true,
+    version: meson.project_version())
+
+# Declare dependency
+usrsctp_dep = declare_dependency(
+    compile_args: compile_args,
+    include_directories: include_dirs,
+    link_with: usrsctp)
+
+# Generate pkg-config file
+pkg = import('pkgconfig')
+pkg.generate(usrsctp,
+    name: 'usrsctp',
+    description: 'A portable SCTP userland stack',
+    url: 'https://github.com/sctplab/usrsctp',
+    extra_cflags: compile_args)
+
+# Programs (optional)
+if get_option('sctp_build_programs')
+    subdir('programs')
+
+    # Build executables
+    foreach name, sources : programs
+        executable(
+            name,
+            programs_helper_sources + sources,
+            dependencies: dependencies,
+            link_with: usrsctp,
+            include_directories: include_dirs)
+    endforeach
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..56d9506
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,10 @@
+option('sctp_invariants', type: 'boolean', value: false,
+    description: 'Add runtime checks')
+option('sctp_debug', type: 'boolean', value: false,
+    description: 'Provide debug information')
+option('sctp_inet', type: 'boolean', value: true,
+    description: 'Support IPv4')
+option('sctp_inet6', type: 'boolean', value: true,
+    description: 'Support IPv6')
+option('sctp_build_programs', type: 'boolean', value: true,
+    description: 'Build example programs')
diff --git a/programs/meson.build b/programs/meson.build
new file mode 100644
index 0000000..daed941
--- /dev/null
+++ b/programs/meson.build
@@ -0,0 +1,28 @@
+# Helper sources for all programs
+programs_helper_sources = files('programs_helper.c')
+
+# Programs and their sources
+programs = {
+    'chargen_server_upcall': files('chargen_server_upcall.c'),
+    'client': files('client.c'),
+    'client_upcall': files('client_upcall.c'),
+    'daytime_server': files('daytime_server.c'),
+    'daytime_server_upcall': files('daytime_server_upcall.c'),
+    'discard_server': files('discard_server.c'),
+    'discard_server_upcall': files('discard_server_upcall.c'),
+    'echo_server': files('echo_server.c'),
+    'echo_server_upcall': files('echo_server_upcall.c'),
+    'ekr_client': files('ekr_client.c'),
+    'ekr_loop': files('ekr_loop.c'),
+    'ekr_loop_offload': files('ekr_loop_offload.c'),
+    'ekr_loop_upcall': files('ekr_loop_upcall.c'),
+    'ekr_peer': files('ekr_peer.c'),
+    'ekr_server': files('ekr_server.c'),
+    'http_client': files('http_client.c'),
+    'http_client_upcall': files('http_client_upcall.c'),
+    'rtcweb': files('rtcweb.c'),
+    'test_libmgmt': files('test_libmgmt.c'),
+    'test_timer': files('test_timer.c'),
+    'tsctp': files('tsctp.c'),
+}
+
diff --git a/usrsctplib/meson.build b/usrsctplib/meson.build
new file mode 100644
index 0000000..c1a6656
--- /dev/null
+++ b/usrsctplib/meson.build
@@ -0,0 +1,20 @@
+# Includes
+include_dirs = include_directories(
+    '.',
+    'netinet',
+    'netinet6',
+)
+
+# Sources
+sources = files([
+    'user_environment.c',
+    'user_mbuf.c',
+    'user_recv_thread.c',
+    'user_socket.c',
+])
+
+subdir('netinet')
+subdir('netinet6')
+
+# Install usrsctp.h
+install_headers('usrsctp.h')
diff --git a/usrsctplib/netinet/meson.build b/usrsctplib/netinet/meson.build
new file mode 100644
index 0000000..4a86615
--- /dev/null
+++ b/usrsctplib/netinet/meson.build
@@ -0,0 +1,20 @@
+sources += files([
+    'sctp_asconf.c',
+    'sctp_auth.c',
+    'sctp_bsd_addr.c',
+    'sctp_callout.c',
+    'sctp_cc_functions.c',
+    'sctp_crc32.c',
+    'sctp_indata.c',
+    'sctp_input.c',
+    'sctp_output.c',
+    'sctp_pcb.c',
+    'sctp_peeloff.c',
+    'sctp_sha1.c',
+    'sctp_ss_functions.c',
+    'sctp_sysctl.c',
+    'sctp_timer.c',
+    'sctp_userspace.c',
+    'sctp_usrreq.c',
+    'sctputil.c',
+])
diff --git a/usrsctplib/netinet6/meson.build b/usrsctplib/netinet6/meson.build
new file mode 100644
index 0000000..04307df
--- /dev/null
+++ b/usrsctplib/netinet6/meson.build
@@ -0,0 +1 @@
+sources += files('sctp6_usrreq.c')