mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-30 14:45:49 +08:00
Compare commits
4 Commits
3883a51969
...
98e8dfb004
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98e8dfb004 | ||
|
|
a090ac8cd8 | ||
|
|
7ffc8f820f | ||
|
|
b4f5ffbf8c |
@ -415,11 +415,12 @@ set(3PROXY_CORE_SOURCES
|
|||||||
# Object libraries for common sources (shared between executables)
|
# Object libraries for common sources (shared between executables)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
# Common object library (sockmap, sockgetchar, common, log)
|
# Common object library (sockmap, sockgetchar, common, sem, log)
|
||||||
add_library(common_obj OBJECT
|
add_library(common_obj OBJECT
|
||||||
src/sockmap.c
|
src/sockmap.c
|
||||||
src/sockgetchar.c
|
src/sockgetchar.c
|
||||||
src/common.c
|
src/common.c
|
||||||
|
src/sem.c
|
||||||
src/log.c
|
src/log.c
|
||||||
)
|
)
|
||||||
target_include_directories(common_obj PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
target_include_directories(common_obj PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
|
|||||||
@ -35,7 +35,7 @@ RUN TAG=$(curl -s https://api.github.com/repos/wolfSSL/wolfssl/releases/latest \
|
|||||||
make -j$(nproc) && make install
|
make -j$(nproc) && make install
|
||||||
|
|
||||||
FROM docker.io/alpine:latest AS buildenv
|
FROM docker.io/alpine:latest AS buildenv
|
||||||
RUN apk add --no-cache gcc make musl-dev pcre2-dev
|
RUN apk add --no-cache gcc make musl-dev linux-headers pcre2-dev
|
||||||
COPY --from=wolfssl /usr/local /usr/local
|
COPY --from=wolfssl /usr/local /usr/local
|
||||||
COPY . 3proxy
|
COPY . 3proxy
|
||||||
RUN cd 3proxy && mkdir -p bin &&\
|
RUN cd 3proxy && mkdir -p bin &&\
|
||||||
|
|||||||
@ -41,7 +41,7 @@ RUN TAG=$(curl -s https://api.github.com/repos/wolfSSL/wolfssl/releases/latest \
|
|||||||
make -j$(nproc) && make install
|
make -j$(nproc) && make install
|
||||||
|
|
||||||
FROM docker.io/alpine:latest AS buildenv
|
FROM docker.io/alpine:latest AS buildenv
|
||||||
RUN apk add --no-cache gcc make musl-dev
|
RUN apk add --no-cache gcc make musl-dev linux-headers
|
||||||
COPY --from=wolfssl /usr/local /usr/local
|
COPY --from=wolfssl /usr/local /usr/local
|
||||||
COPY . 3proxy
|
COPY . 3proxy
|
||||||
RUN cd 3proxy && mkdir -p bin &&\
|
RUN cd 3proxy && mkdir -p bin &&\
|
||||||
|
|||||||
@ -135,7 +135,7 @@ install: all
|
|||||||
install -d $(DESTDIR)$(MANDIR)/man8
|
install -d $(DESTDIR)$(MANDIR)/man8
|
||||||
install -m 644 man/3proxy.8 $(DESTDIR)$(MANDIR)/man8/3proxy.8
|
install -m 644 man/3proxy.8 $(DESTDIR)$(MANDIR)/man8/3proxy.8
|
||||||
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
|
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
|
||||||
if [ -f man/$$f.8 ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \
|
if [ -f man/$$f.8 ] && [ -f bin/$(PREFIX)$$f ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \
|
||||||
done
|
done
|
||||||
install -m 644 man/3proxy_crypt.8 $(DESTDIR)$(MANDIR)/man8/$(CRYPT_PREFIX)crypt.8
|
install -m 644 man/3proxy_crypt.8 $(DESTDIR)$(MANDIR)/man8/$(CRYPT_PREFIX)crypt.8
|
||||||
install -d $(DESTDIR)$(MANDIR)/man5
|
install -d $(DESTDIR)$(MANDIR)/man5
|
||||||
|
|||||||
@ -123,15 +123,18 @@ INSTALL_BIN = $(INSTALL) -m 755
|
|||||||
INSTALL_DATA = $(INSTALL) -m 644
|
INSTALL_DATA = $(INSTALL) -m 644
|
||||||
INSTALL_OBJS = bin/3proxy \
|
INSTALL_OBJS = bin/3proxy \
|
||||||
bin/$(CRYPT_PREFIX)crypt \
|
bin/$(CRYPT_PREFIX)crypt \
|
||||||
bin/$(PREFIX)ftppr \
|
|
||||||
bin/$(PREFIX)imapp \
|
|
||||||
bin/$(PREFIX)pop3p \
|
|
||||||
bin/$(PREFIX)proxy \
|
bin/$(PREFIX)proxy \
|
||||||
bin/$(PREFIX)smtpp \
|
|
||||||
bin/$(PREFIX)socks \
|
bin/$(PREFIX)socks \
|
||||||
bin/$(PREFIX)tcppm \
|
bin/$(PREFIX)tcppm \
|
||||||
bin/$(PREFIX)tlspr \
|
bin/$(PREFIX)tlspr \
|
||||||
bin/$(PREFIX)udppm
|
bin/$(PREFIX)udppm
|
||||||
|
# the mail proxies and ftppr are only there when they were built
|
||||||
|
ifeq ($(MAILPROXY),true)
|
||||||
|
INSTALL_OBJS += bin/$(PREFIX)imapp bin/$(PREFIX)pop3p bin/$(PREFIX)smtpp
|
||||||
|
endif
|
||||||
|
ifeq ($(FTP),true)
|
||||||
|
INSTALL_OBJS += bin/$(PREFIX)ftppr
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
INSTALL_CFG = scripts/3proxy.cfg.chroot
|
INSTALL_CFG = scripts/3proxy.cfg.chroot
|
||||||
@ -189,7 +192,7 @@ install-man:
|
|||||||
$(INSTALL_DATA) man/3proxy.cfg.5 $(MANDIR5)
|
$(INSTALL_DATA) man/3proxy.cfg.5 $(MANDIR5)
|
||||||
$(INSTALL_DATA) man/3proxy.8 $(MANDIR8)
|
$(INSTALL_DATA) man/3proxy.8 $(MANDIR8)
|
||||||
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
|
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
|
||||||
if [ -f man/$$f.8 ]; then $(INSTALL_DATA) man/$$f.8 $(MANDIR8)/$(PREFIX)$$f.8; fi; \
|
if [ -f man/$$f.8 ] && [ -f bin/$(PREFIX)$$f ]; then $(INSTALL_DATA) man/$$f.8 $(MANDIR8)/$(PREFIX)$$f.8; fi; \
|
||||||
done
|
done
|
||||||
$(INSTALL_DATA) man/3proxy_crypt.8 $(MANDIR8)/$(CRYPT_PREFIX)crypt.8
|
$(INSTALL_DATA) man/3proxy_crypt.8 $(MANDIR8)/$(CRYPT_PREFIX)crypt.8
|
||||||
|
|
||||||
|
|||||||
@ -130,7 +130,7 @@ install: all
|
|||||||
install -d $(DESTDIR)$(MANDIR)/man8
|
install -d $(DESTDIR)$(MANDIR)/man8
|
||||||
install -m 644 man/3proxy.8 $(DESTDIR)$(MANDIR)/man8/3proxy.8
|
install -m 644 man/3proxy.8 $(DESTDIR)$(MANDIR)/man8/3proxy.8
|
||||||
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
|
for f in proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr; do \
|
||||||
if [ -f man/$$f.8 ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \
|
if [ -f man/$$f.8 ] && [ -f bin/$(PREFIX)$$f ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \
|
||||||
done
|
done
|
||||||
install -m 644 man/3proxy_crypt.8 $(DESTDIR)$(MANDIR)/man8/$(CRYPT_PREFIX)crypt.8
|
install -m 644 man/3proxy_crypt.8 $(DESTDIR)$(MANDIR)/man8/$(CRYPT_PREFIX)crypt.8
|
||||||
install -d $(DESTDIR)$(MANDIR)/man5
|
install -d $(DESTDIR)$(MANDIR)/man5
|
||||||
|
|||||||
2
debian/control
vendored
2
debian/control
vendored
@ -14,5 +14,5 @@ Depends: ${shlibs:Depends}, ${misc:Depends}
|
|||||||
Description: tiny free proxy server
|
Description: tiny free proxy server
|
||||||
3Proxy tiny free proxy server is really tiny freeware proxy servers set.
|
3Proxy tiny free proxy server is really tiny freeware proxy servers set.
|
||||||
It includes HTTP proxy with HTTPS and FTP support, SOCKSv4/SOCKSv4.5/SOCKSv5 proxy (socks/socks.exe), POP3 proxy, SMTP proxy, FTP proxy, caching DNS proxy, TCP and UDP portmappers.
|
It includes HTTP proxy with HTTPS and FTP support, SOCKSv4/SOCKSv4.5/SOCKSv5 proxy (socks/socks.exe), POP3 proxy, SMTP proxy, FTP proxy, caching DNS proxy, TCP and UDP portmappers.
|
||||||
You can use every proxy as a standalone program (socks, proxy, tcppm, udppm, pop3p) or use combined program (3proxy). Combined proxy additionally supports features like access control, bandwidth limiting, limiting daily/weekly/monthly traffic amount, proxy chaining, log rotation, syslog and ODBC logging, etc.
|
You can use every proxy as a standalone program (socks, proxy, tcppm, udppm, tlspr) or use combined program (3proxy). Combined proxy additionally supports features like access control, bandwidth limiting, limiting daily/weekly/monthly traffic amount, proxy chaining, log rotation, syslog and ODBC logging, etc.
|
||||||
It's created to be small, simple and yet very functional.
|
It's created to be small, simple and yet very functional.
|
||||||
@ -36,11 +36,7 @@ make clean
|
|||||||
%files
|
%files
|
||||||
/bin/3proxy
|
/bin/3proxy
|
||||||
/bin/3proxy_crypt
|
/bin/3proxy_crypt
|
||||||
/bin/3proxy_ftppr
|
|
||||||
/bin/3proxy_imapp
|
|
||||||
/bin/3proxy_pop3p
|
|
||||||
/bin/3proxy_proxy
|
/bin/3proxy_proxy
|
||||||
/bin/3proxy_smtpp
|
|
||||||
/bin/3proxy_socks
|
/bin/3proxy_socks
|
||||||
/bin/3proxy_tcppm
|
/bin/3proxy_tcppm
|
||||||
/bin/3proxy_tlspr
|
/bin/3proxy_tlspr
|
||||||
|
|||||||
@ -13,6 +13,9 @@ udpsockmap$(OBJSUFFICS): udpsockmap.c proxy.h structures.h
|
|||||||
common$(OBJSUFFICS): common.c proxy.h structures.h
|
common$(OBJSUFFICS): common.c proxy.h structures.h
|
||||||
$(CC) $(CFLAGS) common.c
|
$(CC) $(CFLAGS) common.c
|
||||||
|
|
||||||
|
sem$(OBJSUFFICS): sem.c proxy.h structures.h
|
||||||
|
$(CC) $(CFLAGS) sem.c
|
||||||
|
|
||||||
plugins$(OBJSUFFICS): plugins.c proxy.h structures.h
|
plugins$(OBJSUFFICS): plugins.c proxy.h structures.h
|
||||||
$(CC) $(CFLAGS) plugins.c
|
$(CC) $(CFLAGS) plugins.c
|
||||||
|
|
||||||
@ -56,32 +59,32 @@ socks$(OBJSUFFICS): socks.c proxy.h structures.h proxymain.c
|
|||||||
3proxy$(OBJSUFFICS): 3proxy.c proxy.h structures.h
|
3proxy$(OBJSUFFICS): 3proxy.c proxy.h structures.h
|
||||||
$(CC) $(CFLAGS) 3proxy.c
|
$(CC) $(CFLAGS) 3proxy.c
|
||||||
|
|
||||||
$(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS): sockmap$(OBJSUFFICS) proxy$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS)
|
$(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS): sockmap$(OBJSUFFICS) proxy$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) proxy$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) proxy$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
||||||
|
|
||||||
$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS): sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS)
|
$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS): sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
||||||
|
|
||||||
$(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS): sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS)
|
$(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS): sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
||||||
|
|
||||||
$(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS): sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS)
|
$(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS): sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) base64$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) base64$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
||||||
|
|
||||||
$(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS): sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) ftp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS)
|
$(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS): sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) ftp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
|
||||||
|
|
||||||
$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
|
$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(LIBS)
|
||||||
|
|
||||||
$(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
|
$(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(LIBS)
|
||||||
|
|
||||||
$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) hash$(OBJSUFFICS)
|
$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) hash$(OBJSUFFICS)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) hash$(OBJSUFFICS) $(LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) hash$(OBJSUFFICS) $(LIBS)
|
||||||
|
|
||||||
$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
|
$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(LIBS)
|
||||||
|
|
||||||
mainfunc$(OBJSUFFICS): proxy.h structures.h proxymain.c
|
mainfunc$(OBJSUFFICS): proxy.h structures.h proxymain.c
|
||||||
$(CC) $(COUT)mainfunc$(OBJSUFFICS) $(CFLAGS) $(DEFINEOPTION)MODULEMAINFUNC=mainfunc proxymain.c
|
$(CC) $(COUT)mainfunc$(OBJSUFFICS) $(CFLAGS) $(DEFINEOPTION)MODULEMAINFUNC=mainfunc proxymain.c
|
||||||
@ -194,6 +197,6 @@ ssl$(OBJSUFFICS): ssl.c structures.h proxy.h ssl.h
|
|||||||
pcre$(OBJSUFFICS): pcre.c structures.h
|
pcre$(OBJSUFFICS): pcre.c structures.h
|
||||||
$(CC) $(COUT)pcre$(OBJSUFFICS) $(CFLAGS) $(DEFINEOPTION)WITH_PCRE pcre.c
|
$(CC) $(COUT)pcre$(OBJSUFFICS) $(CFLAGS) $(DEFINEOPTION)WITH_PCRE pcre.c
|
||||||
|
|
||||||
$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvimapp$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(VERSIONDEP)
|
$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvimapp$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(VERSIONDEP)
|
||||||
$(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvimapp$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(LIBS) $(PCRE_LIBS)
|
$(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvimapp$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) blake2$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) $(HTTPSRV_OBJS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) mdhash$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(TRANSPARENT_OBJS) $(COMPATLIBS) $(LIBS) $(PCRE_LIBS)
|
||||||
|
|
||||||
|
|||||||
90
src/common.c
90
src/common.c
@ -187,33 +187,6 @@ size_t threadstacksize(int extra){
|
|||||||
if(size < (long)PTHREAD_STACK_MIN) size = (long)PTHREAD_STACK_MIN;
|
if(size < (long)PTHREAD_STACK_MIN) size = (long)PTHREAD_STACK_MIN;
|
||||||
return (size_t)size;
|
return (size_t)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _3proxy_sem_init_f(_3proxy_sem_t *sem, unsigned count, unsigned maxcount){
|
|
||||||
sem->count = count;
|
|
||||||
sem->maxcount = maxcount;
|
|
||||||
if(pthread_mutex_init(&sem->mutex, NULL)) return 1;
|
|
||||||
if(pthread_cond_init(&sem->cond, NULL)){
|
|
||||||
pthread_mutex_destroy(&sem->mutex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _3proxy_sem_lock_f(_3proxy_sem_t *sem){
|
|
||||||
pthread_mutex_lock(&sem->mutex);
|
|
||||||
while(!sem->count) pthread_cond_wait(&sem->cond, &sem->mutex);
|
|
||||||
sem->count--;
|
|
||||||
pthread_mutex_unlock(&sem->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _3proxy_sem_unlock_f(_3proxy_sem_t *sem){
|
|
||||||
pthread_mutex_lock(&sem->mutex);
|
|
||||||
if(sem->count < sem->maxcount){
|
|
||||||
sem->count++;
|
|
||||||
pthread_cond_signal(&sem->cond);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&sem->mutex);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct extparam conf = {
|
struct extparam conf = {
|
||||||
@ -683,6 +656,49 @@ int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa,
|
|||||||
|
|
||||||
static int bindrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa, uint32_t range, int *tries);
|
static int bindrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa, uint32_t range, int *tries);
|
||||||
|
|
||||||
|
/* -Di / -De: ties a socket to the interface asked for, for TCP and UDP alike.
|
||||||
|
Where the option is set per protocol, family is the one of the address the
|
||||||
|
socket will be bound to. */
|
||||||
|
int bindtodevice(struct sockfuncs *sf, void *state, SOCKET sock, const char *device, int family){
|
||||||
|
if(!device) return 0;
|
||||||
|
#if defined SO_BINDTODEVICE
|
||||||
|
if(sf->_setsockopt(state, sock, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1))
|
||||||
|
return 1;
|
||||||
|
#elif defined IP_BOUND_IF
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
idx = if_nametoindex(device);
|
||||||
|
if(!idx || (family == AF_INET && sf->_setsockopt(state, sock, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx))))
|
||||||
|
return 1;
|
||||||
|
#ifndef NOIPV6
|
||||||
|
#ifndef IPV6_BOUND_IF
|
||||||
|
#define IPV6_BOUND_IF 125
|
||||||
|
#endif
|
||||||
|
if(family == AF_INET6 && sf->_setsockopt(state, sock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx))) return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the external side, a socket to be bound to sinsl */
|
||||||
|
int extbindtodevice(struct clientparam *param, SOCKET sock){
|
||||||
|
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
|
||||||
|
return bindtodevice(¶m->srv->so, param->sostate, sock, param->srv->obindtodevice, *SAFAMILY(¶m->sinsl));
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the internal side, a socket to be bound to sincl */
|
||||||
|
int intbindtodevice(struct clientparam *param, SOCKET sock){
|
||||||
|
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
|
||||||
|
return bindtodevice(¶m->srv->so, param->sostate, sock, param->srv->ibindtodevice, *SAFAMILY(¶m->sincl));
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int doconnect(struct clientparam * param){
|
int doconnect(struct clientparam * param){
|
||||||
SASIZETYPE size;
|
SASIZETYPE size;
|
||||||
|
|
||||||
@ -732,25 +748,7 @@ int doconnect(struct clientparam * param){
|
|||||||
setopts(param->remsock, param->srv->srvsockopts);
|
setopts(param->remsock, param->srv->srvsockopts);
|
||||||
|
|
||||||
param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
||||||
#if defined SO_BINDTODEVICE
|
if(extbindtodevice(param, param->remsock)) return 12;
|
||||||
if(param->srv->obindtodevice) {
|
|
||||||
if(param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_BINDTODEVICE, param->srv->obindtodevice, strlen(param->srv->obindtodevice) + 1))
|
|
||||||
return 12;
|
|
||||||
}
|
|
||||||
#elif defined IP_BOUND_IF
|
|
||||||
if(param->srv->obindtodevice) {
|
|
||||||
int idx;
|
|
||||||
idx = if_nametoindex(param->srv->obindtodevice);
|
|
||||||
if(!idx || (*SAFAMILY(¶m->sinsl) == AF_INET && param->srv->so._setsockopt(param->sostate, param->remsock, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx))))
|
|
||||||
return 12;
|
|
||||||
#ifndef NOIPV6
|
|
||||||
#ifndef IPV6_BOUND_IF
|
|
||||||
#define IPV6_BOUND_IF 125
|
|
||||||
#endif
|
|
||||||
if(*SAFAMILY(¶m->sinsl) == AF_INET6 && param->srv->so._setsockopt(param->sostate, param->remsock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx))) return 12;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_UN
|
#ifdef WITH_UN
|
||||||
if(*SAFAMILY(¶m->sinsl) != AF_UNIX)
|
if(*SAFAMILY(¶m->sinsl) != AF_UNIX)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -129,6 +129,7 @@ void * ftpprchild(struct clientparam* param) {
|
|||||||
clidatasock = INVALID_SOCKET;
|
clidatasock = INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
if ((clidatasock=socket(SASOCK(¶m->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);}
|
if ((clidatasock=socket(SASOCK(¶m->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);}
|
||||||
|
if(intbindtodevice(param, clidatasock)){RETURN(822);}
|
||||||
*SAPORT(¶m->sincl) = 0;
|
*SAPORT(¶m->sincl) = 0;
|
||||||
if(bindwithrange(param, clidatasock, ¶m->sincl, param->intport)){RETURN(822);}
|
if(bindwithrange(param, clidatasock, ¶m->sincl, param->intport)){RETURN(822);}
|
||||||
if (pasv) {
|
if (pasv) {
|
||||||
|
|||||||
17
src/proxy.h
17
src/proxy.h
@ -322,13 +322,23 @@ extern _3proxy_sem_t udpinit;
|
|||||||
#define _3proxy_sem_init(x, count, maxcount) (((x) = CreateSemaphore(NULL, (count), (maxcount), NULL))? 0 : 1)
|
#define _3proxy_sem_init(x, count, maxcount) (((x) = CreateSemaphore(NULL, (count), (maxcount), NULL))? 0 : 1)
|
||||||
#define _3proxy_sem_lock(x) WaitForSingleObject(x, INFINITE)
|
#define _3proxy_sem_lock(x) WaitForSingleObject(x, INFINITE)
|
||||||
#define _3proxy_sem_unlock(x) ReleaseSemaphore(x, 1, NULL)
|
#define _3proxy_sem_unlock(x) ReleaseSemaphore(x, 1, NULL)
|
||||||
|
#define _3proxy_sem_init_timed(x, count, maxcount) _3proxy_sem_init(x, (count), (maxcount))
|
||||||
|
#define _3proxy_sem_timedlock(x, ms) (WaitForSingleObject(x, ms) != WAIT_OBJECT_0)
|
||||||
|
#define _3proxy_sem_destroy(x) CloseHandle(x)
|
||||||
#else
|
#else
|
||||||
int _3proxy_sem_init_f(_3proxy_sem_t *sem, unsigned count, unsigned maxcount);
|
int _3proxy_sem_init_f(_3proxy_sem_t *sem, unsigned count, unsigned maxcount, int timed);
|
||||||
void _3proxy_sem_lock_f(_3proxy_sem_t *sem);
|
void _3proxy_sem_lock_f(_3proxy_sem_t *sem);
|
||||||
|
int _3proxy_sem_timedlock_f(_3proxy_sem_t *sem, unsigned ms);
|
||||||
void _3proxy_sem_unlock_f(_3proxy_sem_t *sem);
|
void _3proxy_sem_unlock_f(_3proxy_sem_t *sem);
|
||||||
#define _3proxy_sem_init(x, count, maxcount) _3proxy_sem_init_f(&x, (count), (maxcount))
|
void _3proxy_sem_destroy_f(_3proxy_sem_t *sem);
|
||||||
|
#define _3proxy_sem_init(x, count, maxcount) _3proxy_sem_init_f(&x, (count), (maxcount), 0)
|
||||||
|
/* for a semaphore waited on with a timeout: the wait is not stretched or cut
|
||||||
|
short by the system time being changed, where the platform allows it */
|
||||||
|
#define _3proxy_sem_init_timed(x, count, maxcount) _3proxy_sem_init_f(&x, (count), (maxcount), 1)
|
||||||
#define _3proxy_sem_lock(x) _3proxy_sem_lock_f(&x)
|
#define _3proxy_sem_lock(x) _3proxy_sem_lock_f(&x)
|
||||||
|
#define _3proxy_sem_timedlock(x, ms) _3proxy_sem_timedlock_f(&x, (ms))
|
||||||
#define _3proxy_sem_unlock(x) _3proxy_sem_unlock_f(&x)
|
#define _3proxy_sem_unlock(x) _3proxy_sem_unlock_f(&x)
|
||||||
|
#define _3proxy_sem_destroy(x) _3proxy_sem_destroy_f(&x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -391,6 +401,9 @@ int readconfig(FILE * fp);
|
|||||||
void initcommands(void);
|
void initcommands(void);
|
||||||
int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to);
|
int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to);
|
||||||
int bindwithrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa, uint32_t range);
|
int bindwithrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa, uint32_t range);
|
||||||
|
int bindtodevice(struct sockfuncs *sf, void *state, SOCKET sock, const char *device, int family);
|
||||||
|
int extbindtodevice(struct clientparam *param, SOCKET sock);
|
||||||
|
int intbindtodevice(struct clientparam *param, SOCKET sock);
|
||||||
#ifdef WITH_PCRE
|
#ifdef WITH_PCRE
|
||||||
/* One regular expression implementation for the whole program: the pcre
|
/* One regular expression implementation for the whole program: the pcre
|
||||||
commands and every pattern that carries a pcre: prefix. */
|
commands and every pattern that carries a pcre: prefix. */
|
||||||
|
|||||||
102
src/proxymain.c
102
src/proxymain.c
@ -308,6 +308,7 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
struct linger lg;
|
struct linger lg;
|
||||||
int nlog = 5000;
|
int nlog = 5000;
|
||||||
|
int haveslot = 0, nfull = 0;
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
int saved_nsfd = -1;
|
int saved_nsfd = -1;
|
||||||
#endif
|
#endif
|
||||||
@ -862,29 +863,11 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int));
|
srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if defined SO_BINDTODEVICE
|
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
|
||||||
if(srv.ibindtodevice && srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_BINDTODEVICE, srv.ibindtodevice, strlen(srv.ibindtodevice) + 1)) {
|
if(bindtodevice(&srv.so, srv.so.state, sock, srv.ibindtodevice, *SAFAMILY(&srv.intsa))) {
|
||||||
dolog(&defparam, (unsigned char *)"failed to bind device");
|
dolog(&defparam, (unsigned char *)"failed to bind device");
|
||||||
return -12;
|
return -12;
|
||||||
}
|
}
|
||||||
#elif defined IP_BOUND_IF
|
|
||||||
if(srv.ibindtodevice){
|
|
||||||
int idx;
|
|
||||||
idx = if_nametoindex(srv.ibindtodevice);
|
|
||||||
if(!idx || (*SAFAMILY(&srv.intsa) == AF_INET && setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx)))) {
|
|
||||||
dolog(&defparam, (unsigned char *)"failed to bind device");
|
|
||||||
return -12;
|
|
||||||
}
|
|
||||||
#ifndef NOIPV6
|
|
||||||
#ifndef IPV6_BOUND_IF
|
|
||||||
#define IPV6_BOUND_IF 125
|
|
||||||
#endif
|
|
||||||
if((*SAFAMILY(&srv.intsa) == AF_INET6 && srv.so._setsockopt(srv.so.state, sock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx)))) {
|
|
||||||
dolog(&defparam, (unsigned char *)"failed to bind device");
|
|
||||||
return -12;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef WITH_UN
|
#ifdef WITH_UN
|
||||||
@ -1008,14 +991,19 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
for(;;){
|
for(;;){
|
||||||
while((conf.paused == srv.paused && srv.childcount >= srv.maxchild)){
|
/* A connection is only taken with a slot of maxchild in hand, which
|
||||||
nlog++;
|
goes to its child; a slot not handed on is kept for the next one.
|
||||||
if(!srv.silent && nlog > 5000) {
|
The wait is timed to notice a reload. */
|
||||||
|
while(!haveslot && conf.paused == srv.paused){
|
||||||
|
if(!_3proxy_sem_timedlock(srv.childslots, 1000)){
|
||||||
|
haveslot = 1;
|
||||||
|
nfull = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!srv.silent && !(nfull++ % 5)) {
|
||||||
sprintf((char *)buf, "Warning: too many connected clients (%d/%d)", srv.childcount, srv.maxchild);
|
sprintf((char *)buf, "Warning: too many connected clients (%d/%d)", srv.childcount, srv.maxchild);
|
||||||
dolog(&defparam, buf);
|
dolog(&defparam, buf);
|
||||||
nlog = 0;
|
|
||||||
}
|
}
|
||||||
usleep(SLEEPTIME);
|
|
||||||
}
|
}
|
||||||
if (iscbc) break;
|
if (iscbc) break;
|
||||||
if (conf.paused != srv.paused) break;
|
if (conf.paused != srv.paused) break;
|
||||||
@ -1038,6 +1026,15 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
setopts(new_sock, srv.cbcsockopts);
|
setopts(new_sock, srv.cbcsockopts);
|
||||||
|
|
||||||
parsehost(srv.family, cbc_string, (struct sockaddr *)&defparam.sincr);
|
parsehost(srv.family, cbc_string, (struct sockaddr *)&defparam.sincr);
|
||||||
|
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
|
||||||
|
/* as for a listening socket, an interface that cannot be
|
||||||
|
bound to is not worth retrying */
|
||||||
|
if(bindtodevice(&so, so.state, new_sock, srv.ibindtodevice, *SAFAMILY(&defparam.sincr))) {
|
||||||
|
dolog(&defparam, (unsigned char *)"failed to bind device");
|
||||||
|
so._closesocket(so.state, new_sock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if(connectwithpoll(NULL, new_sock,(struct sockaddr *)&defparam.sincr,SASIZE(&defparam.sincr),CONNBACK_TO)) {
|
if(connectwithpoll(NULL, new_sock,(struct sockaddr *)&defparam.sincr,SASIZE(&defparam.sincr),CONNBACK_TO)) {
|
||||||
so._closesocket(so.state, new_sock);
|
so._closesocket(so.state, new_sock);
|
||||||
new_sock = INVALID_SOCKET;
|
new_sock = INVALID_SOCKET;
|
||||||
@ -1222,6 +1219,7 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
srv.childcount++;
|
srv.childcount++;
|
||||||
|
haveslot = 0;
|
||||||
newparam->threadid = (uint64_t)thread;
|
newparam->threadid = (uint64_t)thread;
|
||||||
}
|
}
|
||||||
_3proxy_mutex_unlock(&srv.counter_mutex);
|
_3proxy_mutex_unlock(&srv.counter_mutex);
|
||||||
@ -1239,6 +1237,8 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!srv.silent) srv.logfunc(&defparam, (unsigned char *)"Exiting thread");
|
if(!srv.silent) srv.logfunc(&defparam, (unsigned char *)"Exiting thread");
|
||||||
|
/* srvfree() waits for every slot to come back, this one included */
|
||||||
|
if(haveslot) _3proxy_sem_unlock(srv.childslots);
|
||||||
srvfree(&srv);
|
srvfree(&srv);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@ -1293,6 +1293,7 @@ void srvinit(struct srvparam * srv, struct clientparam *param){
|
|||||||
param->remsock = param->clisock = param->ctrlsock = param->ctrlsocksrv = INVALID_SOCKET;
|
param->remsock = param->clisock = param->ctrlsock = param->ctrlsocksrv = INVALID_SOCKET;
|
||||||
*SAFAMILY(¶m->req) = *SAFAMILY(¶m->sinsl) = *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->sincr) = *SAFAMILY(¶m->sincl) = AF_INET;
|
*SAFAMILY(¶m->req) = *SAFAMILY(¶m->sinsl) = *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->sincr) = *SAFAMILY(¶m->sincl) = AF_INET;
|
||||||
_3proxy_mutex_init(&srv->counter_mutex);
|
_3proxy_mutex_init(&srv->counter_mutex);
|
||||||
|
(void)_3proxy_sem_init_timed(srv->childslots, srv->maxchild, srv->maxchild);
|
||||||
#ifndef NOUDPMAIN
|
#ifndef NOUDPMAIN
|
||||||
if(!udpinited){
|
if(!udpinited){
|
||||||
(void)_3proxy_sem_init(udpinit, 1, 1);
|
(void)_3proxy_sem_init(udpinit, 1, 1);
|
||||||
@ -1338,6 +1339,8 @@ void srvinit2(struct srvparam * srv, struct clientparam *param){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void srvfree(struct srvparam * srv){
|
void srvfree(struct srvparam * srv){
|
||||||
|
int i;
|
||||||
|
|
||||||
if(srv->srvsock != INVALID_SOCKET) {
|
if(srv->srvsock != INVALID_SOCKET) {
|
||||||
so._closesocket(srv->so.state, srv->srvsock);
|
so._closesocket(srv->so.state, srv->srvsock);
|
||||||
#ifdef WITH_UN
|
#ifdef WITH_UN
|
||||||
@ -1348,7 +1351,13 @@ void srvfree(struct srvparam * srv){
|
|||||||
if(srv->cbsock != INVALID_SOCKET) so._closesocket(srv->so.state, srv->cbsock);
|
if(srv->cbsock != INVALID_SOCKET) so._closesocket(srv->so.state, srv->cbsock);
|
||||||
srv->cbsock = INVALID_SOCKET;
|
srv->cbsock = INVALID_SOCKET;
|
||||||
srv->service = S_ZOMBIE;
|
srv->service = S_ZOMBIE;
|
||||||
while(srv->child) usleep(SLEEPTIME * 100);
|
/* Every child returns its slot as the last thing it does with the service,
|
||||||
|
so once all of them are back no child is left. A child posts its slot
|
||||||
|
holding the mutex: taking the mutex once more waits for the last one to
|
||||||
|
have let go of both before they are destroyed. */
|
||||||
|
for(i = srv->maxchild; i; i--) _3proxy_sem_lock(srv->childslots);
|
||||||
|
_3proxy_mutex_lock(&srv->counter_mutex);
|
||||||
|
_3proxy_mutex_unlock(&srv->counter_mutex);
|
||||||
#ifndef STDMAIN
|
#ifndef STDMAIN
|
||||||
if(srv->filter){
|
if(srv->filter){
|
||||||
while(srv->nfilters){
|
while(srv->nfilters){
|
||||||
@ -1367,6 +1376,7 @@ void srvfree(struct srvparam * srv){
|
|||||||
if(srv->authfuncs)freeauth(srv->authfuncs);
|
if(srv->authfuncs)freeauth(srv->authfuncs);
|
||||||
#endif
|
#endif
|
||||||
_3proxy_mutex_destroy(&srv->counter_mutex);
|
_3proxy_mutex_destroy(&srv->counter_mutex);
|
||||||
|
_3proxy_sem_destroy(srv->childslots);
|
||||||
if(srv->target) free(srv->target);
|
if(srv->target) free(srv->target);
|
||||||
if(srv->logtarget) free(srv->logtarget);
|
if(srv->logtarget) free(srv->logtarget);
|
||||||
if(srv->logformat) free(srv->logformat);
|
if(srv->logformat) free(srv->logformat);
|
||||||
@ -1393,22 +1403,13 @@ void srvfree(struct srvparam * srv){
|
|||||||
void freeparam(struct clientparam * param) {
|
void freeparam(struct clientparam * param) {
|
||||||
if(param->srv){
|
if(param->srv){
|
||||||
if(param->srv->so.freefunc) param->srv->so.freefunc(param->sostate);
|
if(param->srv->so.freefunc) param->srv->so.freefunc(param->sostate);
|
||||||
_3proxy_mutex_lock(¶m->srv->counter_mutex);
|
|
||||||
#ifndef STDMAIN
|
#ifndef STDMAIN
|
||||||
if(param->srv->service == S_UDPPM) hashdelete(&udp_table, param);
|
if(param->srv->service == S_UDPPM){
|
||||||
#endif
|
_3proxy_mutex_lock(¶m->srv->counter_mutex);
|
||||||
if(param->prev || param->next || param->srv->child == param){
|
hashdelete(&udp_table, param);
|
||||||
if(param->prev){
|
_3proxy_mutex_unlock(¶m->srv->counter_mutex);
|
||||||
param->prev->next = param->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
param->srv->child = param->next;
|
|
||||||
if(param->next){
|
|
||||||
param->next->prev = param->prev;
|
|
||||||
}
|
|
||||||
(param->srv->childcount)--;
|
|
||||||
}
|
}
|
||||||
_3proxy_mutex_unlock(¶m->srv->counter_mutex);
|
#endif
|
||||||
}
|
}
|
||||||
if(param->clibuf) free(param->clibuf);
|
if(param->clibuf) free(param->clibuf);
|
||||||
if(param->srvbuf) free(param->srvbuf);
|
if(param->srvbuf) free(param->srvbuf);
|
||||||
@ -1448,6 +1449,27 @@ void freeparam(struct clientparam * param) {
|
|||||||
}
|
}
|
||||||
if(param->connlim) stopconnlims(param);
|
if(param->connlim) stopconnlims(param);
|
||||||
#endif
|
#endif
|
||||||
|
/* Leaving the service comes last. Once its last child is gone, srvfree()
|
||||||
|
frees the service along with its socket functions, filters and mutex,
|
||||||
|
and a close above may have lingered for seconds before getting here. */
|
||||||
|
if(param->srv){
|
||||||
|
_3proxy_mutex_lock(¶m->srv->counter_mutex);
|
||||||
|
if(param->prev || param->next || param->srv->child == param){
|
||||||
|
if(param->prev){
|
||||||
|
param->prev->next = param->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
param->srv->child = param->next;
|
||||||
|
if(param->next){
|
||||||
|
param->next->prev = param->prev;
|
||||||
|
}
|
||||||
|
(param->srv->childcount)--;
|
||||||
|
/* under the mutex too: srvfree() may destroy the semaphore as
|
||||||
|
soon as the mutex shows the last child gone */
|
||||||
|
_3proxy_sem_unlock(param->srv->childslots);
|
||||||
|
}
|
||||||
|
_3proxy_mutex_unlock(¶m->srv->counter_mutex);
|
||||||
|
}
|
||||||
if(param->hostname) free(param->hostname);
|
if(param->hostname) free(param->hostname);
|
||||||
if(param->username) free(param->username);
|
if(param->username) free(param->username);
|
||||||
if(param->password) free(param->password);
|
if(param->password) free(param->password);
|
||||||
|
|||||||
110
src/sem.c
Normal file
110
src/sem.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
3APA3A simplest proxy server
|
||||||
|
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
|
||||||
|
|
||||||
|
please read License Agreement
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Counting semaphores for POSIX systems, built on a mutex and a condition
|
||||||
|
variable: unnamed POSIX semaphores are not available everywhere (macOS)
|
||||||
|
and have no timed wait there. Windows uses its own semaphores, see proxy.h. */
|
||||||
|
|
||||||
|
#include "proxy.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
/* macOS has CLOCK_MONOTONIC but no pthread_condattr_setclock(); a relative
|
||||||
|
wait is used there instead, which the system time does not affect either */
|
||||||
|
#if defined(CLOCK_MONOTONIC) && !defined(__APPLE__)
|
||||||
|
#define SEM_MONOTONIC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int _3proxy_sem_init_f(_3proxy_sem_t *sem, unsigned count, unsigned maxcount, int timed){
|
||||||
|
int res;
|
||||||
|
|
||||||
|
sem->count = count;
|
||||||
|
sem->maxcount = maxcount;
|
||||||
|
sem->monotonic = 0;
|
||||||
|
if(pthread_mutex_init(&sem->mutex, NULL)) return 1;
|
||||||
|
#ifdef SEM_MONOTONIC
|
||||||
|
if(timed){
|
||||||
|
pthread_condattr_t attr;
|
||||||
|
|
||||||
|
if(!pthread_condattr_init(&attr)){
|
||||||
|
if(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) sem->monotonic = 1;
|
||||||
|
res = pthread_cond_init(&sem->cond, &attr);
|
||||||
|
pthread_condattr_destroy(&attr);
|
||||||
|
}
|
||||||
|
else res = pthread_cond_init(&sem->cond, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
res = pthread_cond_init(&sem->cond, NULL);
|
||||||
|
if(res){
|
||||||
|
pthread_mutex_destroy(&sem->mutex);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _3proxy_sem_lock_f(_3proxy_sem_t *sem){
|
||||||
|
pthread_mutex_lock(&sem->mutex);
|
||||||
|
while(!sem->count) pthread_cond_wait(&sem->cond, &sem->mutex);
|
||||||
|
sem->count--;
|
||||||
|
pthread_mutex_unlock(&sem->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns 0 with the semaphore taken, nonzero if ms passed first. */
|
||||||
|
int _3proxy_sem_timedlock_f(_3proxy_sem_t *sem, unsigned ms){
|
||||||
|
struct timespec ts;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
ts.tv_sec = ms / 1000;
|
||||||
|
ts.tv_nsec = (long)(ms % 1000) * 1000000;
|
||||||
|
pthread_mutex_lock(&sem->mutex);
|
||||||
|
while(!sem->count && !res) res = pthread_cond_timedwait_relative_np(&sem->cond, &sem->mutex, &ts);
|
||||||
|
#else
|
||||||
|
/* the deadline is on the clock the condition variable was set up with */
|
||||||
|
#ifdef SEM_MONOTONIC
|
||||||
|
if(sem->monotonic) clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
ts.tv_sec = tv.tv_sec;
|
||||||
|
ts.tv_nsec = tv.tv_usec * 1000;
|
||||||
|
}
|
||||||
|
ts.tv_sec += ms / 1000;
|
||||||
|
ts.tv_nsec += (long)(ms % 1000) * 1000000;
|
||||||
|
if(ts.tv_nsec >= 1000000000){
|
||||||
|
ts.tv_sec++;
|
||||||
|
ts.tv_nsec -= 1000000000;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&sem->mutex);
|
||||||
|
while(!sem->count && !res) res = pthread_cond_timedwait(&sem->cond, &sem->mutex, &ts);
|
||||||
|
#endif
|
||||||
|
if(sem->count){
|
||||||
|
sem->count--;
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&sem->mutex);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _3proxy_sem_unlock_f(_3proxy_sem_t *sem){
|
||||||
|
pthread_mutex_lock(&sem->mutex);
|
||||||
|
if(sem->count < sem->maxcount){
|
||||||
|
sem->count++;
|
||||||
|
pthread_cond_signal(&sem->cond);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&sem->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _3proxy_sem_destroy_f(_3proxy_sem_t *sem){
|
||||||
|
pthread_cond_destroy(&sem->cond);
|
||||||
|
pthread_mutex_destroy(&sem->mutex);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -185,6 +185,7 @@ void * sockschild(struct clientparam* param) {
|
|||||||
if(command == 2){
|
if(command == 2){
|
||||||
if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(¶m->req), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN (11);}
|
if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(¶m->req), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN (11);}
|
||||||
setopts(param->remsock, param->srv->lissockopts);
|
setopts(param->remsock, param->srv->lissockopts);
|
||||||
|
if(extbindtodevice(param, param->remsock)) {RETURN (12);}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -244,6 +245,7 @@ fflush(stderr);
|
|||||||
#else
|
#else
|
||||||
fcntl(param->clisock, F_SETFL, O_NONBLOCK | fcntl(param->clisock, F_GETFL));
|
fcntl(param->clisock, F_SETFL, O_NONBLOCK | fcntl(param->clisock, F_GETFL));
|
||||||
#endif
|
#endif
|
||||||
|
if(intbindtodevice(param, param->clisock)) {RETURN (12);}
|
||||||
sin = param->sincl;
|
sin = param->sincl;
|
||||||
*SAPORT(&sin) = 0;
|
*SAPORT(&sin) = 0;
|
||||||
/* the port the client is told to send its datagrams to */
|
/* the port the client is told to send its datagrams to */
|
||||||
|
|||||||
@ -47,6 +47,7 @@ typedef struct _3proxy_sem_s {
|
|||||||
pthread_cond_t cond;
|
pthread_cond_t cond;
|
||||||
unsigned count;
|
unsigned count;
|
||||||
unsigned maxcount;
|
unsigned maxcount;
|
||||||
|
int monotonic; /* timed waits measured on CLOCK_MONOTONIC */
|
||||||
} _3proxy_sem_t;
|
} _3proxy_sem_t;
|
||||||
#else
|
#else
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
@ -635,6 +636,7 @@ struct srvparam {
|
|||||||
#endif
|
#endif
|
||||||
PROXYSOCKADDRTYPE extsa;
|
PROXYSOCKADDRTYPE extsa;
|
||||||
_3proxy_mutex_t counter_mutex;
|
_3proxy_mutex_t counter_mutex;
|
||||||
|
_3proxy_sem_t childslots; /* maxchild of them, one held by each child */
|
||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
FILE *stdlog;
|
FILE *stdlog;
|
||||||
unsigned char * target;
|
unsigned char * target;
|
||||||
|
|||||||
@ -121,6 +121,11 @@ int udpbind(struct clientparam *param)
|
|||||||
fcntl(s, F_SETFL, O_NONBLOCK | fcntl(s, F_GETFL));
|
fcntl(s, F_SETFL, O_NONBLOCK | fcntl(s, F_GETFL));
|
||||||
#endif
|
#endif
|
||||||
param->remsock = s;
|
param->remsock = s;
|
||||||
|
if (extbindtodevice(param, param->remsock)) {
|
||||||
|
param->srv->so._closesocket(param->sostate, param->remsock);
|
||||||
|
param->remsock = INVALID_SOCKET;
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
if (bindwithrange(param, param->remsock, ¶m->sinsl, param->extport)) {
|
if (bindwithrange(param, param->remsock, ¶m->sinsl, param->extport)) {
|
||||||
if (param->extport) {
|
if (param->extport) {
|
||||||
param->srv->so._closesocket(param->sostate, param->remsock);
|
param->srv->so._closesocket(param->sostate, param->remsock);
|
||||||
|
|||||||
@ -69,7 +69,7 @@ means to stand on its own should start with one - otherwise an earlier
|
|||||||
|
|
||||||
## What is not covered yet
|
## What is not covered yet
|
||||||
|
|
||||||
41 of the 112 configuration commands appear in a test, and the count says
|
42 of the 112 configuration commands appear in a test, and the count says
|
||||||
nothing about service options: the IPv6 case, for instance, exercises -4,
|
nothing about service options: the IPv6 case, for instance, exercises -4,
|
||||||
-6, -46, -64 and -i without adding a command to it. What follows is
|
-6, -46, -64 and -i without adding a command to it. What follows is
|
||||||
roughly the order worth working through: how much of the product a gap
|
roughly the order worth working through: how much of the product a gap
|
||||||
@ -78,12 +78,13 @@ covers, and how much of a fixture it needs.
|
|||||||
### Traffic limits and accounting
|
### Traffic limits and accounting
|
||||||
|
|
||||||
`bandlimin` `bandlimout` `nobandlimin` `nobandlimout` `connlim` `noconnlim`
|
`bandlimin` `bandlimout` `nobandlimin` `nobandlimout` `connlim` `noconnlim`
|
||||||
`countin` `countout` `countall` and the `no*` forms, `maxconn`.
|
`countin` `countout` `countall` and the `no*` forms.
|
||||||
|
|
||||||
Cheap and worth doing first: `data?size=` and a stopwatch measure a
|
Cheap and worth doing first: `data?size=` and a stopwatch measure a
|
||||||
bandwidth limit, and the admin counters page already shows what a counter
|
bandwidth limit, and the admin counters page already shows what a counter
|
||||||
holds. `countin` appears in a configuration today but nothing checks that it
|
holds. `countin` appears in a configuration today but nothing checks that it
|
||||||
counts. `connlim` and `maxconn` need concurrent connections.
|
counts. `connlim` needs concurrent connections, held open the way the
|
||||||
|
`maxconn` case holds them.
|
||||||
|
|
||||||
### The mail proxies
|
### The mail proxies
|
||||||
|
|
||||||
|
|||||||
107
tests/cases/maxconn.py
Normal file
107
tests/cases/maxconn.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
"""maxconn: a service serves at most that many connections at once, and a
|
||||||
|
connection over the limit waits for one of them to finish."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def run(t):
|
||||||
|
# The origin runs in a process of its own, so the limit only applies to
|
||||||
|
# the mapper in front of it.
|
||||||
|
origin = t.free_port()
|
||||||
|
t.start("maxconn_origin", f"""
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
http echo * /echo**
|
||||||
|
httpsrv -p{origin}
|
||||||
|
""", ports=[origin])
|
||||||
|
|
||||||
|
mapped = t.free_port()
|
||||||
|
server = t.start("maxconn", f"""
|
||||||
|
log
|
||||||
|
maxconn 2
|
||||||
|
auth iponly
|
||||||
|
allow *
|
||||||
|
tcppm {mapped} 127.0.0.1 {origin}
|
||||||
|
""", ports=[mapped])
|
||||||
|
|
||||||
|
def connect():
|
||||||
|
sock = socket.create_connection(("127.0.0.1", mapped), 5)
|
||||||
|
opened.append(sock)
|
||||||
|
return sock
|
||||||
|
|
||||||
|
def served(sock, timeout):
|
||||||
|
"""Ask over a kept alive connection; True once the whole reply is in,
|
||||||
|
so the connection is ready for the next request."""
|
||||||
|
sock.sendall(b"GET /echo HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n")
|
||||||
|
sock.settimeout(timeout)
|
||||||
|
data = b""
|
||||||
|
try:
|
||||||
|
while b"\r\n\r\n" not in data:
|
||||||
|
chunk = sock.recv(4096)
|
||||||
|
if not chunk:
|
||||||
|
return False
|
||||||
|
data += chunk
|
||||||
|
head, body = data.split(b"\r\n\r\n", 1)
|
||||||
|
length = 0
|
||||||
|
for line in head.split(b"\r\n")[1:]:
|
||||||
|
name, _, value = line.partition(b":")
|
||||||
|
if name.strip().lower() == b"content-length":
|
||||||
|
length = int(value)
|
||||||
|
while len(body) < length:
|
||||||
|
chunk = sock.recv(4096)
|
||||||
|
if not chunk:
|
||||||
|
return False
|
||||||
|
body += chunk
|
||||||
|
return head.startswith(b"HTTP/1.1 200")
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
opened = []
|
||||||
|
try:
|
||||||
|
# the probe that saw the port open holds a slot until its session
|
||||||
|
# ends, so wait for both slots to be free before taking them
|
||||||
|
deadline = time.time() + 5
|
||||||
|
while True:
|
||||||
|
first, second = connect(), connect()
|
||||||
|
both = served(first, 1) and served(second, 1)
|
||||||
|
if both or time.time() > deadline:
|
||||||
|
break
|
||||||
|
first.close()
|
||||||
|
second.close()
|
||||||
|
t.eq(True, both, "two connections are served under maxconn 2")
|
||||||
|
|
||||||
|
third = connect()
|
||||||
|
t.eq(False, served(third, 1.5),
|
||||||
|
"a third connection waits while both slots are held")
|
||||||
|
t.contains(t.wait_output(server, "too many connected clients"),
|
||||||
|
"too many connected clients",
|
||||||
|
"a service at its limit says so in the log")
|
||||||
|
|
||||||
|
first.close()
|
||||||
|
t.eq(True, served(third, 5),
|
||||||
|
"the waiting connection is served once a slot is freed")
|
||||||
|
t.eq(True, served(second, 5),
|
||||||
|
"a connection holding a slot keeps being served")
|
||||||
|
|
||||||
|
if os.name == "nt":
|
||||||
|
t.skip("reload while at the limit (no SIGUSR1 on Windows)")
|
||||||
|
else:
|
||||||
|
waiting = connect()
|
||||||
|
t.eq(False, served(waiting, 1),
|
||||||
|
"the limit holds again with two connections open")
|
||||||
|
server.proc.send_signal(signal.SIGUSR1)
|
||||||
|
# A connection made the instant the signal arrives can land on
|
||||||
|
# the listener being replaced and be reset; give the new service
|
||||||
|
# the moment it needs.
|
||||||
|
time.sleep(1.5)
|
||||||
|
fresh = connect()
|
||||||
|
t.eq(True, served(fresh, 5),
|
||||||
|
"a reload while the limit is reached starts a service with "
|
||||||
|
"its slots free")
|
||||||
|
t.eq(None, server.proc.poll(), "the process survives the reload")
|
||||||
|
finally:
|
||||||
|
for sock in opened:
|
||||||
|
sock.close()
|
||||||
Loading…
Reference in New Issue
Block a user