summaryrefslogtreecommitdiffstats
path: root/hw4/chttpd
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2014-01-14 01:15:02 +0800
committerLAN-TW <lantw44@gmail.com>2014-01-14 01:15:02 +0800
commit5873050be326f8b645b994d8c5e8b266573a6e40 (patch)
tree46ec76ae4fddc68974fee549cc6d530d408bd044 /hw4/chttpd
parentd045ff1806eb429a2c06203dfda165a21dad14ab (diff)
downloadsp2013-5873050be326f8b645b994d8c5e8b266573a6e40.tar
sp2013-5873050be326f8b645b994d8c5e8b266573a6e40.tar.gz
sp2013-5873050be326f8b645b994d8c5e8b266573a6e40.tar.bz2
sp2013-5873050be326f8b645b994d8c5e8b266573a6e40.tar.lz
sp2013-5873050be326f8b645b994d8c5e8b266573a6e40.tar.xz
sp2013-5873050be326f8b645b994d8c5e8b266573a6e40.tar.zst
sp2013-5873050be326f8b645b994d8c5e8b266573a6e40.zip
HW4: 基本的接聽連線功能
Diffstat (limited to 'hw4/chttpd')
-rw-r--r--hw4/chttpd/chttpd-log.c117
-rw-r--r--hw4/chttpd/chttpd-log.h34
-rw-r--r--hw4/chttpd/chttpd-server.c279
-rw-r--r--hw4/chttpd/chttpd-server.h29
-rw-r--r--hw4/chttpd/chttpd-socket.c120
-rw-r--r--hw4/chttpd/chttpd-socket.h22
6 files changed, 601 insertions, 0 deletions
diff --git a/hw4/chttpd/chttpd-log.c b/hw4/chttpd/chttpd-log.c
new file mode 100644
index 0000000..7214a29
--- /dev/null
+++ b/hw4/chttpd/chttpd-log.c
@@ -0,0 +1,117 @@
+/* b01902062 藍挺瑋 */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "chttpd-log.h"
+#include "memwrap.h"
+#include <l4list.h>
+#include <l4posix.h>
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+ChttpdLog* chttpd_log_new (const char* name, int log_fd) {
+ char* name_start = strrchr (name, '/');
+ name = name_start == NULL ? name : name_start + 1;
+ size_t name_len = (name == NULL) ? 0 : strlen (name);
+ char* mem = xmalloc (sizeof (ChttpdLog) + name_len + 1);
+ void* mem_generic = mem;
+
+ ChttpdLog* hlog = mem_generic;
+ hlog->name = mem + sizeof (ChttpdLog);
+ if (name != NULL) {
+ strncpy (hlog->name, name, name_len + 1);
+ }
+ hlog->name[name_len] = '\0';
+
+ hlog->ref_count = 1;
+ hlog->pid = getpid ();
+ hlog->log_fd = log_fd;
+ hlog->log_data = lbs_list_meta_new (free);
+ pthread_cond_init (&hlog->ref_change, NULL);
+ pthread_mutex_init (&hlog->ref_mutex, NULL);
+ pthread_rwlock_init (&hlog->log_lock, NULL);
+
+ return hlog;
+}
+
+ChttpdLog* chttpd_log_new_file (const char* name, const char* file) {
+ int log_fd = open (file, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0600);
+ if (log_fd < 0) {
+ return NULL;
+ }
+
+ return chttpd_log_new (name, log_fd);
+}
+
+ChttpdLog* chttpd_log_ref (ChttpdLog* hlog) {
+ pthread_mutex_lock (&hlog->ref_mutex);
+ hlog->ref_count++;
+ pthread_mutex_unlock (&hlog->ref_mutex);
+ pthread_cond_broadcast (&hlog->ref_change);
+ return hlog;
+}
+
+void chttpd_log_unref (ChttpdLog* hlog) {
+ pthread_mutex_lock (&hlog->ref_mutex);
+ hlog->ref_count--;
+ if (hlog->ref_count <= 0) {
+ /* No thread has a reference on hlog, so we are going to destory it */
+ pthread_mutex_unlock (&hlog->ref_mutex);
+ pthread_mutex_destroy (&hlog->ref_mutex);
+ pthread_cond_destroy (&hlog->ref_change);
+ pthread_rwlock_destroy (&hlog->log_lock);
+ lbs_list_meta_free (hlog->log_data);
+ free (hlog);
+ } else {
+ pthread_mutex_unlock (&hlog->ref_mutex);
+ pthread_cond_broadcast (&hlog->ref_change);
+ }
+}
+
+int chttpd_log_read_start (ChttpdLog* hlog) {
+ return pthread_rwlock_tryrdlock (&hlog->log_lock);
+}
+
+void chttpd_log_read_stop (ChttpdLog* hlog) {
+ pthread_rwlock_unlock (&hlog->log_lock);
+}
+
+size_t chttpd_log_write (ChttpdLog* hlog, const char* format, ...) {
+ va_list ap;
+ char* str;
+ size_t r;
+
+ va_start (ap, format);
+ str = lbs_str_vprintf (format, ap);
+ va_end (ap);
+
+ r = chttpd_log_write_str (hlog, str);
+ free (str);
+ return r;
+}
+
+size_t chttpd_log_write_str (ChttpdLog* hlog, const char* string) {
+ time_t t;
+ struct tm tmd;
+ char* msg;
+ size_t r;
+
+ time (&t);
+ localtime_r (&t, &tmd);
+ msg = lbs_str_printf ("%04d-%02d-%02d %02d:%02d:%02d %s[%ld]: %s\n",
+ tmd.tm_year + 1900, tmd.tm_mon + 1, tmd.tm_mday,
+ tmd.tm_hour, tmd.tm_min, tmd.tm_sec,
+ hlog->name, (long)(hlog->pid), string);
+
+ pthread_rwlock_wrlock (&hlog->log_lock);
+ lbs_list_push_back (hlog->log_data, msg, NULL);
+ r = lbs_posix_write_all (hlog->log_fd, msg, 0);
+ pthread_rwlock_unlock (&hlog->log_lock);
+
+ return r;
+}
diff --git a/hw4/chttpd/chttpd-log.h b/hw4/chttpd/chttpd-log.h
new file mode 100644
index 0000000..ff57ad0
--- /dev/null
+++ b/hw4/chttpd/chttpd-log.h
@@ -0,0 +1,34 @@
+#ifndef CHTTPD_LOG_H
+#define CHTTPD_LOG_H
+
+#include <l4list.h>
+
+#include <stddef.h>
+#include <pthread.h>
+#include <sys/types.h>
+
+typedef struct {
+ /* read-only */
+ char* name;
+ pid_t pid;
+ int log_fd;
+
+ /* read-write and lock */
+ unsigned ref_count;
+ pthread_cond_t ref_change;
+ pthread_mutex_t ref_mutex;
+ LbsListMeta* log_data;
+ pthread_rwlock_t log_lock;
+} ChttpdLog;
+
+ChttpdLog* chttpd_log_new (const char* name, int log_fd);
+ChttpdLog* chttpd_log_new_file (const char* name, const char* file);
+ChttpdLog* chttpd_log_ref (ChttpdLog* hlog);
+void chttpd_log_unref (ChttpdLog* hlog);
+
+int chttpd_log_read_start (ChttpdLog* hlog);
+void chttpd_log_read_stop (ChttpdLog* hlog);
+size_t chttpd_log_write (ChttpdLog* hlog, const char* format, ...);
+size_t chttpd_log_write_str (ChttpdLog* hlog, const char* string);
+
+#endif /* CHTTPD_LOG_H */
diff --git a/hw4/chttpd/chttpd-server.c b/hw4/chttpd/chttpd-server.c
new file mode 100644
index 0000000..d5c0337
--- /dev/null
+++ b/hw4/chttpd/chttpd-server.c
@@ -0,0 +1,279 @@
+/* b01902062 藍挺瑋 */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "memwrap.h"
+#include "chttpd-log.h"
+#include "chttpd-server.h"
+#include "chttpd-socket.h"
+#include <l4list.h>
+#include <l4str.h>
+#include <l4posix.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#define NULLPTR ((void*)0)
+#define SOCKADDR(x) ((struct sockaddr*)(x))
+#define SOCKADDR_UN(x) ((struct sockaddr_un*)(x))
+#define SOCKADDR_IN(x) ((struct sockaddr_in*)(x))
+#define SOCKADDR_IN6(x) ((struct sockaddr_in6*)(x))
+
+static inline void report_unix_error (int rval) {
+ int errno_backup = errno;
+ switch (rval) {
+ case CHTTPD_SOCKET_NEW_ERROR_SOCKET:
+ fputs ("socket: ", stdout);
+ break;
+ case CHTTPD_SOCKET_NEW_ERROR_BIND:
+ fputs ("bind: ", stdout);
+ break;
+ }
+ puts (strerror (errno_backup));
+ errno_backup = errno;
+}
+
+static inline bool init_runtime_dir (ChttpdServer* server,
+ const char* dir, const char* ctrl, const char* pid) {
+
+ printf ("Trying %s ... ", ctrl);
+ fflush (stdout);
+
+ mkdir (dir, 0700);
+
+ struct stat st;
+ char* chttpd_force = getenv ("CGISH_HTTPD_FORCE");
+ if (chttpd_force != NULL && *chttpd_force != '\0') {
+ if (stat (ctrl, &st) >= 0) {
+ if (S_ISSOCK (st.st_mode)) {
+ unlink (ctrl);
+ }
+ }
+ }
+
+ server->sockfd = chttpd_socket_new_unix (ctrl,
+ SOCKADDR_UN (&server->addr), &server->addrlen);
+ if (server->sockfd < 0) {
+ report_unix_error (server->sockfd);
+ return false;
+ }
+
+ int pidfd = open (pid, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if (pidfd >= 0) {
+ dprintf (pidfd, "%ld", ((long)getpid ()));
+ close (pidfd);
+ }
+
+ puts ("OK");
+ return true;
+}
+
+static inline void report_inet_error (int rval, int gai_error) {
+ int errno_backup = errno;
+ switch (rval) {
+ case CHTTPD_SOCKET_NEW_ERROR_GETADDRINFO:
+ fputs ("getaddrinfo: ", stdout);
+ puts (gai_strerror (gai_error));
+ break;
+ case CHTTPD_SOCKET_NEW_ERROR_SOCKET:
+ fputs ("socket: ", stdout);
+ puts (strerror (errno_backup));
+ break;
+ case CHTTPD_SOCKET_NEW_ERROR_BIND:
+ fputs ("bind: ", stdout);
+ puts (strerror (errno_backup));
+ break;
+ case CHTTPD_SOCKET_NEW_ERROR_UNEXPECTED:
+ puts ("Unexpected error! Is your system broken?");
+ break;
+ }
+ errno_backup = errno;
+}
+
+static LbsListMeta* chttpd_main_init (ChttpdLog* hlog, const char* service) {
+ ChttpdServer* server;
+ LbsListMeta* slist = lbs_list_meta_new (chttpd_server_dtor);
+ int gai_error;
+
+ /* Default: Unix socket (ADMIN) */
+ bool unix_ok = false;
+ uid_t uid = getuid ();
+ server = xmalloc (sizeof (ChttpdServer));
+ if (uid == 0) {
+ /* System runtime */
+ char dir[] = "/var/run/" PACKAGE_NAME;
+ char ctrl[] = "/var/run/" PACKAGE_NAME "/control";
+ char pid[] = "/var/run/" PACKAGE_NAME "/pid";
+ unix_ok = init_runtime_dir (server, dir, ctrl, pid);
+ }
+
+ if (!unix_ok) {
+ /* User XDG runtime */
+ char* xdg_dir = getenv ("XDG_RUNTIME_DIR");
+ if (xdg_dir != NULL && *xdg_dir != '\0') {
+ char* dir = lbs_posix_strcat (xdg_dir, "/" PACKAGE_NAME, NULLPTR);
+ char* ctrl = lbs_posix_strcat (dir, "/control", NULLPTR);
+ char* pid = lbs_posix_strcat (dir, "/pid", NULLPTR);
+ unix_ok = init_runtime_dir (server, dir, ctrl, pid);
+ free (dir);
+ free (ctrl);
+ free (pid);
+ }
+ }
+
+ if (!unix_ok) {
+ /* Just guess user XDG dir ! */
+ char* xdg_dir = lbs_str_printf ("/run/user/%lu", (unsigned long)uid);
+ char* dir = lbs_posix_strcat (xdg_dir, "/" PACKAGE_NAME, NULLPTR);
+ char* ctrl = lbs_posix_strcat (dir, "/control", NULLPTR);
+ char* pid = lbs_posix_strcat (dir, "/pid", NULLPTR);
+ unix_ok = init_runtime_dir (server, dir, ctrl, pid);
+ free (xdg_dir);
+ free (dir);
+ free (ctrl);
+ free (pid);
+ }
+
+ if (!unix_ok) {
+ /* Fallback to XDG_CONFIG_HOME and current working directory */
+ char* xdg_dir = getenv ("XDG_CONFIG_HOME");
+ bool xdg_dir_alloc = false;
+ if (xdg_dir == NULL || *xdg_dir == '\0') {
+ char* home = getenv ("HOME");
+ if (home == NULL || *home == '\0') {
+ home = ".";
+ }
+
+ xdg_dir = lbs_posix_strcat (home, "/.config", LBS_COMMON_NULL_PTR);
+ xdg_dir_alloc = true;
+ }
+
+ char* dir = lbs_posix_strcat (xdg_dir, "/" PACKAGE_NAME, NULLPTR);
+ char* ctrl = lbs_posix_strcat (dir, "/control", NULLPTR);
+ char* pid = lbs_posix_strcat (dir, "/pid", NULLPTR);
+ unix_ok = init_runtime_dir (server, dir, ctrl, pid);
+ if (xdg_dir_alloc) {
+ free (xdg_dir);
+ }
+ free (dir);
+ free (ctrl);
+ free (pid);
+ }
+
+ if (unix_ok) {
+ chttpd_server_ctor (server, hlog, true);
+ lbs_list_push_back (slist, server, NULL);
+ } else {
+ free (server);
+ }
+
+ /* Default: IPv4 socket (HTTP) */
+ server = xmalloc (sizeof (ChttpdServer));
+ printf ("Trying IPv4 any host, service %s ... ", service);
+ server->sockfd = chttpd_socket_new_inet (NULL, service, AF_INET,
+ SOCKADDR (&server->addr), &server->addrlen, &gai_error);
+ if (server->sockfd >= 0) {
+ puts ("OK");
+ chttpd_server_ctor (server, hlog, false);
+ lbs_list_push_back (slist, server, NULL);
+ } else {
+ report_inet_error (server->sockfd, gai_error);
+ free (server);
+ }
+
+ /* Default: IPv6 socket (HTTP) */
+ server = xmalloc (sizeof (ChttpdServer));
+ printf ("Trying IPv6 any host, service %s ... ", service);
+ server->sockfd = chttpd_socket_new_inet (NULL, service, AF_INET6,
+ SOCKADDR (&server->addr), &server->addrlen, &gai_error);
+ if (server->sockfd >= 0) {
+ puts ("OK");
+ chttpd_server_ctor (server, hlog, false);
+ lbs_list_push_back (slist, server, NULL);
+ } else {
+ report_inet_error (server->sockfd, gai_error);
+ free (server);
+ }
+
+ return slist;
+}
+
+int chttpd_server_notify;
+pthread_mutex_t chttpd_server_notify_mutex;
+
+static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) {
+ chttpd_server_notify = 1;
+ pthread_mutex_init (&chttpd_server_notify_mutex, NULL);
+
+
+}
+
+void chttpd_server_ctor (void* server_generic, ChttpdLog* hlog, bool is_admin) {
+ ChttpdServer* server = server_generic;
+ server->attr_admin = is_admin;
+ server->attr_close = false;
+ server->hlog = chttpd_log_ref (hlog);
+ server->conn = lbs_list_meta_new (NULL);
+ pthread_rwlock_init (&server->lock, NULL);
+}
+
+void chttpd_server_dtor (void* server_generic) {
+ ChttpdServer* server = server_generic;
+ if (server->addr.ss_family == AF_UNIX) {
+ CHTTPD_SOCKET_SOCKADDR_UN_SET_NULL (SOCKADDR_UN (&server->addr));
+ unlink (SOCKADDR_UN (&server->addr)->sun_path);
+ }
+ close (server->sockfd);
+ pthread_rwlock_destroy (&server->lock);
+ lbs_list_meta_free (server->conn);
+ free (server);
+}
+
+int main (int argc, char* argv[]) {
+ setlocale (LC_ALL, "");
+ tzset ();
+
+ if (argc < 3) {
+ fprintf (stderr, "Usage: %s port logfile\n", argv[0]);
+ return 1;
+ }
+
+ ChttpdLog* hlog = chttpd_log_new_file (argv[0], argv[2]);
+ if (hlog == NULL) {
+ fprintf (stderr, "Error while opening %s: %s\n",
+ argv[2], strerror (errno));
+ return 2;
+ }
+
+ LbsListMeta* slist = chttpd_main_init (hlog, argv[1]);
+ if (lbs_list_meta_get_len (slist) > 0) {
+ chttpd_main_loop (hlog, slist);
+ } else {
+ puts ("No server is active! Exiting ...");
+ }
+ lbs_list_meta_free (slist);
+
+ chttpd_log_write_str (hlog, "Waiting for all threads to terminate");
+
+ pthread_mutex_lock (&hlog->ref_mutex);
+ while (hlog->ref_count > 1) {
+ pthread_cond_wait (&hlog->ref_change, &hlog->ref_mutex);
+ }
+ pthread_mutex_unlock (&hlog->ref_mutex);
+
+ chttpd_log_write_str (hlog, "All threads terminated. Exit now!");
+ chttpd_log_unref (hlog);
+
+ return 0;
+}
diff --git a/hw4/chttpd/chttpd-server.h b/hw4/chttpd/chttpd-server.h
new file mode 100644
index 0000000..1fd6f7c
--- /dev/null
+++ b/hw4/chttpd/chttpd-server.h
@@ -0,0 +1,29 @@
+#ifndef CHTTPD_SERVER_H
+#define CHTTPD_SERVER_H
+
+#include <l4list.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+
+typedef struct {
+ /* read-only */
+ int sockfd;
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ int attr_admin : 1;
+
+ /* read-write and lock */
+ pthread_rwlock_t lock;
+ ChttpdLog* hlog;
+ LbsListMeta* conn;
+ int attr_close : 1;
+} ChttpdServer;
+
+extern int chttpd_server_notify;
+extern pthread_mutex_t chttpd_server_notify_mutex;
+
+void chttpd_server_ctor (void* server_generic, ChttpdLog* hlog, bool is_admin);
+void chttpd_server_dtor (void* server_generic);
+
+#endif /* CHTTPD_SERVER_H */
diff --git a/hw4/chttpd/chttpd-socket.c b/hw4/chttpd/chttpd-socket.c
new file mode 100644
index 0000000..cd1ff2e
--- /dev/null
+++ b/hw4/chttpd/chttpd-socket.c
@@ -0,0 +1,120 @@
+/* b01902062 藍挺瑋 */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "chttpd-socket.h"
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#define SOCKADDR(x) ((struct sockaddr*)(x))
+#define SOCKLEN(x) ((socklen_t)(x))
+
+int chttpd_socket_new_unix (const char* path,
+ struct sockaddr_un* saddr, socklen_t* saddrlen) {
+
+ struct sockaddr_un addr;
+ socklen_t addrlen = sizeof (addr);
+ size_t pathlen;
+
+ memset (&addr, 0, sizeof (addr));
+ pathlen = sizeof (addr) - offsetof (struct sockaddr_un, sun_path) - 1;
+ addr.sun_family = AF_UNIX;
+ strncpy (addr.sun_path, path, pathlen);
+
+ int sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sockfd < 0) {
+ return CHTTPD_SOCKET_NEW_ERROR_SOCKET;
+ }
+ if (bind (sockfd, SOCKADDR (&addr), addrlen) < 0) {
+ close (sockfd);
+ return CHTTPD_SOCKET_NEW_ERROR_BIND;
+ }
+
+ if (saddr != NULL) {
+ *saddr = addr;
+ }
+ if (saddrlen != NULL) {
+ *saddrlen = addrlen;
+ }
+
+ return sockfd;
+}
+
+int chttpd_socket_new_inet (const char* host, const char* service, int domain,
+ struct sockaddr* saddr, socklen_t* saddrlen, int* error) {
+
+ if (service == NULL) {
+ service = "http";
+ }
+ if (domain != AF_INET && domain != AF_INET6) {
+ domain = AF_UNSPEC;
+ }
+
+ struct addrinfo hints, *result;
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = domain;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+
+ int gai_error = getaddrinfo (host, service, &hints, &result);
+ if (gai_error != 0) {
+ if (error != NULL) {
+ *error = gai_error;
+ }
+ return CHTTPD_SOCKET_NEW_ERROR_GETADDRINFO;
+ }
+
+ int sockfd = -1;
+ int bindrv = -1;
+ for (struct addrinfo* iter = result; iter != NULL; iter = iter->ai_next) {
+ sockfd = socket (iter->ai_family, SOCK_STREAM, 0);
+ if (sockfd < 0) {
+ continue;
+ }
+
+ if (iter->ai_family == AF_INET6) {
+ setsockopt (sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
+ &(int){ 1 }, sizeof (int));
+ }
+
+ bindrv = bind (sockfd, iter->ai_addr, iter->ai_addrlen);
+ if (bindrv < 0) {
+ close (sockfd);
+ } else {
+ if (saddr != NULL) {
+ switch (iter->ai_family) {
+ case AF_INET:
+ *(struct sockaddr_in*)(saddr) =
+ *(struct sockaddr_in*)(iter->ai_addr);
+ break;
+ case AF_INET6:
+ *(struct sockaddr_in6*)(saddr) =
+ *(struct sockaddr_in6*)(iter->ai_addr);
+ break;
+ default:
+ freeaddrinfo (result);
+ return CHTTPD_SOCKET_NEW_ERROR_UNEXPECTED;
+ }
+ }
+ if (saddrlen != NULL) {
+ *saddrlen = iter->ai_addrlen;
+ }
+ freeaddrinfo (result);
+ return sockfd;
+ }
+ }
+
+ freeaddrinfo (result);
+ if (sockfd < 0) {
+ return CHTTPD_SOCKET_NEW_ERROR_SOCKET;
+ }
+
+ return CHTTPD_SOCKET_NEW_ERROR_BIND;
+}
diff --git a/hw4/chttpd/chttpd-socket.h b/hw4/chttpd/chttpd-socket.h
new file mode 100644
index 0000000..2ac05b6
--- /dev/null
+++ b/hw4/chttpd/chttpd-socket.h
@@ -0,0 +1,22 @@
+#ifndef CHTTPD_SOCKET_H
+#define CHTTPD_SOCKET_H
+
+#include <l4common.h>
+
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#define CHTTPD_SOCKET_NEW_ERROR_GETADDRINFO -1
+#define CHTTPD_SOCKET_NEW_ERROR_SOCKET -2
+#define CHTTPD_SOCKET_NEW_ERROR_BIND -3
+#define CHTTPD_SOCKET_NEW_ERROR_UNEXPECTED -100
+int chttpd_socket_new_unix (const char* path,
+ struct sockaddr_un* saddr, socklen_t* saddrlen);
+int chttpd_socket_new_inet (const char* host, const char* service, int domain,
+ struct sockaddr* saddr, socklen_t* saddrlen, int *e);
+
+#define CHTTPD_SOCKET_SOCKADDR_UN_SET_NULL(x) \
+ (LBS_COMMON_CHECK_TYPE (x, struct sockaddr_un*)->sun_path \
+ [sizeof (struct sockaddr_un) - offsetof (struct sockaddr_un, sun_path) - 1])
+
+#endif /* CHTTPD_SOCKET_H */