Compare commits

..

No commits in common. "98e8dfb004ca7ee129e2270bb811a61d35174b0c" and "3883a51969907f604b8e213cb50fb5b8c352c04d" have entirely different histories.

19 changed files with 126 additions and 390 deletions

View File

@ -415,12 +415,11 @@ 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, sem, log) # Common object library (sockmap, sockgetchar, common, 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)

View File

@ -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 linux-headers pcre2-dev RUN apk add --no-cache gcc make musl-dev 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 &&\

View File

@ -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 linux-headers RUN apk add --no-cache gcc make musl-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 &&\

View File

@ -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 ] && [ -f bin/$(PREFIX)$$f ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \ if [ -f man/$$f.8 ]; 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

View File

@ -123,18 +123,15 @@ 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
@ -192,7 +189,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 ] && [ -f bin/$(PREFIX)$$f ]; then $(INSTALL_DATA) man/$$f.8 $(MANDIR8)/$(PREFIX)$$f.8; fi; \ if [ -f man/$$f.8 ]; 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

View File

@ -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 ] && [ -f bin/$(PREFIX)$$f ]; then install -m 644 man/$$f.8 $(DESTDIR)$(MANDIR)/man8/$(PREFIX)$$f.8; fi; \ if [ -f man/$$f.8 ]; 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
View File

@ -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, 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. 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.
It's created to be small, simple and yet very functional. It's created to be small, simple and yet very functional.

View File

@ -36,7 +36,11 @@ 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

View File

@ -13,9 +13,6 @@ 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
@ -59,32 +56,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) sem$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS): sockmap$(OBJSUFFICS) proxy$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(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) sem$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)proxy$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) proxy$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS): sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS) $(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS): sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)pop3p$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) pop3p$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
$(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS): sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS) $(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS): sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)imapp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) imapp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
$(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS): sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) base64$(OBJSUFFICS) $(COMPATLIBS) $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS): sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(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) sem$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) base64$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
$(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS): sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) ftp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS) $(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS): sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) ftp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) $(BUILDDIR)$(PREFIX)socks$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) $(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) hash$(OBJSUFFICS) $(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) hash$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) hash$(OBJSUFFICS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) hash$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) log$(OBJSUFFICS) $(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) sem$(OBJSUFFICS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) log$(OBJSUFFICS) common$(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
@ -197,6 +194,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) 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) $(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)
$(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) $(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)

View File

