├── .gitignore ├── AUTHORS ├── COPYING ├── Makefile.am ├── README.md ├── abi_version.sh ├── autogen.sh ├── configure.ac ├── daemon.c ├── list.c ├── list.h ├── m4 ├── dolt.m4 ├── libtool.m4 ├── ltoptions.m4 ├── ltsugar.m4 ├── ltversion.m4 └── lt~obsolete.m4 ├── package_version.sh ├── tcpmux.c ├── tcpmux.h ├── tcpmux.pc.in └── tests └── e2e.c /.gitignore: -------------------------------------------------------------------------------- 1 | aclocal.m4 2 | autom4te.cache/ 3 | compile 4 | config.guess 5 | config.sub 6 | configure 7 | depcomp 8 | install-sh 9 | ltmain.sh 10 | missing 11 | tcpmuxd 12 | test-driver 13 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Luca Barbato 2 | Martin Lucina 3 | Martin Sustrik 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), 4 | to deal in the Software without restriction, including without limitation 5 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 6 | and/or sell copies of the Software, and to permit persons to whom 7 | the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included 10 | in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 18 | IN THE SOFTWARE. 19 | 20 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Martin Sustrik All rights reserved. 3 | # Copyright (c) 2013 Luca Barbato 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom 10 | # the Software is furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included 13 | # in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | # IN THE SOFTWARE. 22 | 23 | ACLOCAL_AMFLAGS = -I m4 24 | 25 | DISTCLEANFILES = @DOLT_CLEANFILES@ 26 | 27 | ################################################################################ 28 | # tcpmux # 29 | ################################################################################ 30 | 31 | tcpmuxincludedir = $(includedir) 32 | tcpmuxinclude_HEADERS = tcpmux.h 33 | 34 | lib_LTLIBRARIES = libtcpmux.la 35 | 36 | libtcpmux_la_SOURCES = \ 37 | daemon.c\ 38 | list.h\ 39 | list.c\ 40 | tcpmux.c 41 | 42 | pkgconfigdir = $(libdir)/pkgconfig 43 | pkgconfig_DATA = tcpmux.pc 44 | 45 | libtcpmux_la_LDFLAGS = -no-undefined -version-info @TCPMUX_LIBTOOL_VERSION@ 46 | 47 | libtcpmux_la_CFLAGS = \ 48 | -fvisibility=hidden\ 49 | -DTCPMUX_EXPORTS 50 | 51 | ################################################################################ 52 | # automated tests # 53 | ################################################################################ 54 | 55 | check_PROGRAMS = \ 56 | tests/e2e 57 | 58 | LDADD = libtcpmux.la 59 | 60 | TESTS = $(check_PROGRAMS) 61 | 62 | ################################################################################ 63 | # tcpmuxd # 64 | ################################################################################ 65 | 66 | tcpmuxd_SOURCES = tcpmuxd.c 67 | 68 | noinst_PROGRAMS = tcpmuxd 69 | 70 | ################################################################################ 71 | # additional packaging-related stuff # 72 | ################################################################################ 73 | 74 | # Generate ChangeLog file from git. 75 | # Also, there's no git available when building from the source package and 76 | # thus no way to obtain package version. Therefore, package version is 77 | # saved into a file when building a source package. 78 | dist-hook: 79 | @if test -d "$(srcdir)/.git"; \ 80 | then \ 81 | echo Creating ChangeLog; \ 82 | cd "$(top_srcdir)"; \ 83 | (echo '# Generated by Makefile. Do not edit.'; echo; \ 84 | ./missing --run git log --decorate ) > ChangeLog.tmp; \ 85 | mv -f ChangeLog.tmp $(top_distdir)/ChangeLog; \ 86 | rm -f ChangeLog.tmp; \ 87 | else \ 88 | cp -f ChangeLog $(top_distdir)/ChangeLog || \ 89 | echo Failed to generate ChangeLog >&2; \ 90 | fi; \ 91 | $(srcdir)/package_version.sh > $(distdir)/.version 92 | 93 | EXTRA_DIST = \ 94 | ./abi_version.sh \ 95 | ./package_version.sh 96 | 97 | distclean-local: 98 | -rm -f config.h 99 | 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TCPMUX 2 | ====== 3 | 4 | Implementation of TCP multiplexer as defined in 5 | [RFC 1078](https://tools.ietf.org/html/rfc1078). 6 | 7 | The mutliplexer is a stand-alone daemon process that distributes the connections 8 | accepted on a single TCP port (port 1 by default) to other processes on the 9 | same machine. 10 | 11 | The package also contains a libmill-compliant client library. 12 | 13 | To build it you have to install [libmill](http://libmill.org) first. Then: 14 | 15 | ``` 16 | ./autogen.sh 17 | ./configure 18 | make check 19 | sudo make install 20 | ``` 21 | 22 | To start the daemon: 23 | 24 | ``` 25 | sudo tcpmuxd 26 | ``` 27 | 28 | The daemon must be run with sudo because it uses port 1 by default, which 29 | cannot be opened with standard user privilieges. 30 | 31 | If you want to run tcpmuxd without extra privileges, choose a port above 1024: 32 | 33 | ``` 34 | tcpmuxd 5555 35 | ``` 36 | 37 | Once the daemon is running, application can listen for incoming tcpmux 38 | connections. Here's an example application implementing service "foo". 39 | It uses tcpmuxd running on port 5555: 40 | 41 | ``` 42 | #include 43 | 44 | ... 45 | 46 | tcpmuxsock ls = tcpmuxlisten(5555, "foo", -1); 47 | while(1) { 48 | tcpsock s = tcpmuxaccept(ls, -1); 49 | ... 50 | } 51 | ``` 52 | 53 | Client applications can connect to tcpmux server from anywhere. There's no 54 | requirement to run tcpmuxd on the client box: 55 | 56 | ``` 57 | #include 58 | 59 | ... 60 | 61 | ipaddr addr = ipremote("192.168.0.111", 5555, 0, -1); 62 | tcpsock s = tcpmuxconnect(addr, "foo", -1); 63 | ``` 64 | 65 | The software is licensed under MIT/X11 license. 66 | 67 | -------------------------------------------------------------------------------- /abi_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright (c) 2013 Luca Barbato 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom 10 | # the Software is furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included 13 | # in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | # IN THE SOFTWARE. 22 | 23 | if [ ! -f tcpmux.h ]; then 24 | echo "abi_version.sh: error: tcpmux.h does not exist" 1>&2 25 | exit 1 26 | fi 27 | 28 | CURRENT=`egrep '^#define +TCPMUX_VERSION_CURRENT +[0-9]+$' tcpmux.h` 29 | REVISION=`egrep '^#define +TCPMUX_VERSION_REVISION +[0-9]+$' tcpmux.h` 30 | AGE=`egrep '^#define +TCPMUX_VERSION_AGE +[0-9]+$' tcpmux.h` 31 | 32 | if [ -z "$CURRENT" -o -z "$REVISION" -o -z "$AGE" ]; then 33 | echo "abi_version.sh: error: could not extract version from tcpmux.h" 1>&2 34 | exit 1 35 | fi 36 | 37 | CURRENT=`echo $CURRENT | awk '{ print $3 }'` 38 | REVISION=`echo $REVISION | awk '{ print $3 }'` 39 | AGE=`echo $AGE | awk '{ print $3 }'` 40 | 41 | case $1 in 42 | -libtool) 43 | printf '%s' "$CURRENT:$REVISION:$AGE" 44 | ;; 45 | *) 46 | printf '%s' "$CURRENT.$REVISION.$AGE" 47 | ;; 48 | esac 49 | 50 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf -ifv 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2013 Luca Barbato 3 | # Copyright (c) 2015 Martin Sustrik All rights reserved. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom 10 | # the Software is furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included 13 | # in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | # IN THE SOFTWARE. 22 | 23 | ################################################################################ 24 | # Start the configuration phase. # 25 | ################################################################################ 26 | 27 | AC_PREREQ([2.53]) 28 | 29 | AC_INIT([tcpmux], [m4_esyscmd([./package_version.sh])], 30 | [libmill@freelists.org], [tcpmux], [http://libmill.org/]) 31 | AC_CONFIG_SRCDIR([tcpmux.pc.in]) 32 | AM_INIT_AUTOMAKE([1.6 foreign subdir-objects tar-ustar]) 33 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 34 | 35 | AC_CANONICAL_HOST 36 | 37 | ################################################################################ 38 | # Retrieve the versions. # 39 | ################################################################################ 40 | 41 | AC_PROG_SED 42 | AC_PROG_AWK 43 | 44 | TCPMUX_ABI_VERSION=m4_esyscmd([./abi_version.sh]) 45 | TCPMUX_PACKAGE_VERSION=m4_esyscmd([./package_version.sh]) 46 | TCPMUX_LIBTOOL_VERSION=m4_esyscmd([./abi_version.sh -libtool]) 47 | 48 | AC_SUBST(TCPMUX_ABI_VERSION) 49 | AC_SUBST(TCPMUX_PACKAGE_VERSION) 50 | AC_SUBST(TCPMUX_LIBTOOL_VERSION) 51 | 52 | AC_MSG_NOTICE([tcpmux package version: $TCPMUX_PACKAGE_VERSION]) 53 | AC_MSG_NOTICE([tcpmux ABI version: $TCPMUX_ABI_VERSION]) 54 | 55 | ################################################################################ 56 | # Check the compilers. # 57 | ################################################################################ 58 | 59 | AC_PROG_CC_C99 60 | AM_PROG_CC_C_O 61 | 62 | ################################################################################ 63 | # --enable-debug # 64 | ################################################################################ 65 | 66 | AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], 67 | [Enable debugging information [default=no]])]) 68 | 69 | if test "x$enable_debug" = "xyes"; then 70 | # Override original optimisation level - last option specified wins. 71 | CFLAGS="$CFLAGS -g -O0" 72 | fi 73 | 74 | ################################################################################ 75 | # Feature checks. # 76 | ################################################################################ 77 | 78 | AC_CHECK_LIB([mill], [iplocal]) 79 | AC_CHECK_FUNCS([iplocal]) 80 | 81 | ################################################################################ 82 | # Libtool # 83 | ################################################################################ 84 | 85 | LT_INIT 86 | 87 | DOLT 88 | 89 | ################################################################################ 90 | # Finish the configuration phase. # 91 | ################################################################################ 92 | 93 | AC_CONFIG_MACRO_DIR([m4]) 94 | 95 | AC_OUTPUT([Makefile tcpmux.pc]) 96 | cp confdefs.h config.h 97 | 98 | -------------------------------------------------------------------------------- /daemon.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Martin Sustrik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom 10 | the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | IN THE SOFTWARE. 22 | 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "list.h" 39 | #include "tcpmux.h" 40 | 41 | #define cont(ptr, type, member) \ 42 | (ptr ? ((type*) (((char*) ptr) - offsetof(type, member))) : NULL) 43 | 44 | struct service { 45 | struct tcpmux_list_item item; 46 | const char *name; 47 | chan ch; 48 | }; 49 | 50 | struct tcpmux_list services = {0}; 51 | 52 | /* The function does no buffering. Any characters past the will 53 | remain in socket's rx buffer. */ 54 | size_t recvoneline(int fd, char *buf, size_t len) { 55 | size_t i; 56 | for(i = 0; i != len; ++i) { 57 | int rc = fdwait(fd, FDW_IN, -1); 58 | assert(rc == FDW_IN); 59 | ssize_t sz = recv(fd, &buf[i], 1, 0); 60 | assert(sz == 1); 61 | if(i > 0 && buf[i - 1] == '\r' && buf[i] == '\n') { 62 | buf[i - 1] = 0; 63 | errno = 0; 64 | return i - 1; 65 | } 66 | } 67 | errno = ENOBUFS; 68 | return len; 69 | } 70 | 71 | void tcphandler(tcpsock s) { 72 | int success = 0; 73 | /* Get the first line (the service name) from the client. */ 74 | char service[256]; 75 | int fd = tcpdetach(s); 76 | size_t sz = recvoneline(fd, service, sizeof(service)); 77 | if(errno == ENOBUFS) 78 | goto reply; 79 | assert(errno == 0); 80 | size_t i; 81 | for(i = 0; i != sz; ++i) { 82 | if(service[i] < 32 || service[i] > 127) 83 | goto reply; 84 | service[i] = tolower(service[i]); 85 | } 86 | /* Find the registered service. */ 87 | struct tcpmux_list_item *it; 88 | struct service *srvc; 89 | for(it = tcpmux_list_begin(&services); it; it = tcpmux_list_next(it)) { 90 | srvc = cont(it, struct service, item); 91 | if(strcmp(service, srvc->name) == 0) 92 | break; 93 | } 94 | if(!it) 95 | goto reply; 96 | success = 1; 97 | reply: 98 | /* Reply to the TCP peer. */ 99 | s = tcpattach(fd, 0); 100 | const char *msg = success ? "+\r\n" : "-Service not found\r\n"; 101 | tcpsend(s, msg, strlen(msg), -1); 102 | if(errno != 0) { 103 | tcpclose(s); 104 | return; 105 | } 106 | tcpflush(s, -1); 107 | if(errno != 0) { 108 | tcpclose(s); 109 | return; 110 | } 111 | if(!success) { 112 | tcpclose(s); 113 | return; 114 | } 115 | /* Send the fd to the unixhandler connected to the service in question. */ 116 | chs(srvc->ch, int, tcpdetach(s)); 117 | } 118 | 119 | void tcplistener(tcpsock ls) { 120 | while(1) { 121 | tcpsock s = tcpaccept(ls, -1); 122 | go(tcphandler(s)); 123 | } 124 | } 125 | 126 | void unixhandler(unixsock s) { 127 | const char *errmsg = NULL; 128 | /* Get the first line (the service name) from the peer. */ 129 | char service[256]; 130 | int fd = unixdetach(s); 131 | size_t sz = recvoneline(fd, service, sizeof(service)); 132 | if(errno == ENOBUFS) { 133 | const char *errmsg = "-1: Service name too long\r\n"; 134 | goto reply; 135 | } 136 | assert(errno == 0); 137 | size_t i; 138 | for(i = 0; i != sz; ++i) { 139 | if(service[i] < 32 || service[i] > 127) { 140 | errmsg = "-2: Service name contains invalid character\r\n"; 141 | goto reply; 142 | } 143 | service[i] = tolower(service[i]); 144 | } 145 | /* Check whether the service is already registered. */ 146 | struct tcpmux_list_item *it; 147 | for(it = tcpmux_list_begin(&services); it; it = tcpmux_list_next(it)) { 148 | struct service *srvc = cont(it, struct service, item); 149 | if(strcmp(service, srvc->name) == 0) 150 | break; 151 | } 152 | if(it) { 153 | errmsg = "-3: Service already exists\r\n"; 154 | goto reply; 155 | } 156 | struct service self; 157 | self.name = service; 158 | self.ch = chmake(int, 0); 159 | assert(self.ch); 160 | tcpmux_list_insert(&services, &self.item, NULL); 161 | errmsg = "+\r\n"; 162 | reply: 163 | /* Reply to the service. */ 164 | s = unixattach(fd, 0); 165 | if(!s) { 166 | unixclose(s); 167 | return; 168 | } 169 | unixsend(s, errmsg, strlen(errmsg), -1); 170 | if(errno != 0) { 171 | unixclose(s); 172 | return; 173 | } 174 | unixflush(s, -1); 175 | if(errno != 0) { 176 | unixclose(s); 177 | return; 178 | } 179 | if(errmsg[0] == '-') 180 | return; 181 | /* Wait for new incoming connections. Send them to the service. */ 182 | fd = unixdetach(s); 183 | while(1) { 184 | int tcpfd = chr(self.ch, int); 185 | /* Send the fd to the serivce via UNIX connection. */ 186 | struct iovec iov; 187 | unsigned char buf[] = {0x55}; 188 | iov.iov_base = buf; 189 | iov.iov_len = 1; 190 | struct msghdr msg; 191 | memset(&msg, 0, sizeof (msg)); 192 | msg.msg_iov = &iov; 193 | msg.msg_iovlen = 1; 194 | char control [sizeof(struct cmsghdr) + 10]; 195 | msg.msg_control = control; 196 | msg.msg_controllen = sizeof(control); 197 | struct cmsghdr *cmsg; 198 | cmsg = CMSG_FIRSTHDR(&msg); 199 | cmsg->cmsg_level = SOL_SOCKET; 200 | cmsg->cmsg_type = SCM_RIGHTS; 201 | cmsg->cmsg_len = CMSG_LEN(sizeof(tcpfd)); 202 | *((int*)CMSG_DATA(cmsg)) = tcpfd; 203 | msg.msg_controllen = cmsg->cmsg_len; 204 | int rc = sendmsg(fd, &msg, 0); 205 | if (rc != 1) 206 | close(tcpfd); 207 | } 208 | } 209 | 210 | int tcpmuxd(ipaddr addr) { 211 | tcpsock ls = tcplisten(addr, 10); 212 | if(!ls) 213 | return -1; 214 | /* Start listening for registrations from local services. */ 215 | char fname[64]; 216 | snprintf(fname, sizeof(fname), "/tmp/tcpmuxd.%d", tcpport(ls)); 217 | /* This will kick the file from underneath a different instance of 218 | tcpmuxd using the same port. Unfortunately, the need for this behaviour 219 | is caused by a bug in POSIX and there's no real workaround. 220 | TODO: On Linux we may get around it by using abstract namespace. */ 221 | unlink(fname); 222 | unixsock us = unixlisten(fname, 10); 223 | if(!us) { 224 | tcpclose(ls); 225 | return -1; 226 | } 227 | /* Start accepting TCP connections from clients. */ 228 | go(tcplistener(ls)); 229 | /* Process new registrations as they arrive. */ 230 | while(1) { 231 | unixsock s = unixaccept(us, -1); 232 | go(unixhandler(s)); 233 | } 234 | } 235 | 236 | -------------------------------------------------------------------------------- /list.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Martin Sustrik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom 10 | the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | IN THE SOFTWARE. 22 | 23 | */ 24 | 25 | #include 26 | 27 | #include "list.h" 28 | 29 | void tcpmux_list_init(struct tcpmux_list *self) 30 | { 31 | self->first = NULL; 32 | self->last = NULL; 33 | } 34 | 35 | void tcpmux_list_insert(struct tcpmux_list *self, struct tcpmux_list_item *item, 36 | struct tcpmux_list_item *it) 37 | { 38 | item->prev = it ? it->prev : self->last; 39 | item->next = it; 40 | if(item->prev) 41 | item->prev->next = item; 42 | if(item->next) 43 | item->next->prev = item; 44 | if(!self->first || self->first == it) 45 | self->first = item; 46 | if(!it) 47 | self->last = item; 48 | } 49 | 50 | struct tcpmux_list_item *tcpmux_list_erase(struct tcpmux_list *self, 51 | struct tcpmux_list_item *item) 52 | { 53 | struct tcpmux_list_item *next; 54 | 55 | if(item->prev) 56 | item->prev->next = item->next; 57 | else 58 | self->first = item->next; 59 | if(item->next) 60 | item->next->prev = item->prev; 61 | else 62 | self->last = item->prev; 63 | 64 | next = item->next; 65 | 66 | item->prev = NULL; 67 | item->next = NULL; 68 | 69 | return next; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Martin Sustrik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom 10 | the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | IN THE SOFTWARE. 22 | 23 | */ 24 | 25 | #ifndef TCPMUX_LIST_INCLUDED 26 | #define TCPMUX_LIST_INCLUDED 27 | 28 | /* Doubly-linked list. */ 29 | 30 | struct tcpmux_list_item { 31 | struct tcpmux_list_item *next; 32 | struct tcpmux_list_item *prev; 33 | }; 34 | 35 | struct tcpmux_list { 36 | struct tcpmux_list_item *first; 37 | struct tcpmux_list_item *last; 38 | }; 39 | 40 | /* Initialise the list. To statically initialise the list use = {0}. */ 41 | void tcpmux_list_init(struct tcpmux_list *self); 42 | 43 | /* True is the list has no items. */ 44 | #define tcpmux_list_empty(self) (!((self)->first)) 45 | 46 | /* Returns iterator to the first item in the list or NULL if 47 | the list is empty. */ 48 | #define tcpmux_list_begin(self) ((self)->first) 49 | 50 | /* Returns iterator to one past the item pointed to by 'it'. */ 51 | #define tcpmux_list_next(it) ((it)->next) 52 | 53 | /* Adds the item to the list before the item pointed to by 'it'. 54 | If 'it' is NULL the item is inserted to the end of the list. */ 55 | void tcpmux_list_insert(struct tcpmux_list *self, struct tcpmux_list_item *item, 56 | struct tcpmux_list_item *it); 57 | 58 | /* Removes the item from the list and returns pointer to the next item in the 59 | list. Item must be part of the list. */ 60 | struct tcpmux_list_item *tcpmux_list_erase(struct tcpmux_list *self, 61 | struct tcpmux_list_item *item); 62 | 63 | #endif 64 | 65 | -------------------------------------------------------------------------------- /m4/dolt.m4: -------------------------------------------------------------------------------- 1 | dnl dolt, a replacement for libtool 2 | dnl Copyright © 2007-2010 Josh Triplett 3 | dnl Copying and distribution of this file, with or without modification, 4 | dnl are permitted in any medium without royalty provided the copyright 5 | dnl notice and this notice are preserved. 6 | dnl 7 | dnl To use dolt, invoke the DOLT macro immediately after the libtool macros. 8 | dnl Optionally, copy this file into acinclude.m4, to avoid the need to have it 9 | dnl installed when running autoconf on your project. 10 | 11 | AC_DEFUN([DOLT], [ 12 | AC_REQUIRE([AC_CANONICAL_HOST]) 13 | # dolt, a replacement for libtool 14 | # Josh Triplett 15 | AC_PATH_PROG([DOLT_BASH], [bash]) 16 | AC_MSG_CHECKING([if dolt supports this host]) 17 | dolt_supported=yes 18 | AS_IF([test x$DOLT_BASH = x], [dolt_supported=no]) 19 | AS_IF([test x$GCC != xyes], [dolt_supported=no]) 20 | 21 | AS_CASE([$host], 22 | [*-*-linux*|*-*-freebsd*], [pic_options='-fPIC'], 23 | [*-apple-darwin*], [pic_options='-fno-common'], 24 | [*mingw*|*nacl*], [pic_options=''] 25 | [*], [dolt_supported=no] 26 | ) 27 | AS_IF([test x$dolt_supported = xno], [ 28 | AC_MSG_RESULT([no, falling back to libtool]) 29 | LTCOMPILE='$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(COMPILE)' 30 | LTCXXCOMPILE='$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXXCOMPILE)' 31 | m4_pattern_allow([AM_V_lt]) 32 | ], [ 33 | AC_MSG_RESULT([yes, replacing libtool]) 34 | 35 | dnl Start writing out doltcompile. 36 | cat <<__DOLTCOMPILE__EOF__ >doltcompile 37 | #!$DOLT_BASH 38 | __DOLTCOMPILE__EOF__ 39 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 40 | args=("$[]@") 41 | for ((arg=0; arg<${#args@<:@@@:>@}; arg++)) ; do 42 | if test x"${args@<:@$arg@:>@}" = x-o ; then 43 | objarg=$((arg+1)) 44 | break 45 | fi 46 | done 47 | if test x$objarg = x ; then 48 | echo 'Error: no -o on compiler command line' 1>&2 49 | exit 1 50 | fi 51 | lo="${args@<:@$objarg@:>@}" 52 | obj="${lo%.lo}" 53 | if test x"$lo" = x"$obj" ; then 54 | echo "Error: libtool object file name \"$lo\" does not end in .lo" 1>&2 55 | exit 1 56 | fi 57 | objbase="${obj##*/}" 58 | __DOLTCOMPILE__EOF__ 59 | 60 | dnl Write out shared compilation code. 61 | if test x$enable_shared = xyes; then 62 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 63 | libobjdir="${obj%$objbase}.libs" 64 | if test ! -d "$libobjdir" ; then 65 | mkdir_out="$(mkdir "$libobjdir" 2>&1)" 66 | mkdir_ret=$? 67 | if test "$mkdir_ret" -ne 0 && test ! -d "$libobjdir" ; then 68 | echo "$mkdir_out" 1>&2 69 | exit $mkdir_ret 70 | fi 71 | fi 72 | pic_object="$libobjdir/$objbase.o" 73 | args@<:@$objarg@:>@="$pic_object" 74 | __DOLTCOMPILE__EOF__ 75 | cat <<__DOLTCOMPILE__EOF__ >>doltcompile 76 | "\${args@<:@@@:>@}" $pic_options -DPIC || exit \$? 77 | __DOLTCOMPILE__EOF__ 78 | fi 79 | 80 | dnl Write out static compilation code. 81 | dnl Avoid duplicate compiler output if also building shared objects. 82 | if test x$enable_static = xyes; then 83 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 84 | non_pic_object="$obj.o" 85 | args@<:@$objarg@:>@="$non_pic_object" 86 | __DOLTCOMPILE__EOF__ 87 | if test x$enable_shared = xyes; then 88 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 89 | "${args@<:@@@:>@}" >/dev/null 2>&1 || exit $? 90 | __DOLTCOMPILE__EOF__ 91 | else 92 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 93 | "${args@<:@@@:>@}" || exit $? 94 | __DOLTCOMPILE__EOF__ 95 | fi 96 | fi 97 | 98 | dnl Write out the code to write the .lo file. 99 | dnl The second line of the .lo file must match "^# Generated by .*libtool" 100 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 101 | { 102 | echo "# $lo - a libtool object file" 103 | echo "# Generated by doltcompile, not libtool" 104 | __DOLTCOMPILE__EOF__ 105 | 106 | if test x$enable_shared = xyes; then 107 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 108 | echo "pic_object='.libs/${objbase}.o'" 109 | __DOLTCOMPILE__EOF__ 110 | else 111 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 112 | echo pic_object=none 113 | __DOLTCOMPILE__EOF__ 114 | fi 115 | 116 | if test x$enable_static = xyes; then 117 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 118 | echo "non_pic_object='${objbase}.o'" 119 | __DOLTCOMPILE__EOF__ 120 | else 121 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 122 | echo non_pic_object=none 123 | __DOLTCOMPILE__EOF__ 124 | fi 125 | 126 | cat <<'__DOLTCOMPILE__EOF__' >>doltcompile 127 | } > "$lo" 128 | __DOLTCOMPILE__EOF__ 129 | 130 | dnl Done writing out doltcompile; substitute it for libtool compilation. 131 | chmod +x doltcompile 132 | LTCOMPILE='$(top_builddir)/doltcompile $(COMPILE)' 133 | LTCXXCOMPILE='$(top_builddir)/doltcompile $(CXXCOMPILE)' 134 | 135 | dnl automake ignores LTCOMPILE and LTCXXCOMPILE when it has separate CFLAGS for 136 | dnl a target, so write out a libtool wrapper to handle that case. 137 | dnl Note that doltlibtool does not handle inferred tags or option arguments 138 | dnl without '=', because automake does not use them. 139 | cat <<__DOLTLIBTOOL__EOF__ > doltlibtool 140 | #!$DOLT_BASH 141 | __DOLTLIBTOOL__EOF__ 142 | cat <<'__DOLTLIBTOOL__EOF__' >>doltlibtool 143 | top_builddir_slash="${0%%doltlibtool}" 144 | : ${top_builddir_slash:=./} 145 | args=() 146 | modeok=false 147 | tagok=false 148 | for arg in "$[]@"; do 149 | case "$arg" in 150 | --mode=compile) modeok=true ;; 151 | --tag=CC|--tag=CXX) tagok=true ;; 152 | --silent|--quiet) ;; 153 | *) args@<:@${#args[@]}@:>@="$arg" ;; 154 | esac 155 | done 156 | if $modeok && $tagok ; then 157 | . ${top_builddir_slash}doltcompile "${args@<:@@@:>@}" 158 | else 159 | exec ${top_builddir_slash}libtool "$[]@" 160 | fi 161 | __DOLTLIBTOOL__EOF__ 162 | 163 | dnl Done writing out doltlibtool; substitute it for libtool. 164 | chmod +x doltlibtool 165 | LIBTOOL='$(top_builddir)/doltlibtool' 166 | 167 | DOLT_CLEANFILES="doltlibtool doltcompile" 168 | AC_SUBST(DOLT_CLEANFILES) 169 | ]) 170 | AC_SUBST(LTCOMPILE) 171 | AC_SUBST(LTCXXCOMPILE) 172 | # end dolt 173 | ]) 174 | -------------------------------------------------------------------------------- /m4/ltoptions.m4: -------------------------------------------------------------------------------- 1 | # Helper functions for option handling. -*- Autoconf -*- 2 | # 3 | # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, 4 | # Inc. 5 | # Written by Gary V. Vaughan, 2004 6 | # 7 | # This file is free software; the Free Software Foundation gives 8 | # unlimited permission to copy and/or distribute it, with or without 9 | # modifications, as long as this notice is preserved. 10 | 11 | # serial 7 ltoptions.m4 12 | 13 | # This is to help aclocal find these macros, as it can't see m4_define. 14 | AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) 15 | 16 | 17 | # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) 18 | # ------------------------------------------ 19 | m4_define([_LT_MANGLE_OPTION], 20 | [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) 21 | 22 | 23 | # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) 24 | # --------------------------------------- 25 | # Set option OPTION-NAME for macro MACRO-NAME, and if there is a 26 | # matching handler defined, dispatch to it. Other OPTION-NAMEs are 27 | # saved as a flag. 28 | m4_define([_LT_SET_OPTION], 29 | [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl 30 | m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), 31 | _LT_MANGLE_DEFUN([$1], [$2]), 32 | [m4_warning([Unknown $1 option `$2'])])[]dnl 33 | ]) 34 | 35 | 36 | # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) 37 | # ------------------------------------------------------------ 38 | # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. 39 | m4_define([_LT_IF_OPTION], 40 | [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) 41 | 42 | 43 | # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) 44 | # ------------------------------------------------------- 45 | # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME 46 | # are set. 47 | m4_define([_LT_UNLESS_OPTIONS], 48 | [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), 49 | [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), 50 | [m4_define([$0_found])])])[]dnl 51 | m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 52 | ])[]dnl 53 | ]) 54 | 55 | 56 | # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) 57 | # ---------------------------------------- 58 | # OPTION-LIST is a space-separated list of Libtool options associated 59 | # with MACRO-NAME. If any OPTION has a matching handler declared with 60 | # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about 61 | # the unknown option and exit. 62 | m4_defun([_LT_SET_OPTIONS], 63 | [# Set options 64 | m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), 65 | [_LT_SET_OPTION([$1], _LT_Option)]) 66 | 67 | m4_if([$1],[LT_INIT],[ 68 | dnl 69 | dnl Simply set some default values (i.e off) if boolean options were not 70 | dnl specified: 71 | _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no 72 | ]) 73 | _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no 74 | ]) 75 | dnl 76 | dnl If no reference was made to various pairs of opposing options, then 77 | dnl we run the default mode handler for the pair. For example, if neither 78 | dnl `shared' nor `disable-shared' was passed, we enable building of shared 79 | dnl archives by default: 80 | _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) 81 | _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) 82 | _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) 83 | _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], 84 | [_LT_ENABLE_FAST_INSTALL]) 85 | ]) 86 | ])# _LT_SET_OPTIONS 87 | 88 | 89 | ## --------------------------------- ## 90 | ## Macros to handle LT_INIT options. ## 91 | ## --------------------------------- ## 92 | 93 | # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) 94 | # ----------------------------------------- 95 | m4_define([_LT_MANGLE_DEFUN], 96 | [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) 97 | 98 | 99 | # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) 100 | # ----------------------------------------------- 101 | m4_define([LT_OPTION_DEFINE], 102 | [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl 103 | ])# LT_OPTION_DEFINE 104 | 105 | 106 | # dlopen 107 | # ------ 108 | LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes 109 | ]) 110 | 111 | AU_DEFUN([AC_LIBTOOL_DLOPEN], 112 | [_LT_SET_OPTION([LT_INIT], [dlopen]) 113 | AC_DIAGNOSE([obsolete], 114 | [$0: Remove this warning and the call to _LT_SET_OPTION when you 115 | put the `dlopen' option into LT_INIT's first parameter.]) 116 | ]) 117 | 118 | dnl aclocal-1.4 backwards compatibility: 119 | dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) 120 | 121 | 122 | # win32-dll 123 | # --------- 124 | # Declare package support for building win32 dll's. 125 | LT_OPTION_DEFINE([LT_INIT], [win32-dll], 126 | [enable_win32_dll=yes 127 | 128 | case $host in 129 | *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) 130 | AC_CHECK_TOOL(AS, as, false) 131 | AC_CHECK_TOOL(DLLTOOL, dlltool, false) 132 | AC_CHECK_TOOL(OBJDUMP, objdump, false) 133 | ;; 134 | esac 135 | 136 | test -z "$AS" && AS=as 137 | _LT_DECL([], [AS], [1], [Assembler program])dnl 138 | 139 | test -z "$DLLTOOL" && DLLTOOL=dlltool 140 | _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl 141 | 142 | test -z "$OBJDUMP" && OBJDUMP=objdump 143 | _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl 144 | ])# win32-dll 145 | 146 | AU_DEFUN([AC_LIBTOOL_WIN32_DLL], 147 | [AC_REQUIRE([AC_CANONICAL_HOST])dnl 148 | _LT_SET_OPTION([LT_INIT], [win32-dll]) 149 | AC_DIAGNOSE([obsolete], 150 | [$0: Remove this warning and the call to _LT_SET_OPTION when you 151 | put the `win32-dll' option into LT_INIT's first parameter.]) 152 | ]) 153 | 154 | dnl aclocal-1.4 backwards compatibility: 155 | dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) 156 | 157 | 158 | # _LT_ENABLE_SHARED([DEFAULT]) 159 | # ---------------------------- 160 | # implement the --enable-shared flag, and supports the `shared' and 161 | # `disable-shared' LT_INIT options. 162 | # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. 163 | m4_define([_LT_ENABLE_SHARED], 164 | [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl 165 | AC_ARG_ENABLE([shared], 166 | [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], 167 | [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], 168 | [p=${PACKAGE-default} 169 | case $enableval in 170 | yes) enable_shared=yes ;; 171 | no) enable_shared=no ;; 172 | *) 173 | enable_shared=no 174 | # Look at the argument we got. We use all the common list separators. 175 | lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," 176 | for pkg in $enableval; do 177 | IFS="$lt_save_ifs" 178 | if test "X$pkg" = "X$p"; then 179 | enable_shared=yes 180 | fi 181 | done 182 | IFS="$lt_save_ifs" 183 | ;; 184 | esac], 185 | [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) 186 | 187 | _LT_DECL([build_libtool_libs], [enable_shared], [0], 188 | [Whether or not to build shared libraries]) 189 | ])# _LT_ENABLE_SHARED 190 | 191 | LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) 192 | LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) 193 | 194 | # Old names: 195 | AC_DEFUN([AC_ENABLE_SHARED], 196 | [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) 197 | ]) 198 | 199 | AC_DEFUN([AC_DISABLE_SHARED], 200 | [_LT_SET_OPTION([LT_INIT], [disable-shared]) 201 | ]) 202 | 203 | AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) 204 | AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) 205 | 206 | dnl aclocal-1.4 backwards compatibility: 207 | dnl AC_DEFUN([AM_ENABLE_SHARED], []) 208 | dnl AC_DEFUN([AM_DISABLE_SHARED], []) 209 | 210 | 211 | 212 | # _LT_ENABLE_STATIC([DEFAULT]) 213 | # ---------------------------- 214 | # implement the --enable-static flag, and support the `static' and 215 | # `disable-static' LT_INIT options. 216 | # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. 217 | m4_define([_LT_ENABLE_STATIC], 218 | [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl 219 | AC_ARG_ENABLE([static], 220 | [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], 221 | [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], 222 | [p=${PACKAGE-default} 223 | case $enableval in 224 | yes) enable_static=yes ;; 225 | no) enable_static=no ;; 226 | *) 227 | enable_static=no 228 | # Look at the argument we got. We use all the common list separators. 229 | lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," 230 | for pkg in $enableval; do 231 | IFS="$lt_save_ifs" 232 | if test "X$pkg" = "X$p"; then 233 | enable_static=yes 234 | fi 235 | done 236 | IFS="$lt_save_ifs" 237 | ;; 238 | esac], 239 | [enable_static=]_LT_ENABLE_STATIC_DEFAULT) 240 | 241 | _LT_DECL([build_old_libs], [enable_static], [0], 242 | [Whether or not to build static libraries]) 243 | ])# _LT_ENABLE_STATIC 244 | 245 | LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) 246 | LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) 247 | 248 | # Old names: 249 | AC_DEFUN([AC_ENABLE_STATIC], 250 | [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) 251 | ]) 252 | 253 | AC_DEFUN([AC_DISABLE_STATIC], 254 | [_LT_SET_OPTION([LT_INIT], [disable-static]) 255 | ]) 256 | 257 | AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) 258 | AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) 259 | 260 | dnl aclocal-1.4 backwards compatibility: 261 | dnl AC_DEFUN([AM_ENABLE_STATIC], []) 262 | dnl AC_DEFUN([AM_DISABLE_STATIC], []) 263 | 264 | 265 | 266 | # _LT_ENABLE_FAST_INSTALL([DEFAULT]) 267 | # ---------------------------------- 268 | # implement the --enable-fast-install flag, and support the `fast-install' 269 | # and `disable-fast-install' LT_INIT options. 270 | # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. 271 | m4_define([_LT_ENABLE_FAST_INSTALL], 272 | [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl 273 | AC_ARG_ENABLE([fast-install], 274 | [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], 275 | [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], 276 | [p=${PACKAGE-default} 277 | case $enableval in 278 | yes) enable_fast_install=yes ;; 279 | no) enable_fast_install=no ;; 280 | *) 281 | enable_fast_install=no 282 | # Look at the argument we got. We use all the common list separators. 283 | lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," 284 | for pkg in $enableval; do 285 | IFS="$lt_save_ifs" 286 | if test "X$pkg" = "X$p"; then 287 | enable_fast_install=yes 288 | fi 289 | done 290 | IFS="$lt_save_ifs" 291 | ;; 292 | esac], 293 | [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) 294 | 295 | _LT_DECL([fast_install], [enable_fast_install], [0], 296 | [Whether or not to optimize for fast installation])dnl 297 | ])# _LT_ENABLE_FAST_INSTALL 298 | 299 | LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) 300 | LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) 301 | 302 | # Old names: 303 | AU_DEFUN([AC_ENABLE_FAST_INSTALL], 304 | [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) 305 | AC_DIAGNOSE([obsolete], 306 | [$0: Remove this warning and the call to _LT_SET_OPTION when you put 307 | the `fast-install' option into LT_INIT's first parameter.]) 308 | ]) 309 | 310 | AU_DEFUN([AC_DISABLE_FAST_INSTALL], 311 | [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) 312 | AC_DIAGNOSE([obsolete], 313 | [$0: Remove this warning and the call to _LT_SET_OPTION when you put 314 | the `disable-fast-install' option into LT_INIT's first parameter.]) 315 | ]) 316 | 317 | dnl aclocal-1.4 backwards compatibility: 318 | dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) 319 | dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) 320 | 321 | 322 | # _LT_WITH_PIC([MODE]) 323 | # -------------------- 324 | # implement the --with-pic flag, and support the `pic-only' and `no-pic' 325 | # LT_INIT options. 326 | # MODE is either `yes' or `no'. If omitted, it defaults to `both'. 327 | m4_define([_LT_WITH_PIC], 328 | [AC_ARG_WITH([pic], 329 | [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], 330 | [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], 331 | [lt_p=${PACKAGE-default} 332 | case $withval in 333 | yes|no) pic_mode=$withval ;; 334 | *) 335 | pic_mode=default 336 | # Look at the argument we got. We use all the common list separators. 337 | lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," 338 | for lt_pkg in $withval; do 339 | IFS="$lt_save_ifs" 340 | if test "X$lt_pkg" = "X$lt_p"; then 341 | pic_mode=yes 342 | fi 343 | done 344 | IFS="$lt_save_ifs" 345 | ;; 346 | esac], 347 | [pic_mode=default]) 348 | 349 | test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) 350 | 351 | _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl 352 | ])# _LT_WITH_PIC 353 | 354 | LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) 355 | LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) 356 | 357 | # Old name: 358 | AU_DEFUN([AC_LIBTOOL_PICMODE], 359 | [_LT_SET_OPTION([LT_INIT], [pic-only]) 360 | AC_DIAGNOSE([obsolete], 361 | [$0: Remove this warning and the call to _LT_SET_OPTION when you 362 | put the `pic-only' option into LT_INIT's first parameter.]) 363 | ]) 364 | 365 | dnl aclocal-1.4 backwards compatibility: 366 | dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) 367 | 368 | ## ----------------- ## 369 | ## LTDL_INIT Options ## 370 | ## ----------------- ## 371 | 372 | m4_define([_LTDL_MODE], []) 373 | LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], 374 | [m4_define([_LTDL_MODE], [nonrecursive])]) 375 | LT_OPTION_DEFINE([LTDL_INIT], [recursive], 376 | [m4_define([_LTDL_MODE], [recursive])]) 377 | LT_OPTION_DEFINE([LTDL_INIT], [subproject], 378 | [m4_define([_LTDL_MODE], [subproject])]) 379 | 380 | m4_define([_LTDL_TYPE], []) 381 | LT_OPTION_DEFINE([LTDL_INIT], [installable], 382 | [m4_define([_LTDL_TYPE], [installable])]) 383 | LT_OPTION_DEFINE([LTDL_INIT], [convenience], 384 | [m4_define([_LTDL_TYPE], [convenience])]) 385 | -------------------------------------------------------------------------------- /m4/ltsugar.m4: -------------------------------------------------------------------------------- 1 | # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. 4 | # Written by Gary V. Vaughan, 2004 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # serial 6 ltsugar.m4 11 | 12 | # This is to help aclocal find these macros, as it can't see m4_define. 13 | AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) 14 | 15 | 16 | # lt_join(SEP, ARG1, [ARG2...]) 17 | # ----------------------------- 18 | # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their 19 | # associated separator. 20 | # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier 21 | # versions in m4sugar had bugs. 22 | m4_define([lt_join], 23 | [m4_if([$#], [1], [], 24 | [$#], [2], [[$2]], 25 | [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) 26 | m4_define([_lt_join], 27 | [m4_if([$#$2], [2], [], 28 | [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) 29 | 30 | 31 | # lt_car(LIST) 32 | # lt_cdr(LIST) 33 | # ------------ 34 | # Manipulate m4 lists. 35 | # These macros are necessary as long as will still need to support 36 | # Autoconf-2.59 which quotes differently. 37 | m4_define([lt_car], [[$1]]) 38 | m4_define([lt_cdr], 39 | [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], 40 | [$#], 1, [], 41 | [m4_dquote(m4_shift($@))])]) 42 | m4_define([lt_unquote], $1) 43 | 44 | 45 | # lt_append(MACRO-NAME, STRING, [SEPARATOR]) 46 | # ------------------------------------------ 47 | # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. 48 | # Note that neither SEPARATOR nor STRING are expanded; they are appended 49 | # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). 50 | # No SEPARATOR is output if MACRO-NAME was previously undefined (different 51 | # than defined and empty). 52 | # 53 | # This macro is needed until we can rely on Autoconf 2.62, since earlier 54 | # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. 55 | m4_define([lt_append], 56 | [m4_define([$1], 57 | m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) 58 | 59 | 60 | 61 | # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) 62 | # ---------------------------------------------------------- 63 | # Produce a SEP delimited list of all paired combinations of elements of 64 | # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list 65 | # has the form PREFIXmINFIXSUFFIXn. 66 | # Needed until we can rely on m4_combine added in Autoconf 2.62. 67 | m4_define([lt_combine], 68 | [m4_if(m4_eval([$# > 3]), [1], 69 | [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl 70 | [[m4_foreach([_Lt_prefix], [$2], 71 | [m4_foreach([_Lt_suffix], 72 | ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, 73 | [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) 74 | 75 | 76 | # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) 77 | # ----------------------------------------------------------------------- 78 | # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited 79 | # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. 80 | m4_define([lt_if_append_uniq], 81 | [m4_ifdef([$1], 82 | [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], 83 | [lt_append([$1], [$2], [$3])$4], 84 | [$5])], 85 | [lt_append([$1], [$2], [$3])$4])]) 86 | 87 | 88 | # lt_dict_add(DICT, KEY, VALUE) 89 | # ----------------------------- 90 | m4_define([lt_dict_add], 91 | [m4_define([$1($2)], [$3])]) 92 | 93 | 94 | # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) 95 | # -------------------------------------------- 96 | m4_define([lt_dict_add_subkey], 97 | [m4_define([$1($2:$3)], [$4])]) 98 | 99 | 100 | # lt_dict_fetch(DICT, KEY, [SUBKEY]) 101 | # ---------------------------------- 102 | m4_define([lt_dict_fetch], 103 | [m4_ifval([$3], 104 | m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), 105 | m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) 106 | 107 | 108 | # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) 109 | # ----------------------------------------------------------------- 110 | m4_define([lt_if_dict_fetch], 111 | [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], 112 | [$5], 113 | [$6])]) 114 | 115 | 116 | # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) 117 | # -------------------------------------------------------------- 118 | m4_define([lt_dict_filter], 119 | [m4_if([$5], [], [], 120 | [lt_join(m4_quote(m4_default([$4], [[, ]])), 121 | lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), 122 | [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl 123 | ]) 124 | -------------------------------------------------------------------------------- /m4/ltversion.m4: -------------------------------------------------------------------------------- 1 | # ltversion.m4 -- version numbers -*- Autoconf -*- 2 | # 3 | # Copyright (C) 2004 Free Software Foundation, Inc. 4 | # Written by Scott James Remnant, 2004 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # @configure_input@ 11 | 12 | # serial 3337 ltversion.m4 13 | # This file is part of GNU Libtool 14 | 15 | m4_define([LT_PACKAGE_VERSION], [2.4.2]) 16 | m4_define([LT_PACKAGE_REVISION], [1.3337]) 17 | 18 | AC_DEFUN([LTVERSION_VERSION], 19 | [macro_version='2.4.2' 20 | macro_revision='1.3337' 21 | _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) 22 | _LT_DECL(, macro_revision, 0) 23 | ]) 24 | -------------------------------------------------------------------------------- /m4/lt~obsolete.m4: -------------------------------------------------------------------------------- 1 | # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. 4 | # Written by Scott James Remnant, 2004. 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # serial 5 lt~obsolete.m4 11 | 12 | # These exist entirely to fool aclocal when bootstrapping libtool. 13 | # 14 | # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) 15 | # which have later been changed to m4_define as they aren't part of the 16 | # exported API, or moved to Autoconf or Automake where they belong. 17 | # 18 | # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN 19 | # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us 20 | # using a macro with the same name in our local m4/libtool.m4 it'll 21 | # pull the old libtool.m4 in (it doesn't see our shiny new m4_define 22 | # and doesn't know about Autoconf macros at all.) 23 | # 24 | # So we provide this file, which has a silly filename so it's always 25 | # included after everything else. This provides aclocal with the 26 | # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything 27 | # because those macros already exist, or will be overwritten later. 28 | # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 29 | # 30 | # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. 31 | # Yes, that means every name once taken will need to remain here until 32 | # we give up compatibility with versions before 1.7, at which point 33 | # we need to keep only those names which we still refer to. 34 | 35 | # This is to help aclocal find these macros, as it can't see m4_define. 36 | AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) 37 | 38 | m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) 39 | m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) 40 | m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) 41 | m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) 42 | m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) 43 | m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) 44 | m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) 45 | m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) 46 | m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) 47 | m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) 48 | m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) 49 | m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) 50 | m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) 51 | m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) 52 | m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) 53 | m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) 54 | m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) 55 | m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) 56 | m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) 57 | m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) 58 | m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) 59 | m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) 60 | m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) 61 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) 62 | m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) 63 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) 64 | m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) 65 | m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) 66 | m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) 67 | m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) 68 | m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) 69 | m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) 70 | m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) 71 | m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) 72 | m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) 73 | m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) 74 | m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) 75 | m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) 76 | m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) 77 | m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) 78 | m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) 79 | m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) 80 | m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) 81 | m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) 82 | m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) 83 | m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) 84 | m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) 85 | m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) 86 | m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) 87 | m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) 88 | m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) 89 | m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) 90 | m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) 91 | m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) 92 | m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) 93 | m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) 94 | m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) 95 | m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) 96 | m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) 97 | m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) 98 | m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) 99 | -------------------------------------------------------------------------------- /package_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright (c) 2013 Luca Barbato 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom 10 | # the Software is furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included 13 | # in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | # IN THE SOFTWARE. 22 | 23 | if [ -d .git ]; then 24 | # Retrieve the version from the last git tag. 25 | VER=`git describe --always | sed -e "s:v::"` 26 | if [ x"`git diff-index --name-only HEAD`" != x ]; then 27 | # If the sources have been changed locally, add -dirty to the version. 28 | 29 | VER="${VER}-dirty" 30 | fi 31 | elif [ -f .version ]; then 32 | # If git is not available (e.g. when building from source package) 33 | # we can extract the package version from .version file. 34 | VER=`< .version` 35 | else 36 | # The package version cannot be retrieved. 37 | VER="Unknown" 38 | fi 39 | 40 | printf '%s' "$VER" 41 | 42 | -------------------------------------------------------------------------------- /tcpmux.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Martin Sustrik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom 11 | the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "tcpmux.h" 38 | 39 | struct tcpmuxsock { 40 | int fd; 41 | }; 42 | 43 | tcpmuxsock tcpmuxlisten(int port, const char *service, int64_t deadline) { 44 | /* Connect to tcpmuxd. */ 45 | char fname[64]; 46 | snprintf(fname, sizeof(fname), "/tmp/tcpmuxd.%d", port); 47 | unixsock s = unixconnect(fname); 48 | if(!s) 49 | return NULL; 50 | /* Send registration request to tcpmuxd. */ 51 | unixsend(s, service, strlen(service), deadline); 52 | if(errno != 0) 53 | goto error; 54 | unixsend(s, "\r\n", 2, deadline); 55 | if(errno != 0) 56 | goto error; 57 | unixflush(s, deadline); 58 | if(errno != 0) 59 | goto error; 60 | /* Get reply from tcpmuxd. */ 61 | char reply[256]; 62 | size_t sz = unixrecvuntil(s, reply, sizeof(reply), "\n", 1, deadline); 63 | if(errno != 0 || sz < 3 || reply[sz - 2] != '\r' || reply[sz - 1] != '\n') 64 | goto error; 65 | if(reply[0] != '+') { 66 | unixclose(s); 67 | errno = EADDRINUSE; /* TODO: There are multiple reasons... */ 68 | return NULL; 69 | } 70 | 71 | struct tcpmuxsock *res = malloc(sizeof(struct tcpmuxsock)); 72 | if(!res) { 73 | unixclose(s); 74 | errno = ENOMEM; 75 | return NULL; 76 | } 77 | res->fd = unixdetach(s); 78 | assert(res->fd != -1); 79 | return res; 80 | error: 81 | unixclose(s); 82 | errno = ECONNRESET; 83 | return NULL; 84 | } 85 | 86 | tcpsock tcpmuxaccept(tcpmuxsock s, int64_t deadline) { 87 | int rc = fdwait(s->fd, FDW_IN, deadline); 88 | if(rc == 0) { 89 | errno = ETIMEDOUT; 90 | return NULL; 91 | } 92 | if(rc & FDW_ERR) 93 | goto error; 94 | assert(rc & FDW_IN); 95 | /* Get one byte from TCPMUX daemon. A file descriptor should be attached. */ 96 | char buf[1]; 97 | struct iovec iov; 98 | iov.iov_base = buf; 99 | iov.iov_len = sizeof(buf); 100 | struct msghdr msg; 101 | memset(&msg, 0, sizeof(msg)); 102 | msg.msg_iov = &iov; 103 | msg.msg_iovlen = 1; 104 | unsigned char control[1024]; 105 | msg.msg_control = control; 106 | msg.msg_controllen = sizeof(control); 107 | rc = recvmsg(s->fd, &msg, 0); 108 | if(rc != 1 || buf[0] != 0x55) 109 | goto error; 110 | /* Loop over the auxiliary data to find the embedded file descriptor. */ 111 | int fd = -1; 112 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 113 | while(cmsg) { 114 | if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { 115 | fd = *(int*)CMSG_DATA(cmsg); 116 | break; 117 | } 118 | cmsg = CMSG_NXTHDR(&msg, cmsg); 119 | } 120 | if(fd == -1) 121 | goto error; 122 | return tcpattach(fd, 0); 123 | error: 124 | close(s->fd); 125 | s->fd = -1; 126 | errno = ECONNRESET; 127 | return NULL; 128 | } 129 | 130 | tcpsock tcpmuxconnect(ipaddr addr, const char *service, int64_t deadline) { 131 | tcpsock s = tcpconnect(addr, deadline); 132 | /* Send the TCPMUX request. */ 133 | if(!s) 134 | return NULL; 135 | tcpsend(s, service, strlen(service), deadline); 136 | if(errno != 0) 137 | goto error; 138 | tcpsend(s, "\r\n", 2, deadline); 139 | if(errno != 0) 140 | goto error; 141 | tcpflush(s, deadline); 142 | if(errno != 0) 143 | goto error; 144 | /* Receive the TCPMUX reply. */ 145 | char buf[256]; 146 | size_t sz = tcprecvuntil(s, buf, sizeof(buf), "\n", 1, deadline); 147 | if(errno != 0) 148 | goto error; 149 | if(sz < 3 || buf[sz - 2] != '\r' || buf[sz - 1] != '\n' || buf[0] != '+') { 150 | errno = ECONNREFUSED; 151 | goto error; 152 | } 153 | return s; 154 | error:; 155 | int err = errno; 156 | tcpclose(s); 157 | errno = err; 158 | return NULL; 159 | } 160 | 161 | void tcpmuxclose(tcpmuxsock s) { 162 | if(s->fd != -1) 163 | close(s->fd); 164 | free(s); 165 | } 166 | 167 | -------------------------------------------------------------------------------- /tcpmux.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Martin Sustrik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom 10 | the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | IN THE SOFTWARE. 22 | 23 | */ 24 | 25 | #ifndef TCPMUX_H_INCLUDED 26 | #define TCPMUX_H_INCLUDED 27 | 28 | #include 29 | 30 | /******************************************************************************/ 31 | /* ABI versioning support */ 32 | /******************************************************************************/ 33 | 34 | /* Don't change this unless you know exactly what you're doing and have */ 35 | /* read and understand the following documents: */ 36 | /* www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html */ 37 | /* www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html */ 38 | 39 | /* The current interface version. */ 40 | #define TCPMUX_VERSION_CURRENT 0 41 | 42 | /* The latest revision of the current interface. */ 43 | #define TCPMUX_VERSION_REVISION 0 44 | 45 | /* How many past interface versions are still supported. */ 46 | #define TCPMUX_VERSION_AGE 0 47 | 48 | /******************************************************************************/ 49 | /* Symbol visibility */ 50 | /******************************************************************************/ 51 | 52 | #if defined TCPMUX_NO_EXPORTS 53 | # define TCPMUX_EXPORT 54 | #else 55 | # if defined _WIN32 56 | # if defined TCPMUX_EXPORTS 57 | # define TCPMUX_EXPORT __declspec(dllexport) 58 | # else 59 | # define TCPMUX_EXPORT __declspec(dllimport) 60 | # endif 61 | # else 62 | # if defined __SUNPRO_C 63 | # define TCPMUX_EXPORT __global 64 | # elif (defined __GNUC__ && __GNUC__ >= 4) || \ 65 | defined __INTEL_COMPILER || defined __clang__ 66 | # define TCPMUX_EXPORT __attribute__ ((visibility("default"))) 67 | # else 68 | # define TCPMUX_EXPORT 69 | # endif 70 | # endif 71 | #endif 72 | 73 | /******************************************************************************/ 74 | /* tcpmux library */ 75 | /******************************************************************************/ 76 | 77 | typedef struct tcpmuxsock *tcpmuxsock; 78 | 79 | TCPMUX_EXPORT tcpmuxsock tcpmuxlisten(int port, const char *service, 80 | int64_t deadline); 81 | TCPMUX_EXPORT tcpsock tcpmuxaccept(tcpmuxsock s, int64_t deadline); 82 | TCPMUX_EXPORT tcpsock tcpmuxconnect(ipaddr addr, const char *service, 83 | int64_t deadline); 84 | TCPMUX_EXPORT void tcpmuxclose(tcpmuxsock s); 85 | TCPMUX_EXPORT int tcpmuxd(ipaddr addr); 86 | 87 | #endif 88 | 89 | -------------------------------------------------------------------------------- /tcpmux.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: tcpmux 7 | Description: TCP multiplexer (RFC 1078) 8 | URL: http://libmill.org/ 9 | Version: @TCPMUX_ABI_VERSION@ 10 | Requires: 11 | Libs: -L${libdir} -ltcpmux @LIBS@ 12 | Cflags: -I${includedir} 13 | -------------------------------------------------------------------------------- /tests/e2e.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Martin Sustrik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom 10 | the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | IN THE SOFTWARE. 22 | 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "../tcpmux.h" 29 | 30 | void daemon(void) { 31 | tcpmuxd(iplocal(NULL, 5557, 0)); 32 | assert(0); 33 | } 34 | 35 | void doconnect(void) { 36 | ipaddr addr = ipremote("127.0.0.1", 5557, 0, -1); 37 | tcpsock s = tcpmuxconnect(addr, "foo", -1); 38 | assert(s); 39 | tcpsend(s, "abc", 3, -1); 40 | assert(errno == 0); 41 | tcpflush(s, -1); 42 | assert(errno == 0); 43 | } 44 | 45 | int main(void) { 46 | go(daemon()); 47 | msleep(now() + 500); 48 | tcpmuxsock ls = tcpmuxlisten(5557, "foo", -1); 49 | assert(ls); 50 | go(doconnect()); 51 | tcpsock s = tcpmuxaccept(ls, -1); 52 | assert(s); 53 | char buf[3]; 54 | tcprecv(s, buf, sizeof(buf), -1); 55 | assert(errno == 0); 56 | assert(buf[0] == 'a' && buf[1] == 'b' && buf[2] == 'c'); 57 | tcpclose(s); 58 | tcpmuxclose(ls); 59 | 60 | return 0; 61 | } 62 | --------------------------------------------------------------------------------