@ -187,6 +187,33 @@ 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 = {
@ -656,49 +683,6 @@ 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(&param->srv->so, param->sostate, sock, param->srv->obindtodevice, *SAFAMILY(&param->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(&param->srv->so, param->sostate, sock, param->srv->ibindtodevice, *SAFAMILY(&param->sincl));
#else
return 0;
#endif
}
int doconnect(struct clientparam * param){ int doconnect(struct clientparam * param){
SASIZETYPE size; SASIZETYPE size;
@ -748,7 +732,25 @@ 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(extbindtodevice(param, param->remsock)) return 12; #if defined SO_BINDTODEVICE
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(&param->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(&param->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(&param->sinsl) != AF_UNIX) if(*SAFAMILY(&param->sinsl) != AF_UNIX)
#endif #endif

View File

@ -129,7 +129,6 @@ void * ftpprchild(struct clientparam* param) {
clidatasock = INVALID_SOCKET; clidatasock = INVALID_SOCKET;
} }
if ((clidatasock=socket(SASOCK(&param->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);} if ((clidatasock=socket(SASOCK(&param->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);}
if(intbindtodevice(param, clidatasock)){RETURN(822);}
*SAPORT(&param->sincl) = 0; *SAPORT(&param->sincl) = 0;
if(bindwithrange(param, clidatasock, &param->sincl, param->intport)){RETURN(822);} if(bindwithrange(param, clidatasock, &param->sincl, param->intport)){RETURN(822);}
if (pasv) { if (pasv) {

View File

@ -322,23 +322,13 @@ 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 timed); int _3proxy_sem_init_f(_3proxy_sem_t *sem, unsigned count, unsigned maxcount);
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);
void _3proxy_sem_destroy_f(_3proxy_sem_t *sem); #define _3proxy_sem_init(x, count, maxcount) _3proxy_sem_init_f(&x, (count), (maxcount))
#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
@ -401,9 +391,6 @@ 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. */

View File

@ -308,7 +308,6 @@ 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
@ -863,11 +862,29 @@ 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 || defined IP_BOUND_IF #if defined SO_BINDTODEVICE
if(bindtodevice(&srv.so, srv.so.state, sock, srv.ibindtodevice, *SAFAMILY(&srv.intsa))) { if(srv.ibindtodevice && srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_BINDTODEVICE, srv.ibindtodevice, strlen(srv.ibindtodevice) + 1)) {
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
@ -991,19 +1008,14 @@ int MODULEMAINFUNC (int argc, char** argv){
for (;;) { for (;;) {
for(;;){ for(;;){
/* A connection is only taken with a slot of maxchild in hand, which while((conf.paused == srv.paused && srv.childcount >= srv.maxchild)){
goes to its child; a slot not handed on is kept for the next one. nlog++;
The wait is timed to notice a reload. */ if(!srv.silent && nlog > 5000) {
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;
@ -1026,15 +1038,6 @@ 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;
@ -1219,7 +1222,6 @@ 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);
@ -1237,8 +1239,6 @@ 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,7 +1293,6 @@ 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(&param->req) = *SAFAMILY(&param->sinsl) = *SAFAMILY(&param->sinsr) = *SAFAMILY(&param->sincr) = *SAFAMILY(&param->sincl) = AF_INET; *SAFAMILY(&param->req) = *SAFAMILY(&param->sinsl) = *SAFAMILY(&param->sinsr) = *SAFAMILY(&param->sincr) = *SAFAMILY(&param->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);
@ -1339,8 +1338,6 @@ 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
@ -1351,13 +1348,7 @@ 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;
/* Every child returns its slot as the last thing it does with the service, while(srv->child) usleep(SLEEPTIME * 100);
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){
@ -1376,7 +1367,6 @@ 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);
@ -1403,13 +1393,22 @@ 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);
#ifndef STDMAIN
if(param->srv->service == S_UDPPM){
_3proxy_mutex_lock(&param->srv->counter_mutex); _3proxy_mutex_lock(&param->srv->counter_mutex);
hashdelete(&udp_table, param); #ifndef STDMAIN
_3proxy_mutex_unlock(&param->srv->counter_mutex); if(param->srv->service == S_UDPPM) hashdelete(&udp_table, param);
}
#endif #endif
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)--;
}
_3proxy_mutex_unlock(&param->srv->counter_mutex);
} }
if(param->clibuf) free(param->clibuf); if(param->clibuf) free(param->clibuf);
if(param->srvbuf) free(param->srvbuf); if(param->srvbuf) free(param->srvbuf);
@ -1449,27 +1448,6 @@ 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(&param->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(&param->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
View File

@ -1,110 +0,0 @@
/*
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

View File

@ -185,7 +185,6 @@ void * sockschild(struct clientparam* param) {
if(command == 2){ if(command == 2){
if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&param->req), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN (11);} if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&param->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;
@ -245,7 +244,6 @@ 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 */

View File

@ -47,7 +47,6 @@ 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>
@ -636,7 +635,6 @@ 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;

View File

@ -121,11 +121,6 @@ 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, &param->sinsl, param->extport)) { if (bindwithrange(param, param->remsock, &param->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);

View File

@ -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
42 of the 112 configuration commands appear in a test, and the count says 41 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,13 +78,12 @@ 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. `countin` `countout` `countall` and the `no*` forms, `maxconn`.
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` needs concurrent connections, held open the way the counts. `connlim` and `maxconn` need concurrent connections.
`maxconn` case holds them.
### The mail proxies ### The mail proxies

View File

@ -1,107 +0,0 @@
"""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()