Ubuntu 2014-08-25 17:54:51 +00:00
commit 9a68a111bf
285 changed files with 24078 additions and 9990 deletions

View File

@ -41,7 +41,7 @@ ifeq ($(OS),osx)
OSLIBS=-framework CoreServices -framework CoreFoundation
endif
ifeq ($(OS),linux)
OSLIBS=-lpthread -lrt -lcurses
OSLIBS=-lpthread -lrt -lcurses -lz
DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
endif
ifeq ($(OS),bsd)
@ -57,12 +57,13 @@ endif
INCLUDE=include
MDEFINES=-DU2_OS_$(OS) -DU2_OS_ENDIAN_$(ENDIAN) -D U2_LIB=\"$(LIB)\"
# NOTFORCHECKIN - restore -O2
CFLAGS= -O2 -g -msse3 -ffast-math \
-funsigned-char \
-I/usr/local/include \
-I/opt/local/include \
-I$(INCLUDE) \
-Ioutside/libuv/include \
-Ioutside/libuv_0.11/include \
-Ioutside/anachronism/include \
-Ioutside/bpt \
-Ioutside/re2 \
@ -277,23 +278,26 @@ V_OFILES=\
v/cttp.o \
v/http.o \
v/loop.o \
v/main.o \
v/raft.o \
v/reck.o \
v/save.o \
v/sist.o \
v/time.o \
v/term.o \
v/time.o \
v/unix.o \
v/walk.o
MAIN_FILE =\
v/main.o
VERE_OFILES=\
$(BASE_OFILES) \
$(CRE2_OFILES) \
$(OUT_OFILES) \
$(V_OFILES)
$(V_OFILES) \
$(MAIN_FILE)
LIBUV=outside/libuv/libuv.a
LIBUV=outside/libuv_0.11/.libs/libuv.a
LIBRE2=outside/re2/obj/libre2.a
@ -303,10 +307,12 @@ LIBANACHRONISM=outside/anachronism/build/libanachronism.a
BPT_O=outside/bpt/bitmapped_patricia_tree.o
all: $(BIN)/vere
vere: $(BIN)/vere
all: vere
$(LIBUV):
$(MAKE) -C outside/libuv libuv.a
$(MAKE) -C outside/libuv_0.11 all-am
$(LIBRE2):
$(MAKE) -C outside/re2 obj/libre2.a
@ -358,7 +364,7 @@ clean:
$(RM) $(VERE_OFILES) $(BIN)/vere vere.pkg
distclean: clean
$(MAKE) -C outside/libuv clean
$(MAKE) -C outside/libuv_0.11 clean
$(MAKE) -C outside/re2 clean
$(MAKE) -C outside/ed25519 clean
$(MAKE) -C outside/anachronism clean

View File

@ -1,38 +0,0 @@
*.swp
*.[oa]
*.l[oa]
*.opensdf
*.orig
*.pyc
*.sdf
*.suo
core
vgcore.*
.buildstamp
/libuv.so
/libuv.dylib
# Generated by dtrace(1) when doing an in-tree build.
/src/unix/uv-dtrace.h
/out/
/build/gyp
/run-tests
/run-tests.exe
/run-tests.dSYM
/run-benchmarks
/run-benchmarks.exe
/run-benchmarks.dSYM
*.sln
*.vcproj
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
_UpgradeReport_Files/
UpgradeLog*.XML
Debug
Release
ipch

View File

@ -1,18 +0,0 @@
Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com>
Bert Belder <bertbelder@gmail.com> <info@2bs.nl>
Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)>
Brandon Philips <brandon.philips@rackspace.com> <brandon@ifup.org>
Brian White <mscdex@mscdex.net>
Brian White <mscdex@mscdex.net> <mscdex@gmail.com>
Frank Denis <github@pureftpd.org>
Isaac Z. Schlueter <i@izs.me>
Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com>
Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org>
Ryan Dahl <ryan@joyent.com> <ry@tinyclouds.org>
Ryan Emery <seebees@gmail.com>
San-Tai Hsu <vanilla@fatpipi.com>
Saúl Ibarra Corretgé <saghul@gmail.com>
Shigeki Ohtsu <ohtsu@iij.ad.jp> <ohtsu@ohtsu.org>
Timothy J. Fontaine <tjfontaine@gmail.com>
Yasuhiro Matsumoto <mattn.jp@gmail.com>
Yuki Okumura <mjt@cltn.org>

View File

@ -1,362 +0,0 @@
2014.02.19, Version 0.10.25 (Stable)
Changes since version 0.10.24:
* stream: start thread after assignments (Oguz Bastemur)
* unix: correct error when calling uv_shutdown twice (Saúl Ibarra Corretgé)
* windows: freeze in uv_tcp_endgame (Alexis Campailla)
* sunos: handle rearm errors (Fedor Indutny)
2014.01.30, Version 0.10.24 (Stable), aecd296b6bce9b40f06a61c5c94e43d45ac7308a
Changes since version 0.10.23:
* linux: move sscanf() out of the assert() (Trevor Norris)
* linux: fix C99/C++ comment (Fedor Indutny)
2014.01.23, Version 0.10.23 (Stable), dbd218e699fec8be311d85e4788be9e28ae884f8
Changes since version 0.10.22:
* linux: relax assumption on /proc/stat parsing (Luca Bruno)
* openbsd: fix obvious bug in uv_cpu_info (Fedor Indutny)
* process: close stdio after dup2'ing it (Fedor Indutny)
2014.01.08, Version 0.10.22 (Stable), f526c90eeff271d9323a9107b9a64a4671fd3103
Changes since version 0.10.21:
* windows: avoid assertion failure when pipe server is closed (Bert Belder)
2013.12.19, Version 0.10.21 (Stable), 375ebce068555f0ca8151b562edb5f1b263022db
Changes since version 0.10.20:
* unix: fix a possible memory leak in uv_fs_readdir (Alex Crichton)
2013.12.13, Version 0.10.20 (Stable), 04141464dd0fba90ace9aa6f7003ce139b888a40
Changes since version 0.10.19:
* linux: fix up SO_REUSEPORT back-port (Ben Noordhuis)
* fs-event: fix invalid memory access (huxingyi)
2013.11.13, Version 0.10.19 (Stable), 33959f7524090b8d2c6c41e2400ca77e31755059
Changes since version 0.10.18:
* darwin: avoid calling GetCurrentProcess (Fedor Indutny)
* unix: update events from pevents between polls (Fedor Indutny)
* fsevents: support japaneese characters in path (Chris Bank)
* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis)
* build: fix windows smp build with gyp (Geert Jansen)
* linux: handle EPOLLHUP without EPOLLIN/EPOLLOUT (Ben Noordhuis)
* unix: fix reopened fd bug (Fedor Indutny)
* core: fix fake watcher list and count preservation (Fedor Indutny)
2013.10.19, Version 0.10.18 (Stable), 9ec52963b585e822e87bdc5de28d6143aff0d2e5
Changes since version 0.10.17:
* unix: fix uv_spawn() NULL pointer deref on ENOMEM (Ben Noordhuis)
* unix: don't close inherited fds on uv_spawn() fail (Ben Noordhuis)
* unix: revert recent FSEvent changes (Ben Noordhuis)
* unix: fix non-synchronized access in signal.c (Ben Noordhuis)
2013.09.25, Version 0.10.17 (Stable), 9670e0a93540c2f0d86c84a375f2303383c11e7e
Changes since version 0.10.16:
* build: remove GCC_WARN_ABOUT_MISSING_NEWLINE (Ben Noordhuis)
* darwin: fix 10.6 build error in fsevents.c (Ben Noordhuis)
2013.09.06, Version 0.10.16 (Stable), 2bce230d81f4853a23662cbeb26fe98010b1084b
Changes since version 0.10.15:
* windows: make uv_shutdown() for write-only pipes work (Bert Belder)
* windows: make uv_fs_open() report EINVAL when invalid arguments are passed
(Bert Belder)
* windows: make uv_fs_open() report _open_osfhandle() failure correctly (Bert
Belder)
* windows: make uv_fs_chmod() report errors correctly (Bert Belder)
* windows: wrap multi-statement macros in do..while block (Bert Belder)
2013.08.24, Version 0.10.15 (Stable), 221078a8fdd9b853c6b557b3d9a5dd744b4fdd6b
Changes since version 0.10.14:
* fsevents: create FSEvents thread on demand (Ben Noordhuis)
* fsevents: use a single thread for interacting with FSEvents, because it's not
thread-safe. (Fedor Indutny)
* fsevents: share FSEventStream between multiple FS watchers, which removes a
limit on the maximum number of file watchers that can be created on OS X.
(Fedor Indutny)
2013.08.22, Version 0.10.14 (Stable), 15d64132151c18b26346afa892444b95e2addad0
Changes since version 0.10.13:
* unix: retry waitpid() on EINTR (Ben Noordhuis)
2013.07.26, Version 0.10.13 (Stable), 381312e1fe6fecbabc943ccd56f0e7d114b3d064
Changes since version 0.10.12:
* unix, windows: fix uv_fs_chown() function prototype (Ben Noordhuis)
2013.07.10, Version 0.10.12 (Stable), 58a46221bba726746887a661a9f36fe9ff204209
Changes since version 0.10.11:
* linux: add support for MIPS (Andrei Sedoi)
* windows: uv_spawn shouldn't reject reparse points (Bert Belder)
* windows: use WSAGetLastError(), not errno (Ben Noordhuis)
* build: darwin: disable -fstrict-aliasing warnings (Ben Noordhuis)
* build: `all` now builds static and dynamic lib (Ben Noordhuis)
* unix: fix build when !defined(PTHREAD_MUTEX_ERRORCHECK) (Ben Noordhuis)
2013.06.13, Version 0.10.11 (Stable), c3b75406a66a10222a589cb173e8f469e9665c7e
Changes since version 0.10.10:
* unix: unconditionally stop handle on close (Ben Noordhuis)
* freebsd: don't enable dtrace if it's not available (Brian White)
* build: make HAVE_DTRACE=0 should disable dtrace (Timothy J. Fontaine)
* unix: remove overzealous assert (Ben Noordhuis)
* unix: clear UV_STREAM_SHUTTING after shutdown() (Ben Noordhuis)
* unix: fix busy loop, write if POLLERR or POLLHUP (Ben Noordhuis)
2013.06.05, Version 0.10.10 (Stable), 0d95a88bd35fce93863c57a460be613aea34d2c5
Changes since version 0.10.9:
* include: document uv_update_time() and uv_now() (Ben Noordhuis)
* linux: fix cpu model parsing on newer arm kernels (Ben Noordhuis)
* linux: fix memory leak in uv_cpu_info() error path (Ben Noordhuis)
* linux: don't ignore OOM errors in uv_cpu_info() (Ben Noordhuis)
* unix, windows: move uv_now() to uv-common.c (Ben Noordhuis)
* darwin: make uv_fs_sendfile() respect length param (Wynn Wilkes)
2013.05.29, Version 0.10.9 (Stable), a195f9ace23d92345baf57582678bfc3017e6632
Changes since version 0.10.8:
* unix: fix stream refcounting buglet (Ben Noordhuis)
* unix: remove erroneous asserts (Ben Noordhuis)
* unix: add uv__is_closing() macro (Ben Noordhuis)
* unix: stop stream POLLOUT watcher on write error (Ben Noordhuis)
2013.05.25, Version 0.10.8 (Stable), 0f39be12926fe2d8766a9f025797a473003e6504
Changes since version 0.10.7:
* windows: make uv_spawn not fail under job control (Bert Belder)
* darwin: assume CFRunLoopStop() isn't thread-safe (Fedor Indutny)
* win: fix UV_EALREADY incorrectly set (Bert Belder)
* darwin: make two uv__cf_*() functions static (Ben Noordhuis)
* darwin: task_info() cannot fail (Ben Noordhuis)
* unix: add mapping for ENETDOWN (Ben Noordhuis)
* unix: implicitly signal write errors to libuv user (Ben Noordhuis)
* unix: fix assert on signal pipe overflow (Bert Belder)
* unix: turn off POLLOUT after stream connect (Ben Noordhuis)
2013.05.15, Version 0.10.7 (Stable), 028baaf0846b686a81e992cb2f2f5a9b8e841fcf
Changes since version 0.10.6:
* windows: kill child processes when the parent dies (Bert Belder)
2013.05.15, Version 0.10.6 (Stable), 11e6613e6260d95c8cf11bf89a2759c24649319a
Changes since version 0.10.5:
* stream: fix osx select hack (Fedor Indutny)
* stream: fix small nit in select hack, add test (Fedor Indutny)
* build: link with libkvm on openbsd (Ben Noordhuis)
* stream: use harder sync restrictions for osx-hack (Fedor Indutny)
* unix: fix EMFILE error handling (Ben Noordhuis)
* darwin: fix unnecessary include headers (Daisuke Murase)
* darwin: rename darwin-getproctitle.m (Ben Noordhuis)
* build: convert predefined $PLATFORM to lower case (Elliot Saba)
* build: set soname in shared library (Ben Noordhuis)
* build: make `make test` link against .a again (Ben Noordhuis)
* darwin: fix ios build, don't require ApplicationServices (Ben Noordhuis)
* build: only set soname on shared object builds (Timothy J. Fontaine)
2013.04.24, Version 0.10.5 (Stable), 6595a7732c52eb4f8e57c88655f72997a8567a67
Changes since version 0.10.4:
* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis)
* windows: make timers handle large timeouts (Miroslav Bajtoš)
* windows: remove superfluous assert statement (Bert Belder)
* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis)
* linux: don't use fopen() in uv_resident_set_memory() (Ben Noordhuis)
2013.04.12, Version 0.10.4 (Stable), 85827e26403ac6dfa331af8ec9916ea7e27bd833
Changes since version 0.10.3:
* include: update uv_backend_fd() documentation (Ben Noordhuis)
* unix: include uv.h in src/version.c (Ben Noordhuis)
* unix: don't write more than IOV_MAX iovecs (Fedor Indutny)
* mingw-w64: don't call _set_invalid_parameter_handler (Nils Maier)
* build: gyp disable thin archives (Timothy J. Fontaine)
* sunos: re-export entire library when static (Timothy J. Fontaine)
* unix: dtrace probes for tick-start and tick-stop (Timothy J. Fontaine)
* windows: fix memory leak in fs__sendfile (Shannen Saez)
* windows: remove double initialization in uv_tty_init (Shannen Saez)
* build: fix dtrace-enabled out of tree build (Ben Noordhuis)
* build: squelch -Wdollar-in-identifier-extension warnings (Ben Noordhuis)
* inet: snprintf returns int, not size_t (Brian White)
* win: refactor uv_cpu_info (Bert Belder)
* build: add support for Visual Studio 2012 (Nicholas Vavilov)
* build: -Wno-dollar-in-identifier-extension is clang only (Ben Noordhuis)
2013.03.28, Version 0.10.3 (Stable), 31ebe23973dd98fd8a24c042b606f37a794e99d0
Changes since version 0.10.2:
* include: remove extraneous const from uv_version() (Ben Noordhuis)
* doc: update README, replace `OS` by `PLATFORM` (Ben Noordhuis)
* build: simplify .buildstamp rule (Ben Noordhuis)
* build: disable -Wstrict-aliasing on darwin (Ben Noordhuis)
* darwin: don't select(&exceptfds) in fallback path (Ben Noordhuis)
* unix: don't clear flags after closing UDP handle (Saúl Ibarra Corretgé)
2013.03.25, Version 0.10.2 (Stable), 0f36a00568f3e7608f97f6c6cdb081f4800a50c9
This is the first officially versioned release of libuv. Starting now
libuv will make releases independently of Node.js.
Changes since Node.js v0.10.0:
* test: add tap output for windows (Timothy J. Fontaine)
* unix: fix uv_tcp_simultaneous_accepts() logic (Ben Noordhuis)
* include: bump UV_VERSION_MINOR (Ben Noordhuis)
* unix: improve uv_guess_handle() implementation (Ben Noordhuis)
* stream: run try_select only for pipes and ttys (Fedor Indutny)
Changes since Node.js v0.10.1:
* build: rename OS to PLATFORM (Ben Noordhuis)
* unix: make uv_timer_init() initialize repeat (Brian Mazza)
* unix: make timers handle large timeouts (Ben Noordhuis)
* build: add OBJC makefile var (Ben Noordhuis)
* Add `uv_version()` and `uv_version_string()` APIs (Bert Belder)

View File

@ -1,118 +0,0 @@
# libuv
libuv is a new platform layer for Node. Its purpose is to abstract IOCP on
Windows and epoll/kqueue/event ports/etc. on Unix systems. We intend to
eventually contain all platform differences in this library.
http://nodejs.org/
## Features
* Non-blocking TCP sockets
* Non-blocking named pipes
* UDP
* Timers
* Child process spawning
* Asynchronous DNS via `uv_getaddrinfo`.
* Asynchronous file system APIs `uv_fs_*`
* High resolution time `uv_hrtime`
* Current executable path look up `uv_exepath`
* Thread pool scheduling `uv_queue_work`
* ANSI escape code controlled TTY `uv_tty_t`
* File system events Currently supports inotify, `ReadDirectoryChangesW`
and kqueue. Event ports in the near future.
`uv_fs_event_t`
* IPC and socket sharing between processes `uv_write2`
## Community
* [Mailing list](http://groups.google.com/group/libuv)
## Documentation
* [include/uv.h](https://github.com/joyent/libuv/blob/master/include/uv.h)
&mdash; API documentation in the form of detailed header comments.
* [An Introduction to libuv](http://nikhilm.github.com/uvbook/) &mdash; An
overview of libuv with tutorials.
* [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4) - High-level
introductory talk about libuv.
* [Tests and benchmarks](https://github.com/joyent/libuv/tree/master/test) -
API specification and usage examples.
## Build Instructions
For GCC (including MinGW) there are two methods building: via normal
makefiles or via GYP. GYP is a meta-build system which can generate MSVS,
Makefile, and XCode backends. It is best used for integration into other
projects. The old system is using plain GNU Makefiles.
To build via Makefile simply execute:
make
MinGW users should run this instead:
make PLATFORM=mingw
Out-of-tree builds are supported:
make builddir_name=/path/to/builddir
To build with Visual Studio run the vcbuild.bat file which will
checkout the GYP code into build/gyp and generate the uv.sln and
related files.
Windows users can also build from cmd-line using msbuild. This is
done by running vcbuild.bat from Visual Studio command prompt.
To have GYP generate build script for another system, make sure that
you have Python 2.6 or 2.7 installed, then checkout GYP into the
project tree manually:
mkdir -p build
svn co http://gyp.googlecode.com/svn/trunk build/gyp
Or:
mkdir -p build
git clone https://git.chromium.org/external/gyp.git build/gyp
Unix users run
./gyp_uv.py -f make
make -C out
Macintosh users run
./gyp_uv.py -f xcode
xcodebuild -project uv.xcodeproj -configuration Release -target All
Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and
`-D_FILE_OFFSET_BITS=64`. GYP builds take care of that automatically.
Note for Linux users: compile your project with `-D_GNU_SOURCE` when you
include `uv.h`. GYP builds take care of that automatically. If you use
autotools, add a `AC_GNU_SOURCE` declaration to your `configure.ac`.
## Supported Platforms
Microsoft Windows operating systems since Windows XP SP2. It can be built
with either Visual Studio or MinGW.
Linux 2.6 using the GCC toolchain.
MacOS using the GCC or XCode toolchain.
Solaris 121 and later using GCC toolchain.

View File

@ -1,171 +0,0 @@
# Copyright Joyent, Inc. and other Node contributors. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
ifdef PLATFORM
override PLATFORM := $(shell echo $(PLATFORM) | tr "[A-Z]" "[a-z]")
else
PLATFORM = $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"')
endif
CPPFLAGS += -I$(SRCDIR)/include -I$(SRCDIR)/include/uv-private
ifeq (darwin,$(PLATFORM))
SOEXT = dylib
else
SOEXT = so
endif
ifneq (,$(findstring mingw,$(PLATFORM)))
include $(SRCDIR)/config-mingw.mk
else
include $(SRCDIR)/config-unix.mk
endif
BENCHMARKS= \
test/benchmark-async-pummel.o \
test/benchmark-async.o \
test/benchmark-fs-stat.o \
test/benchmark-getaddrinfo.o \
test/benchmark-loop-count.o \
test/benchmark-million-async.o \
test/benchmark-million-timers.o \
test/benchmark-multi-accept.o \
test/benchmark-ping-pongs.o \
test/benchmark-pound.o \
test/benchmark-pump.o \
test/benchmark-sizes.o \
test/benchmark-spawn.o \
test/benchmark-tcp-write-batch.o \
test/benchmark-thread.o \
test/benchmark-udp-pummel.o \
test/blackhole-server.o \
test/dns-server.o \
test/echo-server.o \
TESTS= \
test/blackhole-server.o \
test/dns-server.o \
test/echo-server.o \
test/test-active.o \
test/test-async.o \
test/test-barrier.o \
test/test-callback-order.o \
test/test-callback-stack.o \
test/test-condvar.o \
test/test-connection-fail.o \
test/test-cwd-and-chdir.o \
test/test-delayed-accept.o \
test/test-dlerror.o \
test/test-embed.o \
test/test-emfile.o \
test/test-error.o \
test/test-fail-always.o \
test/test-fs.o \
test/test-fs-event.o \
test/test-fs-poll.o \
test/test-getaddrinfo.o \
test/test-get-currentexe.o \
test/test-get-loadavg.o \
test/test-get-memory.o \
test/test-getsockname.o \
test/test-hrtime.o \
test/test-idle.o \
test/test-ipc.o \
test/test-ipc-send-recv.o \
test/test-loop-handles.o \
test/test-loop-stop.o \
test/test-multiple-listen.o \
test/test-mutexes.o \
test/test-osx-select.o \
test/test-pass-always.o \
test/test-ping-pong.o \
test/test-pipe-bind-error.o \
test/test-pipe-connect-error.o \
test/test-pipe-server-close.o \
test/test-platform-output.o \
test/test-poll.o \
test/test-poll-close.o \
test/test-process-title.o \
test/test-ref.o \
test/test-run-nowait.o \
test/test-run-once.o \
test/test-semaphore.o \
test/test-shutdown-close.o \
test/test-shutdown-eof.o \
test/test-shutdown-twice.o \
test/test-signal.o \
test/test-signal-multiple-loops.o \
test/test-spawn.o \
test/test-stdio-over-pipes.o \
test/test-tcp-bind6-error.o \
test/test-tcp-bind-error.o \
test/test-tcp-close.o \
test/test-tcp-close-accept.o \
test/test-tcp-close-while-connecting.o \
test/test-tcp-connect6-error.o \
test/test-tcp-connect-error-after-write.o \
test/test-tcp-connect-error.o \
test/test-tcp-connect-timeout.o \
test/test-tcp-flags.o \
test/test-tcp-open.o \
test/test-tcp-read-stop.o \
test/test-tcp-shutdown-after-write.o \
test/test-tcp-unexpected-read.o \
test/test-tcp-writealot.o \
test/test-tcp-write-to-half-open-connection.o \
test/test-thread.o \
test/test-threadpool.o \
test/test-threadpool-cancel.o \
test/test-timer-again.o \
test/test-timer-from-check.o \
test/test-timer.o \
test/test-tty.o \
test/test-udp-dgram-too-big.o \
test/test-udp-ipv6.o \
test/test-udp-multicast-join.o \
test/test-udp-multicast-ttl.o \
test/test-udp-open.o \
test/test-udp-options.o \
test/test-udp-send-and-recv.o \
test/test-util.o \
test/test-walk-handles.o \
test/test-watcher-cross-stop.o \
.PHONY: all bench clean clean-platform distclean test
run-tests$(E): test/run-tests.o test/runner.o $(RUNNER_SRC) $(TESTS) libuv.a
$(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o $@ $^ $(RUNNER_LIBS) $(RUNNER_LDFLAGS)
run-benchmarks$(E): test/run-benchmarks.o test/runner.o $(RUNNER_SRC) $(BENCHMARKS) libuv.a
$(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o $@ $^ $(RUNNER_LIBS) $(RUNNER_LDFLAGS)
test/echo.o: test/echo.c test/echo.h
test: run-tests$(E)
$(CURDIR)/$<
bench: run-benchmarks$(E)
$(CURDIR)/$<
clean distclean: clean-platform
$(RM) libuv.a libuv.$(SOEXT) \
test/run-tests.o test/run-benchmarks.o \
test/run-tests$(E) test/run-benchmarks$(E) \
$(BENCHMARKS) $(TESTS) $(RUNNER_LIBS)

View File

@ -1,207 +0,0 @@
# Copyright Joyent, Inc. and other Node contributors. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
E=
CSTDFLAG=--std=c89 -pedantic -Wall -Wextra -Wno-unused-parameter
CFLAGS += -g
CPPFLAGS += -I$(SRCDIR)/src
LDFLAGS=-lm
CPPFLAGS += -D_LARGEFILE_SOURCE
CPPFLAGS += -D_FILE_OFFSET_BITS=64
RUNNER_SRC=test/runner-unix.c
RUNNER_CFLAGS=$(CFLAGS) -I$(SRCDIR)/test
RUNNER_LDFLAGS=
DTRACE_OBJS=
DTRACE_HEADER=
OBJS += src/unix/async.o
OBJS += src/unix/core.o
OBJS += src/unix/dl.o
OBJS += src/unix/error.o
OBJS += src/unix/fs.o
OBJS += src/unix/getaddrinfo.o
OBJS += src/unix/loop.o
OBJS += src/unix/loop-watcher.o
OBJS += src/unix/pipe.o
OBJS += src/unix/poll.o
OBJS += src/unix/process.o
OBJS += src/unix/signal.o
OBJS += src/unix/stream.o
OBJS += src/unix/tcp.o
OBJS += src/unix/thread.o
OBJS += src/unix/threadpool.o
OBJS += src/unix/timer.o
OBJS += src/unix/tty.o
OBJS += src/unix/udp.o
OBJS += src/fs-poll.o
OBJS += src/uv-common.o
OBJS += src/inet.o
OBJS += src/version.o
ifeq (sunos,$(PLATFORM))
HAVE_DTRACE ?= 1
CPPFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
LDFLAGS+=-lkstat -lnsl -lsendfile -lsocket
# Library dependencies are not transitive.
OBJS += src/unix/sunos.o
ifeq (1, $(HAVE_DTRACE))
OBJS += src/unix/dtrace.o
DTRACE_OBJS += src/unix/core.o
endif
endif
ifeq (aix,$(PLATFORM))
CPPFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500
LDFLAGS+= -lperfstat
OBJS += src/unix/aix.o
endif
ifeq (darwin,$(PLATFORM))
HAVE_DTRACE ?= 1
# dtrace(1) probes contain dollar signs on OS X. Mute the warnings they
# generate but only when CC=clang, -Wno-dollar-in-identifier-extension
# is a clang extension.
ifeq (__clang__,$(shell sh -c "$(CC) -dM -E - </dev/null | grep -ow __clang__"))
CFLAGS += -Wno-dollar-in-identifier-extension
endif
CPPFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
LDFLAGS += -framework Foundation \
-framework CoreServices \
-framework ApplicationServices
SOEXT = dylib
OBJS += src/unix/darwin.o
OBJS += src/unix/kqueue.o
OBJS += src/unix/fsevents.o
OBJS += src/unix/proctitle.o
OBJS += src/unix/darwin-proctitle.o
endif
ifeq (linux,$(PLATFORM))
CSTDFLAG += -D_GNU_SOURCE
LDFLAGS+=-ldl -lrt
RUNNER_CFLAGS += -D_GNU_SOURCE
OBJS += src/unix/linux-core.o \
src/unix/linux-inotify.o \
src/unix/linux-syscalls.o \
src/unix/proctitle.o
endif
ifeq (freebsd,$(PLATFORM))
ifeq ($(shell dtrace -l 1>&2 2>/dev/null; echo $$?),0)
HAVE_DTRACE ?= 1
endif
LDFLAGS+=-lkvm
OBJS += src/unix/freebsd.o
OBJS += src/unix/kqueue.o
endif
ifeq (dragonfly,$(PLATFORM))
LDFLAGS+=-lkvm
OBJS += src/unix/freebsd.o
OBJS += src/unix/kqueue.o
endif
ifeq (netbsd,$(PLATFORM))
LDFLAGS+=-lkvm
OBJS += src/unix/netbsd.o
OBJS += src/unix/kqueue.o
endif
ifeq (openbsd,$(PLATFORM))
LDFLAGS+=-lkvm
OBJS += src/unix/openbsd.o
OBJS += src/unix/kqueue.o
endif
ifneq (,$(findstring cygwin,$(PLATFORM)))
# We drop the --std=c89, it hides CLOCK_MONOTONIC on cygwin
CSTDFLAG = -D_GNU_SOURCE
LDFLAGS+=
OBJS += src/unix/cygwin.o
endif
ifeq (sunos,$(PLATFORM))
RUNNER_LDFLAGS += -pthreads
else
RUNNER_LDFLAGS += -pthread
endif
ifeq ($(HAVE_DTRACE), 1)
DTRACE_HEADER = src/unix/uv-dtrace.h
CPPFLAGS += -Isrc/unix
CFLAGS += -DHAVE_DTRACE
endif
ifneq (darwin,$(PLATFORM))
# Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR in src/version.c
SO_LDFLAGS = -Wl,-soname,libuv.so.0.10
endif
RUNNER_LDFLAGS += $(LDFLAGS)
all:
# Force a sequential build of the static and the shared library.
# Works around a make quirk where it forgets to (re)build either
# the *.o or *.pic.o files, depending on what target comes first.
$(MAKE) -f $(SRCDIR)/Makefile libuv.a
$(MAKE) -f $(SRCDIR)/Makefile libuv.$(SOEXT)
libuv.a: $(OBJS)
$(AR) rcs $@ $^
libuv.$(SOEXT): override CFLAGS += -fPIC
libuv.$(SOEXT): $(OBJS:%.o=%.pic.o)
$(CC) -shared -o $@ $^ $(LDFLAGS) $(SO_LDFLAGS)
include/uv-private/uv-unix.h: \
include/uv-private/uv-bsd.h \
include/uv-private/uv-darwin.h \
include/uv-private/uv-linux.h \
include/uv-private/uv-sunos.h
src/unix/internal.h: src/unix/linux-syscalls.h
src/.buildstamp src/unix/.buildstamp test/.buildstamp:
mkdir -p $(@D)
touch $@
src/unix/%.o src/unix/%.pic.o: src/unix/%.c include/uv.h include/uv-private/uv-unix.h src/unix/internal.h src/unix/.buildstamp $(DTRACE_HEADER)
$(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
src/%.o src/%.pic.o: src/%.c include/uv.h include/uv-private/uv-unix.h src/.buildstamp
$(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
test/%.o: test/%.c include/uv.h test/.buildstamp
$(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
clean-platform:
$(RM) test/run-{tests,benchmarks}.dSYM $(OBJS) $(OBJS:%.o=%.pic.o) src/unix/uv-dtrace.h
src/unix/uv-dtrace.h: src/unix/uv-dtrace.d
dtrace -h -xnolibs -s $< -o $@
src/unix/dtrace.o: src/unix/uv-dtrace.d $(DTRACE_OBJS)
dtrace -G -s $^ -o $@
src/unix/dtrace.pic.o: src/unix/uv-dtrace.d $(DTRACE_OBJS:%.o=%.pic.o)
dtrace -G -s $^ -o $@

View File

@ -1,129 +0,0 @@
/*
* Copyright (C) Igor Sysoev
*/
#ifndef NGX_QUEUE_H_INCLUDED_
#define NGX_QUEUE_H_INCLUDED_
typedef struct ngx_queue_s ngx_queue_t;
struct ngx_queue_s {
ngx_queue_t *prev;
ngx_queue_t *next;
};
#define ngx_queue_init(q) \
do { \
(q)->prev = q; \
(q)->next = q; \
} \
while (0)
#define ngx_queue_empty(h) \
(h == (h)->prev)
#define ngx_queue_insert_head(h, x) \
do { \
(x)->next = (h)->next; \
(x)->next->prev = x; \
(x)->prev = h; \
(h)->next = x; \
} \
while (0)
#define ngx_queue_insert_after ngx_queue_insert_head
#define ngx_queue_insert_tail(h, x) \
do { \
(x)->prev = (h)->prev; \
(x)->prev->next = x; \
(x)->next = h; \
(h)->prev = x; \
} \
while (0)
#define ngx_queue_head(h) \
(h)->next
#define ngx_queue_last(h) \
(h)->prev
#define ngx_queue_sentinel(h) \
(h)
#define ngx_queue_next(q) \
(q)->next
#define ngx_queue_prev(q) \
(q)->prev
#if defined(NGX_DEBUG)
#define ngx_queue_remove(x) \
do { \
(x)->next->prev = (x)->prev; \
(x)->prev->next = (x)->next; \
(x)->prev = NULL; \
(x)->next = NULL; \
} \
while (0)
#else
#define ngx_queue_remove(x) \
do { \
(x)->next->prev = (x)->prev; \
(x)->prev->next = (x)->next; \
} \
while (0)
#endif
#define ngx_queue_split(h, q, n) \
do { \
(n)->prev = (h)->prev; \
(n)->prev->next = n; \
(n)->next = q; \
(h)->prev = (q)->prev; \
(h)->prev->next = h; \
(q)->prev = n; \
} \
while (0)
#define ngx_queue_add(h, n) \
do { \
(h)->prev->next = (n)->next; \
(n)->next->prev = (h)->prev; \
(h)->prev = (n)->prev; \
(h)->prev->next = h; \
} \
while (0)
#define ngx_queue_data(q, type, link) \
((type *) ((unsigned char *) q - offsetof(type, link)))
#define ngx_queue_foreach(q, h) \
for ((q) = ngx_queue_head(h); \
(q) != ngx_queue_sentinel(h) && !ngx_queue_empty(h); \
(q) = ngx_queue_next(q))
#endif /* NGX_QUEUE_H_INCLUDED_ */

View File

@ -1,391 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <utmp.h>
#include <sys/protosw.h>
#include <libperfstat.h>
#include <sys/proc.h>
#include <sys/procfs.h>
uint64_t uv__hrtime(void) {
uint64_t G = 1000000000;
timebasestruct_t t;
read_wall_time(&t, TIMEBASE_SZ);
time_base_to_time(&t, TIMEBASE_SZ);
return (uint64_t) t.tb_high * G + t.tb_low;
}
/*
* We could use a static buffer for the path manipulations that we need outside
* of the function, but this function could be called by multiple consumers and
* we don't want to potentially create a race condition in the use of snprintf.
*/
int uv_exepath(char* buffer, size_t* size) {
ssize_t res;
char pp[64], cwdl[PATH_MAX];
struct psinfo ps;
int fd;
if (buffer == NULL)
return (-1);
if (size == NULL)
return (-1);
(void) snprintf(pp, sizeof(pp), "/proc/%lu/cwd", (unsigned long) getpid());
res = readlink(pp, cwdl, sizeof(cwdl) - 1);
if (res < 0)
return res;
cwdl[res] = '\0';
(void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
fd = open(pp, O_RDONLY);
if (fd < 0)
return fd;
res = read(fd, &ps, sizeof(ps));
close(fd);
if (res < 0)
return res;
(void) snprintf(buffer, *size, "%s%s", cwdl, ps.pr_fname);
*size = strlen(buffer);
return 0;
}
uint64_t uv_get_free_memory(void) {
perfstat_memory_total_t mem_total;
int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
if (result == -1) {
return 0;
}
return mem_total.real_free * 4096;
}
uint64_t uv_get_total_memory(void) {
perfstat_memory_total_t mem_total;
int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
if (result == -1) {
return 0;
}
return mem_total.real_total * 4096;
}
void uv_loadavg(double avg[3]) {
perfstat_cpu_total_t ps_total;
int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
if (result == -1) {
avg[0] = 0.; avg[1] = 0.; avg[2] = 0.;
return;
}
avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS);
avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS);
avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS);
}
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
uv_fs_event_cb cb,
int flags) {
loop->counters.fs_event_init++;
uv__set_sys_error(loop, ENOSYS);
return -1;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
UNREACHABLE();
}
char** uv_setup_args(int argc, char** argv) {
return argv;
}
uv_err_t uv_set_process_title(const char* title) {
return uv_ok_;
}
uv_err_t uv_get_process_title(char* buffer, size_t size) {
if (size > 0) {
buffer[0] = '\0';
}
return uv_ok_;
}
uv_err_t uv_resident_set_memory(size_t* rss) {
char pp[64];
psinfo_t psinfo;
uv_err_t err;
int fd;
(void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
fd = open(pp, O_RDONLY);
if (fd == -1)
return uv__new_sys_error(errno);
err = uv_ok_;
if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo))
*rss = (size_t)psinfo.pr_rssize * 1024;
else
err = uv__new_sys_error(EINVAL);
close(fd);
return err;
}
uv_err_t uv_uptime(double* uptime) {
struct utmp *utmp_buf;
size_t entries = 0;
time_t boot_time;
utmpname(UTMP_FILE);
setutent();
while ((utmp_buf = getutent()) != NULL) {
if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS)
++entries;
if (utmp_buf->ut_type == BOOT_TIME)
boot_time = utmp_buf->ut_time;
}
endutent();
if (boot_time == 0)
return uv__new_artificial_error(UV_ENOSYS);
*uptime = time(NULL) - boot_time;
return uv_ok_;
}
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
perfstat_cpu_total_t ps_total;
perfstat_cpu_t* ps_cpus;
perfstat_id_t cpu_id;
int result, ncpus, idx = 0;
result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
if (result == -1) {
return uv__new_artificial_error(UV_ENOSYS);
}
ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
if (result == -1) {
return uv__new_artificial_error(UV_ENOSYS);
}
ps_cpus = (perfstat_cpu_t*) malloc(ncpus * sizeof(perfstat_cpu_t));
if (!ps_cpus) {
return uv__new_artificial_error(UV_ENOMEM);
}
strcpy(cpu_id.name, FIRST_CPU);
result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
if (result == -1) {
free(ps_cpus);
return uv__new_artificial_error(UV_ENOSYS);
}
*cpu_infos = (uv_cpu_info_t*) malloc(ncpus * sizeof(uv_cpu_info_t));
if (!*cpu_infos) {
free(ps_cpus);
return uv__new_artificial_error(UV_ENOMEM);
}
*count = ncpus;
cpu_info = *cpu_infos;
while (idx < ncpus) {
cpu_info->speed = (int)(ps_total.processorHZ / 1000000);
cpu_info->model = strdup(ps_total.description);
cpu_info->cpu_times.user = ps_cpus[idx].user;
cpu_info->cpu_times.sys = ps_cpus[idx].sys;
cpu_info->cpu_times.idle = ps_cpus[idx].idle;
cpu_info->cpu_times.irq = ps_cpus[idx].wait;
cpu_info->cpu_times.nice = 0;
cpu_info++;
idx++;
}
free(ps_cpus);
return uv_ok_;
}
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
int i;
for (i = 0; i < count; ++i) {
free(cpu_infos[i].model);
}
free(cpu_infos);
}
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
int* count) {
uv_interface_address_t* address;
int sockfd, size = 1;
struct ifconf ifc;
struct ifreq *ifr, *p, flg;
*count = 0;
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
return uv__new_artificial_error(UV_ENOSYS);
}
if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
close(sockfd);
return uv__new_artificial_error(UV_ENOSYS);
}
ifc.ifc_req = (struct ifreq*)malloc(size);
ifc.ifc_len = size;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
close(sockfd);
return uv__new_artificial_error(UV_ENOSYS);
}
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
/* Count all up and running ipv4/ipv6 addresses */
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
close(sockfd);
return uv__new_artificial_error(UV_ENOSYS);
}
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
(*count)++;
}
/* Alloc the return interface structs */
*addresses = (uv_interface_address_t*)
malloc(*count * sizeof(uv_interface_address_t));
if (!(*addresses)) {
close(sockfd);
return uv__new_artificial_error(UV_ENOMEM);
}
address = *addresses;
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
close(sockfd);
return uv__new_artificial_error(UV_ENOSYS);
}
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
/* All conditions above must match count loop */
address->name = strdup(p->ifr_name);
if (p->ifr_addr.sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6 *)&p->ifr_addr);
} else {
address->address.address4 = *((struct sockaddr_in *)&p->ifr_addr);
}
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
address++;
}
#undef ADDR_SIZE
close(sockfd);
return uv_ok_;
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; ++i) {
free(addresses[i].name);
}
free(addresses);
}

View File

@ -1,88 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
}
uint64_t uv__hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
void uv_loadavg(double avg[3]) {
/* Unsupported as of cygwin 1.7.7 */
avg[0] = avg[1] = avg[2] = 0;
}
int uv_exepath(char* buffer, size_t* size) {
if (!buffer || !size) {
return -1;
}
*size = readlink("/proc/self/exe", buffer, *size - 1);
if (*size <= 0) return -1;
buffer[*size] = '\0';
return 0;
}
uint64_t uv_get_free_memory(void) {
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
}
uint64_t uv_get_total_memory(void) {
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
}
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
uv_fs_event_cb cb,
int flags) {
uv__set_sys_error(loop, ENOSYS);
return -1;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
assert(0 && "implement me");
}

View File

@ -1,123 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <TargetConditionals.h>
#if !TARGET_OS_IPHONE
# include <CoreFoundation/CoreFoundation.h>
# include <ApplicationServices/ApplicationServices.h>
#endif
int uv__set_process_title(const char* title) {
#if TARGET_OS_IPHONE
return -1;
#else
typedef CFTypeRef (*LSGetCurrentApplicationASNType)(void);
typedef OSStatus (*LSSetApplicationInformationItemType)(int,
CFTypeRef,
CFStringRef,
CFStringRef,
CFDictionaryRef*);
typedef CFDictionaryRef (*LSApplicationCheckInType)(int, CFDictionaryRef);
typedef OSStatus (*SetApplicationIsDaemonType)(int);
typedef void (*LSSetApplicationLaunchServicesServerConnectionStatusType)(
uint64_t, void*);
CFBundleRef launch_services_bundle;
LSGetCurrentApplicationASNType ls_get_current_application_asn;
LSSetApplicationInformationItemType ls_set_application_information_item;
CFStringRef* display_name_key;
CFTypeRef asn;
CFStringRef display_name;
OSStatus err;
CFBundleRef hi_services_bundle;
LSApplicationCheckInType ls_application_check_in;
SetApplicationIsDaemonType set_application_is_daemon;
LSSetApplicationLaunchServicesServerConnectionStatusType
ls_set_application_launch_services_server_connection_status;
launch_services_bundle =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
if (launch_services_bundle == NULL)
return -1;
ls_get_current_application_asn = (LSGetCurrentApplicationASNType)
CFBundleGetFunctionPointerForName(launch_services_bundle,
CFSTR("_LSGetCurrentApplicationASN"));
if (ls_get_current_application_asn == NULL)
return -1;
ls_set_application_information_item = (LSSetApplicationInformationItemType)
CFBundleGetFunctionPointerForName(launch_services_bundle,
CFSTR("_LSSetApplicationInformationItem"));
if (ls_set_application_information_item == NULL)
return -1;
display_name_key = CFBundleGetDataPointerForName(launch_services_bundle,
CFSTR("_kLSDisplayNameKey"));
if (display_name_key == NULL || *display_name_key == NULL)
return -1;
/* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
hi_services_bundle =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIServices"));
if (hi_services_bundle == NULL)
return -1;
set_application_is_daemon = CFBundleGetFunctionPointerForName(
hi_services_bundle,
CFSTR("SetApplicationIsDaemon"));
ls_application_check_in = CFBundleGetFunctionPointerForName(
launch_services_bundle,
CFSTR("_LSApplicationCheckIn"));
ls_set_application_launch_services_server_connection_status =
CFBundleGetFunctionPointerForName(
launch_services_bundle,
CFSTR("_LSSetApplicationLaunchServicesServerConnectionStatus"));
if (set_application_is_daemon == NULL ||
ls_application_check_in == NULL ||
ls_set_application_launch_services_server_connection_status == NULL) {
return -1;
}
if (set_application_is_daemon(1) != noErr)
return -1;
ls_set_application_launch_services_server_connection_status(0, NULL);
/* Check into process manager?! */
ls_application_check_in(-2,
CFBundleGetInfoDictionary(CFBundleGetMainBundle()));
display_name = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
asn = ls_get_current_application_asn();
err = ls_set_application_information_item(-2, /* Magic value. */
asn,
*display_name_key,
display_name,
NULL);
return (err == noErr) ? 0 : -1;
#endif /* !TARGET_OS_IPHONE */
}

View File

@ -1,110 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* TODO Share this code with Windows.
* See https://github.com/joyent/libuv/issues/76
*/
#include "uv.h"
#include "internal.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* TODO Expose callback to user to handle fatal error like V8 does. */
void uv_fatal_error(const int errorno, const char* syscall) {
char* buf = NULL;
const char* errmsg;
if (buf) {
errmsg = buf;
} else {
errmsg = "Unknown error";
}
if (syscall) {
fprintf(stderr, "\nlibuv fatal error. %s: (%d) %s\n", syscall, errorno,
errmsg);
} else {
fprintf(stderr, "\nlibuv fatal error. (%d) %s\n", errorno, errmsg);
}
abort();
}
uv_err_code uv_translate_sys_error(int sys_errno) {
switch (sys_errno) {
case 0: return UV_OK;
case EIO: return UV_EIO;
case EPERM: return UV_EPERM;
case ENOSYS: return UV_ENOSYS;
case ENOTSOCK: return UV_ENOTSOCK;
case ENOENT: return UV_ENOENT;
case EACCES: return UV_EACCES;
case EAFNOSUPPORT: return UV_EAFNOSUPPORT;
case EBADF: return UV_EBADF;
case EPIPE: return UV_EPIPE;
case ESPIPE: return UV_ESPIPE;
case EAGAIN: return UV_EAGAIN;
#if EWOULDBLOCK != EAGAIN
case EWOULDBLOCK: return UV_EAGAIN;
#endif
case ECONNRESET: return UV_ECONNRESET;
case EFAULT: return UV_EFAULT;
case EMFILE: return UV_EMFILE;
case EMSGSIZE: return UV_EMSGSIZE;
case ENAMETOOLONG: return UV_ENAMETOOLONG;
case EINVAL: return UV_EINVAL;
case ENETDOWN: return UV_ENETDOWN;
case ENETUNREACH: return UV_ENETUNREACH;
case ECONNABORTED: return UV_ECONNABORTED;
case ELOOP: return UV_ELOOP;
case ECONNREFUSED: return UV_ECONNREFUSED;
case EADDRINUSE: return UV_EADDRINUSE;
case EADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
case ENOTDIR: return UV_ENOTDIR;
case EISDIR: return UV_EISDIR;
case ENODEV: return UV_ENODEV;
case ENOTCONN: return UV_ENOTCONN;
case EEXIST: return UV_EEXIST;
case EHOSTUNREACH: return UV_EHOSTUNREACH;
case EAI_NONAME: return UV_ENOENT;
case ESRCH: return UV_ESRCH;
case ETIMEDOUT: return UV_ETIMEDOUT;
case EXDEV: return UV_EXDEV;
case EBUSY: return UV_EBUSY;
#if ENOTEMPTY != EEXIST
case ENOTEMPTY: return UV_ENOTEMPTY;
#endif
case ENOSPC: return UV_ENOSPC;
case EROFS: return UV_EROFS;
case ENOMEM: return UV_ENOMEM;
case EDQUOT: return UV_ENOSPC;
default: return UV_UNKNOWN;
}
UNREACHABLE();
}

View File

@ -1,297 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#if TARGET_OS_IPHONE
/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
int uv__fsevents_init(uv_fs_event_t* handle) {
return 0;
}
int uv__fsevents_close(uv_fs_event_t* handle) {
return 0;
}
#else /* TARGET_OS_IPHONE */
#include <assert.h>
#include <stdlib.h>
#include <CoreServices/CoreServices.h>
typedef struct uv__fsevents_event_s uv__fsevents_event_t;
struct uv__fsevents_event_s {
int events;
ngx_queue_t member;
char path[1];
};
#define UV__FSEVENTS_WALK(handle, block) \
{ \
ngx_queue_t* curr; \
ngx_queue_t split_head; \
uv__fsevents_event_t* event; \
uv_mutex_lock(&(handle)->cf_mutex); \
ngx_queue_init(&split_head); \
if (!ngx_queue_empty(&(handle)->cf_events)) { \
ngx_queue_t* split_pos = ngx_queue_next(&(handle)->cf_events); \
ngx_queue_split(&(handle)->cf_events, split_pos, &split_head); \
} \
uv_mutex_unlock(&(handle)->cf_mutex); \
while (!ngx_queue_empty(&split_head)) { \
curr = ngx_queue_head(&split_head); \
/* Invoke callback */ \
event = ngx_queue_data(curr, uv__fsevents_event_t, member); \
ngx_queue_remove(curr); \
/* Invoke block code, but only if handle wasn't closed */ \
if (((handle)->flags & (UV_CLOSING | UV_CLOSED)) == 0) \
block \
/* Free allocated data */ \
free(event); \
} \
}
void uv__fsevents_cb(uv_async_t* cb, int status) {
uv_fs_event_t* handle;
handle = cb->data;
UV__FSEVENTS_WALK(handle, {
if (handle->event_watcher.fd != -1)
handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
});
if ((handle->flags & (UV_CLOSING | UV_CLOSED)) == 0 &&
handle->event_watcher.fd == -1) {
uv__fsevents_close(handle);
}
}
void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
void* info,
size_t numEvents,
void* eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[]) {
size_t i;
int len;
char** paths;
char* path;
char* pos;
uv_fs_event_t* handle;
uv__fsevents_event_t* event;
ngx_queue_t add_list;
int kFSEventsModified;
int kFSEventsRenamed;
kFSEventsModified = kFSEventStreamEventFlagItemFinderInfoMod |
kFSEventStreamEventFlagItemModified |
kFSEventStreamEventFlagItemInodeMetaMod |
kFSEventStreamEventFlagItemChangeOwner |
kFSEventStreamEventFlagItemXattrMod;
kFSEventsRenamed = kFSEventStreamEventFlagItemCreated |
kFSEventStreamEventFlagItemRemoved |
kFSEventStreamEventFlagItemRenamed;
handle = info;
paths = eventPaths;
ngx_queue_init(&add_list);
for (i = 0; i < numEvents; i++) {
/* Ignore system events */
if (eventFlags[i] & (kFSEventStreamEventFlagUserDropped |
kFSEventStreamEventFlagKernelDropped |
kFSEventStreamEventFlagEventIdsWrapped |
kFSEventStreamEventFlagHistoryDone |
kFSEventStreamEventFlagMount |
kFSEventStreamEventFlagUnmount |
kFSEventStreamEventFlagRootChanged)) {
continue;
}
/* TODO: Report errors */
path = paths[i];
len = strlen(path);
/* Remove absolute path prefix */
if (strstr(path, handle->realpath) == path) {
path += handle->realpath_len;
len -= handle->realpath_len;
/* Skip back slash */
if (*path != 0) {
path++;
len--;
}
}
#ifdef MAC_OS_X_VERSION_10_7
/* Ignore events with path equal to directory itself */
if (len == 0)
continue;
#endif /* MAC_OS_X_VERSION_10_7 */
/* Do not emit events from subdirectories (without option set) */
pos = strchr(path, '/');
if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 &&
pos != NULL &&
pos != path + 1)
continue;
#ifndef MAC_OS_X_VERSION_10_7
path = "";
len = 0;
#endif /* MAC_OS_X_VERSION_10_7 */
event = malloc(sizeof(*event) + len);
if (event == NULL)
break;
memcpy(event->path, path, len + 1);
if ((eventFlags[i] & kFSEventsModified) != 0 &&
(eventFlags[i] & kFSEventsRenamed) == 0)
event->events = UV_CHANGE;
else
event->events = UV_RENAME;
ngx_queue_insert_tail(&add_list, &event->member);
}
uv_mutex_lock(&handle->cf_mutex);
ngx_queue_add(&handle->cf_events, &add_list);
uv_mutex_unlock(&handle->cf_mutex);
uv_async_send(handle->cf_cb);
}
void uv__fsevents_schedule(void* arg) {
uv_fs_event_t* handle;
handle = arg;
FSEventStreamScheduleWithRunLoop(handle->cf_eventstream,
handle->loop->cf_loop,
kCFRunLoopDefaultMode);
FSEventStreamStart(handle->cf_eventstream);
uv_sem_post(&handle->cf_sem);
}
int uv__fsevents_init(uv_fs_event_t* handle) {
FSEventStreamContext ctx;
FSEventStreamRef ref;
CFStringRef path;
CFArrayRef paths;
CFAbsoluteTime latency;
FSEventStreamCreateFlags flags;
/* Initialize context */
ctx.version = 0;
ctx.info = handle;
ctx.retain = NULL;
ctx.release = NULL;
ctx.copyDescription = NULL;
/* Get absolute path to file */
handle->realpath = realpath(handle->filename, NULL);
if (handle->realpath != NULL)
handle->realpath_len = strlen(handle->realpath);
/* Initialize paths array */
path = CFStringCreateWithFileSystemRepresentation(NULL, handle->filename);
paths = CFArrayCreate(NULL, (const void**)&path, 1, NULL);
latency = 0.15;
/* Set appropriate flags */
flags = kFSEventStreamCreateFlagFileEvents;
ref = FSEventStreamCreate(NULL,
&uv__fsevents_event_cb,
&ctx,
paths,
kFSEventStreamEventIdSinceNow,
latency,
flags);
handle->cf_eventstream = ref;
/*
* Events will occur in other thread.
* Initialize callback for getting them back into event loop's thread
*/
handle->cf_cb = malloc(sizeof(*handle->cf_cb));
if (handle->cf_cb == NULL)
return uv__set_sys_error(handle->loop, ENOMEM);
handle->cf_cb->data = handle;
uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
uv_unref((uv_handle_t*) handle->cf_cb);
uv_mutex_init(&handle->cf_mutex);
uv_sem_init(&handle->cf_sem, 0);
ngx_queue_init(&handle->cf_events);
uv__cf_loop_signal(handle->loop, uv__fsevents_schedule, handle);
return 0;
}
int uv__fsevents_close(uv_fs_event_t* handle) {
if (handle->cf_eventstream == NULL)
return -1;
/* Ensure that event stream was scheduled */
uv_sem_wait(&handle->cf_sem);
/* Stop emitting events */
FSEventStreamStop(handle->cf_eventstream);
/* Release stream */
FSEventStreamInvalidate(handle->cf_eventstream);
FSEventStreamRelease(handle->cf_eventstream);
handle->cf_eventstream = NULL;
uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) free);
/* Free data in queue */
UV__FSEVENTS_WALK(handle, {
/* NOP */
})
uv_mutex_destroy(&handle->cf_mutex);
uv_sem_destroy(&handle->cf_sem);
free(handle->realpath);
handle->realpath = NULL;
handle->realpath_len = 0;
return 0;
}
#endif /* TARGET_OS_IPHONE */

View File

@ -1,709 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
static void uv__udp_run_completed(uv_udp_t* handle);
static void uv__udp_run_pending(uv_udp_t* handle);
static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
static void uv__udp_sendmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain);
static int uv__send(uv_udp_send_t* req,
uv_udp_t* handle,
uv_buf_t bufs[],
int bufcnt,
struct sockaddr* addr,
socklen_t addrlen,
uv_udp_send_cb send_cb);
void uv__udp_close(uv_udp_t* handle) {
uv__io_close(handle->loop, &handle->io_watcher);
uv__handle_stop(handle);
close(handle->io_watcher.fd);
handle->io_watcher.fd = -1;
}
void uv__udp_finish_close(uv_udp_t* handle) {
uv_udp_send_t* req;
ngx_queue_t* q;
assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
assert(handle->io_watcher.fd == -1);
uv__udp_run_completed(handle);
while (!ngx_queue_empty(&handle->write_queue)) {
q = ngx_queue_head(&handle->write_queue);
ngx_queue_remove(q);
req = ngx_queue_data(q, uv_udp_send_t, queue);
uv__req_unregister(handle->loop, req);
if (req->bufs != req->bufsml)
free(req->bufs);
req->bufs = NULL;
if (req->send_cb) {
uv__set_artificial_error(handle->loop, UV_ECANCELED);
req->send_cb(req, -1);
}
}
/* Now tear down the handle. */
handle->recv_cb = NULL;
handle->alloc_cb = NULL;
/* but _do not_ touch close_cb */
}
static void uv__udp_run_pending(uv_udp_t* handle) {
uv_udp_send_t* req;
ngx_queue_t* q;
struct msghdr h;
ssize_t size;
while (!ngx_queue_empty(&handle->write_queue)) {
q = ngx_queue_head(&handle->write_queue);
assert(q != NULL);
req = ngx_queue_data(q, uv_udp_send_t, queue);
assert(req != NULL);
memset(&h, 0, sizeof h);
h.msg_name = &req->addr;
h.msg_namelen = (req->addr.sin6_family == AF_INET6 ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
h.msg_iov = (struct iovec*)req->bufs;
h.msg_iovlen = req->bufcnt;
do {
size = sendmsg(handle->io_watcher.fd, &h, 0);
}
while (size == -1 && errno == EINTR);
/* TODO try to write once or twice more in the
* hope that the socket becomes readable again?
*/
if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
break;
req->status = (size == -1 ? -errno : size);
#ifndef NDEBUG
/* Sanity check. */
if (size != -1) {
ssize_t nbytes;
int i;
for (nbytes = i = 0; i < req->bufcnt; i++)
nbytes += req->bufs[i].len;
assert(size == nbytes);
}
#endif
/* Sending a datagram is an atomic operation: either all data
* is written or nothing is (and EMSGSIZE is raised). That is
* why we don't handle partial writes. Just pop the request
* off the write queue and onto the completed queue, done.
*/
ngx_queue_remove(&req->queue);
ngx_queue_insert_tail(&handle->write_completed_queue, &req->queue);
}
}
static void uv__udp_run_completed(uv_udp_t* handle) {
uv_udp_send_t* req;
ngx_queue_t* q;
while (!ngx_queue_empty(&handle->write_completed_queue)) {
q = ngx_queue_head(&handle->write_completed_queue);
ngx_queue_remove(q);
req = ngx_queue_data(q, uv_udp_send_t, queue);
uv__req_unregister(handle->loop, req);
if (req->bufs != req->bufsml)
free(req->bufs);
req->bufs = NULL;
if (req->send_cb == NULL)
continue;
/* req->status >= 0 == bytes written
* req->status < 0 == errno
*/
if (req->status >= 0) {
req->send_cb(req, 0);
}
else {
uv__set_sys_error(handle->loop, -req->status);
req->send_cb(req, -1);
}
}
}
static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
if (revents & UV__POLLIN)
uv__udp_recvmsg(loop, w, revents);
if (revents & UV__POLLOUT)
uv__udp_sendmsg(loop, w, revents);
}
static void uv__udp_recvmsg(uv_loop_t* loop,
uv__io_t* w,
unsigned int revents) {
struct sockaddr_storage peer;
struct msghdr h;
uv_udp_t* handle;
ssize_t nread;
uv_buf_t buf;
int flags;
int count;
handle = container_of(w, uv_udp_t, io_watcher);
assert(handle->type == UV_UDP);
assert(revents & UV__POLLIN);
assert(handle->recv_cb != NULL);
assert(handle->alloc_cb != NULL);
/* Prevent loop starvation when the data comes in as fast as (or faster than)
* we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
*/
count = 32;
memset(&h, 0, sizeof(h));
h.msg_name = &peer;
do {
buf = handle->alloc_cb((uv_handle_t*)handle, 64 * 1024);
assert(buf.len > 0);
assert(buf.base != NULL);
h.msg_namelen = sizeof(peer);
h.msg_iov = (void*) &buf;
h.msg_iovlen = 1;
do {
nread = recvmsg(handle->io_watcher.fd, &h, 0);
}
while (nread == -1 && errno == EINTR);
if (nread == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
uv__set_sys_error(handle->loop, EAGAIN);
handle->recv_cb(handle, 0, buf, NULL, 0);
}
else {
uv__set_sys_error(handle->loop, errno);
handle->recv_cb(handle, -1, buf, NULL, 0);
}
}
else {
flags = 0;
if (h.msg_flags & MSG_TRUNC)
flags |= UV_UDP_PARTIAL;
handle->recv_cb(handle,
nread,
buf,
(struct sockaddr*)&peer,
flags);
}
}
/* recv_cb callback may decide to pause or close the handle */
while (nread != -1
&& count-- > 0
&& handle->io_watcher.fd != -1
&& handle->recv_cb != NULL);
}
static void uv__udp_sendmsg(uv_loop_t* loop,
uv__io_t* w,
unsigned int revents) {
uv_udp_t* handle;
handle = container_of(w, uv_udp_t, io_watcher);
assert(handle->type == UV_UDP);
assert(revents & UV__POLLOUT);
assert(!ngx_queue_empty(&handle->write_queue)
|| !ngx_queue_empty(&handle->write_completed_queue));
/* Write out pending data first. */
uv__udp_run_pending(handle);
/* Drain 'request completed' queue. */
uv__udp_run_completed(handle);
if (!ngx_queue_empty(&handle->write_completed_queue)) {
/* Schedule completion callbacks. */
uv__io_feed(handle->loop, &handle->io_watcher);
}
else if (ngx_queue_empty(&handle->write_queue)) {
/* Pending queue and completion queue empty, stop watcher. */
uv__io_stop(loop, &handle->io_watcher, UV__POLLOUT);
if (!uv__io_active(&handle->io_watcher, UV__POLLIN))
uv__handle_stop(handle);
}
}
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
* refinements for programs that use multicast.
*
* Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
* are different from the BSDs: it _shares_ the port rather than steal it
* from the current listener. While useful, it's not something we can emulate
* on other platforms so we don't enable it.
*/
static int uv__set_reuse(int fd) {
int yes;
#if defined(SO_REUSEPORT) && !defined(__linux__)
yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
return -errno;
#else
yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
return -errno;
#endif
return 0;
}
static int uv__bind(uv_udp_t* handle,
int domain,
struct sockaddr* addr,
socklen_t len,
unsigned flags) {
int saved_errno;
int status;
int err;
int yes;
int fd;
saved_errno = errno;
status = -1;
fd = -1;
/* Check for bad flags. */
if (flags & ~UV_UDP_IPV6ONLY) {
uv__set_sys_error(handle->loop, EINVAL);
goto out;
}
/* Cannot set IPv6-only mode on non-IPv6 socket. */
if ((flags & UV_UDP_IPV6ONLY) && domain != AF_INET6) {
uv__set_sys_error(handle->loop, EINVAL);
goto out;
}
if (handle->io_watcher.fd == -1) {
if ((fd = uv__socket(domain, SOCK_DGRAM, 0)) == -1) {
uv__set_sys_error(handle->loop, errno);
goto out;
}
handle->io_watcher.fd = fd;
}
fd = handle->io_watcher.fd;
err = uv__set_reuse(fd);
if (err) {
uv__set_sys_error(handle->loop, -err);
goto out;
}
if (flags & UV_UDP_IPV6ONLY) {
#ifdef IPV6_V6ONLY
yes = 1;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
uv__set_sys_error(handle->loop, errno);
goto out;
}
#else
uv__set_sys_error(handle->loop, ENOTSUP);
goto out;
#endif
}
if (bind(fd, addr, len) == -1) {
uv__set_sys_error(handle->loop, errno);
goto out;
}
handle->io_watcher.fd = fd;
status = 0;
out:
if (status) {
close(handle->io_watcher.fd);
handle->io_watcher.fd = -1;
}
errno = saved_errno;
return status;
}
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain) {
unsigned char taddr[sizeof(struct sockaddr_in6)];
socklen_t addrlen;
assert(domain == AF_INET || domain == AF_INET6);
if (handle->io_watcher.fd != -1)
return 0;
switch (domain) {
case AF_INET:
{
struct sockaddr_in* addr = (void*)&taddr;
memset(addr, 0, sizeof *addr);
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = INADDR_ANY;
addrlen = sizeof *addr;
break;
}
case AF_INET6:
{
struct sockaddr_in6* addr = (void*)&taddr;
memset(addr, 0, sizeof *addr);
addr->sin6_family = AF_INET6;
addr->sin6_addr = in6addr_any;
addrlen = sizeof *addr;
break;
}
default:
assert(0 && "unsupported address family");
abort();
}
return uv__bind(handle, domain, (struct sockaddr*)&taddr, addrlen, 0);
}
static int uv__send(uv_udp_send_t* req,
uv_udp_t* handle,
uv_buf_t bufs[],
int bufcnt,
struct sockaddr* addr,
socklen_t addrlen,
uv_udp_send_cb send_cb) {
assert(bufcnt > 0);
if (uv__udp_maybe_deferred_bind(handle, addr->sa_family))
return -1;
uv__req_init(handle->loop, req, UV_UDP_SEND);
assert(addrlen <= sizeof(req->addr));
memcpy(&req->addr, addr, addrlen);
req->send_cb = send_cb;
req->handle = handle;
req->bufcnt = bufcnt;
if (bufcnt <= (int) ARRAY_SIZE(req->bufsml)) {
req->bufs = req->bufsml;
}
else if ((req->bufs = malloc(bufcnt * sizeof(bufs[0]))) == NULL) {
uv__set_sys_error(handle->loop, ENOMEM);
return -1;
}
memcpy(req->bufs, bufs, bufcnt * sizeof(bufs[0]));
ngx_queue_insert_tail(&handle->write_queue, &req->queue);
uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
uv__handle_start(handle);
return 0;
}
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
handle->alloc_cb = NULL;
handle->recv_cb = NULL;
uv__io_init(&handle->io_watcher, uv__udp_io, -1);
ngx_queue_init(&handle->write_queue);
ngx_queue_init(&handle->write_completed_queue);
return 0;
}
int uv__udp_bind(uv_udp_t* handle, struct sockaddr_in addr, unsigned flags) {
return uv__bind(handle,
AF_INET,
(struct sockaddr*)&addr,
sizeof addr,
flags);
}
int uv__udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr, unsigned flags) {
return uv__bind(handle,
AF_INET6,
(struct sockaddr*)&addr,
sizeof addr,
flags);
}
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
int saved_errno;
int status;
int err;
saved_errno = errno;
status = -1;
/* Check for already active socket. */
if (handle->io_watcher.fd != -1) {
uv__set_artificial_error(handle->loop, UV_EALREADY);
goto out;
}
err = uv__set_reuse(sock);
if (err) {
uv__set_sys_error(handle->loop, -err);
goto out;
}
handle->io_watcher.fd = sock;
status = 0;
out:
errno = saved_errno;
return status;
}
int uv_udp_set_membership(uv_udp_t* handle,
const char* multicast_addr,
const char* interface_addr,
uv_membership membership) {
struct ip_mreq mreq;
int optname;
memset(&mreq, 0, sizeof mreq);
if (interface_addr) {
mreq.imr_interface.s_addr = inet_addr(interface_addr);
} else {
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
}
mreq.imr_multiaddr.s_addr = inet_addr(multicast_addr);
switch (membership) {
case UV_JOIN_GROUP:
optname = IP_ADD_MEMBERSHIP;
break;
case UV_LEAVE_GROUP:
optname = IP_DROP_MEMBERSHIP;
break;
default:
return uv__set_artificial_error(handle->loop, UV_EINVAL);
}
if (setsockopt(handle->io_watcher.fd,
IPPROTO_IP,
optname,
&mreq,
sizeof(mreq))) {
return uv__set_sys_error(handle->loop, errno);
}
return 0;
}
static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) {
#if defined(__sun)
char arg = val;
#else
int arg = val;
#endif
if (val < 0 || val > 255)
return uv__set_sys_error(handle->loop, EINVAL);
if (setsockopt(handle->io_watcher.fd, IPPROTO_IP, option, &arg, sizeof(arg)))
return uv__set_sys_error(handle->loop, errno);
return 0;
}
int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
if (setsockopt(handle->io_watcher.fd,
SOL_SOCKET,
SO_BROADCAST,
&on,
sizeof(on))) {
return uv__set_sys_error(handle->loop, errno);
}
return 0;
}
int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
if (ttl < 1 || ttl > 255)
return uv__set_sys_error(handle->loop, EINVAL);
if (setsockopt(handle->io_watcher.fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)))
return uv__set_sys_error(handle->loop, errno);
return 0;
}
int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, ttl);
}
int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, on);
}
int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) {
socklen_t socklen;
int saved_errno;
int rv = 0;
/* Don't clobber errno. */
saved_errno = errno;
if (handle->io_watcher.fd == -1) {
uv__set_sys_error(handle->loop, EINVAL);
rv = -1;
goto out;
}
/* sizeof(socklen_t) != sizeof(int) on some systems. */
socklen = (socklen_t)*namelen;
if (getsockname(handle->io_watcher.fd, name, &socklen) == -1) {
uv__set_sys_error(handle->loop, errno);
rv = -1;
} else {
*namelen = (int)socklen;
}
out:
errno = saved_errno;
return rv;
}
int uv__udp_send(uv_udp_send_t* req,
uv_udp_t* handle,
uv_buf_t bufs[],
int bufcnt,
struct sockaddr_in addr,
uv_udp_send_cb send_cb) {
return uv__send(req,
handle,
bufs,
bufcnt,
(struct sockaddr*)&addr,
sizeof addr,
send_cb);
}
int uv__udp_send6(uv_udp_send_t* req,
uv_udp_t* handle,
uv_buf_t bufs[],
int bufcnt,
struct sockaddr_in6 addr,
uv_udp_send_cb send_cb) {
return uv__send(req,
handle,
bufs,
bufcnt,
(struct sockaddr*)&addr,
sizeof addr,
send_cb);
}
int uv__udp_recv_start(uv_udp_t* handle,
uv_alloc_cb alloc_cb,
uv_udp_recv_cb recv_cb) {
if (alloc_cb == NULL || recv_cb == NULL) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
return -1;
}
if (uv__io_active(&handle->io_watcher, UV__POLLIN)) {
uv__set_artificial_error(handle->loop, UV_EALREADY);
return -1;
}
if (uv__udp_maybe_deferred_bind(handle, AF_INET))
return -1;
handle->alloc_cb = alloc_cb;
handle->recv_cb = recv_cb;
uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN);
uv__handle_start(handle);
return 0;
}
int uv__udp_recv_stop(uv_udp_t* handle) {
uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN);
if (!uv__io_active(&handle->io_watcher, UV__POLLOUT))
uv__handle_stop(handle);
handle->alloc_cb = NULL;
handle->recv_cb = NULL;
return 0;
}

View File

@ -1,436 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "uv-common.h"
#include <stdio.h>
#include <assert.h>
#include <stddef.h> /* NULL */
#include <stdlib.h> /* malloc */
#include <string.h> /* memset */
#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
size_t uv_handle_size(uv_handle_type type) {
switch (type) {
UV_HANDLE_TYPE_MAP(XX)
default:
return -1;
}
}
size_t uv_req_size(uv_req_type type) {
switch(type) {
UV_REQ_TYPE_MAP(XX)
default:
return -1;
}
}
#undef XX
size_t uv_strlcpy(char* dst, const char* src, size_t size) {
size_t n;
if (size == 0)
return 0;
for (n = 0; n < (size - 1) && *src != '\0'; n++)
*dst++ = *src++;
*dst = '\0';
return n;
}
size_t uv_strlcat(char* dst, const char* src, size_t size) {
size_t n;
if (size == 0)
return 0;
for (n = 0; n < size && *dst != '\0'; n++, dst++);
if (n == size)
return n;
while (n < (size - 1) && *src != '\0')
n++, *dst++ = *src++;
*dst = '\0';
return n;
}
uv_buf_t uv_buf_init(char* base, unsigned int len) {
uv_buf_t buf;
buf.base = base;
buf.len = len;
return buf;
}
const uv_err_t uv_ok_ = { UV_OK, 0 };
#define UV_ERR_NAME_GEN(val, name, s) case UV_##name : return #name;
const char* uv_err_name(uv_err_t err) {
switch (err.code) {
UV_ERRNO_MAP(UV_ERR_NAME_GEN)
default:
assert(0);
return NULL;
}
}
#undef UV_ERR_NAME_GEN
#define UV_STRERROR_GEN(val, name, s) case UV_##name : return s;
const char* uv_strerror(uv_err_t err) {
switch (err.code) {
UV_ERRNO_MAP(UV_STRERROR_GEN)
default:
return "Unknown system error";
}
}
#undef UV_STRERROR_GEN
int uv__set_error(uv_loop_t* loop, uv_err_code code, int sys_error) {
loop->last_err.code = code;
loop->last_err.sys_errno_ = sys_error;
return -1;
}
int uv__set_sys_error(uv_loop_t* loop, int sys_error) {
loop->last_err.code = uv_translate_sys_error(sys_error);
loop->last_err.sys_errno_ = sys_error;
return -1;
}
int uv__set_artificial_error(uv_loop_t* loop, uv_err_code code) {
loop->last_err = uv__new_artificial_error(code);
return -1;
}
uv_err_t uv__new_sys_error(int sys_error) {
uv_err_t error;
error.code = uv_translate_sys_error(sys_error);
error.sys_errno_ = sys_error;
return error;
}
uv_err_t uv__new_artificial_error(uv_err_code code) {
uv_err_t error;
error.code = code;
error.sys_errno_ = 0;
return error;
}
uv_err_t uv_last_error(uv_loop_t* loop) {
return loop->last_err;
}
struct sockaddr_in uv_ip4_addr(const char* ip, int port) {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);
return addr;
}
struct sockaddr_in6 uv_ip6_addr(const char* ip, int port) {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(struct sockaddr_in6));
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port);
uv_inet_pton(AF_INET6, ip, &addr.sin6_addr);
return addr;
}
int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) {
uv_err_t err = uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
return err.code != UV_OK;
}
int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) {
uv_err_t err = uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
return err.code != UV_OK;
}
int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr) {
if (handle->type != UV_TCP || addr.sin_family != AF_INET)
return uv__set_artificial_error(handle->loop, UV_EINVAL);
else
return uv__tcp_bind(handle, addr);
}
int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) {
if (handle->type != UV_TCP || addr.sin6_family != AF_INET6)
return uv__set_artificial_error(handle->loop, UV_EINVAL);
else
return uv__tcp_bind6(handle, addr);
}
int uv_udp_bind(uv_udp_t* handle,
struct sockaddr_in addr,
unsigned int flags) {
if (handle->type != UV_UDP || addr.sin_family != AF_INET)
return uv__set_artificial_error(handle->loop, UV_EINVAL);
else
return uv__udp_bind(handle, addr, flags);
}
int uv_udp_bind6(uv_udp_t* handle,
struct sockaddr_in6 addr,
unsigned int flags) {
if (handle->type != UV_UDP || addr.sin6_family != AF_INET6)
return uv__set_artificial_error(handle->loop, UV_EINVAL);
else
return uv__udp_bind6(handle, addr, flags);
}
int uv_tcp_connect(uv_connect_t* req,
uv_tcp_t* handle,
struct sockaddr_in address,
uv_connect_cb cb) {
if (handle->type != UV_TCP || address.sin_family != AF_INET)
return uv__set_artificial_error(handle->loop, UV_EINVAL);
else
return uv__tcp_connect(req, handle, address, cb);
}
int uv_tcp_connect6(uv_connect_t* req,
uv_tcp_t* handle,
struct sockaddr_in6 address,
uv_connect_cb cb) {
if (handle->type != UV_TCP || address.sin6_family != AF_INET6)
return uv__set_artificial_error(handle->loop, UV_EINVAL);
else
return uv__tcp_connect6(req, handle, address, cb);
}
int uv_udp_send(uv_udp_send_t* req,
uv_udp_t* handle,
uv_buf_t bufs[],
int bufcnt,
struct sockaddr_in addr,
uv_udp_send_cb send_cb) {
if (handle->type != UV_UDP || addr.sin_family != AF_INET) {
return uv__set_artificial_error(handle->loop, UV_EINVAL);
}
return uv__udp_send(req, handle, bufs, bufcnt, addr, send_cb);
}
int uv_udp_send6(uv_udp_send_t* req,
uv_udp_t* handle,
uv_buf_t bufs[],
int bufcnt,
struct sockaddr_in6 addr,
uv_udp_send_cb send_cb) {
if (handle->type != UV_UDP || addr.sin6_family != AF_INET6) {
return uv__set_artificial_error(handle->loop, UV_EINVAL);
}
return uv__udp_send6(req, handle, bufs, bufcnt, addr, send_cb);
}
int uv_udp_recv_start(uv_udp_t* handle,
uv_alloc_cb alloc_cb,
uv_udp_recv_cb recv_cb) {
if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL) {
return uv__set_artificial_error(handle->loop, UV_EINVAL);
}
return uv__udp_recv_start(handle, alloc_cb, recv_cb);
}
int uv_udp_recv_stop(uv_udp_t* handle) {
if (handle->type != UV_UDP) {
return uv__set_artificial_error(handle->loop, UV_EINVAL);
}
return uv__udp_recv_stop(handle);
}
#ifdef _WIN32
static UINT __stdcall uv__thread_start(void *ctx_v)
#else
static void *uv__thread_start(void *ctx_v)
#endif
{
void (*entry)(void *arg);
void *arg;
struct {
void (*entry)(void *arg);
void *arg;
} *ctx;
ctx = ctx_v;
arg = ctx->arg;
entry = ctx->entry;
free(ctx);
entry(arg);
return 0;
}
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
struct {
void (*entry)(void *arg);
void *arg;
} *ctx;
if ((ctx = malloc(sizeof *ctx)) == NULL)
return -1;
ctx->entry = entry;
ctx->arg = arg;
#ifdef _WIN32
*tid = (HANDLE) _beginthreadex(NULL, 0, uv__thread_start, ctx, 0, NULL);
if (*tid == 0) {
#else
if (pthread_create(tid, NULL, uv__thread_start, ctx)) {
#endif
free(ctx);
return -1;
}
return 0;
}
unsigned long uv_thread_self(void) {
#ifdef _WIN32
return (unsigned long) GetCurrentThreadId();
#else
return (unsigned long) pthread_self();
#endif
}
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
ngx_queue_t* q;
uv_handle_t* h;
ngx_queue_foreach(q, &loop->handle_queue) {
h = ngx_queue_data(q, uv_handle_t, handle_queue);
if (h->flags & UV__HANDLE_INTERNAL) continue;
walk_cb(h, arg);
}
}
#ifndef NDEBUG
static void uv__print_handles(uv_loop_t* loop, int only_active) {
const char* type;
ngx_queue_t* q;
uv_handle_t* h;
if (loop == NULL)
loop = uv_default_loop();
ngx_queue_foreach(q, &loop->handle_queue) {
h = ngx_queue_data(q, uv_handle_t, handle_queue);
if (only_active && !uv__is_active(h))
continue;
switch (h->type) {
#define X(uc, lc) case UV_##uc: type = #lc; break;
UV_HANDLE_TYPE_MAP(X)
#undef X
default: type = "<unknown>";
}
fprintf(stderr,
"[%c%c%c] %-8s %p\n",
"R-"[!(h->flags & UV__HANDLE_REF)],
"A-"[!(h->flags & UV__HANDLE_ACTIVE)],
"I-"[!(h->flags & UV__HANDLE_INTERNAL)],
type,
(void*)h);
}
}
void uv_print_all_handles(uv_loop_t* loop) {
uv__print_handles(loop, 0);
}
void uv_print_active_handles(uv_loop_t* loop) {
uv__print_handles(loop, 1);
}
#endif
void uv_ref(uv_handle_t* handle) {
uv__handle_ref(handle);
}
void uv_unref(uv_handle_t* handle) {
uv__handle_unref(handle);
}
void uv_stop(uv_loop_t* loop) {
loop->stop_flag = 1;
}
uint64_t uv_now(uv_loop_t* loop) {
return loop->time;
}

View File

@ -1,82 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include "uv.h"
#include "internal.h"
#include "req-inl.h"
static void uv_work_req_init(uv_loop_t* loop, uv_work_t* req,
uv_work_cb work_cb, uv_after_work_cb after_work_cb) {
uv_req_init(loop, (uv_req_t*) req);
req->type = UV_WORK;
req->loop = loop;
req->work_cb = work_cb;
req->after_work_cb = after_work_cb;
memset(&req->overlapped, 0, sizeof(req->overlapped));
}
static DWORD WINAPI uv_work_thread_proc(void* parameter) {
uv_work_t* req = (uv_work_t*)parameter;
uv_loop_t* loop = req->loop;
assert(req != NULL);
assert(req->type == UV_WORK);
assert(req->work_cb);
req->work_cb(req);
POST_COMPLETION_FOR_REQ(loop, req);
return 0;
}
int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb,
uv_after_work_cb after_work_cb) {
if (work_cb == NULL)
return uv__set_artificial_error(loop, UV_EINVAL);
uv_work_req_init(loop, req, work_cb, after_work_cb);
if (!QueueUserWorkItem(&uv_work_thread_proc, req, WT_EXECUTELONGFUNCTION)) {
uv__set_sys_error(loop, GetLastError());
return -1;
}
uv__req_register(loop, req);
return 0;
}
int uv_cancel(uv_req_t* req) {
return -1;
}
void uv_process_work_req(uv_loop_t* loop, uv_work_t* req) {
uv__req_unregister(loop, req);
if(req->after_work_cb)
req->after_work_cb(req, 0);
}

63
outside/libuv_0.11/.gitignore vendored Normal file
View File

@ -0,0 +1,63 @@
*.swp
*.[oa]
*.l[oa]
*.opensdf
*.orig
*.pyc
*.sdf
*.suo
core
vgcore.*
.buildstamp
.dirstamp
.deps/
/.libs/
/aclocal.m4
/ar-lib
/autom4te.cache/
/compile
/config.guess
/config.log
/config.status
/config.sub
/configure
/depcomp
/install-sh
/libtool
/libuv.a
/libuv.dylib
/libuv.pc
/libuv.so
/ltmain.sh
/missing
/test-driver
Makefile
Makefile.in
# Generated by dtrace(1) when doing an in-tree build.
/include/uv-dtrace.h
# Generated by gyp for android
*.target.mk
/out/
/build/gyp
/test/.libs/
/test/run-tests
/test/run-tests.exe
/test/run-tests.dSYM
/test/run-benchmarks
/test/run-benchmarks.exe
/test/run-benchmarks.dSYM
*.sln
*.vcproj
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
_UpgradeReport_Files/
UpgradeLog*.XML
Debug
Release
ipch

View File

@ -0,0 +1,34 @@
Aaron Bieber <qbit@deftly.net> <deftly@gmail.com>
Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com>
Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com>
Bert Belder <bertbelder@gmail.com> <info@2bs.nl>
Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)>
Brandon Philips <brandon.philips@rackspace.com> <brandon@ifup.org>
Brian White <mscdex@mscdex.net>
Brian White <mscdex@mscdex.net> <mscdex@gmail.com>
Caleb James DeLisle <cjd@hyperboria.ca> <cjd@cjdns.fr>
Christoph Iserlohn <christoph.iserlohn@innoq.com>
Fedor Indutny <fedor.indutny@gmail.com> <fedor@indutny.com>
Frank Denis <github@pureftpd.org>
Isaac Z. Schlueter <i@izs.me>
Justin Venus <justin.venus@gmail.com> <justin.venus@orbitz.com>
Keno Fischer <kenof@stanford.edu> <kfischer+github@college.harvard.edu>
Keno Fischer <kenof@stanford.edu> <kfischer@college.harvard.edu>
Maciej Małecki <maciej.malecki@notimplemented.org> <me@mmalecki.com>
Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com>
Rasmus Christian Pedersen <ruysch@outlook.com>
Rasmus Christian Pedersen <ruysch@outlook.com>
Rasmus Christian Pedersen <ruysch@outlook.com>
Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com>
Rasmus Pedersen <ruysch@outlook.com> <zerhacken@yahoo.com>
Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org>
Ryan Dahl <ryan@joyent.com> <ry@tinyclouds.org>
Ryan Emery <seebees@gmail.com>
Sam Roberts <vieuxtech@gmail.com> <sam@strongloop.com>
San-Tai Hsu <vanilla@fatpipi.com>
Saúl Ibarra Corretgé <saghul@gmail.com>
Shigeki Ohtsu <ohtsu@iij.ad.jp> <ohtsu@ohtsu.org>
Timothy J. Fontaine <tjfontaine@gmail.com>
Yasuhiro Matsumoto <mattn.jp@gmail.com>
Yazhong Liu <yorkiefixer@gmail.com>
Yuki Okumura <mjt@cltn.org>

View File

@ -79,18 +79,79 @@ Tim Bradshaw <tfb@cley.com>
Timothy J. Fontaine <tjfontaine@gmail.com>
Marc Schlaich <marc.schlaich@googlemail.com>
Brian Mazza <louseman@gmail.com>
Elliot Saba <staticfloat@gmail.com>
Ben Kelly <ben@wanderview.com>
Nils Maier <maierman@web.de>
Nicholas Vavilov <vvnicholas@gmail.com>
Miroslav Bajtoš <miro.bajtos@gmail.com>
Elliot Saba <staticfloat@gmail.com>
Sean Silva <chisophugis@gmail.com>
Wynn Wilkes <wynnw@movenetworks.com>
Linus Mårtensson <linus.martensson@sonymobile.com>
Andrei Sedoi <bsnote@gmail.com>
Navaneeth Kedaram Nambiathan <navaneethkn@gmail.com>
Alex Crichton <alex@alexcrichton.com>
Brent Cook <brent@boundary.com>
Brian Kaisner <bkize1@gmail.com>
Luca Bruno <lucab@debian.org>
Reini Urban <rurban@cpanel.net>
Maks Naumov <maksqwe1@ukr.net>
Sean Farrell <sean.farrell@rioki.org>
Chris Bank <cbank@adobe.com>
Geert Jansen <geertj@gmail.com>
Christoph Iserlohn <christoph.iserlohn@innoq.com>
Steven Kabbes <stevenkabbes@gmail.com>
Alex Gaynor <alex.gaynor@gmail.com>
huxingyi <huxingyi@msn.com>
Alex Crichton <alex@alexcrichton.com>
Tenor Biel <tenorbiel@gmail.com>
Andrej Manduch <AManduch@gmail.com>
Joshua Neuheisel <joshua@neuheisel.us>
Alexis Campailla <alexis@janeasystems.com>
Yazhong Liu <yorkiefixer@gmail.com>
Sam Roberts <vieuxtech@gmail.com>
River Tarnell <river@loreley.flyingparchment.org.uk>
Nathan Sweet <nathanjsweet@gmail.com>
Luca Bruno <lucab@debian.org>
Trevor Norris <trev.norris@gmail.com>
Oguz Bastemur <obastemur@gmail.com>
Alexis Campailla <alexis@janeasystems.com>
Dylan Cali <calid1984@gmail.com>
Austin Foxley <austinf@cetoncorp.com>
Benjamin Saunders <ben.e.saunders@gmail.com>
Geoffry Song <goffrie@gmail.com>
Rasmus Christian Pedersen <ruysch@outlook.com>
William Light <wrl@illest.net>
Oleg Efimov <o.efimov@corp.badoo.com>
Lars Gierth <larsg@systemli.org>
Rasmus Christian Pedersen <zerhacken@yahoo.com>
Justin Venus <justin.venus@gmail.com>
Kristian Evensen <kristian.evensen@gmail.com>
Linus Mårtensson <linus.martensson@sonymobile.com>
Navaneeth Kedaram Nambiathan <navaneethkn@gmail.com>
Yorkie <yorkiefixer@gmail.com>
StarWing <weasley.wx@gmail.com>
thierry-FreeBSD <thierry@FreeBSD.org>
Isaiah Norton <isaiah.norton@gmail.com>
Raul Martins <raulms.martins@gmail.com>
David Capello <davidcapello@gmail.com>
Paul Tan <pyokagan@gmail.com>
Javier Hernández <jhernandez@emergya.com>
Tonis Tiigi <tonistiigi@gmail.com>
Norio Kobota <nori.0428@gmail.com>
李港平 <chopdown@gmail.com>
Chernyshev Viacheslav <astellar@ro.ru>
Stephen von Takach <steve@advancedcontrol.com.au>
JD Ballard <jd@pixelandline.com>
Luka Perkov <luka.perkov@sartura.hr>
Ryan Cole <ryan@rycole.com>
HungMingWu <u9089000@gmail.com>
Jay Satiro <raysatiro@yahoo.com>
Leith Bade <leith@leithalweapon.geek.nz>
Peter Atashian <retep998@gmail.com>
Tim Cooper <tim.cooper@layeh.com>
Caleb James DeLisle <cjd@hyperboria.ca>
Jameson Nash <vtjnash@gmail.com>
Graham Lee <ghmlee@ghmlee.com>
Andrew Low <Andrew_Low@ca.ibm.com>
Pavel Platto <hinidu@gmail.com>
Tony Kelman <tony@kelman.net>
John Firebaugh <john.firebaugh@gmail.com>
lilohuang <lilohuang@hotmail.com>

View File

@ -0,0 +1,166 @@
# CONTRIBUTING
The libuv project welcomes new contributors. This document will guide you
through the process.
### FORK
Fork the project [on GitHub](https://github.com/joyent/libuv) and check out
your copy.
```
$ git clone https://github.com/username/libuv.git
$ cd libuv
$ git remote add upstream https://github.com/joyent/libuv.git
```
Now decide if you want your feature or bug fix to go into the master branch
or the stable branch. As a rule of thumb, bug fixes go into the stable branch
while new features go into the master branch.
The stable branch is effectively frozen; patches that change the libuv
API/ABI or affect the run-time behavior of applications get rejected.
In case of doubt, open an issue in the [issue tracker][], post your question
to the [libuv mailing list], or contact one of project maintainers
(@bnoordhuis, @piscisaureus, @indutny or @saghul) on [IRC][].
Especially do so if you plan to work on something big. Nothing is more
frustrating than seeing your hard work go to waste because your vision
does not align with that of a project maintainers.
### BRANCH
Okay, so you have decided on the proper branch. Create a feature branch
and start hacking:
```
$ git checkout -b my-feature-branch -t origin/v0.10
```
(Where v0.10 is the latest stable branch as of this writing.)
### CODE
Please adhere to libuv's code style. In general it follows the conventions from
the [Google C/C++ style guide]. Some of the key points, as well as some
additional guidelines, are enumerated below.
* Code that is specific to unix-y platforms should be placed in `src/unix`, and
declarations go into `src/uv-unix.h`.
* Source code that is Windows-specific goes into `src/win`, and related
publicly exported types, functions and macro declarations should generally
be declared in `include/uv-win.h`.
* Names should be descriptive and concise.
* All the symbols and types that libuv makes available publicly should be
prefixed with `uv_` (or `UV_` in case of macros).
* Internal, non-static functions should be prefixed with `uv__`.
* Use two spaces and no tabs.
* Lines should be wrapped at 80 characters.
* Ensure that lines have no trailing whitespace, and use unix-style (LF) line
endings.
* Use C89-compliant syntax. In other words, variables can only be declared at
the top of a scope (function, if/for/while-block).
* When writing comments, use properly constructed sentences, including
punctuation.
* When documenting APIs and/or source code, don't make assumptions or make
implications about race, gender, religion, political orientation or anything
else that isn't relevant to the project.
* Remember that source code usually gets written once and read often: ensure
the reader doesn't have to make guesses. Make sure that the purpose and inner
logic are either obvious to a reasonably skilled professional, or add a
comment that explains it.
### COMMIT
Make sure git knows your name and email address:
```
$ git config --global user.name "J. Random User"
$ git config --global user.email "j.random.user@example.com"
```
Writing good commit logs is important. A commit log should describe what
changed and why. Follow these guidelines when writing one:
1. The first line should be 50 characters or less and contain a short
description of the change prefixed with the name of the changed
subsystem (e.g. "net: add localAddress and localPort to Socket").
2. Keep the second line blank.
3. Wrap all other lines at 72 columns.
A good commit log looks like this:
```
subsystem: explaining the commit in one line
Body of commit message is a few lines of text, explaining things
in more detail, possibly giving some background about the issue
being fixed, etc etc.
The body of the commit message can be several paragraphs, and
please do proper word-wrap and keep columns shorter than about
72 characters or so. That way `git log` will show things
nicely even when it is indented.
```
The header line should be meaningful; it is what other people see when they
run `git shortlog` or `git log --oneline`.
Check the output of `git log --oneline files_that_you_changed` to find out
what subsystem (or subsystems) your changes touch.
### REBASE
Use `git rebase` (not `git merge`) to sync your work from time to time.
```
$ git fetch upstream
$ git rebase upstream/v0.10 # or upstream/master
```
### TEST
Bug fixes and features should come with tests. Add your tests in the
`test/` directory. Tests also need to be registered in `test/test-list.h`.
Look at other tests to see how they should be structured (license boilerplate,
the way entry points are declared, etc.).
Check README.md file to find out how to run the test suite and make sure that
there are no test regressions.
### PUSH
```
$ git push origin my-feature-branch
```
Go to https://github.com/username/libuv and select your feature branch. Click
the 'Pull Request' button and fill out the form.
Pull requests are usually reviewed within a few days. If there are comments
to address, apply your changes in a separate commit and push that to your
feature branch. Post a comment in the pull request afterwards; GitHub does
not send out notifications when you add commits.
[issue tracker]: https://github.com/joyent/libuv/issues
[libuv mailing list]: http://groups.google.com/group/libuv
[IRC]: http://webchat.freelibuv.net/?channels=libuv
[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml

1380
outside/libuv_0.11/ChangeLog Normal file

File diff suppressed because it is too large Load Diff

View File

@ -31,11 +31,16 @@ The externally maintained libraries used by libuv are:
- tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license.
- ngx_queue.h (from Nginx), copyright Igor Sysoev. Two clause BSD license.
- inet_pton and inet_ntop implementations, contained in src/inet.c, are
copyright the Internet Systems Consortium, Inc., and licensed under the ISC
license.
- stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three
clause BSD license.
- pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile
Communications AB. Three clause BSD license.
- android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design
Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement
n° 289016). Three clause BSD license.

View File

@ -0,0 +1,336 @@
# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS = -I$(top_srcdir)/include \
-I$(top_srcdir)/src
include_HEADERS=include/uv.h include/uv-errno.h include/uv-threadpool.h include/uv-version.h
CLEANFILES =
lib_LTLIBRARIES = libuv.la
libuv_la_CFLAGS = @CFLAGS@
libuv_la_LDFLAGS = -no-undefined -version-info 11:0:0
libuv_la_SOURCES = src/fs-poll.c \
src/heap-inl.h \
src/inet.c \
src/queue.h \
src/threadpool.c \
src/uv-common.c \
src/uv-common.h \
src/version.c
if SUNOS
libuv_la_CFLAGS += -pthread
endif
if WINNT
include_HEADERS += include/uv-win.h include/tree.h
AM_CPPFLAGS += -I$(top_srcdir)/src/win \
-DWIN32_LEAN_AND_MEAN \
-D_WIN32_WINNT=0x0600
LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32
libuv_la_SOURCES += src/win/async.c \
src/win/atomicops-inl.h \
src/win/core.c \
src/win/dl.c \
src/win/error.c \
src/win/fs-event.c \
src/win/fs.c \
src/win/getaddrinfo.c \
src/win/getnameinfo.c \
src/win/handle.c \
src/win/handle-inl.h \
src/win/internal.h \
src/win/loop-watcher.c \
src/win/pipe.c \
src/win/poll.c \
src/win/process-stdio.c \
src/win/process.c \
src/win/req.c \
src/win/req-inl.h \
src/win/signal.c \
src/win/stream.c \
src/win/stream-inl.h \
src/win/tcp.c \
src/win/thread.c \
src/win/timer.c \
src/win/tty.c \
src/win/udp.c \
src/win/util.c \
src/win/winapi.c \
src/win/winapi.h \
src/win/winsock.c \
src/win/winsock.h
else # WINNT
include_HEADERS += include/uv-unix.h
AM_CPPFLAGS += -I$(top_srcdir)/src/unix
libuv_la_SOURCES += src/unix/async.c \
src/unix/atomic-ops.h \
src/unix/core.c \
src/unix/dl.c \
src/unix/fs.c \
src/unix/getaddrinfo.c \
src/unix/getnameinfo.c \
src/unix/internal.h \
src/unix/loop-watcher.c \
src/unix/loop.c \
src/unix/pipe.c \
src/unix/poll.c \
src/unix/process.c \
src/unix/signal.c \
src/unix/spinlock.h \
src/unix/stream.c \
src/unix/tcp.c \
src/unix/thread.c \
src/unix/timer.c \
src/unix/tty.c \
src/unix/udp.c
endif # WINNT
TESTS = test/run-tests
check_PROGRAMS = test/run-tests
test_run_tests_CFLAGS =
test_run_tests_SOURCES = test/blackhole-server.c \
test/dns-server.c \
test/echo-server.c \
test/run-tests.c \
test/runner.c \
test/runner.h \
test/task.h \
test/test-active.c \
test/test-async.c \
test/test-async-null-cb.c \
test/test-barrier.c \
test/test-callback-order.c \
test/test-callback-stack.c \
test/test-close-fd.c \
test/test-close-order.c \
test/test-condvar.c \
test/test-connection-fail.c \
test/test-cwd-and-chdir.c \
test/test-delayed-accept.c \
test/test-dlerror.c \
test/test-embed.c \
test/test-emfile.c \
test/test-error.c \
test/test-fail-always.c \
test/test-fs-event.c \
test/test-fs-poll.c \
test/test-fs.c \
test/test-get-currentexe.c \
test/test-get-loadavg.c \
test/test-get-memory.c \
test/test-getaddrinfo.c \
test/test-getnameinfo.c \
test/test-getsockname.c \
test/test-hrtime.c \
test/test-idle.c \
test/test-ip4-addr.c \
test/test-ip6-addr.c \
test/test-ipc-send-recv.c \
test/test-ipc.c \
test/test-list.h \
test/test-loop-handles.c \
test/test-loop-alive.c \
test/test-loop-close.c \
test/test-loop-stop.c \
test/test-loop-time.c \
test/test-multiple-listen.c \
test/test-mutexes.c \
test/test-osx-select.c \
test/test-pass-always.c \
test/test-ping-pong.c \
test/test-pipe-bind-error.c \
test/test-pipe-connect-error.c \
test/test-pipe-getsockname.c \
test/test-pipe-sendmsg.c \
test/test-pipe-server-close.c \
test/test-platform-output.c \
test/test-poll-close.c \
test/test-poll-closesocket.c \
test/test-poll.c \
test/test-process-title.c \
test/test-ref.c \
test/test-run-nowait.c \
test/test-run-once.c \
test/test-semaphore.c \
test/test-shutdown-close.c \
test/test-shutdown-eof.c \
test/test-shutdown-twice.c \
test/test-signal-multiple-loops.c \
test/test-signal.c \
test/test-socket-buffer-size.c \
test/test-spawn.c \
test/test-stdio-over-pipes.c \
test/test-tcp-bind-error.c \
test/test-tcp-bind6-error.c \
test/test-tcp-close-accept.c \
test/test-tcp-close-while-connecting.c \
test/test-tcp-close.c \
test/test-tcp-connect-error-after-write.c \
test/test-tcp-connect-error.c \
test/test-tcp-connect-timeout.c \
test/test-tcp-connect6-error.c \
test/test-tcp-flags.c \
test/test-tcp-open.c \
test/test-tcp-read-stop.c \
test/test-tcp-shutdown-after-write.c \
test/test-tcp-unexpected-read.c \
test/test-tcp-write-to-half-open-connection.c \
test/test-tcp-writealot.c \
test/test-tcp-try-write.c \
test/test-tcp-write-queue-order.c \
test/test-thread.c \
test/test-threadpool-cancel.c \
test/test-threadpool.c \
test/test-timer-again.c \
test/test-timer-from-check.c \
test/test-timer.c \
test/test-tty.c \
test/test-udp-bind.c \
test/test-udp-dgram-too-big.c \
test/test-udp-ipv6.c \
test/test-udp-multicast-interface.c \
test/test-udp-multicast-interface6.c \
test/test-udp-multicast-join.c \
test/test-udp-multicast-join6.c \
test/test-udp-multicast-ttl.c \
test/test-udp-open.c \
test/test-udp-options.c \
test/test-udp-send-and-recv.c \
test/test-udp-send-immediate.c \
test/test-udp-try-send.c \
test/test-walk-handles.c \
test/test-watcher-cross-stop.c
test_run_tests_LDADD = libuv.la
if WINNT
test_run_tests_SOURCES += test/runner-win.c \
test/runner-win.h
else
test_run_tests_SOURCES += test/runner-unix.c \
test/runner-unix.h
endif
if AIX
test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
endif
if SUNOS
test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
endif
if AIX
libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
libuv_la_SOURCES += src/unix/aix.c
endif
if ANDROID
include_HEADERS += include/android-ifaddrs.h \
include/pthread-fixes.h
libuv_la_SOURCES += src/unix/android-ifaddrs.c \
src/unix/pthread-fixes.c
endif
if DARWIN
include_HEADERS += include/uv-darwin.h
libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
libuv_la_SOURCES += src/unix/darwin.c \
src/unix/darwin-proctitle.c \
src/unix/fsevents.c \
src/unix/kqueue.c \
src/unix/proctitle.c
endif
if FREEBSD
include_HEADERS += include/uv-bsd.h
libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c
endif
if LINUX
include_HEADERS += include/uv-linux.h
libuv_la_SOURCES += src/unix/linux-core.c \
src/unix/linux-inotify.c \
src/unix/linux-syscalls.c \
src/unix/linux-syscalls.h \
src/unix/proctitle.c
endif
if NETBSD
include_HEADERS += include/uv-bsd.h
libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c
endif
if OPENBSD
include_HEADERS += include/uv-bsd.h
libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c
endif
if SUNOS
include_HEADERS += include/uv-sunos.h
libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
libuv_la_SOURCES += src/unix/sunos.c
endif
if HAVE_DTRACE
BUILT_SOURCES = include/uv-dtrace.h
CLEANFILES += include/uv-dtrace.h
if FREEBSD
libuv_la_LDFLAGS += -lelf
endif
endif
if DTRACE_NEEDS_OBJECTS
libuv_la_SOURCES += src/unix/uv-dtrace.d
libuv_la_DEPENDENCIES = src/unix/uv-dtrace.o
libuv_la_LIBADD = uv-dtrace.lo
CLEANFILES += src/unix/uv-dtrace.o src/unix/uv-dtrace.lo
endif
if HAVE_PKG_CONFIG
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = @PACKAGE_NAME@.pc
endif
if HAVE_DTRACE
include/uv-dtrace.h: src/unix/uv-dtrace.d
$(AM_V_GEN)$(DTRACE) $(DTRACEFLAGS) -h -xnolibs -s $< -o $(top_srcdir)/$@
endif
if DTRACE_NEEDS_OBJECTS
SUFFIXES = .d
src/unix/uv-dtrace.o: src/unix/uv-dtrace.d ${libuv_la_OBJECTS}
# It's ok to specify the output here, because we have 1 .d file, and we process
# every created .o, most projects don't need to include more than one .d
.d.o:
$(AM_V_GEN)$(DTRACE) $(DTRACEFLAGS) -G -o $(top_builddir)/uv-dtrace.o -s $< \
`find ${top_builddir}/src -name "*.o"`
$(AM_V_GEN)printf %s\\n \
'# ${top_builddir}/uv-dtrace.lo - a libtool object file' \
'# Generated by libtool (GNU libtool) 2.4' \
'# libtool wants a .lo not a .o' \
"pic_object='uv-dtrace.o'" \
"non_pic_object='uv-dtrace.o'" \
> ${top_builddir}/uv-dtrace.lo
endif

View File

@ -0,0 +1,84 @@
# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
CC ?= gcc
CFLAGS += -Wall \
-Wextra \
-Wno-unused-parameter \
-Iinclude \
-Isrc \
-Isrc/win \
-DWIN32_LEAN_AND_MEAN \
-D_WIN32_WINNT=0x0600
INCLUDES = include/stdint-msvc2008.h \
include/tree.h \
include/uv-errno.h \
include/uv-threadpool.h \
include/uv-version.h \
include/uv-win.h \
include/uv.h \
src/heap-inl.h \
src/queue.h \
src/uv-common.h \
src/win/atomicops-inl.h \
src/win/handle-inl.h \
src/win/internal.h \
src/win/req-inl.h \
src/win/stream-inl.h \
src/win/winapi.h \
src/win/winsock.h
OBJS = src/fs-poll.o \
src/inet.o \
src/threadpool.o \
src/uv-common.o \
src/version.o \
src/win/async.o \
src/win/core.o \
src/win/dl.o \
src/win/error.o \
src/win/fs-event.o \
src/win/fs.o \
src/win/getaddrinfo.o \
src/win/getnameinfo.o \
src/win/handle.o \
src/win/loop-watcher.o \
src/win/pipe.o \
src/win/poll.o \
src/win/process-stdio.o \
src/win/process.o \
src/win/req.o \
src/win/signal.o \
src/win/stream.o \
src/win/tcp.o \
src/win/thread.o \
src/win/timer.o \
src/win/tty.o \
src/win/udp.o \
src/win/util.o \
src/win/winapi.o \
src/win/winsock.o
all: libuv.a
clean:
-$(RM) $(OBJS) libuv.a
libuv.a: $(OBJS)
$(AR) crs $@ $^
$(OBJS): %.o : %.c $(INCLUDES)
$(CC) $(CFLAGS) -c -o $@ $<

View File

@ -0,0 +1,146 @@
![libuv][libuv_banner]
## Overview
libuv is a multi-platform support library with a focus on asynchronous I/O. It
was primarily developed for use by [Node.js](http://nodejs.org), but it's also
used by Mozilla's [Rust language](http://www.rust-lang.org/),
[Luvit](http://luvit.io/), [Julia](http://julialang.org/),
[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/joyent/libuv/wiki/Projects-that-use-libuv).
## Feature highlights
* Full-featured event loop backed by epoll, kqueue, IOCP, event ports.
* Asynchronous TCP and UDP sockets
* Asynchronous DNS resolution
* Asynchronous file and file system operations
* File system events
* ANSI escape code controlled TTY
* IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
* Child processes
* Thread pool
* Signal handling
* High resolution clock
* Threading and synchronization primitives
## Community
* [Mailing list](http://groups.google.com/group/libuv)
## Documentation
* [include/uv.h](https://github.com/joyent/libuv/blob/master/include/uv.h)
&mdash; API documentation in the form of detailed header comments.
* [An Introduction to libuv](http://nikhilm.github.com/uvbook/)
&mdash; An overview of libuv with tutorials.
* [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4)
&mdash; High-level introductory talk about libuv.
* [Tests and benchmarks](https://github.com/joyent/libuv/tree/master/test)
&mdash; API specification and usage examples.
* [libuv-dox](https://github.com/thlorenz/libuv-dox)
&mdash; Documenting types and methods of libuv, mostly by reading uv.h.
## Build Instructions
For GCC there are two methods building: via autotools or via [GYP][].
GYP is a meta-build system which can generate MSVS, Makefile, and XCode
backends. It is best used for integration into other projects.
To build with autotools:
$ sh autogen.sh
$ ./configure
$ make
$ make check
$ make install
### Windows
First, [Python][] 2.6 or 2.7 must be installed as it is required by [GYP][].
If python is not in your path set the environment variable `PYTHON` to its
location. For example: `set PYTHON=C:\Python27\python.exe`
To build with Visual Studio, launch a git shell (e.g. Cmd or PowerShell)
and run vcbuild.bat which will checkout the GYP code into build/gyp and
generate uv.sln as well as related project files.
To have GYP generate build script for another system, checkout GYP into the
project tree manually:
$ mkdir -p build
$ git clone https://git.chromium.org/external/gyp.git build/gyp
### Unix
Run:
$ ./gyp_uv.py -f make
$ make -C out
### OS X
Run:
$ ./gyp_uv.py -f xcode
$ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \
-configuration Release -target All
Note to OS X users:
Make sure that you specify the architecture you wish to build for in the
"ARCHS" flag. You can specify more than one by delimiting with a space
(e.g. "x86_64 i386").
### Android
Run:
$ source ./android-configure NDK_PATH gyp
$ make -C out
Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and
`-D_FILE_OFFSET_BITS=64`. GYP builds take care of that automatically.
### Running tests
Run:
$ ./gyp_uv.py -f make
$ make -C out
$ ./out/Debug/run-tests
## Supported Platforms
Microsoft Windows operating systems since Windows XP SP2. It can be built
with either Visual Studio or MinGW. Consider using
[Visual Studio Express 2010][] or later if you do not have a full Visual
Studio license.
Linux using the GCC toolchain.
OS X using the GCC or XCode toolchain.
Solaris 121 and later using GCC toolchain.
## Patches
See the [guidelines for contributing][].
[node.js]: http://nodejs.org/
[GYP]: http://code.google.com/p/gyp/
[Python]: https://www.python.org/downloads/
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
[guidelines for contributing]: https://github.com/joyent/libuv/blob/master/CONTRIBUTING.md
[libuv_banner]: https://raw.githubusercontent.com/joyent/libuv/master/img/banner.png

View File

@ -0,0 +1,20 @@
#!/bin/bash
export TOOLCHAIN=$PWD/android-toolchain
mkdir -p $TOOLCHAIN
$1/build/tools/make-standalone-toolchain.sh \
--toolchain=arm-linux-androideabi-4.8 \
--arch=arm \
--install-dir=$TOOLCHAIN \
--platform=android-9
export PATH=$TOOLCHAIN/bin:$PATH
export AR=arm-linux-androideabi-ar
export CC=arm-linux-androideabi-gcc
export CXX=arm-linux-androideabi-g++
export LINK=arm-linux-androideabi-g++
export PLATFORM=android
if [ $2 -a $2 == 'gyp' ]
then
./gyp_uv.py -Dtarget_arch=arm -DOS=android
fi

46
outside/libuv_0.11/autogen.sh Executable file
View File

@ -0,0 +1,46 @@
#!/bin/sh
# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
cd `dirname "$0"`
if [ "$LIBTOOLIZE" = "" ] && [ "`uname`" = "Darwin" ]; then
LIBTOOLIZE=glibtoolize
fi
ACLOCAL=${ACLOCAL:-aclocal}
AUTOCONF=${AUTOCONF:-autoconf}
AUTOMAKE=${AUTOMAKE:-automake}
LIBTOOLIZE=${LIBTOOLIZE:-libtoolize}
automake_version=`"$AUTOMAKE" --version | head -n 1 | sed 's/[^.0-9]//g'`
automake_version_major=`echo "$automake_version" | cut -d. -f1`
automake_version_minor=`echo "$automake_version" | cut -d. -f2`
UV_EXTRA_AUTOMAKE_FLAGS=
if test "$automake_version_major" -gt 1 || \
test "$automake_version_major" -eq 1 && \
test "$automake_version_minor" -gt 11; then
# serial-tests is available in v0.12 and newer.
UV_EXTRA_AUTOMAKE_FLAGS="$UV_EXTRA_AUTOMAKE_FLAGS serial-tests"
fi
echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \
> m4/libuv-extra-automake-flags.m4
set -ex
"$LIBTOOLIZE"
"$ACLOCAL" -I m4
"$AUTOCONF"
"$AUTOMAKE" --add-missing --copy

View File

@ -22,21 +22,19 @@ SPARSE_FLAGS=${SPARSE_FLAGS:-"
-Wno-do-while
-Wno-transparent-union
-Iinclude
-Iinclude/uv-private
-Isrc
"}
SOURCES="
include/uv-private/ngx-queue.h
include/uv-private/tree.h
include/uv-private/uv-unix.h
include/tree.h
include/uv-unix.h
include/uv.h
src/fs-poll.c
src/inet.c
src/queue.h
src/unix/async.c
src/unix/core.c
src/unix/dl.c
src/unix/error.c
src/unix/fs.c
src/unix/getaddrinfo.c
src/unix/internal.h
@ -107,6 +105,7 @@ test/test-getaddrinfo.c
test/test-getsockname.c
test/test-hrtime.c
test/test-idle.c
test/test-ip6-addr.c
test/test-ipc-send-recv.c
test/test-ipc.c
test/test-loop-handles.c
@ -116,6 +115,7 @@ test/test-pass-always.c
test/test-ping-pong.c
test/test-pipe-bind-error.c
test/test-pipe-connect-error.c
test/test-pipe-sendmsg.c
test/test-pipe-server-close.c
test/test-platform-output.c
test/test-poll-close.c
@ -161,7 +161,6 @@ test/test-udp-multicast-ttl.c
test/test-udp-open.c
test/test-udp-options.c
test/test-udp-send-and-recv.c
test/test-util.c
test/test-walk-handles.c
test/test-watcher-cross-stop.c
"
@ -175,7 +174,7 @@ AIX)
Darwin)
SPARSE_FLAGS="$SPARSE_FLAGS -D__APPLE__=1"
SOURCES="$SOURCES
include/uv-private/uv-bsd.h
include/uv-bsd.h
src/unix/darwin.c
src/unix/kqueue.c
src/unix/fsevents.c"
@ -183,21 +182,21 @@ Darwin)
DragonFly)
SPARSE_FLAGS="$SPARSE_FLAGS -D__DragonFly__=1"
SOURCES="$SOURCES
include/uv-private/uv-bsd.h
include/uv-bsd.h
src/unix/kqueue.c
src/unix/freebsd.c"
;;
FreeBSD)
SPARSE_FLAGS="$SPARSE_FLAGS -D__FreeBSD__=1"
SOURCES="$SOURCES
include/uv-private/uv-bsd.h
include/uv-bsd.h
src/unix/kqueue.c
src/unix/freebsd.c"
;;
Linux)
SPARSE_FLAGS="$SPARSE_FLAGS -D__linux__=1"
SOURCES="$SOURCES
include/uv-private/uv-linux.h
include/uv-linux.h
src/unix/linux-inotify.c
src/unix/linux-core.c
src/unix/linux-syscalls.c
@ -206,21 +205,21 @@ Linux)
NetBSD)
SPARSE_FLAGS="$SPARSE_FLAGS -D__NetBSD__=1"
SOURCES="$SOURCES
include/uv-private/uv-bsd.h
include/uv-bsd.h
src/unix/kqueue.c
src/unix/netbsd.c"
;;
OpenBSD)
SPARSE_FLAGS="$SPARSE_FLAGS -D__OpenBSD__=1"
SOURCES="$SOURCES
include/uv-private/uv-bsd.h
include/uv-bsd.h
src/unix/kqueue.c
src/unix/openbsd.c"
;;
SunOS)
SPARSE_FLAGS="$SPARSE_FLAGS -D__sun=1"
SOURCES="$SOURCES
include/uv-private/uv-sunos.h
include/uv-sunos.h
src/unix/sunos.c"
;;
esac

View File

@ -3,7 +3,7 @@
'visibility%': 'hidden', # V8's visibility setting
'target_arch%': 'ia32', # set v8's target architecture
'host_arch%': 'ia32', # set v8's host architecture
'library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds
'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds
'component%': 'static_library', # NB. these names match with what V8 expects
'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way
'gcc_version%': 'unknown',
@ -19,7 +19,7 @@
'msvs_settings': {
'VCCLCompilerTool': {
'target_conditions': [
['library=="static_library"', {
['uv_library=="static_library"', {
'RuntimeLibrary': 1, # static debug
}, {
'RuntimeLibrary': 3, # DLL debug
@ -56,7 +56,7 @@
'msvs_settings': {
'VCCLCompilerTool': {
'target_conditions': [
['library=="static_library"', {
['uv_library=="static_library"', {
'RuntimeLibrary': 0, # static release
}, {
'RuntimeLibrary': 2, # debug release
@ -130,7 +130,7 @@
}]
]
}],
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
['OS in "freebsd linux openbsd solaris android"', {
'cflags': [ '-Wall' ],
'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ],
'target_conditions': [
@ -149,7 +149,8 @@
[ 'OS=="solaris"', {
'cflags': [ '-pthreads' ],
'ldflags': [ '-pthreads' ],
}, {
}],
[ 'OS not in "solaris android"', {
'cflags': [ '-pthread' ],
'ldflags': [ '-pthread' ],
}],

View File

@ -0,0 +1,57 @@
# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57)
AC_INIT([libuv], [0.11.29], [https://github.com/joyent/libuv/issues])
AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4])
m4_include([m4/as_case.m4])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS)
AC_CANONICAL_HOST
AC_ENABLE_SHARED
AC_ENABLE_STATIC
AC_PROG_CC
AM_PROG_CC_C_O
# AM_PROG_AR is not available in automake v0.11 but it's essential in v0.12.
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
LT_INIT
# TODO(bnoordhuis) Check for -pthread vs. -pthreads
AC_CHECK_LIB([dl], [dlopen])
AC_CHECK_LIB([kstat], [kstat_lookup])
AC_CHECK_LIB([kvm], [kvm_open])
AC_CHECK_LIB([nsl], [gethostbyname])
AC_CHECK_LIB([perfstat], [perfstat_cpu])
AC_CHECK_LIB([pthread], [pthread_mutex_init])
AC_CHECK_LIB([rt], [clock_gettime])
AC_CHECK_LIB([sendfile], [sendfile])
AC_CHECK_LIB([socket], [socket])
AC_SYS_LARGEFILE
AM_CONDITIONAL([AIX], [AS_CASE([$host_os],[aix*], [true], [false])])
AM_CONDITIONAL([ANDROID],[AS_CASE([$host_os],[linux-android*],[true], [false])])
AM_CONDITIONAL([DARWIN], [AS_CASE([$host_os],[darwin*], [true], [false])])
AM_CONDITIONAL([FREEBSD],[AS_CASE([$host_os],[freebsd*], [true], [false])])
AM_CONDITIONAL([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])])
AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])])
AM_CONDITIONAL([OPENBSD],[AS_CASE([$host_os],[openbsd*], [true], [false])])
AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])])
AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])])
PANDORA_ENABLE_DTRACE
AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes)
AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"])
AS_IF([test "x$PKG_CONFIG" != "x"], [
AC_CONFIG_FILES([libuv.pc])
])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View File

@ -6,6 +6,13 @@ import os
import subprocess
import sys
try:
import multiprocessing.synchronize
gyp_parallel_support = True
except ImportError:
gyp_parallel_support = False
CC = os.environ.get('CC', 'cc')
script_dir = os.path.dirname(__file__)
uv_root = os.path.normpath(script_dir)
@ -88,12 +95,17 @@ if __name__ == '__main__':
if not any(a.startswith('-Dtarget_arch=') for a in args):
args.append('-Dtarget_arch=%s' % host_arch())
if not any(a.startswith('-Dlibrary=') for a in args):
args.append('-Dlibrary=static_library')
if not any(a.startswith('-Duv_library=') for a in args):
args.append('-Duv_library=static_library')
if not any(a.startswith('-Dcomponent=') for a in args):
args.append('-Dcomponent=static_library')
# Some platforms (OpenBSD for example) don't have multiprocessing.synchronize
# so gyp must be run with --no-parallel
if not gyp_parallel_support:
args.append('--no-parallel')
gyp_args = list(args)
print gyp_args
run_gyp(gyp_args)

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 1995, 1999
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
*/
#ifndef _IFADDRS_H_
#define _IFADDRS_H_
struct ifaddrs {
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
struct sockaddr *ifa_dstaddr;
void *ifa_data;
};
/*
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
* to be included it must be included before this header file.
*/
#ifndef ifa_broadaddr
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
#endif
#include <sys/cdefs.h>
__BEGIN_DECLS
extern int getifaddrs(struct ifaddrs **ifap);
extern void freeifaddrs(struct ifaddrs *ifa);
__END_DECLS
#endif

View File

@ -0,0 +1,72 @@
/* Copyright (c) 2013, Sony Mobile Communications AB
* Copyright (c) 2012, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H
#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H
#include <pthread.h>
/*Android doesn't provide pthread_barrier_t for now.*/
#ifndef PTHREAD_BARRIER_SERIAL_THREAD
/* Anything except 0 will do here.*/
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
unsigned count;
} pthread_barrier_t;
int pthread_barrier_init(pthread_barrier_t* barrier,
const void* barrier_attr,
unsigned count);
int pthread_barrier_wait(pthread_barrier_t* barrier);
int pthread_barrier_destroy(pthread_barrier_t *barrier);
#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */
int pthread_yield(void);
/* Workaround pthread_sigmask() returning EINVAL on versions < 4.1 by
* replacing all calls to pthread_sigmask with sigprocmask. See:
* https://android.googlesource.com/platform/bionic/+/9bf330b5
* https://code.google.com/p/android/issues/detail?id=15337
*/
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
#ifdef pthread_sigmask
#undef pthread_sigmask
#endif
#define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
#endif /* GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H */

View File

@ -0,0 +1,32 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_AIX_H
#define UV_AIX_H
#define UV_PLATFORM_LOOP_FIELDS \
int fs_fd; \
#define UV_PLATFORM_FS_EVENT_FIELDS \
uv__io_t event_watcher; \
char *dir_filename; \
#endif /* UV_AIX_H */

View File

@ -36,21 +36,21 @@
#define UV_PLATFORM_LOOP_FIELDS \
uv_thread_t cf_thread; \
void* cf_cb; \
void* cf_loop; \
void* _cf_reserved; \
void* cf_state; \
uv_mutex_t cf_mutex; \
uv_sem_t cf_sem; \
ngx_queue_t cf_signals; \
void* cf_signals[2]; \
#define UV_PLATFORM_FS_EVENT_FIELDS \
uv__io_t event_watcher; \
char* realpath; \
int realpath_len; \
int cf_flags; \
void* cf_eventstream; \
uv_async_t* cf_cb; \
ngx_queue_t cf_events; \
uv_sem_t cf_sem; \
void* cf_events[2]; \
void* cf_member[2]; \
int cf_error; \
uv_mutex_t cf_mutex; \
#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \

View File

@ -0,0 +1,402 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_ERRNO_H_
#define UV_ERRNO_H_
#include <errno.h>
#define UV__EOF (-4095)
#define UV__UNKNOWN (-4094)
#define UV__EAI_ADDRFAMILY (-3000)
#define UV__EAI_AGAIN (-3001)
#define UV__EAI_BADFLAGS (-3002)
#define UV__EAI_CANCELED (-3003)
#define UV__EAI_FAIL (-3004)
#define UV__EAI_FAMILY (-3005)
#define UV__EAI_MEMORY (-3006)
#define UV__EAI_NODATA (-3007)
#define UV__EAI_NONAME (-3008)
#define UV__EAI_OVERFLOW (-3009)
#define UV__EAI_SERVICE (-3010)
#define UV__EAI_SOCKTYPE (-3011)
#define UV__EAI_BADHINTS (-3013)
#define UV__EAI_PROTOCOL (-3014)
/* Only map to the system errno on non-Windows platforms. It's apparently
* a fairly common practice for Windows programmers to redefine errno codes.
*/
#if defined(E2BIG) && !defined(_WIN32)
# define UV__E2BIG (-E2BIG)
#else
# define UV__E2BIG (-4093)
#endif
#if defined(EACCES) && !defined(_WIN32)
# define UV__EACCES (-EACCES)
#else
# define UV__EACCES (-4092)
#endif
#if defined(EADDRINUSE) && !defined(_WIN32)
# define UV__EADDRINUSE (-EADDRINUSE)
#else
# define UV__EADDRINUSE (-4091)
#endif
#if defined(EADDRNOTAVAIL) && !defined(_WIN32)
# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL)
#else
# define UV__EADDRNOTAVAIL (-4090)
#endif
#if defined(EAFNOSUPPORT) && !defined(_WIN32)
# define UV__EAFNOSUPPORT (-EAFNOSUPPORT)
#else
# define UV__EAFNOSUPPORT (-4089)
#endif
#if defined(EAGAIN) && !defined(_WIN32)
# define UV__EAGAIN (-EAGAIN)
#else
# define UV__EAGAIN (-4088)
#endif
#if defined(EALREADY) && !defined(_WIN32)
# define UV__EALREADY (-EALREADY)
#else
# define UV__EALREADY (-4084)
#endif
#if defined(EBADF) && !defined(_WIN32)
# define UV__EBADF (-EBADF)
#else
# define UV__EBADF (-4083)
#endif
#if defined(EBUSY) && !defined(_WIN32)
# define UV__EBUSY (-EBUSY)
#else
# define UV__EBUSY (-4082)
#endif
#if defined(ECANCELED) && !defined(_WIN32)
# define UV__ECANCELED (-ECANCELED)
#else
# define UV__ECANCELED (-4081)
#endif
#if defined(ECHARSET) && !defined(_WIN32)
# define UV__ECHARSET (-ECHARSET)
#else
# define UV__ECHARSET (-4080)
#endif
#if defined(ECONNABORTED) && !defined(_WIN32)
# define UV__ECONNABORTED (-ECONNABORTED)
#else
# define UV__ECONNABORTED (-4079)
#endif
#if defined(ECONNREFUSED) && !defined(_WIN32)
# define UV__ECONNREFUSED (-ECONNREFUSED)
#else
# define UV__ECONNREFUSED (-4078)
#endif
#if defined(ECONNRESET) && !defined(_WIN32)
# define UV__ECONNRESET (-ECONNRESET)
#else
# define UV__ECONNRESET (-4077)
#endif
#if defined(EDESTADDRREQ) && !defined(_WIN32)
# define UV__EDESTADDRREQ (-EDESTADDRREQ)
#else
# define UV__EDESTADDRREQ (-4076)
#endif
#if defined(EEXIST) && !defined(_WIN32)
# define UV__EEXIST (-EEXIST)
#else
# define UV__EEXIST (-4075)
#endif
#if defined(EFAULT) && !defined(_WIN32)
# define UV__EFAULT (-EFAULT)
#else
# define UV__EFAULT (-4074)
#endif
#if defined(EHOSTUNREACH) && !defined(_WIN32)
# define UV__EHOSTUNREACH (-EHOSTUNREACH)
#else
# define UV__EHOSTUNREACH (-4073)
#endif
#if defined(EINTR) && !defined(_WIN32)
# define UV__EINTR (-EINTR)
#else
# define UV__EINTR (-4072)
#endif
#if defined(EINVAL) && !defined(_WIN32)
# define UV__EINVAL (-EINVAL)
#else
# define UV__EINVAL (-4071)
#endif
#if defined(EIO) && !defined(_WIN32)
# define UV__EIO (-EIO)
#else
# define UV__EIO (-4070)
#endif
#if defined(EISCONN) && !defined(_WIN32)
# define UV__EISCONN (-EISCONN)
#else
# define UV__EISCONN (-4069)
#endif
#if defined(EISDIR) && !defined(_WIN32)
# define UV__EISDIR (-EISDIR)
#else
# define UV__EISDIR (-4068)
#endif
#if defined(ELOOP) && !defined(_WIN32)
# define UV__ELOOP (-ELOOP)
#else
# define UV__ELOOP (-4067)
#endif
#if defined(EMFILE) && !defined(_WIN32)
# define UV__EMFILE (-EMFILE)
#else
# define UV__EMFILE (-4066)
#endif
#if defined(EMSGSIZE) && !defined(_WIN32)
# define UV__EMSGSIZE (-EMSGSIZE)
#else
# define UV__EMSGSIZE (-4065)
#endif
#if defined(ENAMETOOLONG) && !defined(_WIN32)
# define UV__ENAMETOOLONG (-ENAMETOOLONG)
#else
# define UV__ENAMETOOLONG (-4064)
#endif
#if defined(ENETDOWN) && !defined(_WIN32)
# define UV__ENETDOWN (-ENETDOWN)
#else
# define UV__ENETDOWN (-4063)
#endif
#if defined(ENETUNREACH) && !defined(_WIN32)
# define UV__ENETUNREACH (-ENETUNREACH)
#else
# define UV__ENETUNREACH (-4062)
#endif
#if defined(ENFILE) && !defined(_WIN32)
# define UV__ENFILE (-ENFILE)
#else
# define UV__ENFILE (-4061)
#endif
#if defined(ENOBUFS) && !defined(_WIN32)
# define UV__ENOBUFS (-ENOBUFS)
#else
# define UV__ENOBUFS (-4060)
#endif
#if defined(ENODEV) && !defined(_WIN32)
# define UV__ENODEV (-ENODEV)
#else
# define UV__ENODEV (-4059)
#endif
#if defined(ENOENT) && !defined(_WIN32)
# define UV__ENOENT (-ENOENT)
#else
# define UV__ENOENT (-4058)
#endif
#if defined(ENOMEM) && !defined(_WIN32)
# define UV__ENOMEM (-ENOMEM)
#else
# define UV__ENOMEM (-4057)
#endif
#if defined(ENONET) && !defined(_WIN32)
# define UV__ENONET (-ENONET)
#else
# define UV__ENONET (-4056)
#endif
#if defined(ENOSPC) && !defined(_WIN32)
# define UV__ENOSPC (-ENOSPC)
#else
# define UV__ENOSPC (-4055)
#endif
#if defined(ENOSYS) && !defined(_WIN32)
# define UV__ENOSYS (-ENOSYS)
#else
# define UV__ENOSYS (-4054)
#endif
#if defined(ENOTCONN) && !defined(_WIN32)
# define UV__ENOTCONN (-ENOTCONN)
#else
# define UV__ENOTCONN (-4053)
#endif
#if defined(ENOTDIR) && !defined(_WIN32)
# define UV__ENOTDIR (-ENOTDIR)
#else
# define UV__ENOTDIR (-4052)
#endif
#if defined(ENOTEMPTY) && !defined(_WIN32)
# define UV__ENOTEMPTY (-ENOTEMPTY)
#else
# define UV__ENOTEMPTY (-4051)
#endif
#if defined(ENOTSOCK) && !defined(_WIN32)
# define UV__ENOTSOCK (-ENOTSOCK)
#else
# define UV__ENOTSOCK (-4050)
#endif
#if defined(ENOTSUP) && !defined(_WIN32)
# define UV__ENOTSUP (-ENOTSUP)
#else
# define UV__ENOTSUP (-4049)
#endif
#if defined(EPERM) && !defined(_WIN32)
# define UV__EPERM (-EPERM)
#else
# define UV__EPERM (-4048)
#endif
#if defined(EPIPE) && !defined(_WIN32)
# define UV__EPIPE (-EPIPE)
#else
# define UV__EPIPE (-4047)
#endif
#if defined(EPROTO) && !defined(_WIN32)
# define UV__EPROTO (-EPROTO)
#else
# define UV__EPROTO (-4046)
#endif
#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT)
#else
# define UV__EPROTONOSUPPORT (-4045)
#endif
#if defined(EPROTOTYPE) && !defined(_WIN32)
# define UV__EPROTOTYPE (-EPROTOTYPE)
#else
# define UV__EPROTOTYPE (-4044)
#endif
#if defined(EROFS) && !defined(_WIN32)
# define UV__EROFS (-EROFS)
#else
# define UV__EROFS (-4043)
#endif
#if defined(ESHUTDOWN) && !defined(_WIN32)
# define UV__ESHUTDOWN (-ESHUTDOWN)
#else
# define UV__ESHUTDOWN (-4042)
#endif
#if defined(ESPIPE) && !defined(_WIN32)
# define UV__ESPIPE (-ESPIPE)
#else
# define UV__ESPIPE (-4041)
#endif
#if defined(ESRCH) && !defined(_WIN32)
# define UV__ESRCH (-ESRCH)
#else
# define UV__ESRCH (-4040)
#endif
#if defined(ETIMEDOUT) && !defined(_WIN32)
# define UV__ETIMEDOUT (-ETIMEDOUT)
#else
# define UV__ETIMEDOUT (-4039)
#endif
#if defined(ETXTBSY) && !defined(_WIN32)
# define UV__ETXTBSY (-ETXTBSY)
#else
# define UV__ETXTBSY (-4038)
#endif
#if defined(EXDEV) && !defined(_WIN32)
# define UV__EXDEV (-EXDEV)
#else
# define UV__EXDEV (-4037)
#endif
#if defined(EFBIG) && !defined(_WIN32)
# define UV__EFBIG (-EFBIG)
#else
# define UV__EFBIG (-4036)
#endif
#if defined(ENOPROTOOPT) && !defined(_WIN32)
# define UV__ENOPROTOOPT (-ENOPROTOOPT)
#else
# define UV__ENOPROTOOPT (-4035)
#endif
#if defined(ERANGE) && !defined(_WIN32)
# define UV__ERANGE (-ERANGE)
#else
# define UV__ERANGE (-4034)
#endif
#if defined(ENXIO) && !defined(_WIN32)
# define UV__ENXIO (-ENXIO)
#else
# define UV__ENXIO (-4033)
#endif
#if defined(EMLINK) && !defined(_WIN32)
# define UV__EMLINK (-EMLINK)
#else
# define UV__EMLINK (-4032)
#endif
#endif /* UV_ERRNO_H_ */

View File

@ -28,7 +28,7 @@
int inotify_fd; \
#define UV_PLATFORM_FS_EVENT_FIELDS \
ngx_queue_t watchers; \
void* watchers[2]; \
int wd; \
#endif /* UV_LINUX_H */

View File

@ -0,0 +1,37 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* This file is private to libuv. It provides common functionality to both
* Windows and Unix backends.
*/
#ifndef UV_THREADPOOL_H_
#define UV_THREADPOOL_H_
struct uv__work {
void (*work)(struct uv__work *w);
void (*done)(struct uv__work *w, int status);
struct uv_loop_s* loop;
void* wq[2];
};
#endif /* UV_THREADPOOL_H_ */

View File

@ -22,11 +22,10 @@
#ifndef UV_UNIX_H
#define UV_UNIX_H
#include "ngx-queue.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
@ -39,10 +38,17 @@
#include <semaphore.h>
#include <pthread.h>
#ifdef __ANDROID__
#include "pthread-fixes.h"
#endif
#include <signal.h>
#include "uv-threadpool.h"
#if defined(__linux__)
# include "uv-linux.h"
#elif defined(_AIX)
# include "uv-aix.h"
#elif defined(__sun)
# include "uv-sunos.h"
#elif defined(__APPLE__)
@ -54,13 +60,18 @@
# include "uv-bsd.h"
#endif
#ifndef NI_MAXHOST
# define NI_MAXHOST 1025
#endif
#ifndef NI_MAXSERV
# define NI_MAXSERV 32
#endif
#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS
# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */
#endif
#define UV_IO_PRIVATE_FIELDS \
UV_IO_PRIVATE_PLATFORM_FIELDS \
struct uv__io_s;
struct uv__async;
struct uv_loop_s;
@ -72,12 +83,12 @@ typedef struct uv__io_s uv__io_t;
struct uv__io_s {
uv__io_cb cb;
ngx_queue_t pending_queue;
ngx_queue_t watcher_queue;
void* pending_queue[2];
void* watcher_queue[2];
unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
unsigned int events; /* Current event mask. */
int fd;
UV_IO_PRIVATE_FIELDS
UV_IO_PRIVATE_PLATFORM_FIELDS
};
typedef void (*uv__async_cb)(struct uv_loop_s* loop,
@ -90,13 +101,6 @@ struct uv__async {
int wfd;
};
struct uv__work {
void (*work)(struct uv__work *w);
void (*done)(struct uv__work *w, int status);
struct uv_loop_s* loop;
ngx_queue_t wq;
};
#ifndef UV_PLATFORM_SEM_T
# define UV_PLATFORM_SEM_T sem_t
#endif
@ -114,14 +118,13 @@ struct uv__work {
#endif
/* Note: May be cast to struct iovec. See writev(2). */
typedef struct {
typedef struct uv_buf_t {
char* base;
size_t len;
} uv_buf_t;
typedef int uv_file;
typedef int uv_os_sock_t;
typedef struct stat uv_statbuf_t;
#define UV_ONCE_INIT PTHREAD_ONCE_INIT
@ -131,7 +134,7 @@ typedef pthread_mutex_t uv_mutex_t;
typedef pthread_rwlock_t uv_rwlock_t;
typedef UV_PLATFORM_SEM_T uv_sem_t;
typedef pthread_cond_t uv_cond_t;
typedef pthread_key_t uv_key_t;
#if defined(__APPLE__) && defined(__MACH__)
@ -153,6 +156,10 @@ typedef pthread_barrier_t uv_barrier_t;
typedef gid_t uv_gid_t;
typedef uid_t uv_uid_t;
typedef struct dirent uv__dirent_t;
#define UV__DT_DIR DT_DIR
/* Platform-specific definitions for uv_dlopen support. */
#define UV_DYNAMIC /* empty */
@ -164,31 +171,32 @@ typedef struct {
#define UV_LOOP_PRIVATE_FIELDS \
unsigned long flags; \
int backend_fd; \
ngx_queue_t pending_queue; \
ngx_queue_t watcher_queue; \
void* pending_queue[2]; \
void* watcher_queue[2]; \
uv__io_t** watchers; \
unsigned int nwatchers; \
unsigned int nfds; \
ngx_queue_t wq; \
void* wq[2]; \
uv_mutex_t wq_mutex; \
uv_async_t wq_async; \
uv_rwlock_t cloexec_lock; \
uv_handle_t* closing_handles; \
ngx_queue_t process_handles[1]; \
ngx_queue_t prepare_handles; \
ngx_queue_t check_handles; \
ngx_queue_t idle_handles; \
ngx_queue_t async_handles; \
void* process_handles[1][2]; \
void* prepare_handles[2]; \
void* check_handles[2]; \
void* idle_handles[2]; \
void* async_handles[2]; \
struct uv__async async_watcher; \
/* RB_HEAD(uv__timers, uv_timer_s) */ \
struct uv__timers { \
struct uv_timer_s* rbh_root; \
} timer_handles; \
struct { \
void* min; \
unsigned int nelts; \
} timer_heap; \
uint64_t timer_counter; \
uint64_t time; \
int signal_pipefd[2]; \
uv__io_t signal_io_watcher; \
uv_signal_t child_watcher; \
int emfile_fd; \
uint64_t timer_counter; \
UV_PLATFORM_LOOP_FIELDS \
#define UV_REQ_TYPE_PRIVATE /* empty */
@ -198,40 +206,41 @@ typedef struct {
#define UV_PRIVATE_REQ_TYPES /* empty */
#define UV_WRITE_PRIVATE_FIELDS \
ngx_queue_t queue; \
int write_index; \
void* queue[2]; \
unsigned int write_index; \
uv_buf_t* bufs; \
int bufcnt; \
unsigned int nbufs; \
int error; \
uv_buf_t bufsml[4]; \
#define UV_CONNECT_PRIVATE_FIELDS \
ngx_queue_t queue; \
void* queue[2]; \
#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
#define UV_UDP_SEND_PRIVATE_FIELDS \
ngx_queue_t queue; \
struct sockaddr_in6 addr; \
int bufcnt; \
void* queue[2]; \
struct sockaddr_storage addr; \
unsigned int nbufs; \
uv_buf_t* bufs; \
ssize_t status; \
uv_udp_send_cb send_cb; \
uv_buf_t bufsml[4]; \
#define UV_HANDLE_PRIVATE_FIELDS \
int flags; \
uv_handle_t* next_closing; \
unsigned int flags; \
#define UV_STREAM_PRIVATE_FIELDS \
uv_connect_t *connect_req; \
uv_shutdown_t *shutdown_req; \
uv__io_t io_watcher; \
ngx_queue_t write_queue; \
ngx_queue_t write_completed_queue; \
void* write_queue[2]; \
void* write_completed_queue[2]; \
uv_connection_cb connection_cb; \
int delayed_error; \
int accepted_fd; \
void* queued_fds; \
UV_STREAM_PRIVATE_PLATFORM_FIELDS \
#define UV_TCP_PRIVATE_FIELDS /* empty */
@ -240,8 +249,8 @@ typedef struct {
uv_alloc_cb alloc_cb; \
uv_udp_recv_cb recv_cb; \
uv__io_t io_watcher; \
ngx_queue_t write_queue; \
ngx_queue_t write_completed_queue; \
void* write_queue[2]; \
void* write_completed_queue[2]; \
#define UV_PIPE_PRIVATE_FIELDS \
const char* pipe_fname; /* strdup'ed */
@ -251,30 +260,24 @@ typedef struct {
#define UV_PREPARE_PRIVATE_FIELDS \
uv_prepare_cb prepare_cb; \
ngx_queue_t queue;
void* queue[2]; \
#define UV_CHECK_PRIVATE_FIELDS \
uv_check_cb check_cb; \
ngx_queue_t queue;
void* queue[2]; \
#define UV_IDLE_PRIVATE_FIELDS \
uv_idle_cb idle_cb; \
ngx_queue_t queue;
void* queue[2]; \
#define UV_ASYNC_PRIVATE_FIELDS \
uv_async_cb async_cb; \
ngx_queue_t queue; \
void* queue[2]; \
int pending; \
#define UV_TIMER_PRIVATE_FIELDS \
/* RB_ENTRY(uv_timer_s) tree_entry; */ \
struct { \
struct uv_timer_s* rbe_left; \
struct uv_timer_s* rbe_right; \
struct uv_timer_s* rbe_parent; \
int rbe_color; \
} tree_entry; \
uv_timer_cb timer_cb; \
void* heap_node[3]; \
uint64_t timeout; \
uint64_t repeat; \
uint64_t start_id;
@ -288,23 +291,33 @@ typedef struct {
struct addrinfo* res; \
int retcode;
#define UV_GETNAMEINFO_PRIVATE_FIELDS \
struct uv__work work_req; \
uv_getnameinfo_cb getnameinfo_cb; \
struct sockaddr_storage storage; \
int flags; \
char host[NI_MAXHOST]; \
char service[NI_MAXSERV]; \
int retcode;
#define UV_PROCESS_PRIVATE_FIELDS \
ngx_queue_t queue; \
int errorno; \
void* queue[2]; \
int status; \
#define UV_FS_PRIVATE_FIELDS \
const char *new_path; \
uv_file file; \
int flags; \
mode_t mode; \
void* buf; \
size_t len; \
unsigned int nbufs; \
uv_buf_t* bufs; \
off_t off; \
uv_uid_t uid; \
uv_gid_t gid; \
double atime; \
double mtime; \
struct uv__work work_req; \
uv_buf_t bufsml[4]; \
#define UV_WORK_PRIVATE_FIELDS \
struct uv__work work_req;

View File

@ -0,0 +1,38 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_VERSION_H
#define UV_VERSION_H
/*
* Versions with an even minor version (e.g. 0.6.1 or 1.0.4) are API and ABI
* stable. When the minor version is odd, the API can change between patch
* releases. Make sure you update the -soname directives in configure.ac
* and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
* not UV_VERSION_PATCH.)
*/
#define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 11
#define UV_VERSION_PATCH 29
#define UV_VERSION_IS_RELEASE 0
#endif /* UV_VERSION_H */

View File

@ -30,6 +30,29 @@ typedef intptr_t ssize_t;
#endif
#include <winsock2.h>
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
typedef struct pollfd {
SOCKET fd;
short events;
short revents;
} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
#endif
#ifndef LOCALE_INVARIANT
# define LOCALE_INVARIANT 0x007f
#endif
#ifndef _malloca
# if defined(_DEBUG)
# define _malloca(size) malloc(size)
# define _freea(ptr) free(ptr)
# else
# define _malloca(size) alloca(size)
# define _freea(ptr)
# endif
#endif
#include <mswsock.h>
#include <ws2tcpip.h>
#include <windows.h>
@ -39,13 +62,13 @@ typedef intptr_t ssize_t;
#include <sys/stat.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
# include "uv-private/stdint-msvc2008.h"
# include "stdint-msvc2008.h"
#else
# include <stdint.h>
#endif
#include "tree.h"
#include "ngx-queue.h"
#include "uv-threadpool.h"
#define MAX_PIPENAME_LEN 256
@ -207,8 +230,6 @@ typedef struct uv_buf_t {
typedef int uv_file;
typedef struct _stati64 uv_statbuf_t;
typedef SOCKET uv_os_sock_t;
typedef HANDLE uv_thread_t;
@ -253,6 +274,10 @@ typedef struct {
uv_sem_t turnstile2;
} uv_barrier_t;
typedef struct {
DWORD tls_index;
} uv_key_t;
#define UV_ONCE_INIT { 0, NULL }
typedef struct uv_once_s {
@ -264,6 +289,14 @@ typedef struct uv_once_s {
typedef unsigned char uv_uid_t;
typedef unsigned char uv_gid_t;
typedef struct uv__dirent_s {
int d_type;
char d_name[1];
} uv__dirent_t;
#define UV__DT_DIR UV_DIRENT_DIR
#define UV__DT_FILE UV_DIRENT_FILE
/* Platform-specific definitions for uv_dlopen support. */
#define UV_DYNAMIC FAR WINAPI
typedef struct {
@ -278,6 +311,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
HANDLE iocp; \
/* The current time according to the event loop. in msecs. */ \
uint64_t time; \
/* GetTickCount() result when the event loop time was last updated. */ \
DWORD last_tick_count; \
/* Tail of a single-linked circular queue of pending reqs. If the queue */ \
/* is empty, tail_ is NULL. If there is only one item, */ \
/* tail_->next_req == tail_ */ \
@ -304,7 +339,11 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
/* Counter to keep track of active udp streams */ \
unsigned int active_udp_streams; \
/* Counter to started timer */ \
uint64_t timer_counter;
uint64_t timer_counter; \
/* Threadpool */ \
void* wq[2]; \
uv_mutex_t wq_mutex; \
uv_async_t wq_async;
#define UV_REQ_TYPE_PRIVATE \
/* TODO: remove the req suffix */ \
@ -392,7 +431,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
#define UV_TCP_PRIVATE_FIELDS \
SOCKET socket; \
int bind_error; \
int delayed_error; \
union { \
struct { uv_tcp_server_fields }; \
struct { uv_tcp_connection_fields }; \
@ -421,12 +460,14 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
uv_write_t ipc_header_write_req; \
int ipc_pid; \
uint64_t remaining_ipc_rawdata_bytes; \
unsigned char reserved[sizeof(void*)]; \
struct { \
WSAPROTOCOL_INFOW* socket_info; \
int tcp_connection; \
void* queue[2]; \
int queue_len; \
} pending_ipc_info; \
uv_write_t* non_overlapped_writes_tail;
uv_write_t* non_overlapped_writes_tail; \
uv_mutex_t readfile_mutex; \
volatile HANDLE readfile_thread; \
void* reserved;
#define UV_PIPE_PRIVATE_FIELDS \
HANDLE handle; \
@ -517,6 +558,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
unsigned int flags;
#define UV_GETADDRINFO_PRIVATE_FIELDS \
struct uv__work work_req; \
uv_getaddrinfo_cb getaddrinfo_cb; \
void* alloc; \
WCHAR* node; \
@ -525,18 +567,27 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
struct addrinfoW* res; \
int retcode;
#define UV_GETNAMEINFO_PRIVATE_FIELDS \
struct uv__work work_req; \
uv_getnameinfo_cb getnameinfo_cb; \
struct sockaddr_storage storage; \
int flags; \
char host[NI_MAXHOST]; \
char service[NI_MAXSERV]; \
int retcode;
#define UV_PROCESS_PRIVATE_FIELDS \
struct uv_process_exit_s { \
UV_REQ_FIELDS \
} exit_req; \
BYTE* child_stdio_buffer; \
uv_err_t spawn_error; \
int exit_signal; \
HANDLE wait_handle; \
HANDLE process_handle; \
volatile char exit_cb_pending;
#define UV_FS_PRIVATE_FIELDS \
struct uv__work work_req; \
int flags; \
DWORD sys_errno_; \
union { \
@ -550,9 +601,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
WCHAR* new_pathw; \
int file_flags; \
int fd_out; \
void* buf; \
size_t length; \
unsigned int nbufs; \
uv_buf_t* bufs; \
int64_t offset; \
uv_buf_t bufsml[4]; \
}; \
struct { \
double atime; \
@ -561,6 +613,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
};
#define UV_WORK_PRIVATE_FIELDS \
struct uv__work work_req;
#define UV_FS_EVENT_PRIVATE_FIELDS \
struct uv_fs_event_req_s { \
@ -583,3 +636,4 @@ int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
char* utf8Buffer, size_t utf8Size);
int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
size_t utf16Size);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@prefix@
libdir=@libdir@
includedir=@includedir@
Name: @PACKAGE_NAME@
Version: @PACKAGE_VERSION@
Description: multi-platform support library with a focus on asynchronous I/O.
Libs: -L${libdir} -luv @LIBS@
Cflags: -I${includedir}

2
outside/libuv_0.11/m4/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Ignore libtoolize-generated files.
*.m4

View File

@ -1,4 +1,4 @@
# Copyright Joyent, Inc. and other Node contributors. All rights reserved.
# Copyright StrongLoop, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
@ -18,36 +18,5 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
SRCDIR ?= $(CURDIR)
ifeq (,$(builddir_name))
VPATH := $(SRCDIR)
include $(SRCDIR)/build.mk
else # Out of tree build.
# Drop all built-in rules.
.SUFFIXES:
.PHONY: $(builddir_name)
$(builddir_name): $(builddir_name)/.buildstamp
$(MAKE) -C $@ -f $(CURDIR)/Makefile $(MAKECMDGOALS) \
SRCDIR=$(CURDIR) builddir_name=
$(builddir_name)/.buildstamp:
mkdir -p $(dir $@)
touch $@
# Add no-op rules for Makefiles to stop make from trying to rebuild them.
Makefile:: ;
%.mk:: ;
# Turn everything else into a no-op rule that depends on the build directory.
%:: $(builddir_name) ;
.PHONY: clean distclean
clean distclean:
$(RM) -fr $(builddir_name)
endif
*.mk
*.Makefile

View File

@ -1,4 +1,4 @@
# Copyright Joyent, Inc. and other Node contributors. All rights reserved.
# Copyright StrongLoop, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
@ -18,31 +18,4 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
# Use make -f Makefile.gcc PREFIX=i686-w64-mingw32-
# for cross compilation
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
E=.exe
CFLAGS=$(CPPFLAGS) -g --std=gnu89 -D_WIN32_WINNT=0x0600
LDFLAGS=-lm
WIN_SRCS=$(wildcard $(SRCDIR)/src/win/*.c)
WIN_OBJS=$(WIN_SRCS:.c=.o)
RUNNER_CFLAGS=$(CFLAGS) -D_GNU_SOURCE # Need _GNU_SOURCE for strdup?
RUNNER_LDFLAGS=$(LDFLAGS)
RUNNER_LIBS=-lws2_32 -lpsapi -liphlpapi
RUNNER_SRC=test/runner-win.c
libuv.a: $(WIN_OBJS) src/fs-poll.o src/inet.o src/uv-common.o src/version.o
$(AR) rcs $@ $^
src/%.o: src/%.c include/uv.h include/uv-private/uv-win.h
$(CC) $(CFLAGS) -c $< -o $@
src/win/%.o: src/win/%.c include/uv.h include/uv-private/uv-win.h src/win/internal.h
$(CC) $(CFLAGS) -o $@ -c $<
clean-platform:
-rm -f src/win/*.o
/build/

View File

@ -0,0 +1,53 @@
Files: *
========
Copyright StrongLoop, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
Files: getopt.c
===============
Copyright (c) 1987, 1993, 1994
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

View File

@ -0,0 +1,46 @@
# Copyright StrongLoop, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
{
'targets': [
{
'dependencies': ['../../uv.gyp:libuv'],
'target_name': 's5-proxy',
'type': 'executable',
'sources': [
'client.c',
'defs.h',
'main.c',
's5.c',
's5.h',
'server.c',
'util.c',
],
'conditions': [
['OS=="win"', {
'defines': ['HAVE_UNISTD_H=0'],
'sources': ['getopt.c']
}, {
'defines': ['HAVE_UNISTD_H=1']
}]
]
}
]
}

View File

@ -0,0 +1,737 @@
/* Copyright StrongLoop, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "defs.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
/* A connection is modeled as an abstraction on top of two simple state
* machines, one for reading and one for writing. Either state machine
* is, when active, in one of three states: busy, done or stop; the fourth
* and final state, dead, is an end state and only relevant when shutting
* down the connection. A short overview:
*
* busy done stop
* ----------|---------------------------|--------------------|------|
* readable | waiting for incoming data | have incoming data | idle |
* writable | busy writing out data | completed write | idle |
*
* We could remove the done state from the writable state machine. For our
* purposes, it's functionally equivalent to the stop state.
*
* When the connection with upstream has been established, the client_ctx
* moves into a state where incoming data from the client is sent upstream
* and vice versa, incoming data from upstream is sent to the client. In
* other words, we're just piping data back and forth. See conn_cycle()
* for details.
*
* An interesting deviation from libuv's I/O model is that reads are discrete
* rather than continuous events. In layman's terms, when a read operation
* completes, the connection stops reading until further notice.
*
* The rationale for this approach is that we have to wait until the data
* has been sent out again before we can reuse the read buffer.
*
* It also pleasingly unifies with the request model that libuv uses for
* writes and everything else; libuv may switch to a request model for
* reads in the future.
*/
enum conn_state {
c_busy, /* Busy; waiting for incoming data or for a write to complete. */
c_done, /* Done; read incoming data or write finished. */
c_stop, /* Stopped. */
c_dead
};
/* Session states. */
enum sess_state {
s_handshake, /* Wait for client handshake. */
s_handshake_auth, /* Wait for client authentication data. */
s_req_start, /* Start waiting for request data. */
s_req_parse, /* Wait for request data. */
s_req_lookup, /* Wait for upstream hostname DNS lookup to complete. */
s_req_connect, /* Wait for uv_tcp_connect() to complete. */
s_proxy_start, /* Connected. Start piping data. */
s_proxy, /* Connected. Pipe data back and forth. */
s_kill, /* Tear down session. */
s_almost_dead_0, /* Waiting for finalizers to complete. */
s_almost_dead_1, /* Waiting for finalizers to complete. */
s_almost_dead_2, /* Waiting for finalizers to complete. */
s_almost_dead_3, /* Waiting for finalizers to complete. */
s_almost_dead_4, /* Waiting for finalizers to complete. */
s_dead /* Dead. Safe to free now. */
};
static void do_next(client_ctx *cx);
static int do_handshake(client_ctx *cx);
static int do_handshake_auth(client_ctx *cx);
static int do_req_start(client_ctx *cx);
static int do_req_parse(client_ctx *cx);
static int do_req_lookup(client_ctx *cx);
static int do_req_connect_start(client_ctx *cx);
static int do_req_connect(client_ctx *cx);
static int do_proxy_start(client_ctx *cx);
static int do_proxy(client_ctx *cx);
static int do_kill(client_ctx *cx);
static int do_almost_dead(client_ctx *cx);
static int conn_cycle(const char *who, conn *a, conn *b);
static void conn_timer_reset(conn *c);
static void conn_timer_expire(uv_timer_t *handle, int status);
static void conn_getaddrinfo(conn *c, const char *hostname);
static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
int status,
struct addrinfo *ai);
static int conn_connect(conn *c);
static void conn_connect_done(uv_connect_t *req, int status);
static void conn_read(conn *c);
static void conn_read_done(uv_stream_t *handle,
ssize_t nread,
const uv_buf_t *buf);
static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf);
static void conn_write(conn *c, const void *data, unsigned int len);
static void conn_write_done(uv_write_t *req, int status);
static void conn_close(conn *c);
static void conn_close_done(uv_handle_t *handle);
/* |incoming| has been initialized by server.c when this is called. */
void client_finish_init(server_ctx *sx, client_ctx *cx) {
conn *incoming;
conn *outgoing;
cx->sx = sx;
cx->state = s_handshake;
s5_init(&cx->parser);
incoming = &cx->incoming;
incoming->client = cx;
incoming->result = 0;
incoming->rdstate = c_stop;
incoming->wrstate = c_stop;
incoming->idle_timeout = sx->idle_timeout;
CHECK(0 == uv_timer_init(sx->loop, &incoming->timer_handle));
outgoing = &cx->outgoing;
outgoing->client = cx;
outgoing->result = 0;
outgoing->rdstate = c_stop;
outgoing->wrstate = c_stop;
outgoing->idle_timeout = sx->idle_timeout;
CHECK(0 == uv_tcp_init(cx->sx->loop, &outgoing->handle.tcp));
CHECK(0 == uv_timer_init(cx->sx->loop, &outgoing->timer_handle));
/* Wait for the initial packet. */
conn_read(incoming);
}
/* This is the core state machine that drives the client <-> upstream proxy.
* We move through the initial handshake and authentication steps first and
* end up (if all goes well) in the proxy state where we're just proxying
* data between the client and upstream.
*/
static void do_next(client_ctx *cx) {
int new_state;
ASSERT(cx->state != s_dead);
switch (cx->state) {
case s_handshake:
new_state = do_handshake(cx);
break;
case s_handshake_auth:
new_state = do_handshake_auth(cx);
break;
case s_req_start:
new_state = do_req_start(cx);
break;
case s_req_parse:
new_state = do_req_parse(cx);
break;
case s_req_lookup:
new_state = do_req_lookup(cx);
break;
case s_req_connect:
new_state = do_req_connect(cx);
break;
case s_proxy_start:
new_state = do_proxy_start(cx);
break;
case s_proxy:
new_state = do_proxy(cx);
break;
case s_kill:
new_state = do_kill(cx);
break;
case s_almost_dead_0:
case s_almost_dead_1:
case s_almost_dead_2:
case s_almost_dead_3:
case s_almost_dead_4:
new_state = do_almost_dead(cx);
break;
default:
UNREACHABLE();
}
cx->state = new_state;
if (cx->state == s_dead) {
if (DEBUG_CHECKS) {
memset(cx, -1, sizeof(*cx));
}
free(cx);
}
}
static int do_handshake(client_ctx *cx) {
unsigned int methods;
conn *incoming;
s5_ctx *parser;
uint8_t *data;
size_t size;
int err;
parser = &cx->parser;
incoming = &cx->incoming;
ASSERT(incoming->rdstate == c_done);
ASSERT(incoming->wrstate == c_stop);
incoming->rdstate = c_stop;
if (incoming->result < 0) {
pr_err("read error: %s", uv_strerror(incoming->result));
return do_kill(cx);
}
data = (uint8_t *) incoming->t.buf;
size = (size_t) incoming->result;
err = s5_parse(parser, &data, &size);
if (err == s5_ok) {
conn_read(incoming);
return s_handshake; /* Need more data. */
}
if (size != 0) {
/* Could allow a round-trip saving shortcut here if the requested auth
* method is S5_AUTH_NONE (provided unauthenticated traffic is allowed.)
* Requires client support however.
*/
pr_err("junk in handshake");
return do_kill(cx);
}
if (err != s5_auth_select) {
pr_err("handshake error: %s", s5_strerror(err));
return do_kill(cx);
}
methods = s5_auth_methods(parser);
if ((methods & S5_AUTH_NONE) && can_auth_none(cx->sx, cx)) {
s5_select_auth(parser, S5_AUTH_NONE);
conn_write(incoming, "\5\0", 2); /* No auth required. */
return s_req_start;
}
if ((methods & S5_AUTH_PASSWD) && can_auth_passwd(cx->sx, cx)) {
/* TODO(bnoordhuis) Implement username/password auth. */
}
conn_write(incoming, "\5\377", 2); /* No acceptable auth. */
return s_kill;
}
/* TODO(bnoordhuis) Implement username/password auth. */
static int do_handshake_auth(client_ctx *cx) {
UNREACHABLE();
return do_kill(cx);
}
static int do_req_start(client_ctx *cx) {
conn *incoming;
incoming = &cx->incoming;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_done);
incoming->wrstate = c_stop;
if (incoming->result < 0) {
pr_err("write error: %s", uv_strerror(incoming->result));
return do_kill(cx);
}
conn_read(incoming);
return s_req_parse;
}
static int do_req_parse(client_ctx *cx) {
conn *incoming;
conn *outgoing;
s5_ctx *parser;
uint8_t *data;
size_t size;
int err;
parser = &cx->parser;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_done);
ASSERT(incoming->wrstate == c_stop);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
incoming->rdstate = c_stop;
if (incoming->result < 0) {
pr_err("read error: %s", uv_strerror(incoming->result));
return do_kill(cx);
}
data = (uint8_t *) incoming->t.buf;
size = (size_t) incoming->result;
err = s5_parse(parser, &data, &size);
if (err == s5_ok) {
conn_read(incoming);
return s_req_parse; /* Need more data. */
}
if (size != 0) {
pr_err("junk in request %u", (unsigned) size);
return do_kill(cx);
}
if (err != s5_exec_cmd) {
pr_err("request error: %s", s5_strerror(err));
return do_kill(cx);
}
if (parser->cmd == s5_cmd_tcp_bind) {
/* Not supported but relatively straightforward to implement. */
pr_warn("BIND requests are not supported.");
return do_kill(cx);
}
if (parser->cmd == s5_cmd_udp_assoc) {
/* Not supported. Might be hard to implement because libuv has no
* functionality for detecting the MTU size which the RFC mandates.
*/
pr_warn("UDP ASSOC requests are not supported.");
return do_kill(cx);
}
ASSERT(parser->cmd == s5_cmd_tcp_connect);
if (parser->atyp == s5_atyp_host) {
conn_getaddrinfo(outgoing, (const char *) parser->daddr);
return s_req_lookup;
}
if (parser->atyp == s5_atyp_ipv4) {
memset(&outgoing->t.addr4, 0, sizeof(outgoing->t.addr4));
outgoing->t.addr4.sin_family = AF_INET;
outgoing->t.addr4.sin_port = htons(parser->dport);
memcpy(&outgoing->t.addr4.sin_addr,
parser->daddr,
sizeof(outgoing->t.addr4.sin_addr));
} else if (parser->atyp == s5_atyp_ipv6) {
memset(&outgoing->t.addr6, 0, sizeof(outgoing->t.addr6));
outgoing->t.addr6.sin6_family = AF_INET6;
outgoing->t.addr6.sin6_port = htons(parser->dport);
memcpy(&outgoing->t.addr6.sin6_addr,
parser->daddr,
sizeof(outgoing->t.addr6.sin6_addr));
} else {
UNREACHABLE();
}
return do_req_connect_start(cx);
}
static int do_req_lookup(client_ctx *cx) {
s5_ctx *parser;
conn *incoming;
conn *outgoing;
parser = &cx->parser;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_stop);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
if (outgoing->result < 0) {
/* TODO(bnoordhuis) Escape control characters in parser->daddr. */
pr_err("lookup error for \"%s\": %s",
parser->daddr,
uv_strerror(outgoing->result));
/* Send back a 'Host unreachable' reply. */
conn_write(incoming, "\5\4\0\1\0\0\0\0\0\0", 10);
return s_kill;
}
/* Don't make assumptions about the offset of sin_port/sin6_port. */
switch (outgoing->t.addr.sa_family) {
case AF_INET:
outgoing->t.addr4.sin_port = htons(parser->dport);
break;
case AF_INET6:
outgoing->t.addr6.sin6_port = htons(parser->dport);
break;
default:
UNREACHABLE();
}
return do_req_connect_start(cx);
}
/* Assumes that cx->outgoing.t.sa contains a valid AF_INET/AF_INET6 address. */
static int do_req_connect_start(client_ctx *cx) {
conn *incoming;
conn *outgoing;
int err;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_stop);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
if (!can_access(cx->sx, cx, &outgoing->t.addr)) {
pr_warn("connection not allowed by ruleset");
/* Send a 'Connection not allowed by ruleset' reply. */
conn_write(incoming, "\5\2\0\1\0\0\0\0\0\0", 10);
return s_kill;
}
err = conn_connect(outgoing);
if (err != 0) {
pr_err("connect error: %s\n", uv_strerror(err));
return do_kill(cx);
}
return s_req_connect;
}
static int do_req_connect(client_ctx *cx) {
const struct sockaddr_in6 *in6;
const struct sockaddr_in *in;
char addr_storage[sizeof(*in6)];
conn *incoming;
conn *outgoing;
uint8_t *buf;
int addrlen;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_stop);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
/* Build and send the reply. Not very pretty but gets the job done. */
buf = (uint8_t *) incoming->t.buf;
if (outgoing->result == 0) {
/* The RFC mandates that the SOCKS server must include the local port
* and address in the reply. So that's what we do.
*/
addrlen = sizeof(addr_storage);
CHECK(0 == uv_tcp_getsockname(&outgoing->handle.tcp,
(struct sockaddr *) addr_storage,
&addrlen));
buf[0] = 5; /* Version. */
buf[1] = 0; /* Success. */
buf[2] = 0; /* Reserved. */
if (addrlen == sizeof(*in)) {
buf[3] = 1; /* IPv4. */
in = (const struct sockaddr_in *) &addr_storage;
memcpy(buf + 4, &in->sin_addr, 4);
memcpy(buf + 8, &in->sin_port, 2);
conn_write(incoming, buf, 10);
} else if (addrlen == sizeof(*in6)) {
buf[3] = 4; /* IPv6. */
in6 = (const struct sockaddr_in6 *) &addr_storage;
memcpy(buf + 4, &in6->sin6_addr, 16);
memcpy(buf + 20, &in6->sin6_port, 2);
conn_write(incoming, buf, 22);
} else {
UNREACHABLE();
}
return s_proxy_start;
} else {
pr_err("upstream connection error: %s\n", uv_strerror(outgoing->result));
/* Send a 'Connection refused' reply. */
conn_write(incoming, "\5\5\0\1\0\0\0\0\0\0", 10);
return s_kill;
}
UNREACHABLE();
return s_kill;
}
static int do_proxy_start(client_ctx *cx) {
conn *incoming;
conn *outgoing;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_done);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
incoming->wrstate = c_stop;
if (incoming->result < 0) {
pr_err("write error: %s", uv_strerror(incoming->result));
return do_kill(cx);
}
conn_read(incoming);
conn_read(outgoing);
return s_proxy;
}
/* Proxy incoming data back and forth. */
static int do_proxy(client_ctx *cx) {
if (conn_cycle("client", &cx->incoming, &cx->outgoing)) {
return do_kill(cx);
}
if (conn_cycle("upstream", &cx->outgoing, &cx->incoming)) {
return do_kill(cx);
}
return s_proxy;
}
static int do_kill(client_ctx *cx) {
int new_state;
if (cx->state >= s_almost_dead_0) {
return cx->state;
}
/* Try to cancel the request. The callback still runs but if the
* cancellation succeeded, it gets called with status=UV_ECANCELED.
*/
new_state = s_almost_dead_1;
if (cx->state == s_req_lookup) {
new_state = s_almost_dead_0;
uv_cancel(&cx->outgoing.t.req);
}
conn_close(&cx->incoming);
conn_close(&cx->outgoing);
return new_state;
}
static int do_almost_dead(client_ctx *cx) {
ASSERT(cx->state >= s_almost_dead_0);
return cx->state + 1; /* Another finalizer completed. */
}
static int conn_cycle(const char *who, conn *a, conn *b) {
if (a->result < 0) {
if (a->result != UV_EOF) {
pr_err("%s error: %s", who, uv_strerror(a->result));
}
return -1;
}
if (b->result < 0) {
return -1;
}
if (a->wrstate == c_done) {
a->wrstate = c_stop;
}
/* The logic is as follows: read when we don't write and write when we don't
* read. That gives us back-pressure handling for free because if the peer
* sends data faster than we consume it, TCP congestion control kicks in.
*/
if (a->wrstate == c_stop) {
if (b->rdstate == c_stop) {
conn_read(b);
} else if (b->rdstate == c_done) {
conn_write(a, b->t.buf, b->result);
b->rdstate = c_stop; /* Triggers the call to conn_read() above. */
}
}
return 0;
}
static void conn_timer_reset(conn *c) {
CHECK(0 == uv_timer_start(&c->timer_handle,
conn_timer_expire,
c->idle_timeout,
0));
}
static void conn_timer_expire(uv_timer_t *handle, int status) {
conn *c;
CHECK(0 == status);
c = CONTAINER_OF(handle, conn, timer_handle);
c->result = UV_ETIMEDOUT;
do_next(c->client);
}
static void conn_getaddrinfo(conn *c, const char *hostname) {
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
CHECK(0 == uv_getaddrinfo(c->client->sx->loop,
&c->t.addrinfo_req,
conn_getaddrinfo_done,
hostname,
NULL,
&hints));
conn_timer_reset(c);
}
static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
int status,
struct addrinfo *ai) {
conn *c;
c = CONTAINER_OF(req, conn, t.addrinfo_req);
c->result = status;
if (status == 0) {
/* FIXME(bnoordhuis) Should try all addresses. */
if (ai->ai_family == AF_INET) {
c->t.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
} else if (ai->ai_family == AF_INET6) {
c->t.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
} else {
UNREACHABLE();
}
}
uv_freeaddrinfo(ai);
do_next(c->client);
}
/* Assumes that c->t.sa contains a valid AF_INET or AF_INET6 address. */
static int conn_connect(conn *c) {
ASSERT(c->t.addr.sa_family == AF_INET ||
c->t.addr.sa_family == AF_INET6);
conn_timer_reset(c);
return uv_tcp_connect(&c->t.connect_req,
&c->handle.tcp,
&c->t.addr,
conn_connect_done);
}
static void conn_connect_done(uv_connect_t *req, int status) {
conn *c;
if (status == UV_ECANCELED) {
return; /* Handle has been closed. */
}
c = CONTAINER_OF(req, conn, t.connect_req);
c->result = status;
do_next(c->client);
}
static void conn_read(conn *c) {
ASSERT(c->rdstate == c_stop);
CHECK(0 == uv_read_start(&c->handle.stream, conn_alloc, conn_read_done));
c->rdstate = c_busy;
conn_timer_reset(c);
}
static void conn_read_done(uv_stream_t *handle,
ssize_t nread,
const uv_buf_t *buf) {
conn *c;
c = CONTAINER_OF(handle, conn, handle);
ASSERT(c->t.buf == buf->base);
ASSERT(c->rdstate == c_busy);
c->rdstate = c_done;
c->result = nread;
uv_read_stop(&c->handle.stream);
do_next(c->client);
}
static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
conn *c;
c = CONTAINER_OF(handle, conn, handle);
ASSERT(c->rdstate == c_busy);
buf->base = c->t.buf;
buf->len = sizeof(c->t.buf);
}
static void conn_write(conn *c, const void *data, unsigned int len) {
uv_buf_t buf;
ASSERT(c->wrstate == c_stop || c->wrstate == c_done);
c->wrstate = c_busy;
/* It's okay to cast away constness here, uv_write() won't modify the
* memory.
*/
buf.base = (char *) data;
buf.len = len;
CHECK(0 == uv_write(&c->write_req,
&c->handle.stream,
&buf,
1,
conn_write_done));
conn_timer_reset(c);
}
static void conn_write_done(uv_write_t *req, int status) {
conn *c;
if (status == UV_ECANCELED) {
return; /* Handle has been closed. */
}
c = CONTAINER_OF(req, conn, write_req);
ASSERT(c->wrstate == c_busy);
c->wrstate = c_done;
c->result = status;
do_next(c->client);
}
static void conn_close(conn *c) {
ASSERT(c->rdstate != c_dead);
ASSERT(c->wrstate != c_dead);
c->rdstate = c_dead;
c->wrstate = c_dead;
c->timer_handle.data = c;
c->handle.handle.data = c;
uv_close(&c->handle.handle, conn_close_done);
uv_close((uv_handle_t *) &c->timer_handle, conn_close_done);
}
static void conn_close_done(uv_handle_t *handle) {
conn *c;
c = handle->data;
do_next(c->client);
}

View File

@ -0,0 +1,139 @@
/* Copyright StrongLoop, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DEFS_H_
#define DEFS_H_
#include "s5.h"
#include "uv.h"
#include <assert.h>
#include <netinet/in.h> /* sockaddr_in, sockaddr_in6 */
#include <stddef.h> /* size_t, ssize_t */
#include <stdint.h>
#include <sys/socket.h> /* sockaddr */
struct client_ctx;
typedef struct {
const char *bind_host;
unsigned short bind_port;
unsigned int idle_timeout;
} server_config;
typedef struct {
unsigned int idle_timeout; /* Connection idle timeout in ms. */
uv_tcp_t tcp_handle;
uv_loop_t *loop;
} server_ctx;
typedef struct {
unsigned char rdstate;
unsigned char wrstate;
unsigned int idle_timeout;
struct client_ctx *client; /* Backlink to owning client context. */
ssize_t result;
union {
uv_handle_t handle;
uv_stream_t stream;
uv_tcp_t tcp;
uv_udp_t udp;
} handle;
uv_timer_t timer_handle; /* For detecting timeouts. */
uv_write_t write_req;
/* We only need one of these at a time so make them share memory. */
union {
uv_getaddrinfo_t addrinfo_req;
uv_connect_t connect_req;
uv_req_t req;
struct sockaddr_in6 addr6;
struct sockaddr_in addr4;
struct sockaddr addr;
char buf[2048]; /* Scratch space. Used to read data into. */
} t;
} conn;
typedef struct client_ctx {
unsigned int state;
server_ctx *sx; /* Backlink to owning server context. */
s5_ctx parser; /* The SOCKS protocol parser. */
conn incoming; /* Connection with the SOCKS client. */
conn outgoing; /* Connection with upstream. */
} client_ctx;
/* server.c */
int server_run(const server_config *cf, uv_loop_t *loop);
int can_auth_none(const server_ctx *sx, const client_ctx *cx);
int can_auth_passwd(const server_ctx *sx, const client_ctx *cx);
int can_access(const server_ctx *sx,
const client_ctx *cx,
const struct sockaddr *addr);
/* client.c */
void client_finish_init(server_ctx *sx, client_ctx *cx);
/* util.c */
#if defined(__GNUC__)
# define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__((format(printf, a, b)))
#else
# define ATTRIBUTE_FORMAT_PRINTF(a, b)
#endif
void pr_info(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
void pr_warn(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
void pr_err(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
void *xmalloc(size_t size);
/* main.c */
const char *_getprogname(void);
/* getopt.c */
#if !HAVE_UNISTD_H
extern char *optarg;
int getopt(int argc, char **argv, const char *options);
#endif
/* ASSERT() is for debug checks, CHECK() for run-time sanity checks.
* DEBUG_CHECKS is for expensive debug checks that we only want to
* enable in debug builds but still want type-checked by the compiler
* in release builds.
*/
#if defined(NDEBUG)
# define ASSERT(exp)
# define CHECK(exp) do { if (!(exp)) abort(); } while (0)
# define DEBUG_CHECKS (0)
#else
# define ASSERT(exp) assert(exp)
# define CHECK(exp) assert(exp)
# define DEBUG_CHECKS (1)
#endif
#define UNREACHABLE() CHECK(!"Unreachable code reached.")
/* This macro looks complicated but it's not: it calculates the address
* of the embedding struct through the address of the embedded struct.
* In other words, if struct A embeds struct B, then we can obtain
* the address of A by taking the address of B and subtracting the
* field offset of B in A.
*/
#define CONTAINER_OF(ptr, type, field) \
((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
#endif /* DEFS_H_ */

View File

@ -0,0 +1,131 @@
/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
#endif /* LIBC_SCCS and not lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern const char *_getprogname(void);
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(nargc, nargv, ostr)
int nargc;
char * const nargv[];
const char *ostr;
{
static char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (optreset || *place == 0) { /* update scanning pointer */
optreset = 0;
place = nargv[optind];
if (optind >= nargc || *place++ != '-') {
/* Argument is absent or is not an option */
place = EMSG;
return (-1);
}
optopt = *place++;
if (optopt == '-' && *place == 0) {
/* "--" => end of options */
++optind;
place = EMSG;
return (-1);
}
if (optopt == 0) {
/* Solitary '-', treat as a '-' option
if the program (eg su) is looking for it. */
place = EMSG;
if (strchr(ostr, '-') == NULL)
return (-1);
optopt = '-';
}
} else
optopt = *place++;
/* See if option letter is one the caller wanted... */
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
if (*place == 0)
++optind;
if (opterr && *ostr != ':')
(void)fprintf(stderr,
"%s: illegal option -- %c\n", _getprogname(),
optopt);
return (BADCH);
}
/* Does this option need an argument? */
if (oli[1] != ':') {
/* don't need argument */
optarg = NULL;
if (*place == 0)
++optind;
} else {
/* Option-argument is either the rest of this argument or the
entire next argument. */
if (*place)
optarg = place;
else if (nargc > ++optind)
optarg = nargv[optind];
else {
/* option-argument absent */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
_getprogname(), optopt);
return (BADCH);
}
place = EMSG;
++optind;
}
return (optopt); /* return option letter */
}

View File

@ -0,0 +1,99 @@
/* Copyright StrongLoop, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "defs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h> /* getopt */
#endif
#define DEFAULT_BIND_HOST "127.0.0.1"
#define DEFAULT_BIND_PORT 1080
#define DEFAULT_IDLE_TIMEOUT (60 * 1000)
static void parse_opts(server_config *cf, int argc, char **argv);
static void usage(void);
static const char *progname = __FILE__; /* Reset in main(). */
int main(int argc, char **argv) {
server_config config;
int err;
progname = argv[0];
memset(&config, 0, sizeof(config));
config.bind_host = DEFAULT_BIND_HOST;
config.bind_port = DEFAULT_BIND_PORT;
config.idle_timeout = DEFAULT_IDLE_TIMEOUT;
parse_opts(&config, argc, argv);
err = server_run(&config, uv_default_loop());
if (err) {
exit(1);
}
return 0;
}
const char *_getprogname(void) {
return progname;
}
static void parse_opts(server_config *cf, int argc, char **argv) {
int opt;
while (-1 != (opt = getopt(argc, argv, "H:hp:"))) {
switch (opt) {
case 'H':
cf->bind_host = optarg;
break;
case 'p':
if (1 != sscanf(optarg, "%hu", &cf->bind_port)) {
pr_err("bad port number: %s", optarg);
usage();
}
break;
default:
usage();
}
}
}
static void usage(void) {
printf("Usage:\n"
"\n"
" %s [-b <address> [-h] [-p <port>]\n"
"\n"
"Options:\n"
"\n"
" -b <hostname|address> Bind to this address or hostname.\n"
" Default: \"127.0.0.1\"\n"
" -h Show this help message.\n"
" -p <port> Bind to this port number. Default: 1080\n"
"",
progname);
exit(1);
}

View File

@ -0,0 +1,271 @@
/* Copyright StrongLoop, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "s5.h"
#include <errno.h>
#include <stdint.h>
#include <stdlib.h> /* abort() */
#include <string.h> /* memset() */
enum {
s5_version,
s5_nmethods,
s5_methods,
s5_auth_pw_version,
s5_auth_pw_userlen,
s5_auth_pw_username,
s5_auth_pw_passlen,
s5_auth_pw_password,
s5_req_version,
s5_req_cmd,
s5_req_reserved,
s5_req_atyp,
s5_req_atyp_host,
s5_req_daddr,
s5_req_dport0,
s5_req_dport1,
s5_dead
};
void s5_init(s5_ctx *cx) {
memset(cx, 0, sizeof(*cx));
cx->state = s5_version;
}
s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size) {
s5_err err;
uint8_t *p;
uint8_t c;
size_t i;
size_t n;
p = *data;
n = *size;
i = 0;
while (i < n) {
c = p[i];
i += 1;
switch (cx->state) {
case s5_version:
if (c != 5) {
err = s5_bad_version;
goto out;
}
cx->state = s5_nmethods;
break;
case s5_nmethods:
cx->arg0 = 0;
cx->arg1 = c; /* Number of bytes to read. */
cx->state = s5_methods;
break;
case s5_methods:
if (cx->arg0 < cx->arg1) {
switch (c) {
case 0:
cx->methods |= S5_AUTH_NONE;
break;
case 1:
cx->methods |= S5_AUTH_GSSAPI;
break;
case 2:
cx->methods |= S5_AUTH_PASSWD;
break;
/* Ignore everything we don't understand. */
}
cx->arg0 += 1;
}
if (cx->arg0 == cx->arg1) {
err = s5_auth_select;
goto out;
}
break;
case s5_auth_pw_version:
if (c != 1) {
err = s5_bad_version;
goto out;
}
cx->state = s5_auth_pw_userlen;
break;
case s5_auth_pw_userlen:
cx->arg0 = 0;
cx->userlen = c;
cx->state = s5_auth_pw_username;
break;
case s5_auth_pw_username:
if (cx->arg0 < cx->userlen) {
cx->username[cx->arg0] = c;
cx->arg0 += 1;
}
if (cx->arg0 == cx->userlen) {
cx->username[cx->userlen] = '\0';
cx->state = s5_auth_pw_passlen;
}
break;
case s5_auth_pw_passlen:
cx->arg0 = 0;
cx->passlen = c;
cx->state = s5_auth_pw_password;
break;
case s5_auth_pw_password:
if (cx->arg0 < cx->passlen) {
cx->password[cx->arg0] = c;
cx->arg0 += 1;
}
if (cx->arg0 == cx->passlen) {
cx->password[cx->passlen] = '\0';
cx->state = s5_req_version;
err = s5_auth_verify;
goto out;
}
break;
case s5_req_version:
if (c != 5) {
err = s5_bad_version;
goto out;
}
cx->state = s5_req_cmd;
break;
case s5_req_cmd:
switch (c) {
case 1: /* TCP connect */
cx->cmd = s5_cmd_tcp_connect;
break;
case 3: /* UDP associate */
cx->cmd = s5_cmd_udp_assoc;
break;
default:
err = s5_bad_cmd;
goto out;
}
cx->state = s5_req_reserved;
break;
case s5_req_reserved:
cx->state = s5_req_atyp;
break;
case s5_req_atyp:
cx->arg0 = 0;
switch (c) {
case 1: /* IPv4, four octets. */
cx->state = s5_req_daddr;
cx->atyp = s5_atyp_ipv4;
cx->arg1 = 4;
break;
case 3: /* Hostname. First byte is length. */
cx->state = s5_req_atyp_host;
cx->atyp = s5_atyp_host;
cx->arg1 = 0;
break;
case 4: /* IPv6, sixteen octets. */
cx->state = s5_req_daddr;
cx->atyp = s5_atyp_ipv6;
cx->arg1 = 16;
break;
default:
err = s5_bad_atyp;
goto out;
}
break;
case s5_req_atyp_host:
cx->arg1 = c;
cx->state = s5_req_daddr;
break;
case s5_req_daddr:
if (cx->arg0 < cx->arg1) {
cx->daddr[cx->arg0] = c;
cx->arg0 += 1;
}
if (cx->arg0 == cx->arg1) {
cx->daddr[cx->arg1] = '\0';
cx->state = s5_req_dport0;
}
break;
case s5_req_dport0:
cx->dport = c << 8;
cx->state = s5_req_dport1;
break;
case s5_req_dport1:
cx->dport |= c;
cx->state = s5_dead;
err = s5_exec_cmd;
goto out;
case s5_dead:
break;
default:
abort();
}
}
err = s5_ok;
out:
*data = p + i;
*size = n - i;
return err;
}
unsigned int s5_auth_methods(const s5_ctx *cx) {
return cx->methods;
}
int s5_select_auth(s5_ctx *cx, s5_auth_method method) {
int err;
err = 0;
switch (method) {
case S5_AUTH_NONE:
cx->state = s5_req_version;
break;
case S5_AUTH_PASSWD:
cx->state = s5_auth_pw_version;
break;
default:
err = -EINVAL;
}
return err;
}
const char *s5_strerror(s5_err err) {
#define S5_ERR_GEN(_, name, errmsg) case s5_ ## name: return errmsg;
switch (err) {
S5_ERR_MAP(S5_ERR_GEN)
default: ; /* Silence s5_max_errors -Wswitch warning. */
}
#undef S5_ERR_GEN
return "Unknown error.";
}

View File

@ -0,0 +1,94 @@
/* Copyright StrongLoop, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef S5_H_
#define S5_H_
#include <stddef.h>
#include <stdint.h>
#define S5_ERR_MAP(V) \
V(-1, bad_version, "Bad protocol version.") \
V(-2, bad_cmd, "Bad protocol command.") \
V(-3, bad_atyp, "Bad address type.") \
V(0, ok, "No error.") \
V(1, auth_select, "Select authentication method.") \
V(2, auth_verify, "Verify authentication.") \
V(3, exec_cmd, "Execute command.") \
typedef enum {
#define S5_ERR_GEN(code, name, _) s5_ ## name = code,
S5_ERR_MAP(S5_ERR_GEN)
#undef S5_ERR_GEN
s5_max_errors
} s5_err;
typedef enum {
S5_AUTH_NONE = 1 << 0,
S5_AUTH_GSSAPI = 1 << 1,
S5_AUTH_PASSWD = 1 << 2
} s5_auth_method;
typedef enum {
s5_auth_allow,
s5_auth_deny
} s5_auth_result;
typedef enum {
s5_atyp_ipv4,
s5_atyp_ipv6,
s5_atyp_host
} s5_atyp;
typedef enum {
s5_cmd_tcp_connect,
s5_cmd_tcp_bind,
s5_cmd_udp_assoc
} s5_cmd;
typedef struct {
uint32_t arg0; /* Scratch space for the state machine. */
uint32_t arg1; /* Scratch space for the state machine. */
uint8_t state;
uint8_t methods;
uint8_t cmd;
uint8_t atyp;
uint8_t userlen;
uint8_t passlen;
uint16_t dport;
uint8_t username[257];
uint8_t password[257];
uint8_t daddr[257]; /* TODO(bnoordhuis) Merge with username/password. */
} s5_ctx;
void s5_init(s5_ctx *ctx);
s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size);
/* Only call after s5_parse() has returned s5_want_auth_method. */
unsigned int s5_auth_methods(const s5_ctx *cx);
/* Call after s5_parse() has returned s5_want_auth_method. */
int s5_select_auth(s5_ctx *cx, s5_auth_method method);
const char *s5_strerror(s5_err err);
#endif /* S5_H_ */

View File

@ -0,0 +1,241 @@
/* Copyright StrongLoop, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "defs.h"
#include <netinet/in.h> /* INET6_ADDRSTRLEN */
#include <stdlib.h>
#include <string.h>
#ifndef INET6_ADDRSTRLEN
# define INET6_ADDRSTRLEN 63
#endif
typedef struct {
uv_getaddrinfo_t getaddrinfo_req;
server_config config;
server_ctx *servers;
uv_loop_t *loop;
} server_state;
static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *ai);
static void on_connection(uv_stream_t *server, int status);
int server_run(const server_config *cf, uv_loop_t *loop) {
struct addrinfo hints;
server_state state;
int err;
memset(&state, 0, sizeof(state));
state.servers = NULL;
state.config = *cf;
state.loop = loop;
/* Resolve the address of the interface that we should bind to.
* The getaddrinfo callback starts the server and everything else.
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
err = uv_getaddrinfo(loop,
&state.getaddrinfo_req,
do_bind,
cf->bind_host,
NULL,
&hints);
if (err != 0) {
pr_err("getaddrinfo: %s", uv_strerror(err));
return err;
}
/* Start the event loop. Control continues in do_bind(). */
if (uv_run(loop, UV_RUN_DEFAULT)) {
abort();
}
/* Please Valgrind. */
uv_loop_delete(loop);
free(state.servers);
return 0;
}
/* Bind a server to each address that getaddrinfo() reported. */
static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *addrs) {
char addrbuf[INET6_ADDRSTRLEN + 1];
unsigned int ipv4_naddrs;
unsigned int ipv6_naddrs;
server_state *state;
server_config *cf;
struct addrinfo *ai;
const void *addrv;
const char *what;
uv_loop_t *loop;
server_ctx *sx;
unsigned int n;
int err;
union {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
} s;
state = CONTAINER_OF(req, server_state, getaddrinfo_req);
loop = state->loop;
cf = &state->config;
if (status < 0) {
pr_err("getaddrinfo(\"%s\"): %s", cf->bind_host, uv_strerror(status));
uv_freeaddrinfo(addrs);
return;
}
ipv4_naddrs = 0;
ipv6_naddrs = 0;
for (ai = addrs; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family == AF_INET) {
ipv4_naddrs += 1;
} else if (ai->ai_family == AF_INET6) {
ipv6_naddrs += 1;
}
}
if (ipv4_naddrs == 0 && ipv6_naddrs == 0) {
pr_err("%s has no IPv4/6 addresses", cf->bind_host);
uv_freeaddrinfo(addrs);
return;
}
state->servers =
xmalloc((ipv4_naddrs + ipv6_naddrs) * sizeof(state->servers[0]));
n = 0;
for (ai = addrs; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
continue;
}
if (ai->ai_family == AF_INET) {
s.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
s.addr4.sin_port = htons(cf->bind_port);
addrv = &s.addr4.sin_addr;
} else if (ai->ai_family == AF_INET6) {
s.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
s.addr6.sin6_port = htons(cf->bind_port);
addrv = &s.addr6.sin6_addr;
} else {
UNREACHABLE();
}
if (uv_inet_ntop(s.addr.sa_family, addrv, addrbuf, sizeof(addrbuf))) {
UNREACHABLE();
}
sx = state->servers + n;
sx->loop = loop;
sx->idle_timeout = state->config.idle_timeout;
CHECK(0 == uv_tcp_init(loop, &sx->tcp_handle));
what = "uv_tcp_bind";
err = uv_tcp_bind(&sx->tcp_handle, &s.addr, 0);
if (err == 0) {
what = "uv_listen";
err = uv_listen((uv_stream_t *) &sx->tcp_handle, 128, on_connection);
}
if (err != 0) {
pr_err("%s(\"%s:%hu\"): %s",
what,
addrbuf,
cf->bind_port,
uv_strerror(err));
while (n > 0) {
n -= 1;
uv_close((uv_handle_t *) (state->servers + n), NULL);
}
break;
}
pr_info("listening on %s:%hu", addrbuf, cf->bind_port);
n += 1;
}
uv_freeaddrinfo(addrs);
}
static void on_connection(uv_stream_t *server, int status) {
server_ctx *sx;
client_ctx *cx;
CHECK(status == 0);
sx = CONTAINER_OF(server, server_ctx, tcp_handle);
cx = xmalloc(sizeof(*cx));
CHECK(0 == uv_tcp_init(sx->loop, &cx->incoming.handle.tcp));
CHECK(0 == uv_accept(server, &cx->incoming.handle.stream));
client_finish_init(sx, cx);
}
int can_auth_none(const server_ctx *sx, const client_ctx *cx) {
return 1;
}
int can_auth_passwd(const server_ctx *sx, const client_ctx *cx) {
return 0;
}
int can_access(const server_ctx *sx,
const client_ctx *cx,
const struct sockaddr *addr) {
const struct sockaddr_in6 *addr6;
const struct sockaddr_in *addr4;
const uint32_t *p;
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
/* TODO(bnoordhuis) Implement proper access checks. For now, just reject
* traffic to localhost.
*/
if (addr->sa_family == AF_INET) {
addr4 = (const struct sockaddr_in *) addr;
d = ntohl(addr4->sin_addr.s_addr);
return (d >> 24) != 0x7F;
}
if (addr->sa_family == AF_INET6) {
addr6 = (const struct sockaddr_in6 *) addr;
p = (const uint32_t *) &addr6->sin6_addr.s6_addr;
a = ntohl(p[0]);
b = ntohl(p[1]);
c = ntohl(p[2]);
d = ntohl(p[3]);
if (a == 0 && b == 0 && c == 0 && d == 1) {
return 0; /* "::1" style address. */
}
if (a == 0 && b == 0 && c == 0xFFFF && (d >> 24) == 0x7F) {
return 0; /* "::ffff:127.x.x.x" style address. */
}
return 1;
}
return 0;
}

View File

@ -0,0 +1,72 @@
/* Copyright StrongLoop, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "defs.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
static void pr_do(FILE *stream,
const char *label,
const char *fmt,
va_list ap);
void *xmalloc(size_t size) {
void *ptr;
ptr = malloc(size);
if (ptr == NULL) {
pr_err("out of memory, need %lu bytes", (unsigned long) size);
exit(1);
}
return ptr;
}
void pr_info(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
pr_do(stdout, "info", fmt, ap);
va_end(ap);
}
void pr_warn(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
pr_do(stderr, "warn", fmt, ap);
va_end(ap);
}
void pr_err(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
pr_do(stderr, "error", fmt, ap);
va_end(ap);
}
static void pr_do(FILE *stream,
const char *label,
const char *fmt,
va_list ap) {
char fmtbuf[1024];
vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
fprintf(stream, "%s:%s: %s\n", _getprogname(), label, fmtbuf);
}

View File

@ -35,16 +35,16 @@ struct poll_ctx {
uv_fs_poll_cb poll_cb;
uv_timer_t timer_handle;
uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
uv_statbuf_t statbuf;
uv_stat_t statbuf;
char path[1]; /* variable length */
};
static int statbuf_eq(const uv_statbuf_t* a, const uv_statbuf_t* b);
static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b);
static void poll_cb(uv_fs_t* req);
static void timer_cb(uv_timer_t* timer, int status);
static void timer_cb(uv_timer_t* timer);
static void timer_close_cb(uv_handle_t* handle);
static uv_statbuf_t zero_statbuf;
static uv_stat_t zero_statbuf;
int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
@ -60,6 +60,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
struct poll_ctx* ctx;
uv_loop_t* loop;
size_t len;
int err;
if (uv__is_active(handle))
return 0;
@ -69,7 +70,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
ctx = calloc(1, sizeof(*ctx) + len);
if (ctx == NULL)
return uv__set_artificial_error(loop, UV_ENOMEM);
return UV_ENOMEM;
ctx->loop = loop;
ctx->poll_cb = cb;
@ -78,19 +79,25 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
ctx->parent_handle = handle;
memcpy(ctx->path, path, len + 1);
if (uv_timer_init(loop, &ctx->timer_handle))
abort();
err = uv_timer_init(loop, &ctx->timer_handle);
if (err < 0)
goto error;
ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
uv__handle_unref(&ctx->timer_handle);
if (uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb))
abort();
err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
if (err < 0)
goto error;
handle->poll_ctx = ctx;
uv__handle_start(handle);
return 0;
error:
free(ctx);
return err;
}
@ -118,12 +125,37 @@ int uv_fs_poll_stop(uv_fs_poll_t* handle) {
}
int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buf, size_t* len) {
struct poll_ctx* ctx;
size_t required_len;
if (!uv__is_active(handle)) {
*len = 0;
return UV_EINVAL;
}
ctx = handle->poll_ctx;
assert(ctx != NULL);
required_len = strlen(ctx->path) + 1;
if (required_len > *len) {
*len = required_len;
return UV_ENOBUFS;
}
memcpy(buf, ctx->path, required_len);
*len = required_len;
return 0;
}
void uv__fs_poll_close(uv_fs_poll_t* handle) {
uv_fs_poll_stop(handle);
}
static void timer_cb(uv_timer_t* timer, int status) {
static void timer_cb(uv_timer_t* timer) {
struct poll_ctx* ctx;
ctx = container_of(timer, struct poll_ctx, timer_handle);
@ -137,7 +169,7 @@ static void timer_cb(uv_timer_t* timer, int status) {
static void poll_cb(uv_fs_t* req) {
uv_statbuf_t* statbuf;
uv_stat_t* statbuf;
struct poll_ctx* ctx;
uint64_t interval;
@ -150,10 +182,12 @@ static void poll_cb(uv_fs_t* req) {
}
if (req->result != 0) {
if (ctx->busy_polling != -req->errorno) {
uv__set_artificial_error(ctx->loop, req->errorno);
ctx->poll_cb(ctx->parent_handle, -1, &ctx->statbuf, &zero_statbuf);
ctx->busy_polling = -req->errorno;
if (ctx->busy_polling != req->result) {
ctx->poll_cb(ctx->parent_handle,
req->result,
&ctx->statbuf,
&zero_statbuf);
ctx->busy_polling = req->result;
}
goto out;
}
@ -189,48 +223,21 @@ static void timer_close_cb(uv_handle_t* handle) {
}
static int statbuf_eq(const uv_statbuf_t* a, const uv_statbuf_t* b) {
#if defined(_WIN32)
return a->st_mtime == b->st_mtime
&& a->st_size == b->st_size
&& a->st_mode == b->st_mode;
#else
/* Jump through a few hoops to get sub-second granularity on Linux. */
# if defined(__linux__)
# if defined(__USE_MISC) /* _BSD_SOURCE || _SVID_SOURCE */
if (a->st_ctim.tv_nsec != b->st_ctim.tv_nsec) return 0;
if (a->st_mtim.tv_nsec != b->st_mtim.tv_nsec) return 0;
# else
if (a->st_ctimensec != b->st_ctimensec) return 0;
if (a->st_mtimensec != b->st_mtimensec) return 0;
# endif
# endif
/* Jump through different hoops on OS X. */
# if defined(__APPLE__)
# if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
if (a->st_ctimespec.tv_nsec != b->st_ctimespec.tv_nsec) return 0;
if (a->st_mtimespec.tv_nsec != b->st_mtimespec.tv_nsec) return 0;
# else
if (a->st_ctimensec != b->st_ctimensec) return 0;
if (a->st_mtimensec != b->st_mtimensec) return 0;
# endif
# endif
/* TODO(bnoordhuis) Other Unices have st_ctim and friends too, provided
* the stars and compiler flags are right...
*/
return a->st_ctime == b->st_ctime
&& a->st_mtime == b->st_mtime
static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec
&& a->st_mtim.tv_nsec == b->st_mtim.tv_nsec
&& a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec
&& a->st_ctim.tv_sec == b->st_ctim.tv_sec
&& a->st_mtim.tv_sec == b->st_mtim.tv_sec
&& a->st_birthtim.tv_sec == b->st_birthtim.tv_sec
&& a->st_size == b->st_size
&& a->st_mode == b->st_mode
&& a->st_uid == b->st_uid
&& a->st_gid == b->st_gid
&& a->st_ino == b->st_ino
&& a->st_dev == b->st_dev;
#endif
&& a->st_dev == b->st_dev
&& a->st_flags == b->st_flags
&& a->st_gen == b->st_gen;
}

View File

@ -0,0 +1,245 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef UV_SRC_HEAP_H_
#define UV_SRC_HEAP_H_
#include <stddef.h> /* NULL */
#if defined(__GNUC__)
# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration
#else
# define HEAP_EXPORT(declaration) static declaration
#endif
struct heap_node {
struct heap_node* left;
struct heap_node* right;
struct heap_node* parent;
};
/* A binary min heap. The usual properties hold: the root is the lowest
* element in the set, the height of the tree is at most log2(nodes) and
* it's always a complete binary tree.
*
* The heap function try hard to detect corrupted tree nodes at the cost
* of a minor reduction in performance. Compile with -DNDEBUG to disable.
*/
struct heap {
struct heap_node* min;
unsigned int nelts;
};
/* Return non-zero if a < b. */
typedef int (*heap_compare_fn)(const struct heap_node* a,
const struct heap_node* b);
/* Public functions. */
HEAP_EXPORT(void heap_init(struct heap* heap));
HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap));
HEAP_EXPORT(void heap_insert(struct heap* heap,
struct heap_node* newnode,
heap_compare_fn less_than));
HEAP_EXPORT(void heap_remove(struct heap* heap,
struct heap_node* node,
heap_compare_fn less_than));
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than));
/* Implementation follows. */
HEAP_EXPORT(void heap_init(struct heap* heap)) {
heap->min = NULL;
heap->nelts = 0;
}
HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) {
return heap->min;
}
/* Swap parent with child. Child moves closer to the root, parent moves away. */
static void heap_node_swap(struct heap* heap,
struct heap_node* parent,
struct heap_node* child) {
struct heap_node* sibling;
struct heap_node t;
t = *parent;
*parent = *child;
*child = t;
parent->parent = child;
if (child->left == child) {
child->left = parent;
sibling = child->right;
} else {
child->right = parent;
sibling = child->left;
}
if (sibling != NULL)
sibling->parent = child;
if (parent->left != NULL)
parent->left->parent = parent;
if (parent->right != NULL)
parent->right->parent = parent;
if (child->parent == NULL)
heap->min = child;
else if (child->parent->left == parent)
child->parent->left = child;
else
child->parent->right = child;
}
HEAP_EXPORT(void heap_insert(struct heap* heap,
struct heap_node* newnode,
heap_compare_fn less_than)) {
struct heap_node** parent;
struct heap_node** child;
unsigned int path;
unsigned int n;
unsigned int k;
newnode->left = NULL;
newnode->right = NULL;
newnode->parent = NULL;
/* Calculate the path from the root to the insertion point. This is a min
* heap so we always insert at the left-most free node of the bottom row.
*/
path = 0;
for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2)
path = (path << 1) | (n & 1);
/* Now traverse the heap using the path we calculated in the previous step. */
parent = child = &heap->min;
while (k > 0) {
parent = child;
if (path & 1)
child = &(*child)->right;
else
child = &(*child)->left;
path >>= 1;
k -= 1;
}
/* Insert the new node. */
newnode->parent = *parent;
*child = newnode;
heap->nelts += 1;
/* Walk up the tree and check at each node if the heap property holds.
* It's a min heap so parent < child must be true.
*/
while (newnode->parent != NULL && less_than(newnode, newnode->parent))
heap_node_swap(heap, newnode->parent, newnode);
}
HEAP_EXPORT(void heap_remove(struct heap* heap,
struct heap_node* node,
heap_compare_fn less_than)) {
struct heap_node* smallest;
struct heap_node** max;
struct heap_node* child;
unsigned int path;
unsigned int k;
unsigned int n;
if (heap->nelts == 0)
return;
/* Calculate the path from the min (the root) to the max, the left-most node
* of the bottom row.
*/
path = 0;
for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2)
path = (path << 1) | (n & 1);
/* Now traverse the heap using the path we calculated in the previous step. */
max = &heap->min;
while (k > 0) {
if (path & 1)
max = &(*max)->right;
else
max = &(*max)->left;
path >>= 1;
k -= 1;
}
heap->nelts -= 1;
/* Unlink the max node. */
child = *max;
*max = NULL;
if (child == node) {
/* We're removing either the max or the last node in the tree. */
if (child == heap->min) {
heap->min = NULL;
}
return;
}
/* Replace the to be deleted node with the max node. */
child->left = node->left;
child->right = node->right;
child->parent = node->parent;
if (child->left != NULL) {
child->left->parent = child;
}
if (child->right != NULL) {
child->right->parent = child;
}
if (node->parent == NULL) {
heap->min = child;
} else if (node->parent->left == node) {
node->parent->left = child;
} else {
node->parent->right = child;
}
/* Walk down the subtree and check at each node if the heap property holds.
* It's a min heap so parent < child must be true. If the parent is bigger,
* swap it with the smallest child.
*/
for (;;) {
smallest = child;
if (child->left != NULL && less_than(child->left, smallest))
smallest = child->left;
if (child->right != NULL && less_than(child->right, smallest))
smallest = child->right;
if (smallest == child)
break;
heap_node_swap(heap, child, smallest);
}
/* Walk up the subtree and check that each parent is less than the node
* this is required, because `max` node is not guaranteed to be the
* actual maximum in tree
*/
while (child->parent != NULL && less_than(child, child->parent))
heap_node_swap(heap, child->parent, child);
}
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
heap_remove(heap, heap->min, less_than);
}
#undef HEAP_EXPORT
#endif /* UV_SRC_HEAP_H_ */

View File

@ -19,7 +19,7 @@
#include <string.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
# include "uv-private/stdint-msvc2008.h"
# include "stdint-msvc2008.h"
#else
# include <stdint.h>
#endif
@ -27,33 +27,32 @@
#include "uv.h"
#include "uv-common.h"
static const uv_err_t uv_eafnosupport_ = { UV_EAFNOSUPPORT, 0 };
static const uv_err_t uv_enospc_ = { UV_ENOSPC, 0 };
static const uv_err_t uv_einval_ = { UV_EINVAL, 0 };
static uv_err_t inet_ntop4(const unsigned char *src, char *dst, size_t size);
static uv_err_t inet_ntop6(const unsigned char *src, char *dst, size_t size);
static uv_err_t inet_pton4(const char *src, unsigned char *dst);
static uv_err_t inet_pton6(const char *src, unsigned char *dst);
#define UV__INET_ADDRSTRLEN 16
#define UV__INET6_ADDRSTRLEN 46
uv_err_t uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
static int inet_pton4(const char *src, unsigned char *dst);
static int inet_pton6(const char *src, unsigned char *dst);
int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
switch (af) {
case AF_INET:
return (inet_ntop4(src, dst, size));
case AF_INET6:
return (inet_ntop6(src, dst, size));
default:
return uv_eafnosupport_;
return UV_EAFNOSUPPORT;
}
/* NOTREACHED */
}
static uv_err_t inet_ntop4(const unsigned char *src, char *dst, size_t size) {
static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
static const char fmt[] = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
char tmp[UV__INET_ADDRSTRLEN];
int l;
#ifndef _WIN32
@ -62,15 +61,15 @@ static uv_err_t inet_ntop4(const unsigned char *src, char *dst, size_t size) {
l = _snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
#endif
if (l <= 0 || (size_t) l >= size) {
return uv_enospc_;
return UV_ENOSPC;
}
strncpy(dst, tmp, size);
dst[size - 1] = '\0';
return uv_ok_;
return 0;
}
static uv_err_t inet_ntop6(const unsigned char *src, char *dst, size_t size) {
static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
@ -78,7 +77,7 @@ static uv_err_t inet_ntop6(const unsigned char *src, char *dst, size_t size) {
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
char tmp[UV__INET6_ADDRSTRLEN], *tp;
struct { int base, len; } best, cur;
unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
int i;
@ -135,13 +134,13 @@ static uv_err_t inet_ntop6(const unsigned char *src, char *dst, size_t size) {
if (i == 6 && best.base == 0 && (best.len == 6 ||
(best.len == 7 && words[7] != 0x0001) ||
(best.len == 5 && words[5] == 0xffff))) {
uv_err_t err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
if (err.code != UV_OK)
int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
if (err)
return err;
tp += strlen(tp);
break;
}
tp += snprintf(tp, tmp + sizeof tmp - tp, "%x", words[i]);
tp += sprintf(tp, "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
@ -152,27 +151,43 @@ static uv_err_t inet_ntop6(const unsigned char *src, char *dst, size_t size) {
* Check for overflow, copy, and we're done.
*/
if ((size_t)(tp - tmp) > size) {
return uv_enospc_;
return UV_ENOSPC;
}
uv_strlcpy(dst, tmp, size);
return uv_ok_;
strcpy(dst, tmp);
return 0;
}
uv_err_t uv_inet_pton(int af, const char* src, void* dst) {
int uv_inet_pton(int af, const char* src, void* dst) {
if (src == NULL || dst == NULL)
return UV_EINVAL;
switch (af) {
case AF_INET:
return (inet_pton4(src, dst));
case AF_INET6:
return (inet_pton6(src, dst));
case AF_INET6: {
int len;
char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
s = (char*) src;
p = strchr(src, '%');
if (p != NULL) {
s = tmp;
len = p - src;
if (len > UV__INET6_ADDRSTRLEN-1)
return UV_EINVAL;
memcpy(s, src, len);
s[len] = '\0';
}
return inet_pton6(s, dst);
}
default:
return uv_eafnosupport_;
return UV_EAFNOSUPPORT;
}
/* NOTREACHED */
}
static uv_err_t inet_pton4(const char *src, unsigned char *dst) {
static int inet_pton4(const char *src, unsigned char *dst) {
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
unsigned char tmp[sizeof(struct in_addr)], *tp;
@ -187,31 +202,31 @@ static uv_err_t inet_pton4(const char *src, unsigned char *dst) {
unsigned int nw = *tp * 10 + (pch - digits);
if (saw_digit && *tp == 0)
return uv_einval_;
return UV_EINVAL;
if (nw > 255)
return uv_einval_;
return UV_EINVAL;
*tp = nw;
if (!saw_digit) {
if (++octets > 4)
return uv_einval_;
return UV_EINVAL;
saw_digit = 1;
}
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return uv_einval_;
return UV_EINVAL;
*++tp = 0;
saw_digit = 0;
} else
return uv_einval_;
return UV_EINVAL;
}
if (octets < 4)
return uv_einval_;
return UV_EINVAL;
memcpy(dst, tmp, sizeof(struct in_addr));
return uv_ok_;
return 0;
}
static uv_err_t inet_pton6(const char *src, unsigned char *dst) {
static int inet_pton6(const char *src, unsigned char *dst) {
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
@ -225,7 +240,7 @@ static uv_err_t inet_pton6(const char *src, unsigned char *dst) {
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return uv_einval_;
return UV_EINVAL;
curtok = src;
seen_xdigits = 0;
val = 0;
@ -238,21 +253,21 @@ static uv_err_t inet_pton6(const char *src, unsigned char *dst) {
val <<= 4;
val |= (pch - xdigits);
if (++seen_xdigits > 4)
return uv_einval_;
return UV_EINVAL;
continue;
}
if (ch == ':') {
curtok = src;
if (!seen_xdigits) {
if (colonp)
return uv_einval_;
return UV_EINVAL;
colonp = tp;
continue;
} else if (*src == '\0') {
return uv_einval_;
return UV_EINVAL;
}
if (tp + sizeof(uint16_t) > endp)
return uv_einval_;
return UV_EINVAL;
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
seen_xdigits = 0;
@ -260,18 +275,18 @@ static uv_err_t inet_pton6(const char *src, unsigned char *dst) {
continue;
}
if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
uv_err_t err = inet_pton4(curtok, tp);
if (err.code == 0) {
int err = inet_pton4(curtok, tp);
if (err == 0) {
tp += sizeof(struct in_addr);
seen_xdigits = 0;
break; /*%< '\\0' was seen by inet_pton4(). */
}
}
return uv_einval_;
return UV_EINVAL;
}
if (seen_xdigits) {
if (tp + sizeof(uint16_t) > endp)
return uv_einval_;
return UV_EINVAL;
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
}
@ -284,7 +299,7 @@ static uv_err_t inet_pton6(const char *src, unsigned char *dst) {
int i;
if (tp == endp)
return uv_einval_;
return UV_EINVAL;
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
@ -292,7 +307,7 @@ static uv_err_t inet_pton6(const char *src, unsigned char *dst) {
tp = endp;
}
if (tp != endp)
return uv_einval_;
return UV_EINVAL;
memcpy(dst, tmp, sizeof tmp);
return uv_ok_;
return 0;
}

View File

@ -0,0 +1,92 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef QUEUE_H_
#define QUEUE_H_
typedef void *QUEUE[2];
/* Private macros. */
#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
/* Public macros. */
#define QUEUE_DATA(ptr, type, field) \
((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
#define QUEUE_FOREACH(q, h) \
for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
#define QUEUE_EMPTY(q) \
((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
#define QUEUE_HEAD(q) \
(QUEUE_NEXT(q))
#define QUEUE_INIT(q) \
do { \
QUEUE_NEXT(q) = (q); \
QUEUE_PREV(q) = (q); \
} \
while (0)
#define QUEUE_ADD(h, n) \
do { \
QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
QUEUE_PREV(h) = QUEUE_PREV(n); \
QUEUE_PREV_NEXT(h) = (h); \
} \
while (0)
#define QUEUE_SPLIT(h, q, n) \
do { \
QUEUE_PREV(n) = QUEUE_PREV(h); \
QUEUE_PREV_NEXT(n) = (n); \
QUEUE_NEXT(n) = (q); \
QUEUE_PREV(h) = QUEUE_PREV(q); \
QUEUE_PREV_NEXT(h) = (h); \
QUEUE_PREV(q) = (n); \
} \
while (0)
#define QUEUE_INSERT_HEAD(h, q) \
do { \
QUEUE_NEXT(q) = QUEUE_NEXT(h); \
QUEUE_PREV(q) = (h); \
QUEUE_NEXT_PREV(q) = (q); \
QUEUE_NEXT(h) = (q); \
} \
while (0)
#define QUEUE_INSERT_TAIL(h, q) \
do { \
QUEUE_NEXT(q) = (h); \
QUEUE_PREV(q) = QUEUE_PREV(h); \
QUEUE_PREV_NEXT(q) = (q); \
QUEUE_PREV(h) = (q); \
} \
while (0)
#define QUEUE_REMOVE(q) \
do { \
QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
} \
while (0)
#endif /* QUEUE_H_ */

View File

@ -19,7 +19,24 @@
* IN THE SOFTWARE.
*/
#include "internal.h"
#include "uv-common.h"
#if !defined(_WIN32)
# include "unix/internal.h"
#else
# include "win/req-inl.h"
/* TODO(saghul): unify internal req functions */
static void uv__req_init(uv_loop_t* loop,
uv_req_t* req,
uv_req_type type) {
uv_req_init(loop, req);
req->type = type;
uv__req_register(loop, req);
}
# define uv__req_init(loop, req, type) \
uv__req_init((loop), (uv_req_t*)(req), (type))
#endif
#include <stdlib.h>
#define MAX_THREADPOOL_SIZE 128
@ -30,8 +47,8 @@ static uv_mutex_t mutex;
static unsigned int nthreads;
static uv_thread_t* threads;
static uv_thread_t default_threads[4];
static ngx_queue_t exit_message;
static ngx_queue_t wq;
static QUEUE exit_message;
static QUEUE wq;
static volatile int initialized;
@ -45,23 +62,23 @@ static void uv__cancelled(struct uv__work* w) {
*/
static void worker(void* arg) {
struct uv__work* w;
ngx_queue_t* q;
QUEUE* q;
(void) arg;
for (;;) {
uv_mutex_lock(&mutex);
while (ngx_queue_empty(&wq))
while (QUEUE_EMPTY(&wq))
uv_cond_wait(&cond, &mutex);
q = ngx_queue_head(&wq);
q = QUEUE_HEAD(&wq);
if (q == &exit_message)
uv_cond_signal(&cond);
else {
ngx_queue_remove(q);
ngx_queue_init(q); /* Signal uv_cancel() that the work req is
QUEUE_REMOVE(q);
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
executing. */
}
@ -70,27 +87,53 @@ static void worker(void* arg) {
if (q == &exit_message)
break;
w = ngx_queue_data(q, struct uv__work, wq);
w = QUEUE_DATA(q, struct uv__work, wq);
w->work(w);
uv_mutex_lock(&w->loop->wq_mutex);
w->work = NULL; /* Signal uv_cancel() that the work req is done
executing. */
ngx_queue_insert_tail(&w->loop->wq, &w->wq);
QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
uv_async_send(&w->loop->wq_async);
uv_mutex_unlock(&w->loop->wq_mutex);
}
}
static void post(ngx_queue_t* q) {
static void post(QUEUE* q) {
uv_mutex_lock(&mutex);
ngx_queue_insert_tail(&wq, q);
QUEUE_INSERT_TAIL(&wq, q);
uv_cond_signal(&cond);
uv_mutex_unlock(&mutex);
}
#ifndef _WIN32
UV_DESTRUCTOR(static void cleanup(void)) {
unsigned int i;
if (initialized == 0)
return;
post(&exit_message);
for (i = 0; i < nthreads; i++)
if (uv_thread_join(threads + i))
abort();
if (threads != default_threads)
free(threads);
uv_mutex_destroy(&mutex);
uv_cond_destroy(&cond);
threads = NULL;
nthreads = 0;
initialized = 0;
}
#endif
static void init_once(void) {
unsigned int i;
const char* val;
@ -119,7 +162,7 @@ static void init_once(void) {
if (uv_mutex_init(&mutex))
abort();
ngx_queue_init(&wq);
QUEUE_INIT(&wq);
for (i = 0; i < nthreads; i++)
if (uv_thread_create(threads + i, worker, NULL))
@ -129,33 +172,6 @@ static void init_once(void) {
}
#if defined(__GNUC__)
__attribute__((destructor))
static void cleanup(void) {
unsigned int i;
if (initialized == 0)
return;
post(&exit_message);
for (i = 0; i < nthreads; i++)
if (uv_thread_join(threads + i))
abort();
if (threads != default_threads)
free(threads);
uv_mutex_destroy(&mutex);
uv_cond_destroy(&cond);
threads = NULL;
nthreads = 0;
initialized = 0;
}
#endif
void uv__work_submit(uv_loop_t* loop,
struct uv__work* w,
void (*work)(struct uv__work* w),
@ -174,19 +190,19 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
uv_mutex_lock(&mutex);
uv_mutex_lock(&w->loop->wq_mutex);
cancelled = !ngx_queue_empty(&w->wq) && w->work != NULL;
cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
if (cancelled)
ngx_queue_remove(&w->wq);
QUEUE_REMOVE(&w->wq);
uv_mutex_unlock(&w->loop->wq_mutex);
uv_mutex_unlock(&mutex);
if (!cancelled)
return -1;
return UV_EBUSY;
w->work = uv__cancelled;
uv_mutex_lock(&loop->wq_mutex);
ngx_queue_insert_tail(&loop->wq, &w->wq);
QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
uv_async_send(&loop->wq_async);
uv_mutex_unlock(&loop->wq_mutex);
@ -194,29 +210,29 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
}
void uv__work_done(uv_async_t* handle, int status) {
void uv__work_done(uv_async_t* handle) {
struct uv__work* w;
uv_loop_t* loop;
ngx_queue_t* q;
ngx_queue_t wq;
QUEUE* q;
QUEUE wq;
int err;
loop = container_of(handle, uv_loop_t, wq_async);
ngx_queue_init(&wq);
QUEUE_INIT(&wq);
uv_mutex_lock(&loop->wq_mutex);
if (!ngx_queue_empty(&loop->wq)) {
q = ngx_queue_head(&loop->wq);
ngx_queue_split(&loop->wq, q, &wq);
if (!QUEUE_EMPTY(&loop->wq)) {
q = QUEUE_HEAD(&loop->wq);
QUEUE_SPLIT(&loop->wq, q, &wq);
}
uv_mutex_unlock(&loop->wq_mutex);
while (!ngx_queue_empty(&wq)) {
q = ngx_queue_head(&wq);
ngx_queue_remove(q);
while (!QUEUE_EMPTY(&wq)) {
q = QUEUE_HEAD(&wq);
QUEUE_REMOVE(q);
w = container_of(q, struct uv__work, wq);
err = (w->work == uv__cancelled) ? -UV_ECANCELED : 0;
err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
w->done(w, err);
}
}
@ -229,7 +245,7 @@ static void uv__queue_work(struct uv__work* w) {
}
static void uv__queue_done(struct uv__work* w, int status) {
static void uv__queue_done(struct uv__work* w, int err) {
uv_work_t* req;
req = container_of(w, uv_work_t, work_req);
@ -238,10 +254,7 @@ static void uv__queue_done(struct uv__work* w, int status) {
if (req->after_work_cb == NULL)
return;
if (status == -UV_ECANCELED)
uv__set_artificial_error(req->loop, UV_ECANCELED);
req->after_work_cb(req, status ? -1 : 0);
req->after_work_cb(req, err);
}
@ -250,7 +263,7 @@ int uv_queue_work(uv_loop_t* loop,
uv_work_cb work_cb,
uv_after_work_cb after_work_cb) {
if (work_cb == NULL)
return uv__set_artificial_error(loop, UV_EINVAL);
return UV_EINVAL;
uv__req_init(loop, req, UV_WORK);
req->loop = loop;
@ -274,12 +287,16 @@ int uv_cancel(uv_req_t* req) {
loop = ((uv_getaddrinfo_t*) req)->loop;
wreq = &((uv_getaddrinfo_t*) req)->work_req;
break;
case UV_GETNAMEINFO:
loop = ((uv_getnameinfo_t*) req)->loop;
wreq = &((uv_getnameinfo_t*) req)->work_req;
break;
case UV_WORK:
loop = ((uv_work_t*) req)->loop;
wreq = &((uv_work_t*) req)->work_req;
break;
default:
return -1;
return UV_EINVAL;
}
return uv__work_cancel(loop, req, wreq);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,702 @@
/*
Copyright (c) 2013, Kenneth MacKay
Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement n° 289016)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "android-ifaddrs.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
typedef struct NetlinkList
{
struct NetlinkList *m_next;
struct nlmsghdr *m_data;
unsigned int m_size;
} NetlinkList;
static int netlink_socket(void)
{
struct sockaddr_nl l_addr;
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if(l_socket < 0)
{
return -1;
}
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
{
close(l_socket);
return -1;
}
return l_socket;
}
static int netlink_send(int p_socket, int p_request)
{
char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
struct nlmsghdr *l_hdr;
struct rtgenmsg *l_msg;
struct sockaddr_nl l_addr;
memset(l_buffer, 0, sizeof(l_buffer));
l_hdr = (struct nlmsghdr *)l_buffer;
l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
l_hdr->nlmsg_type = p_request;
l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
l_hdr->nlmsg_pid = 0;
l_hdr->nlmsg_seq = p_socket;
l_msg->rtgen_family = AF_UNSPEC;
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
}
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
{
struct sockaddr_nl l_addr;
struct msghdr l_msg;
struct iovec l_iov;
l_iov.iov_base = p_buffer;
l_iov.iov_len = p_len;
for(;;)
{
int l_result;
l_msg.msg_name = (void *)&l_addr;
l_msg.msg_namelen = sizeof(l_addr);
l_msg.msg_iov = &l_iov;
l_msg.msg_iovlen = 1;
l_msg.msg_control = NULL;
l_msg.msg_controllen = 0;
l_msg.msg_flags = 0;
l_result = recvmsg(p_socket, &l_msg, 0);
if(l_result < 0)
{
if(errno == EINTR)
{
continue;
}
return -2;
}
/* Buffer was too small */
if(l_msg.msg_flags & MSG_TRUNC)
{
return -1;
}
return l_result;
}
}
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
{
size_t l_size = 4096;
void *l_buffer = NULL;
for(;;)
{
int l_read;
free(l_buffer);
l_buffer = malloc(l_size);
if (l_buffer == NULL)
{
return NULL;
}
l_read = netlink_recv(p_socket, l_buffer, l_size);
*p_size = l_read;
if(l_read == -2)
{
free(l_buffer);
return NULL;
}
if(l_read >= 0)
{
pid_t l_pid = getpid();
struct nlmsghdr *l_hdr;
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
*p_done = 1;
break;
}
if(l_hdr->nlmsg_type == NLMSG_ERROR)
{
free(l_buffer);
return NULL;
}
}
return l_buffer;
}
l_size *= 2;
}
}
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
{
NetlinkList *l_item = malloc(sizeof(NetlinkList));
if (l_item == NULL)
{
return NULL;
}
l_item->m_next = NULL;
l_item->m_data = p_data;
l_item->m_size = p_size;
return l_item;
}
static void freeResultList(NetlinkList *p_list)
{
NetlinkList *l_cur;
while(p_list)
{
l_cur = p_list;
p_list = p_list->m_next;
free(l_cur->m_data);
free(l_cur);
}
}
static NetlinkList *getResultList(int p_socket, int p_request)
{
int l_size;
int l_done;
NetlinkList *l_list;
NetlinkList *l_end;
if(netlink_send(p_socket, p_request) < 0)
{
return NULL;
}
l_list = NULL;
l_end = NULL;
l_done = 0;
while(!l_done)
{
NetlinkList *l_item;
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
/* Error */
if(!l_hdr)
{
freeResultList(l_list);
return NULL;
}
l_item = newListItem(l_hdr, l_size);
if (!l_item)
{
freeResultList(l_list);
return NULL;
}
if(!l_list)
{
l_list = l_item;
}
else
{
l_end->m_next = l_item;
}
l_end = l_item;
}
return l_list;
}
static size_t maxSize(size_t a, size_t b)
{
return (a > b ? a : b);
}
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
{
switch(p_family)
{
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_PACKET:
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
default:
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
}
}
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
{
switch(p_family)
{
case AF_INET:
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
break;
case AF_INET6:
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
break;
case AF_PACKET:
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
break;
default:
memcpy(p_dest->sa_data, p_data, p_size);
break;
}
p_dest->sa_family = p_family;
}
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
{
if(!*p_resultList)
{
*p_resultList = p_entry;
}
else
{
struct ifaddrs *l_cur = *p_resultList;
while(l_cur->ifa_next)
{
l_cur = l_cur->ifa_next;
}
l_cur->ifa_next = p_entry;
}
}
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
{
struct ifaddrs *l_entry;
char *l_index;
char *l_name;
char *l_addr;
char *l_data;
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
size_t l_nameSize = 0;
size_t l_addrSize = 0;
size_t l_dataSize = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
struct rtattr *l_rta;
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFLA_ADDRESS:
case IFLA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
break;
case IFLA_IFNAME:
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
break;
case IFLA_STATS:
l_dataSize += NLMSG_ALIGN(l_rtaSize);
break;
default:
break;
}
}
l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
if (l_entry == NULL)
{
return -1;
}
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = "";
l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
l_name = l_index + sizeof(int);
l_addr = l_name + l_nameSize;
l_data = l_addr + l_addrSize;
/* Save the interface index so we can look it up when handling the
* addresses.
*/
memcpy(l_index, &l_info->ifi_index, sizeof(int));
l_entry->ifa_flags = l_info->ifi_flags;
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFLA_ADDRESS:
case IFLA_BROADCAST:
{
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
if(l_rta->rta_type == IFLA_ADDRESS)
{
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFLA_IFNAME:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
case IFLA_STATS:
memcpy(l_data, l_rtaData, l_rtaDataSize);
l_entry->ifa_data = l_data;
break;
default:
break;
}
}
addToEnd(p_resultList, l_entry);
return 0;
}
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
{
int l_num = 0;
struct ifaddrs *l_cur = *p_links;
while(l_cur && l_num < p_numLinks)
{
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
int l_index;
memcpy(&l_index, l_indexPtr, sizeof(int));
if(l_index == p_index)
{
return l_cur;
}
l_cur = l_cur->ifa_next;
++l_num;
}
return NULL;
}
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
{
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
size_t l_nameSize = 0;
size_t l_addrSize = 0;
int l_addedNetmask = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
struct rtattr *l_rta;
struct ifaddrs *l_entry;
char *l_name;
char *l_addr;
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
if(l_info->ifa_family == AF_PACKET)
{
continue;
}
switch(l_rta->rta_type)
{
case IFA_ADDRESS:
case IFA_LOCAL:
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
{
/* Make room for netmask */
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
l_addedNetmask = 1;
}
case IFA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
break;
case IFA_LABEL:
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
break;
default:
break;
}
}
l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
if (l_entry == NULL)
{
return -1;
}
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
l_addr = l_name + l_nameSize;
l_entry->ifa_flags = l_info->ifa_flags;
if(l_interface)
{
l_entry->ifa_flags |= l_interface->ifa_flags;
}
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFA_ADDRESS:
case IFA_BROADCAST:
case IFA_LOCAL:
{
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
if(l_info->ifa_family == AF_INET6)
{
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
{
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
}
}
/* Apparently in a point-to-point network IFA_ADDRESS contains
* the dest address and IFA_LOCAL contains the local address
*/
if(l_rta->rta_type == IFA_ADDRESS)
{
if(l_entry->ifa_addr)
{
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
}
else if(l_rta->rta_type == IFA_LOCAL)
{
if(l_entry->ifa_addr)
{
l_entry->ifa_dstaddr = l_entry->ifa_addr;
}
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFA_LABEL:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
default:
break;
}
}
if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
{
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
char l_mask[16] = {0};
unsigned i;
for(i=0; i<(l_prefix/8); ++i)
{
l_mask[i] = 0xff;
}
if(l_prefix % 8)
{
l_mask[i] = 0xff << (8 - (l_prefix % 8));
}
makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
}
addToEnd(p_resultList, l_entry);
return 0;
}
static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
{
int l_numLinks = 0;
pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
break;
}
if(l_hdr->nlmsg_type == RTM_NEWLINK)
{
if(interpretLink(l_hdr, p_resultList) == -1)
{
return -1;
}
++l_numLinks;
}
}
}
return l_numLinks;
}
static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
{
pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
break;
}
if(l_hdr->nlmsg_type == RTM_NEWADDR)
{
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
{
return -1;
}
}
}
}
return 0;
}
int getifaddrs(struct ifaddrs **ifap)
{
int l_socket;
int l_result;
int l_numLinks;
NetlinkList *l_linkResults;
NetlinkList *l_addrResults;
if(!ifap)
{
return -1;
}
*ifap = NULL;
l_socket = netlink_socket();
if(l_socket < 0)
{
return -1;
}
l_linkResults = getResultList(l_socket, RTM_GETLINK);
if(!l_linkResults)
{
close(l_socket);
return -1;
}
l_addrResults = getResultList(l_socket, RTM_GETADDR);
if(!l_addrResults)
{
close(l_socket);
freeResultList(l_linkResults);
return -1;
}
l_result = 0;
l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
{
l_result = -1;
}
freeResultList(l_linkResults);
freeResultList(l_addrResults);
close(l_socket);
return l_result;
}
void freeifaddrs(struct ifaddrs *ifa)
{
struct ifaddrs *l_cur;
while(ifa)
{
l_cur = ifa;
ifa = ifa->ifa_next;
free(l_cur);
}
}

View File

@ -26,6 +26,7 @@
#include "internal.h"
#include <errno.h>
#include <stdio.h> /* snprintf() */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@ -39,14 +40,17 @@ static int uv__async_eventfd(void);
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
if (uv__async_start(loop, &loop->async_watcher, uv__async_event))
return uv__set_sys_error(loop, errno);
int err;
err = uv__async_start(loop, &loop->async_watcher, uv__async_event);
if (err)
return err;
uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
handle->async_cb = async_cb;
handle->pending = 0;
ngx_queue_insert_tail(&loop->async_handles, &handle->queue);
QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
uv__handle_start(handle);
return 0;
@ -62,7 +66,7 @@ int uv_async_send(uv_async_t* handle) {
void uv__async_close(uv_async_t* handle) {
ngx_queue_remove(&handle->queue);
QUEUE_REMOVE(&handle->queue);
uv__handle_stop(handle);
}
@ -70,14 +74,19 @@ void uv__async_close(uv_async_t* handle) {
static void uv__async_event(uv_loop_t* loop,
struct uv__async* w,
unsigned int nevents) {
ngx_queue_t* q;
QUEUE* q;
uv_async_t* h;
ngx_queue_foreach(q, &loop->async_handles) {
h = ngx_queue_data(q, uv_async_t, queue);
if (!h->pending) continue;
QUEUE_FOREACH(q, &loop->async_handles) {
h = QUEUE_DATA(q, uv_async_t, queue);
if (h->pending == 0)
continue;
h->pending = 0;
h->async_cb(h, 0);
if (h->async_cb == NULL)
continue;
h->async_cb(h);
}
}
@ -199,20 +208,41 @@ void uv__async_init(struct uv__async* wa) {
int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) {
int pipefd[2];
int fd;
int err;
if (wa->io_watcher.fd != -1)
return 0;
fd = uv__async_eventfd();
if (fd >= 0) {
pipefd[0] = fd;
err = uv__async_eventfd();
if (err >= 0) {
pipefd[0] = err;
pipefd[1] = -1;
}
else if (fd != -ENOSYS)
return -1;
else if (uv__make_pipe(pipefd, UV__F_NONBLOCK))
return -1;
else if (err == -ENOSYS) {
err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
#if defined(__linux__)
/* Save a file descriptor by opening one of the pipe descriptors as
* read/write through the procfs. That file descriptor can then
* function as both ends of the pipe.
*/
if (err == 0) {
char buf[32];
int fd;
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
fd = uv__open_cloexec(buf, O_RDWR);
if (fd >= 0) {
uv__close(pipefd[0]);
uv__close(pipefd[1]);
pipefd[0] = fd;
pipefd[1] = fd;
}
}
#endif
}
if (err < 0)
return err;
uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]);
uv__io_start(loop, &wa->io_watcher, UV__POLLIN);
@ -227,14 +257,15 @@ void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) {
if (wa->io_watcher.fd == -1)
return;
uv__io_stop(loop, &wa->io_watcher, UV__POLLIN);
close(wa->io_watcher.fd);
wa->io_watcher.fd = -1;
if (wa->wfd != -1) {
close(wa->wfd);
if (wa->wfd != wa->io_watcher.fd)
uv__close(wa->wfd);
wa->wfd = -1;
}
uv__io_stop(loop, &wa->io_watcher, UV__POLLIN);
uv__close(wa->io_watcher.fd);
wa->io_watcher.fd = -1;
}

View File

@ -0,0 +1,60 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef UV_ATOMIC_OPS_H_
#define UV_ATOMIC_OPS_H_
#include "internal.h" /* UV_UNUSED */
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval));
UV_UNUSED(static void cpu_relax(void));
/* Prefer hand-rolled assembly over the gcc builtins because the latter also
* issue full memory barriers.
*/
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
#if defined(__i386__) || defined(__x86_64__)
int out;
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
: "=a" (out), "+m" (*(volatile int*) ptr)
: "r" (newval), "0" (oldval)
: "memory");
return out;
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
}
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
#if defined(__i386__) || defined(__x86_64__)
long out;
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
: "=a" (out), "+m" (*(volatile long*) ptr)
: "r" (newval), "0" (oldval)
: "memory");
return out;
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
}
UV_UNUSED(static void cpu_relax(void)) {
#if defined(__i386__) || defined(__x86_64__)
__asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
#endif
}
#endif /* UV_ATOMIC_OPS_H_ */

View File

@ -37,6 +37,7 @@
#include <arpa/inet.h>
#include <limits.h> /* INT_MAX, PATH_MAX */
#include <sys/uio.h> /* writev */
#include <sys/resource.h> /* getrusage */
#ifdef __linux__
# include <sys/ioctl.h>
@ -58,13 +59,23 @@
# include <sys/filio.h>
# include <sys/ioctl.h>
# include <sys/wait.h>
# define UV__O_CLOEXEC O_CLOEXEC
# if __FreeBSD__ >= 10
# define uv__accept4 accept4
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
# endif
# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
# endif
#endif
#ifdef _AIX
#include <sys/ioctl.h>
#endif
static void uv__run_pending(uv_loop_t* loop);
static uv_loop_t default_loop_struct;
static uv_loop_t* default_loop_ptr;
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) ==
@ -76,7 +87,7 @@ STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
uint64_t uv_hrtime(void) {
return uv__hrtime();
return uv__hrtime(UV_CLOCK_PRECISE);
}
@ -152,6 +163,33 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
uv__make_close_pending(handle);
}
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
int r;
int fd;
socklen_t len;
if (handle == NULL || value == NULL)
return -EINVAL;
if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE)
fd = uv__stream_fd((uv_stream_t*) handle);
else if (handle->type == UV_UDP)
fd = ((uv_udp_t *) handle)->io_watcher.fd;
else
return -ENOTSUP;
len = sizeof(*value);
if (*value == 0)
r = getsockopt(fd, SOL_SOCKET, optname, value, &len);
else
r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len);
if (r < 0)
return -errno;
return 0;
}
void uv__make_close_pending(uv_handle_t* handle) {
assert(handle->flags & UV_CLOSING);
@ -201,7 +239,7 @@ static void uv__finish_close(uv_handle_t* handle) {
}
uv__handle_unref(handle);
ngx_queue_remove(&handle->handle_queue);
QUEUE_REMOVE(&handle->handle_queue);
if (handle->close_cb) {
handle->close_cb(handle);
@ -229,44 +267,6 @@ int uv_is_closing(const uv_handle_t* handle) {
}
uv_loop_t* uv_default_loop(void) {
if (default_loop_ptr)
return default_loop_ptr;
if (uv__loop_init(&default_loop_struct, /* default_loop? */ 1))
return NULL;
return (default_loop_ptr = &default_loop_struct);
}
uv_loop_t* uv_loop_new(void) {
uv_loop_t* loop;
if ((loop = malloc(sizeof(*loop))) == NULL)
return NULL;
if (uv__loop_init(loop, /* default_loop? */ 0)) {
free(loop);
return NULL;
}
return loop;
}
void uv_loop_delete(uv_loop_t* loop) {
uv__loop_delete(loop);
#ifndef NDEBUG
memset(loop, -1, sizeof *loop);
#endif
if (loop == default_loop_ptr)
default_loop_ptr = NULL;
else
free(loop);
}
int uv_backend_fd(const uv_loop_t* loop) {
return loop->backend_fd;
}
@ -279,7 +279,7 @@ int uv_backend_timeout(const uv_loop_t* loop) {
if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
return 0;
if (!ngx_queue_empty(&loop->idle_handles))
if (!QUEUE_EMPTY(&loop->idle_handles))
return 0;
if (loop->closing_handles)
@ -289,26 +289,34 @@ int uv_backend_timeout(const uv_loop_t* loop) {
}
static int uv__loop_alive(uv_loop_t* loop) {
static int uv__loop_alive(const uv_loop_t* loop) {
return uv__has_active_handles(loop) ||
uv__has_active_reqs(loop) ||
loop->closing_handles != NULL;
}
int uv_loop_alive(const uv_loop_t* loop) {
return uv__loop_alive(loop);
}
int uv_run(uv_loop_t* loop, uv_run_mode mode) {
int timeout;
int r;
r = uv__loop_alive(loop);
if (!r)
uv__update_time(loop);
while (r != 0 && loop->stop_flag == 0) {
UV_TICK_START(loop, mode);
uv__update_time(loop);
uv__run_timers(loop);
uv__run_pending(loop);
uv__run_idle(loop);
uv__run_prepare(loop);
uv__run_pending(loop);
timeout = 0;
if ((mode & UV_RUN_NOWAIT) == 0)
@ -317,8 +325,21 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
uv__io_poll(loop, timeout);
uv__run_check(loop);
uv__run_closing_handles(loop);
r = uv__loop_alive(loop);
if (mode == UV_RUN_ONCE) {
/* UV_RUN_ONCE implies forward progess: at least one callback must have
* been invoked when it returns. uv__io_poll() can return without doing
* I/O (meaning: no callbacks) when its timeout expires - which means we
* have pending timers that satisfy the forward progress constraint.
*
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
* the check.
*/
uv__update_time(loop);
uv__run_timers(loop);
}
r = uv__loop_alive(loop);
UV_TICK_STOP(loop, mode);
if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
@ -348,25 +369,28 @@ int uv_is_active(const uv_handle_t* handle) {
/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */
int uv__socket(int domain, int type, int protocol) {
int sockfd;
int err;
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
if (sockfd != -1)
goto out;
return sockfd;
if (errno != EINVAL)
goto out;
return -errno;
#endif
sockfd = socket(domain, type, protocol);
if (sockfd == -1)
goto out;
return -errno;
if (uv__nonblock(sockfd, 1) || uv__cloexec(sockfd, 1)) {
close(sockfd);
sockfd = -1;
err = uv__nonblock(sockfd, 1);
if (err == 0)
err = uv__cloexec(sockfd, 1);
if (err) {
uv__close(sockfd);
return err;
}
#if defined(SO_NOSIGPIPE)
@ -376,18 +400,18 @@ int uv__socket(int domain, int type, int protocol) {
}
#endif
out:
return sockfd;
}
int uv__accept(int sockfd) {
int peerfd;
int err;
assert(sockfd >= 0);
while (1) {
#if defined(__linux__)
#if defined(__linux__) || __FreeBSD__ >= 10
static int no_accept4;
if (no_accept4)
@ -397,42 +421,62 @@ int uv__accept(int sockfd) {
NULL,
NULL,
UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC);
if (peerfd != -1)
break;
return peerfd;
if (errno == EINTR)
continue;
if (errno != ENOSYS)
break;
return -errno;
no_accept4 = 1;
skip:
#endif
peerfd = accept(sockfd, NULL, NULL);
if (peerfd == -1) {
if (errno == EINTR)
continue;
else
break;
return -errno;
}
if (uv__cloexec(peerfd, 1) || uv__nonblock(peerfd, 1)) {
close(peerfd);
peerfd = -1;
}
err = uv__cloexec(peerfd, 1);
if (err == 0)
err = uv__nonblock(peerfd, 1);
break;
if (err) {
uv__close(peerfd);
return err;
}
return peerfd;
}
}
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
int uv__close(int fd) {
int saved_errno;
int rc;
assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */
assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
saved_errno = errno;
rc = close(fd);
if (rc == -1) {
rc = -errno;
if (rc == -EINTR)
rc = -EINPROGRESS; /* For platform/libc consistency. */
errno = saved_errno;
}
return rc;
}
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(_AIX)
int uv__nonblock(int fd, int set) {
int r;
@ -441,7 +485,10 @@ int uv__nonblock(int fd, int set) {
r = ioctl(fd, FIONBIO, &set);
while (r == -1 && errno == EINTR);
return r;
if (r)
return -errno;
return 0;
}
@ -452,7 +499,10 @@ int uv__cloexec(int fd, int set) {
r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
while (r == -1 && errno == EINTR);
return r;
if (r)
return -errno;
return 0;
}
#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) */
@ -466,7 +516,7 @@ int uv__nonblock(int fd, int set) {
while (r == -1 && errno == EINTR);
if (r == -1)
return -1;
return -errno;
/* Bail out now if already set/clear. */
if (!!(r & O_NONBLOCK) == !!set)
@ -481,7 +531,10 @@ int uv__nonblock(int fd, int set) {
r = fcntl(fd, F_SETFL, flags);
while (r == -1 && errno == EINTR);
return r;
if (r)
return -errno;
return 0;
}
@ -494,7 +547,7 @@ int uv__cloexec(int fd, int set) {
while (r == -1 && errno == EINTR);
if (r == -1)
return -1;
return -errno;
/* Bail out now if already set/clear. */
if (!!(r & FD_CLOEXEC) == !!set)
@ -509,7 +562,10 @@ int uv__cloexec(int fd, int set) {
r = fcntl(fd, F_SETFD, flags);
while (r == -1 && errno == EINTR);
return r;
if (r)
return -errno;
return 0;
}
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) */
@ -519,39 +575,78 @@ int uv__cloexec(int fd, int set) {
* between the call to dup() and fcntl(FD_CLOEXEC).
*/
int uv__dup(int fd) {
int err;
fd = dup(fd);
if (fd == -1)
return -1;
return -errno;
if (uv__cloexec(fd, 1)) {
SAVE_ERRNO(close(fd));
return -1;
err = uv__cloexec(fd, 1);
if (err) {
uv__close(fd);
return err;
}
return fd;
}
uv_err_t uv_cwd(char* buffer, size_t size) {
if (!buffer || !size) {
return uv__new_artificial_error(UV_EINVAL);
}
if (getcwd(buffer, size)) {
return uv_ok_;
ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
struct cmsghdr* cmsg;
ssize_t rc;
int* pfd;
int* end;
#if defined(__linux__)
static int no_msg_cmsg_cloexec;
if (no_msg_cmsg_cloexec == 0) {
rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
if (rc != -1)
return rc;
if (errno != EINVAL)
return -errno;
rc = recvmsg(fd, msg, flags);
if (rc == -1)
return -errno;
no_msg_cmsg_cloexec = 1;
} else {
return uv__new_sys_error(errno);
rc = recvmsg(fd, msg, flags);
}
#else
rc = recvmsg(fd, msg, flags);
#endif
if (rc == -1)
return -errno;
if (msg->msg_controllen == 0)
return rc;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
if (cmsg->cmsg_type == SCM_RIGHTS)
for (pfd = (int*) CMSG_DATA(cmsg),
end = (int*) ((char*) cmsg + cmsg->cmsg_len);
pfd < end;
pfd += 1)
uv__cloexec(*pfd, 1);
return rc;
}
uv_err_t uv_chdir(const char* dir) {
if (chdir(dir) == 0) {
return uv_ok_;
} else {
return uv__new_sys_error(errno);
}
int uv_cwd(char* buffer, size_t* size) {
if (buffer == NULL || size == NULL)
return -EINVAL;
if (getcwd(buffer, *size) == NULL)
return -errno;
*size = strlen(buffer) + 1;
return 0;
}
int uv_chdir(const char* dir) {
if (chdir(dir))
return -errno;
return 0;
}
@ -568,15 +663,15 @@ void uv_disable_stdio_inheritance(void) {
static void uv__run_pending(uv_loop_t* loop) {
ngx_queue_t* q;
QUEUE* q;
uv__io_t* w;
while (!ngx_queue_empty(&loop->pending_queue)) {
q = ngx_queue_head(&loop->pending_queue);
ngx_queue_remove(q);
ngx_queue_init(q);
while (!QUEUE_EMPTY(&loop->pending_queue)) {
q = QUEUE_HEAD(&loop->pending_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = ngx_queue_data(q, uv__io_t, pending_queue);
w = QUEUE_DATA(q, uv__io_t, pending_queue);
w->cb(loop, w, UV__POLLOUT);
}
}
@ -631,8 +726,8 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) {
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
assert(cb != NULL);
assert(fd >= -1);
ngx_queue_init(&w->pending_queue);
ngx_queue_init(&w->watcher_queue);
QUEUE_INIT(&w->pending_queue);
QUEUE_INIT(&w->watcher_queue);
w->cb = cb;
w->fd = fd;
w->events = 0;
@ -660,16 +755,16 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
* short-circuit here if the event mask is unchanged.
*/
if (w->events == w->pevents) {
if (w->events == 0 && !ngx_queue_empty(&w->watcher_queue)) {
ngx_queue_remove(&w->watcher_queue);
ngx_queue_init(&w->watcher_queue);
if (w->events == 0 && !QUEUE_EMPTY(&w->watcher_queue)) {
QUEUE_REMOVE(&w->watcher_queue);
QUEUE_INIT(&w->watcher_queue);
}
return;
}
#endif
if (ngx_queue_empty(&w->watcher_queue))
ngx_queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
if (QUEUE_EMPTY(&w->watcher_queue))
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
if (loop->watchers[w->fd] == NULL) {
loop->watchers[w->fd] = w;
@ -694,8 +789,8 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
w->pevents &= ~events;
if (w->pevents == 0) {
ngx_queue_remove(&w->watcher_queue);
ngx_queue_init(&w->watcher_queue);
QUEUE_REMOVE(&w->watcher_queue);
QUEUE_INIT(&w->watcher_queue);
if (loop->watchers[w->fd] != NULL) {
assert(loop->watchers[w->fd] == w);
@ -705,14 +800,14 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
w->events = 0;
}
}
else if (ngx_queue_empty(&w->watcher_queue))
ngx_queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
else if (QUEUE_EMPTY(&w->watcher_queue))
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
}
void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
ngx_queue_remove(&w->pending_queue);
QUEUE_REMOVE(&w->pending_queue);
/* Remove stale events for this file descriptor */
uv__platform_invalidate_fd(loop, w->fd);
@ -720,8 +815,8 @@ void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
if (ngx_queue_empty(&w->pending_queue))
ngx_queue_insert_tail(&loop->pending_queue, &w->pending_queue);
if (QUEUE_EMPTY(&w->pending_queue))
QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
}
@ -730,3 +825,124 @@ int uv__io_active(const uv__io_t* w, unsigned int events) {
assert(0 != events);
return 0 != (w->pevents & events);
}
int uv_getrusage(uv_rusage_t* rusage) {
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage))
return -errno;
rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec;
rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec;
rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec;
rusage->ru_maxrss = usage.ru_maxrss;
rusage->ru_ixrss = usage.ru_ixrss;
rusage->ru_idrss = usage.ru_idrss;
rusage->ru_isrss = usage.ru_isrss;
rusage->ru_minflt = usage.ru_minflt;
rusage->ru_majflt = usage.ru_majflt;
rusage->ru_nswap = usage.ru_nswap;
rusage->ru_inblock = usage.ru_inblock;
rusage->ru_oublock = usage.ru_oublock;
rusage->ru_msgsnd = usage.ru_msgsnd;
rusage->ru_msgrcv = usage.ru_msgrcv;
rusage->ru_nsignals = usage.ru_nsignals;
rusage->ru_nvcsw = usage.ru_nvcsw;
rusage->ru_nivcsw = usage.ru_nivcsw;
return 0;
}
int uv__open_cloexec(const char* path, int flags) {
int err;
int fd;
#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9)
static int no_cloexec;
if (!no_cloexec) {
fd = open(path, flags | UV__O_CLOEXEC);
if (fd != -1)
return fd;
if (errno != EINVAL)
return -errno;
/* O_CLOEXEC not supported. */
no_cloexec = 1;
}
#endif
fd = open(path, flags);
if (fd == -1)
return -errno;
err = uv__cloexec(fd, 1);
if (err) {
uv__close(fd);
return err;
}
return fd;
}
int uv__dup2_cloexec(int oldfd, int newfd) {
int r;
#if defined(__FreeBSD__) && __FreeBSD__ >= 10
do
r = dup3(oldfd, newfd, O_CLOEXEC);
while (r == -1 && errno == EINTR);
if (r == -1)
return -errno;
return r;
#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
do
r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
while (r == -1 && errno == EINTR);
if (r != -1)
return r;
if (errno != EINVAL)
return -errno;
/* Fall through. */
#elif defined(__linux__)
static int no_dup3;
if (!no_dup3) {
do
r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
while (r == -1 && (errno == EINTR || errno == EBUSY));
if (r != -1)
return r;
if (errno != ENOSYS)
return -errno;
/* Fall through. */
no_dup3 = 1;
}
#endif
{
int err;
do
r = dup2(oldfd, newfd);
#if defined(__linux__)
while (r == -1 && (errno == EINTR || errno == EBUSY));
#else
while (r == -1 && errno == EINTR);
#endif
if (r == -1)
return -errno;
err = uv__cloexec(newfd, 1);
if (err) {
uv__close(newfd);
return err;
}
return r;
}
}

View File

@ -0,0 +1,203 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
#include <TargetConditionals.h>
#if !TARGET_OS_IPHONE
# include <CoreFoundation/CoreFoundation.h>
# include <ApplicationServices/ApplicationServices.h>
#endif
static int uv__pthread_setname_np(const char* name) {
int (*dynamic_pthread_setname_np)(const char* name);
char namebuf[64]; /* MAXTHREADNAMESIZE */
int err;
/* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
dynamic_pthread_setname_np = dlsym(RTLD_DEFAULT, "pthread_setname_np");
if (dynamic_pthread_setname_np == NULL)
return -ENOSYS;
strncpy(namebuf, name, sizeof(namebuf) - 1);
namebuf[sizeof(namebuf) - 1] = '\0';
err = dynamic_pthread_setname_np(namebuf);
if (err)
return -err;
return 0;
}
int uv__set_process_title(const char* title) {
#if TARGET_OS_IPHONE
return uv__pthread_setname_np(title);
#else
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
const char*,
CFStringEncoding);
CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
CFTypeRef (*pLSGetCurrentApplicationASN)(void);
OSStatus (*pLSSetApplicationInformationItem)(int,
CFTypeRef,
CFStringRef,
CFStringRef,
CFDictionaryRef*);
void* application_services_handle;
void* core_foundation_handle;
CFBundleRef launch_services_bundle;
CFStringRef* display_name_key;
CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
CFBundleRef (*pCFBundleGetMainBundle)(void);
CFBundleRef hi_services_bundle;
OSStatus (*pSetApplicationIsDaemon)(int);
CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
void*);
CFTypeRef asn;
int err;
err = -ENOENT;
application_services_handle = dlopen("/System/Library/Frameworks/"
"ApplicationServices.framework/"
"Versions/A/ApplicationServices",
RTLD_LAZY | RTLD_LOCAL);
core_foundation_handle = dlopen("/System/Library/Frameworks/"
"CoreFoundation.framework/"
"Versions/A/CoreFoundation",
RTLD_LAZY | RTLD_LOCAL);
if (application_services_handle == NULL || core_foundation_handle == NULL)
goto out;
pCFStringCreateWithCString =
dlsym(core_foundation_handle, "CFStringCreateWithCString");
pCFBundleGetBundleWithIdentifier =
dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
pCFBundleGetDataPointerForName =
dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
pCFBundleGetFunctionPointerForName =
dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");
if (pCFStringCreateWithCString == NULL ||
pCFBundleGetBundleWithIdentifier == NULL ||
pCFBundleGetDataPointerForName == NULL ||
pCFBundleGetFunctionPointerForName == NULL) {
goto out;
}
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
launch_services_bundle =
pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
if (launch_services_bundle == NULL)
goto out;
pLSGetCurrentApplicationASN =
pCFBundleGetFunctionPointerForName(launch_services_bundle,
S("_LSGetCurrentApplicationASN"));
if (pLSGetCurrentApplicationASN == NULL)
goto out;
pLSSetApplicationInformationItem =
pCFBundleGetFunctionPointerForName(launch_services_bundle,
S("_LSSetApplicationInformationItem"));
if (pLSSetApplicationInformationItem == NULL)
goto out;
display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle,
S("_kLSDisplayNameKey"));
if (display_name_key == NULL || *display_name_key == NULL)
goto out;
pCFBundleGetInfoDictionary = dlsym(core_foundation_handle,
"CFBundleGetInfoDictionary");
pCFBundleGetMainBundle = dlsym(core_foundation_handle,
"CFBundleGetMainBundle");
if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
goto out;
/* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
hi_services_bundle =
pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
err = -ENOENT;
if (hi_services_bundle == NULL)
goto out;
pSetApplicationIsDaemon = pCFBundleGetFunctionPointerForName(
hi_services_bundle,
S("SetApplicationIsDaemon"));
pLSApplicationCheckIn = pCFBundleGetFunctionPointerForName(
launch_services_bundle,
S("_LSApplicationCheckIn"));
pLSSetApplicationLaunchServicesServerConnectionStatus =
pCFBundleGetFunctionPointerForName(
launch_services_bundle,
S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
if (pSetApplicationIsDaemon == NULL ||
pLSApplicationCheckIn == NULL ||
pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
goto out;
}
if (pSetApplicationIsDaemon(1) != noErr)
goto out;
pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
/* Check into process manager?! */
pLSApplicationCheckIn(-2,
pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
asn = pLSGetCurrentApplicationASN();
err = -EINVAL;
if (pLSSetApplicationInformationItem(-2, /* Magic value. */
asn,
*display_name_key,
S(title),
NULL) != noErr) {
goto out;
}
uv__pthread_setname_np(title); /* Don't care if it fails. */
err = 0;
out:
if (core_foundation_handle != NULL)
dlclose(core_foundation_handle);
if (application_services_handle != NULL)
dlclose(application_services_handle);
return err;
#endif /* !TARGET_OS_IPHONE */
}

View File

@ -27,8 +27,7 @@
#include <ifaddrs.h>
#include <net/if.h>
#include <CoreFoundation/CFRunLoop.h>
#include <net/if_dl.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
@ -37,151 +36,28 @@
#include <sys/sysctl.h>
#include <unistd.h> /* sysconf */
/* Forward declarations */
static void uv__cf_loop_runner(void* arg);
static void uv__cf_loop_cb(void* arg);
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
struct uv__cf_loop_signal_s {
void* arg;
cf_loop_signal_cb cb;
ngx_queue_t member;
};
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
CFRunLoopSourceContext ctx;
int r;
loop->cf_state = NULL;
if (uv__kqueue_init(loop))
return -1;
loop->cf_loop = NULL;
if ((r = uv_mutex_init(&loop->cf_mutex)))
return r;
if ((r = uv_sem_init(&loop->cf_sem, 0)))
return r;
ngx_queue_init(&loop->cf_signals);
memset(&ctx, 0, sizeof(ctx));
ctx.info = loop;
ctx.perform = uv__cf_loop_cb;
loop->cf_cb = CFRunLoopSourceCreate(NULL, 0, &ctx);
if ((r = uv_thread_create(&loop->cf_thread, uv__cf_loop_runner, loop)))
return r;
/* Synchronize threads */
uv_sem_wait(&loop->cf_sem);
assert(ACCESS_ONCE(CFRunLoopRef, loop->cf_loop) != NULL);
return -errno;
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
ngx_queue_t* item;
uv__cf_loop_signal_t* s;
assert(loop->cf_loop != NULL);
uv__cf_loop_signal(loop, NULL, NULL);
uv_thread_join(&loop->cf_thread);
uv_sem_destroy(&loop->cf_sem);
uv_mutex_destroy(&loop->cf_mutex);
/* Free any remaining data */
while (!ngx_queue_empty(&loop->cf_signals)) {
item = ngx_queue_head(&loop->cf_signals);
s = ngx_queue_data(item, uv__cf_loop_signal_t, member);
ngx_queue_remove(item);
free(s);
}
uv__fsevents_loop_delete(loop);
}
static void uv__cf_loop_runner(void* arg) {
uv_loop_t* loop;
uint64_t uv__hrtime(uv_clocktype_t type) {
static mach_timebase_info_data_t info;
loop = arg;
/* Get thread's loop */
ACCESS_ONCE(CFRunLoopRef, loop->cf_loop) = CFRunLoopGetCurrent();
CFRunLoopAddSource(loop->cf_loop,
loop->cf_cb,
kCFRunLoopDefaultMode);
uv_sem_post(&loop->cf_sem);
CFRunLoopRun();
CFRunLoopRemoveSource(loop->cf_loop,
loop->cf_cb,
kCFRunLoopDefaultMode);
}
static void uv__cf_loop_cb(void* arg) {
uv_loop_t* loop;
ngx_queue_t* item;
ngx_queue_t split_head;
uv__cf_loop_signal_t* s;
loop = arg;
uv_mutex_lock(&loop->cf_mutex);
ngx_queue_init(&split_head);
if (!ngx_queue_empty(&loop->cf_signals)) {
ngx_queue_t* split_pos = ngx_queue_next(&loop->cf_signals);
ngx_queue_split(&loop->cf_signals, split_pos, &split_head);
}
uv_mutex_unlock(&loop->cf_mutex);
while (!ngx_queue_empty(&split_head)) {
item = ngx_queue_head(&split_head);
s = ngx_queue_data(item, uv__cf_loop_signal_t, member);
/* This was a termination signal */
if (s->cb == NULL)
CFRunLoopStop(loop->cf_loop);
else
s->cb(s->arg);
ngx_queue_remove(item);
free(s);
}
}
void uv__cf_loop_signal(uv_loop_t* loop, cf_loop_signal_cb cb, void* arg) {
uv__cf_loop_signal_t* item;
item = malloc(sizeof(*item));
/* XXX: Fail */
if (item == NULL)
abort();
item->arg = arg;
item->cb = cb;
uv_mutex_lock(&loop->cf_mutex);
ngx_queue_insert_tail(&loop->cf_signals, &item->member);
uv_mutex_unlock(&loop->cf_mutex);
assert(loop->cf_loop != NULL);
CFRunLoopSourceSignal(loop->cf_cb);
CFRunLoopWakeUp(loop->cf_loop);
}
uint64_t uv__hrtime(void) {
mach_timebase_info_data_t info;
if (mach_timebase_info(&info) != KERN_SUCCESS)
if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
ACCESS_ONCE(uint32_t, info.denom) == 0) &&
mach_timebase_info(&info) != KERN_SUCCESS)
abort();
return mach_absolute_time() * info.numer / info.denom;
@ -194,20 +70,18 @@ int uv_exepath(char* buffer, size_t* size) {
char* path;
char* fullpath;
if (!buffer || !size) {
return -1;
}
if (buffer == NULL || size == NULL)
return -EINVAL;
usize = *size;
result = _NSGetExecutablePath(buffer, &usize);
if (result) return result;
path = (char*)malloc(2 * PATH_MAX);
path = malloc(2 * PATH_MAX);
fullpath = realpath(buffer, path);
if (fullpath == NULL) {
free(path);
return -1;
SAVE_ERRNO(free(path));
return -errno;
}
strncpy(buffer, fullpath, *size);
@ -223,7 +97,7 @@ uint64_t uv_get_free_memory(void) {
if (host_statistics(mach_host_self(), HOST_VM_INFO,
(host_info_t)&info, &count) != KERN_SUCCESS) {
return -1;
return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
}
return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
@ -235,9 +109,8 @@ uint64_t uv_get_total_memory(void) {
int which[] = {CTL_HW, HW_MEMSIZE};
size_t size = sizeof(info);
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
return (uint64_t) info;
}
@ -256,7 +129,7 @@ void uv_loadavg(double avg[3]) {
}
uv_err_t uv_resident_set_memory(size_t* rss) {
int uv_resident_set_memory(size_t* rss) {
mach_msg_type_number_t count;
task_basic_info_data_t info;
kern_return_t err;
@ -273,27 +146,26 @@ uv_err_t uv_resident_set_memory(size_t* rss) {
assert(err == KERN_SUCCESS);
*rss = info.resident_size;
return uv_ok_;
return 0;
}
uv_err_t uv_uptime(double* uptime) {
int uv_uptime(double* uptime) {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return uv__new_sys_error(errno);
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
now = time(NULL);
*uptime = now - info.tv_sec;
*uptime = (double)(now - info.tv_sec);
return uv_ok_;
return 0;
}
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks);
char model[512];
@ -306,25 +178,24 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
size = sizeof(model);
if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) < 0 &&
sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) {
return uv__new_sys_error(errno);
if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
sysctlbyname("hw.model", &model, &size, NULL, 0)) {
return -errno;
}
size = sizeof(cpuspeed);
if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0) < 0) {
return uv__new_sys_error(errno);
}
if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0))
return -errno;
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
(processor_info_array_t*)&info,
&msg_type) != KERN_SUCCESS) {
return uv__new_sys_error(errno);
return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
}
*cpu_infos = (uv_cpu_info_t*)malloc(numcpus * sizeof(uv_cpu_info_t));
if (!(*cpu_infos)) {
return uv__new_artificial_error(UV_ENOMEM);
}
*cpu_infos = malloc(numcpus * sizeof(**cpu_infos));
if (!(*cpu_infos))
return -ENOMEM; /* FIXME(bnoordhuis) Deallocate info? */
*count = numcpus;
@ -342,7 +213,7 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
}
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
return uv_ok_;
return 0;
}
@ -357,21 +228,20 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
}
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
int* count) {
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifaddrs *addrs, *ent;
char ip[INET6_ADDRSTRLEN];
uv_interface_address_t* address;
int i;
struct sockaddr_dl *sa_addr;
if (getifaddrs(&addrs) != 0) {
return uv__new_sys_error(errno);
}
if (getifaddrs(&addrs))
return -errno;
*count = 0;
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) ||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family == AF_LINK)) {
continue;
@ -380,48 +250,67 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
(*count)++;
}
*addresses = (uv_interface_address_t*)
malloc(*count * sizeof(uv_interface_address_t));
if (!(*addresses)) {
return uv__new_artificial_error(UV_ENOMEM);
}
*addresses = malloc(*count * sizeof(**addresses));
if (!(*addresses))
return -ENOMEM;
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
bzero(&ip, sizeof (ip));
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
continue;
}
if (ent->ifa_addr == NULL) {
if (ent->ifa_addr == NULL)
continue;
}
/*
* On Mac OS X getifaddrs returns information related to Mac Addresses for
* various devices, such as firewire, etc. These are not relevant here.
*/
if (ent->ifa_addr->sa_family == AF_LINK) {
if (ent->ifa_addr->sa_family == AF_LINK)
continue;
}
address->name = strdup(ent->ifa_name);
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6 *)ent->ifa_addr);
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
} else {
address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr);
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
address->is_internal = ent->ifa_flags & IFF_LOOPBACK ? 1 : 0;
if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
}
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
address++;
}
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family != AF_LINK)) {
continue;
}
address = *addresses;
for (i = 0; i < (*count); i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
}
address++;
}
}
freeifaddrs(addrs);
return uv_ok_;
return 0;
}

View File

@ -59,13 +59,13 @@ int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
}
const char* uv_dlerror(uv_lib_t* lib) {
const char* uv_dlerror(const uv_lib_t* lib) {
return lib->errmsg ? lib->errmsg : "no error";
}
static int uv__dlerror(uv_lib_t* lib) {
char* errmsg;
const char* errmsg;
if (lib->errmsg)
free(lib->errmsg);

View File

@ -25,6 +25,10 @@
#include <string.h>
#include <errno.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <kvm.h>
#include <paths.h>
#include <sys/user.h>
@ -63,7 +67,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
uint64_t uv__hrtime(void) {
uint64_t uv__hrtime(uv_clocktype_t type) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
@ -74,9 +78,8 @@ int uv_exepath(char* buffer, size_t* size) {
int mib[4];
size_t cb;
if (!buffer || !size) {
return -1;
}
if (buffer == NULL || size == NULL)
return -EINVAL;
#ifdef __DragonFly__
mib[0] = CTL_KERN;
@ -91,10 +94,8 @@ int uv_exepath(char* buffer, size_t* size) {
#endif
cb = *size;
if (sysctl(mib, 4, buffer, &cb, NULL, 0) < 0) {
*size = 0;
return -1;
}
if (sysctl(mib, 4, buffer, &cb, NULL, 0))
return -errno;
*size = strlen(buffer);
return 0;
@ -105,10 +106,9 @@ uint64_t uv_get_free_memory(void) {
int freecount;
size_t size = sizeof(freecount);
if(sysctlbyname("vm.stats.vm.v_free_count",
&freecount, &size, NULL, 0) == -1){
return -1;
}
if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
return -errno;
return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
}
@ -120,9 +120,8 @@ uint64_t uv_get_total_memory(void) {
size_t size = sizeof(info);
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
return (uint64_t) info;
}
@ -147,7 +146,7 @@ char** uv_setup_args(int argc, char** argv) {
}
uv_err_t uv_set_process_title(const char* title) {
int uv_set_process_title(const char* title) {
int oid[4];
if (process_title) free(process_title);
@ -165,11 +164,11 @@ uv_err_t uv_set_process_title(const char* title) {
process_title,
strlen(process_title) + 1);
return uv_ok_;
return 0;
}
uv_err_t uv_get_process_title(char* buffer, size_t size) {
int uv_get_process_title(char* buffer, size_t size) {
if (process_title) {
strncpy(buffer, process_title, size);
} else {
@ -178,11 +177,11 @@ uv_err_t uv_get_process_title(char* buffer, size_t size) {
}
}
return uv_ok_;
return 0;
}
uv_err_t uv_resident_set_memory(size_t* rss) {
int uv_resident_set_memory(size_t* rss) {
kvm_t *kd = NULL;
struct kinfo_proc *kinfo = NULL;
pid_t pid;
@ -205,32 +204,31 @@ uv_err_t uv_resident_set_memory(size_t* rss) {
kvm_close(kd);
return uv_ok_;
return 0;
error:
if (kd) kvm_close(kd);
return uv__new_sys_error(errno);
return -EPERM;
}
uv_err_t uv_uptime(double* uptime) {
int uv_uptime(double* uptime) {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return uv__new_sys_error(errno);
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
now = time(NULL);
*uptime = (double)(now - info.tv_sec);
return uv_ok_;
return 0;
}
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
cur = 0;
@ -256,32 +254,32 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
#endif
size = sizeof(model);
if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) {
return uv__new_sys_error(errno);
}
size = sizeof(numcpus);
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0) < 0) {
return uv__new_sys_error(errno);
}
if (sysctlbyname("hw.model", &model, &size, NULL, 0))
return -errno;
*cpu_infos = (uv_cpu_info_t*)malloc(numcpus * sizeof(uv_cpu_info_t));
if (!(*cpu_infos)) {
return uv__new_artificial_error(UV_ENOMEM);
}
size = sizeof(numcpus);
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
return -errno;
*cpu_infos = malloc(numcpus * sizeof(**cpu_infos));
if (!(*cpu_infos))
return -ENOMEM;
*count = numcpus;
size = sizeof(cpuspeed);
if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0) < 0) {
free(*cpu_infos);
return uv__new_sys_error(errno);
if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) {
SAVE_ERRNO(free(*cpu_infos));
return -errno;
}
/* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of ncpu */
/* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
* ncpu.
*/
size = sizeof(maxcpus);
if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0) < 0) {
free(*cpu_infos);
return uv__new_sys_error(errno);
if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
SAVE_ERRNO(free(*cpu_infos));
return -errno;
}
size = maxcpus * CPUSTATES * sizeof(long);
@ -289,13 +287,13 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cp_times = malloc(size);
if (cp_times == NULL) {
free(*cpu_infos);
return uv__new_sys_error(ENOMEM);
return -ENOMEM;
}
if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0) < 0) {
free(cp_times);
free(*cpu_infos);
return uv__new_sys_error(errno);
if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
SAVE_ERRNO(free(cp_times));
SAVE_ERRNO(free(*cpu_infos));
return -errno;
}
for (i = 0; i < numcpus; i++) {
@ -314,7 +312,7 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
}
free(cp_times);
return uv_ok_;
return 0;
}
@ -329,15 +327,99 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
}
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
int* count) {
/* TODO: implement */
*addresses = NULL;
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifaddrs *addrs, *ent;
uv_interface_address_t* address;
int i;
struct sockaddr_dl *sa_addr;
if (getifaddrs(&addrs))
return -errno;
*count = 0;
return uv_ok_;
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family == AF_LINK)) {
continue;
}
(*count)++;
}
*addresses = malloc(*count * sizeof(**addresses));
if (!(*addresses))
return -ENOMEM;
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
continue;
if (ent->ifa_addr == NULL)
continue;
/*
* On FreeBSD getifaddrs returns information related to the raw underlying
* devices. We're not interested in this information yet.
*/
if (ent->ifa_addr->sa_family == AF_LINK)
continue;
address->name = strdup(ent->ifa_name);
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
} else {
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
}
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
address++;
}
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family != AF_LINK)) {
continue;
}
address = *addresses;
for (i = 0; i < (*count); i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
}
address++;
}
}
freeifaddrs(addrs);
return 0;
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; i++) {
free(addresses[i].name);
}
free(addresses);
}

View File

@ -19,6 +19,13 @@
* IN THE SOFTWARE.
*/
/* Caveat emptor: this file deviates from the libuv convention of returning
* negated errno codes. Most uv_fs_*() functions map directly to the system
* call of the same name. For more complex wrappers, it's easier to just
* return -1 with errno set. The dispatcher in uv__fs_work() takes care of
* getting the errno to the right place (req->result or as the return value.)
*/
#include "uv.h"
#include "internal.h"
@ -31,16 +38,39 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <pthread.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <utime.h>
#include <poll.h>
#if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
# define HAVE_PREADV 1
#elif defined(__linux__)
# include <linux/version.h>
# if defined(__GLIBC_PREREQ)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) && \
__GLIBC_PREREQ(2,10)
# define HAVE_PREADV 1
# else
# define HAVE_PREADV 0
# endif
# else
# define HAVE_PREADV 0
# endif
#else
# define HAVE_PREADV 0
#endif
#if defined(__linux__) || defined(__sun)
# include <sys/sendfile.h>
#elif defined(__APPLE__) || defined(__FreeBSD__)
# include <sys/socket.h>
#endif
#if HAVE_PREADV || defined(__APPLE__)
# include <sys/uio.h>
#endif
@ -48,7 +78,6 @@
do { \
uv__req_init((loop), (req), UV_FS); \
(req)->fs_type = UV_FS_ ## type; \
(req)->errorno = 0; \
(req)->result = 0; \
(req)->ptr = NULL; \
(req)->loop = loop; \
@ -60,8 +89,9 @@
#define PATH \
do { \
if (NULL == ((req)->path = strdup((path)))) \
return uv__set_sys_error((loop), ENOMEM); \
(req)->path = strdup(path); \
if ((req)->path == NULL) \
return -ENOMEM; \
} \
while (0)
@ -69,13 +99,11 @@
do { \
size_t path_len; \
size_t new_path_len; \
\
path_len = strlen((path)) + 1; \
new_path_len = strlen((new_path)) + 1; \
\
if (NULL == ((req)->path = malloc(path_len + new_path_len))) \
return uv__set_sys_error((loop), ENOMEM); \
\
(req)->path = malloc(path_len + new_path_len); \
if ((req)->path == NULL) \
return -ENOMEM; \
(req)->new_path = (req)->path + path_len; \
memcpy((void*) (req)->path, (path), path_len); \
memcpy((void*) (req)->new_path, (new_path), new_path_len); \
@ -165,13 +193,19 @@ skip:
#elif defined(__APPLE__) \
|| defined(__DragonFly__) \
|| defined(__FreeBSD__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__) \
|| defined(__sun)
struct timeval tv[2];
tv[0].tv_sec = req->atime;
tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
tv[1].tv_sec = req->mtime;
tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
# if defined(__sun)
return futimesat(req->file, NULL, tv);
# else
return futimes(req->file, tv);
# endif
#else
errno = ENOSYS;
return -1;
@ -179,27 +213,100 @@ skip:
}
static ssize_t uv__fs_read(uv_fs_t* req) {
if (req->off < 0)
return read(req->file, req->buf, req->len);
else
return pread(req->file, req->buf, req->len, req->off);
static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
return mkdtemp((char*) req->path) ? 0 : -1;
}
static int uv__fs_readdir_filter(const struct dirent* dent) {
static ssize_t uv__fs_read(uv_fs_t* req) {
ssize_t result;
#if defined(_AIX)
struct stat buf;
if(fstat(req->file, &buf))
return -1;
if(S_ISDIR(buf.st_mode)) {
errno = EISDIR;
return -1;
}
#endif /* defined(_AIX) */
if (req->off < 0) {
if (req->nbufs == 1)
result = read(req->file, req->bufs[0].base, req->bufs[0].len);
else
result = readv(req->file, (struct iovec*) req->bufs, req->nbufs);
} else {
if (req->nbufs == 1) {
result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
goto done;
}
#if HAVE_PREADV
result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if defined(__linux__)
static int no_preadv;
if (no_preadv)
# endif
{
off_t nread;
size_t index;
# if defined(__linux__)
retry:
# endif
nread = 0;
index = 0;
result = 1;
do {
if (req->bufs[index].len > 0) {
result = pread(req->file,
req->bufs[index].base,
req->bufs[index].len,
req->off + nread);
if (result > 0)
nread += result;
}
index++;
} while (index < req->nbufs && result > 0);
if (nread > 0)
result = nread;
}
# if defined(__linux__)
else {
result = uv__preadv(req->file,
(struct iovec*)req->bufs,
req->nbufs,
req->off);
if (result == -1 && errno == ENOSYS) {
no_preadv = 1;
goto retry;
}
}
# endif
#endif
}
done:
if (req->bufs != req->bufsml)
free(req->bufs);
return result;
}
#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8))
static int uv__fs_readdir_filter(uv__dirent_t* dent) {
#else
static int uv__fs_readdir_filter(const uv__dirent_t* dent) {
#endif
return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
}
/* This should have been called uv__fs_scandir(). */
static ssize_t uv__fs_readdir(uv_fs_t* req) {
struct dirent **dents;
uv__dirent_t **dents;
int saved_errno;
size_t off;
size_t len;
char *buf;
int i;
int n;
dents = NULL;
@ -210,32 +317,17 @@ static ssize_t uv__fs_readdir(uv_fs_t* req) {
else if (n == -1)
return n;
len = 0;
/* NOTE: We will use nbufs as an index field */
req->ptr = dents;
req->nbufs = 0;
for (i = 0; i < n; i++)
len += strlen(dents[i]->d_name) + 1;
buf = malloc(len);
if (buf == NULL) {
errno = ENOMEM;
n = -1;
goto out;
}
off = 0;
for (i = 0; i < n; i++) {
len = strlen(dents[i]->d_name) + 1;
memcpy(buf + off, dents[i]->d_name, len);
off += len;
}
req->ptr = buf;
return n;
out:
saved_errno = errno;
if (dents != NULL) {
int i;
for (i = 0; i < n; i++)
free(dents[i]);
free(dents);
@ -295,7 +387,7 @@ static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
int out_fd;
char buf[8192];
len = req->len;
len = req->bufsml[0].len;
in_fd = req->flags;
out_fd = req->file;
offset = req->off;
@ -408,7 +500,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
ssize_t r;
off = req->off;
r = sendfile(out_fd, in_fd, &off, req->len);
r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len);
/* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
* it still writes out data. Fortunately, we can detect it by checking if
@ -442,11 +534,11 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
#if defined(__FreeBSD__)
len = 0;
r = sendfile(in_fd, out_fd, req->off, req->len, NULL, &len, 0);
r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
#else
/* The darwin sendfile takes len as an input for the length to send,
* so make sure to initialize it with the caller's value. */
len = req->len;
len = req->bufsml[0].len;
r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
#endif
@ -466,6 +558,10 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
return -1;
}
#else
/* Squelch compiler warnings. */
(void) &in_fd;
(void) &out_fd;
return uv__fs_sendfile_emul(req);
#endif
}
@ -491,23 +587,167 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
pthread_mutex_lock(&lock);
#endif
if (req->off < 0)
r = write(req->file, req->buf, req->len);
if (req->off < 0) {
if (req->nbufs == 1)
r = write(req->file, req->bufs[0].base, req->bufs[0].len);
else
r = pwrite(req->file, req->buf, req->len, req->off);
r = writev(req->file, (struct iovec*) req->bufs, req->nbufs);
} else {
if (req->nbufs == 1) {
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
goto done;
}
#if HAVE_PREADV
r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if defined(__linux__)
static int no_pwritev;
if (no_pwritev)
# endif
{
off_t written;
size_t index;
# if defined(__linux__)
retry:
# endif
written = 0;
index = 0;
r = 0;
do {
if (req->bufs[index].len > 0) {
r = pwrite(req->file,
req->bufs[index].base,
req->bufs[index].len,
req->off + written);
if (r > 0)
written += r;
}
index++;
} while (index < req->nbufs && r >= 0);
if (written > 0)
r = written;
}
# if defined(__linux__)
else {
r = uv__pwritev(req->file,
(struct iovec*) req->bufs,
req->nbufs,
req->off);
if (r == -1 && errno == ENOSYS) {
no_pwritev = 1;
goto retry;
}
}
# endif
#endif
}
done:
#if defined(__APPLE__)
pthread_mutex_unlock(&lock);
#endif
if (req->bufs != req->bufsml)
free(req->bufs);
return r;
}
static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_dev = src->st_dev;
dst->st_mode = src->st_mode;
dst->st_nlink = src->st_nlink;
dst->st_uid = src->st_uid;
dst->st_gid = src->st_gid;
dst->st_rdev = src->st_rdev;
dst->st_ino = src->st_ino;
dst->st_size = src->st_size;
dst->st_blksize = src->st_blksize;
dst->st_blocks = src->st_blocks;
#if defined(__APPLE__)
dst->st_atim.tv_sec = src->st_atimespec.tv_sec;
dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec;
dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec;
dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec;
dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec;
dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec;
dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec;
dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec;
dst->st_flags = src->st_flags;
dst->st_gen = src->st_gen;
#elif !defined(_AIX) && \
(defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE))
dst->st_atim.tv_sec = src->st_atim.tv_sec;
dst->st_atim.tv_nsec = src->st_atim.tv_nsec;
dst->st_mtim.tv_sec = src->st_mtim.tv_sec;
dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
# if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
dst->st_flags = src->st_flags;
dst->st_gen = src->st_gen;
# else
dst->st_birthtim.tv_sec = src->st_ctim.tv_sec;
dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec;
dst->st_flags = 0;
dst->st_gen = 0;
# endif
#else
dst->st_atim.tv_sec = src->st_atime;
dst->st_atim.tv_nsec = 0;
dst->st_mtim.tv_sec = src->st_mtime;
dst->st_mtim.tv_nsec = 0;
dst->st_ctim.tv_sec = src->st_ctime;
dst->st_ctim.tv_nsec = 0;
dst->st_birthtim.tv_sec = src->st_ctime;
dst->st_birthtim.tv_nsec = 0;
dst->st_flags = 0;
dst->st_gen = 0;
#endif
}
static int uv__fs_stat(const char *path, uv_stat_t *buf) {
struct stat pbuf;
int ret;
ret = stat(path, &pbuf);
uv__to_stat(&pbuf, buf);
return ret;
}
static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
struct stat pbuf;
int ret;
ret = lstat(path, &pbuf);
uv__to_stat(&pbuf, buf);
return ret;
}
static int uv__fs_fstat(int fd, uv_stat_t *buf) {
struct stat pbuf;
int ret;
ret = fstat(fd, &pbuf);
uv__to_stat(&pbuf, buf);
return ret;
}
static void uv__fs_work(struct uv__work* w) {
int retry_on_eintr;
uv_fs_t* req;
ssize_t r;
#ifdef O_CLOEXEC
static int no_cloexec_support;
#endif /* O_CLOEXEC */
req = container_of(w, uv_fs_t, work_req);
retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
@ -527,25 +767,54 @@ static void uv__fs_work(struct uv__work* w) {
X(FCHMOD, fchmod(req->file, req->mode));
X(FCHOWN, fchown(req->file, req->uid, req->gid));
X(FDATASYNC, uv__fs_fdatasync(req));
X(FSTAT, fstat(req->file, &req->statbuf));
X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
X(FSYNC, fsync(req->file));
X(FTRUNCATE, ftruncate(req->file, req->off));
X(FUTIME, uv__fs_futime(req));
X(LSTAT, lstat(req->path, &req->statbuf));
X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
X(LINK, link(req->path, req->new_path));
X(MKDIR, mkdir(req->path, req->mode));
X(OPEN, open(req->path, req->flags, req->mode));
X(MKDTEMP, uv__fs_mkdtemp(req));
X(READ, uv__fs_read(req));
X(READDIR, uv__fs_readdir(req));
X(READLINK, uv__fs_readlink(req));
X(RENAME, rename(req->path, req->new_path));
X(RMDIR, rmdir(req->path));
X(SENDFILE, uv__fs_sendfile(req));
X(STAT, stat(req->path, &req->statbuf));
X(STAT, uv__fs_stat(req->path, &req->statbuf));
X(SYMLINK, symlink(req->path, req->new_path));
X(UNLINK, unlink(req->path));
X(UTIME, uv__fs_utime(req));
X(WRITE, uv__fs_write(req));
case UV_FS_OPEN:
#ifdef O_CLOEXEC
/* Try O_CLOEXEC before entering locks */
if (!no_cloexec_support) {
r = open(req->path, req->flags | O_CLOEXEC, req->mode);
if (r >= 0)
break;
if (errno != EINVAL)
break;
no_cloexec_support = 1;
}
#endif /* O_CLOEXEC */
if (req->cb != NULL)
uv_rwlock_rdlock(&req->loop->cloexec_lock);
r = open(req->path, req->flags, req->mode);
/*
* In case of failure `uv__cloexec` will leave error in `errno`,
* so it is enough to just set `r` to `-1`.
*/
if (r >= 0 && uv__cloexec(r, 1) != 0) {
r = uv__close(r);
if (r != 0 && r != -EINPROGRESS)
abort();
r = -1;
}
if (req->cb != NULL)
uv_rwlock_rdunlock(&req->loop->cloexec_lock);
break;
default: abort();
}
@ -553,7 +822,9 @@ static void uv__fs_work(struct uv__work* w) {
}
while (r == -1 && errno == EINTR && retry_on_eintr);
req->errorno = errno;
if (r == -1)
req->result = -errno;
else
req->result = r;
if (r == 0 && (req->fs_type == UV_FS_STAT ||
@ -570,15 +841,9 @@ static void uv__fs_done(struct uv__work* w, int status) {
req = container_of(w, uv_fs_t, work_req);
uv__req_unregister(req->loop, req);
if (req->errorno != 0) {
req->errorno = uv_translate_sys_error(req->errorno);
uv__set_artificial_error(req->loop, req->errorno);
}
if (status == -UV_ECANCELED) {
assert(req->errorno == 0);
req->errorno = UV_ECANCELED;
uv__set_artificial_error(req->loop, UV_ECANCELED);
if (status == -ECANCELED) {
assert(req->result == 0);
req->result = -ECANCELED;
}
if (req->cb != NULL)
@ -722,6 +987,18 @@ int uv_fs_mkdir(uv_loop_t* loop,
}
int uv_fs_mkdtemp(uv_loop_t* loop,
uv_fs_t* req,
const char* tpl,
uv_fs_cb cb) {
INIT(MKDTEMP);
req->path = strdup(tpl);
if (req->path == NULL)
return -ENOMEM;
POST;
}
int uv_fs_open(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
@ -738,14 +1015,23 @@ int uv_fs_open(uv_loop_t* loop,
int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
uv_file file,
void* buf,
size_t len,
const uv_buf_t bufs[],
unsigned int nbufs,
int64_t off,
uv_fs_cb cb) {
INIT(READ);
req->file = file;
req->buf = buf;
req->len = len;
req->nbufs = nbufs;
req->bufs = req->bufsml;
if (nbufs > ARRAY_SIZE(req->bufsml))
req->bufs = malloc(nbufs * sizeof(*bufs));
if (req->bufs == NULL)
return -ENOMEM;
memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
req->off = off;
POST;
}
@ -802,7 +1088,7 @@ int uv_fs_sendfile(uv_loop_t* loop,
req->flags = in_fd; /* hack */
req->file = out_fd;
req->off = off;
req->len = len;
req->bufsml[0].len = len;
POST;
}
@ -851,14 +1137,23 @@ int uv_fs_utime(uv_loop_t* loop,
int uv_fs_write(uv_loop_t* loop,
uv_fs_t* req,
uv_file file,
void* buf,
size_t len,
const uv_buf_t bufs[],
unsigned int nbufs,
int64_t off,
uv_fs_cb cb) {
INIT(WRITE);
req->file = file;
req->buf = buf;
req->len = len;
req->nbufs = nbufs;
req->bufs = req->bufsml;
if (nbufs > ARRAY_SIZE(req->bufsml))
req->bufs = malloc(nbufs * sizeof(*bufs));
if (req->bufs == NULL)
return -ENOMEM;
memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
req->off = off;
POST;
}
@ -869,6 +1164,9 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
req->path = NULL;
req->new_path = NULL;
if (req->fs_type == UV_FS_READDIR && req->ptr != NULL)
uv__fs_readdir_cleanup(req);
if (req->ptr != &req->statbuf)
free(req->ptr);
req->ptr = NULL;

View File

@ -0,0 +1,899 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#if TARGET_OS_IPHONE
/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
int uv__fsevents_init(uv_fs_event_t* handle) {
return 0;
}
int uv__fsevents_close(uv_fs_event_t* handle) {
return 0;
}
void uv__fsevents_loop_delete(uv_loop_t* loop) {
}
#else /* TARGET_OS_IPHONE */
#include <dlfcn.h>
#include <assert.h>
#include <stdlib.h>
#include <pthread.h>
#include <CoreFoundation/CFRunLoop.h>
#include <CoreServices/CoreServices.h>
/* These are macros to avoid "initializer element is not constant" errors
* with old versions of gcc.
*/
#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
kFSEventStreamEventFlagItemModified | \
kFSEventStreamEventFlagItemInodeMetaMod | \
kFSEventStreamEventFlagItemChangeOwner | \
kFSEventStreamEventFlagItemXattrMod)
#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
kFSEventStreamEventFlagItemRemoved | \
kFSEventStreamEventFlagItemRenamed)
#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
kFSEventStreamEventFlagKernelDropped | \
kFSEventStreamEventFlagEventIdsWrapped | \
kFSEventStreamEventFlagHistoryDone | \
kFSEventStreamEventFlagMount | \
kFSEventStreamEventFlagUnmount | \
kFSEventStreamEventFlagRootChanged)
typedef struct uv__fsevents_event_s uv__fsevents_event_t;
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
struct uv__cf_loop_signal_s {
QUEUE member;
uv_fs_event_t* handle;
};
struct uv__fsevents_event_s {
QUEUE member;
int events;
char path[1];
};
struct uv__cf_loop_state_s {
CFRunLoopRef loop;
CFRunLoopSourceRef signal_source;
int fsevent_need_reschedule;
FSEventStreamRef fsevent_stream;
uv_sem_t fsevent_sem;
uv_mutex_t fsevent_mutex;
void* fsevent_handles[2];
unsigned int fsevent_handle_count;
};
/* Forward declarations */
static void uv__cf_loop_cb(void* arg);
static void* uv__cf_loop_runner(void* arg);
static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle);
/* Lazy-loaded by uv__fsevents_global_init(). */
static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
const void**,
CFIndex,
const CFArrayCallBacks*);
static void (*pCFRelease)(CFTypeRef);
static void (*pCFRunLoopAddSource)(CFRunLoopRef,
CFRunLoopSourceRef,
CFStringRef);
static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
CFRunLoopSourceRef,
CFStringRef);
static void (*pCFRunLoopRun)(void);
static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
CFIndex,
CFRunLoopSourceContext*);
static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
static void (*pCFRunLoopStop)(CFRunLoopRef);
static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
CFAllocatorRef,
const char*);
static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
static CFStringRef (*pkCFRunLoopDefaultMode);
static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
FSEventStreamCallback,
FSEventStreamContext*,
CFArrayRef,
FSEventStreamEventId,
CFTimeInterval,
FSEventStreamCreateFlags);
static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
static void (*pFSEventStreamRelease)(FSEventStreamRef);
static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
CFRunLoopRef,
CFStringRef);
static Boolean (*pFSEventStreamStart)(FSEventStreamRef);
static void (*pFSEventStreamStop)(FSEventStreamRef);
#define UV__FSEVENTS_PROCESS(handle, block) \
do { \
QUEUE events; \
QUEUE* q; \
uv__fsevents_event_t* event; \
int err; \
uv_mutex_lock(&(handle)->cf_mutex); \
/* Split-off all events and empty original queue */ \
QUEUE_INIT(&events); \
if (!QUEUE_EMPTY(&(handle)->cf_events)) { \
q = QUEUE_HEAD(&(handle)->cf_events); \
QUEUE_SPLIT(&(handle)->cf_events, q, &events); \
} \
/* Get error (if any) and zero original one */ \
err = (handle)->cf_error; \
(handle)->cf_error = 0; \
uv_mutex_unlock(&(handle)->cf_mutex); \
/* Loop through events, deallocating each after processing */ \
while (!QUEUE_EMPTY(&events)) { \
q = QUEUE_HEAD(&events); \
event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
QUEUE_REMOVE(q); \
/* NOTE: Checking uv__is_active() is required here, because handle \
* callback may close handle and invoking it after it will lead to \
* incorrect behaviour */ \
if (!uv__is_closing((handle)) && uv__is_active((handle))) \
block \
/* Free allocated data */ \
free(event); \
} \
if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
(handle)->cb((handle), NULL, 0, err); \
} while (0)
/* Runs in UV loop's thread, when there're events to report to handle */
static void uv__fsevents_cb(uv_async_t* cb) {
uv_fs_event_t* handle;
handle = cb->data;
UV__FSEVENTS_PROCESS(handle, {
handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
});
}
/* Runs in CF thread, pushed event into handle's event list */
static void uv__fsevents_push_event(uv_fs_event_t* handle,
QUEUE* events,
int err) {
assert(events != NULL || err != 0);
uv_mutex_lock(&handle->cf_mutex);
/* Concatenate two queues */
if (events != NULL)
QUEUE_ADD(&handle->cf_events, events);
/* Propagate error */
if (err != 0)
handle->cf_error = err;
uv_mutex_unlock(&handle->cf_mutex);
uv_async_send(handle->cf_cb);
}
/* Runs in CF thread, when there're events in FSEventStream */
static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
void* info,
size_t numEvents,
void* eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[]) {
size_t i;
int len;
char** paths;
char* path;
char* pos;
uv_fs_event_t* handle;
QUEUE* q;
uv_loop_t* loop;
uv__cf_loop_state_t* state;
uv__fsevents_event_t* event;
QUEUE head;
loop = info;
state = loop->cf_state;
assert(state != NULL);
paths = eventPaths;
/* For each handle */
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_FOREACH(q, &state->fsevent_handles) {
handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
QUEUE_INIT(&head);
/* Process and filter out events */
for (i = 0; i < numEvents; i++) {
/* Ignore system events */
if (eventFlags[i] & kFSEventsSystem)
continue;
path = paths[i];
len = strlen(path);
/* Filter out paths that are outside handle's request */
if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
continue;
if (handle->realpath_len > 1 || *handle->realpath != '/') {
path += handle->realpath_len;
len -= handle->realpath_len;
/* Skip forward slash */
if (*path != '\0') {
path++;
len--;
}
}
#ifdef MAC_OS_X_VERSION_10_7
/* Ignore events with path equal to directory itself */
if (len == 0)
continue;
#endif /* MAC_OS_X_VERSION_10_7 */
/* Do not emit events from subdirectories (without option set) */
if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) {
pos = strchr(path + 1, '/');
if (pos != NULL)
continue;
}
#ifndef MAC_OS_X_VERSION_10_7
path = "";
len = 0;
#endif /* MAC_OS_X_VERSION_10_7 */
event = malloc(sizeof(*event) + len);
if (event == NULL)
break;
memset(event, 0, sizeof(*event));
memcpy(event->path, path, len + 1);
if ((eventFlags[i] & kFSEventsModified) != 0 &&
(eventFlags[i] & kFSEventsRenamed) == 0)
event->events = UV_CHANGE;
else
event->events = UV_RENAME;
QUEUE_INSERT_TAIL(&head, &event->member);
}
if (!QUEUE_EMPTY(&head))
uv__fsevents_push_event(handle, &head, 0);
}
uv_mutex_unlock(&state->fsevent_mutex);
}
/* Runs in CF thread */
static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
uv__cf_loop_state_t* state;
FSEventStreamContext ctx;
FSEventStreamRef ref;
CFAbsoluteTime latency;
FSEventStreamCreateFlags flags;
/* Initialize context */
ctx.version = 0;
ctx.info = loop;
ctx.retain = NULL;
ctx.release = NULL;
ctx.copyDescription = NULL;
latency = 0.05;
/* Explanation of selected flags:
* 1. NoDefer - without this flag, events that are happening continuously
* (i.e. each event is happening after time interval less than `latency`,
* counted from previous event), will be deferred and passed to callback
* once they'll either fill whole OS buffer, or when this continuous stream
* will stop (i.e. there'll be delay between events, bigger than
* `latency`).
* Specifying this flag will invoke callback after `latency` time passed
* since event.
* 2. FileEvents - fire callback for file changes too (by default it is firing
* it only for directory changes).
*/
flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
/*
* NOTE: It might sound like a good idea to remember last seen StreamEventId,
* but in reality one dir might have last StreamEventId less than, the other,
* that is being watched now. Which will cause FSEventStream API to report
* changes to files from the past.
*/
ref = pFSEventStreamCreate(NULL,
&uv__fsevents_event_cb,
&ctx,
paths,
kFSEventStreamEventIdSinceNow,
latency,
flags);
assert(ref != NULL);
state = loop->cf_state;
pFSEventStreamScheduleWithRunLoop(ref,
state->loop,
*pkCFRunLoopDefaultMode);
if (!pFSEventStreamStart(ref)) {
pFSEventStreamInvalidate(ref);
pFSEventStreamRelease(ref);
return -EMFILE;
}
state->fsevent_stream = ref;
return 0;
}
/* Runs in CF thread */
static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
uv__cf_loop_state_t* state;
state = loop->cf_state;
if (state->fsevent_stream == NULL)
return;
/* Flush all accumulated events */
pFSEventStreamFlushSync(state->fsevent_stream);
/* Stop emitting events */
pFSEventStreamStop(state->fsevent_stream);
/* Release stream */
pFSEventStreamInvalidate(state->fsevent_stream);
pFSEventStreamRelease(state->fsevent_stream);
state->fsevent_stream = NULL;
}
/* Runs in CF thread, when there're new fsevent handles to add to stream */
static void uv__fsevents_reschedule(uv_fs_event_t* handle) {
uv__cf_loop_state_t* state;
QUEUE* q;
uv_fs_event_t* curr;
CFArrayRef cf_paths;
CFStringRef* paths;
unsigned int i;
int err;
unsigned int path_count;
state = handle->loop->cf_state;
paths = NULL;
cf_paths = NULL;
err = 0;
/* NOTE: `i` is used in deallocation loop below */
i = 0;
/* Optimization to prevent O(n^2) time spent when starting to watch
* many files simultaneously
*/
uv_mutex_lock(&state->fsevent_mutex);
if (state->fsevent_need_reschedule == 0) {
uv_mutex_unlock(&state->fsevent_mutex);
goto final;
}
state->fsevent_need_reschedule = 0;
uv_mutex_unlock(&state->fsevent_mutex);
/* Destroy previous FSEventStream */
uv__fsevents_destroy_stream(handle->loop);
/* Any failure below will be a memory failure */
err = -ENOMEM;
/* Create list of all watched paths */
uv_mutex_lock(&state->fsevent_mutex);
path_count = state->fsevent_handle_count;
if (path_count != 0) {
paths = malloc(sizeof(*paths) * path_count);
if (paths == NULL) {
uv_mutex_unlock(&state->fsevent_mutex);
goto final;
}
q = &state->fsevent_handles;
for (; i < path_count; i++) {
q = QUEUE_NEXT(q);
assert(q != &state->fsevent_handles);
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
assert(curr->realpath != NULL);
paths[i] =
pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
if (paths[i] == NULL) {
uv_mutex_unlock(&state->fsevent_mutex);
goto final;
}
}
}
uv_mutex_unlock(&state->fsevent_mutex);
err = 0;
if (path_count != 0) {
/* Create new FSEventStream */
cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
if (cf_paths == NULL) {
err = -ENOMEM;
goto final;
}
err = uv__fsevents_create_stream(handle->loop, cf_paths);
}
final:
/* Deallocate all paths in case of failure */
if (err != 0) {
if (cf_paths == NULL) {
while (i != 0)
pCFRelease(paths[--i]);
free(paths);
} else {
/* CFArray takes ownership of both strings and original C-array */
pCFRelease(cf_paths);
}
/* Broadcast error to all handles */
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_FOREACH(q, &state->fsevent_handles) {
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
uv__fsevents_push_event(curr, NULL, err);
}
uv_mutex_unlock(&state->fsevent_mutex);
}
/*
* Main thread will block until the removal of handle from the list,
* we must tell it when we're ready.
*
* NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
*/
if (!uv__is_active(handle))
uv_sem_post(&state->fsevent_sem);
}
static int uv__fsevents_global_init(void) {
static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
static void* core_foundation_handle;
static void* core_services_handle;
int err;
err = 0;
pthread_mutex_lock(&global_init_mutex);
if (core_foundation_handle != NULL)
goto out;
/* The libraries are never unloaded because we currently don't have a good
* mechanism for keeping a reference count. It's unlikely to be an issue
* but if it ever becomes one, we can turn the dynamic library handles into
* per-event loop properties and have the dynamic linker keep track for us.
*/
err = -ENOSYS;
core_foundation_handle = dlopen("/System/Library/Frameworks/"
"CoreFoundation.framework/"
"Versions/A/CoreFoundation",
RTLD_LAZY | RTLD_LOCAL);
if (core_foundation_handle == NULL)
goto out;
core_services_handle = dlopen("/System/Library/Frameworks/"
"CoreServices.framework/"
"Versions/A/CoreServices",
RTLD_LAZY | RTLD_LOCAL);
if (core_services_handle == NULL)
goto out;
err = -ENOENT;
#define V(handle, symbol) \
do { \
p ## symbol = dlsym((handle), #symbol); \
if (p ## symbol == NULL) \
goto out; \
} \
while (0)
V(core_foundation_handle, CFArrayCreate);
V(core_foundation_handle, CFRelease);
V(core_foundation_handle, CFRunLoopAddSource);
V(core_foundation_handle, CFRunLoopGetCurrent);
V(core_foundation_handle, CFRunLoopRemoveSource);
V(core_foundation_handle, CFRunLoopRun);
V(core_foundation_handle, CFRunLoopSourceCreate);
V(core_foundation_handle, CFRunLoopSourceSignal);
V(core_foundation_handle, CFRunLoopStop);
V(core_foundation_handle, CFRunLoopWakeUp);
V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
V(core_foundation_handle, CFStringGetSystemEncoding);
V(core_foundation_handle, kCFRunLoopDefaultMode);
V(core_services_handle, FSEventStreamCreate);
V(core_services_handle, FSEventStreamFlushSync);
V(core_services_handle, FSEventStreamInvalidate);
V(core_services_handle, FSEventStreamRelease);
V(core_services_handle, FSEventStreamScheduleWithRunLoop);
V(core_services_handle, FSEventStreamStart);
V(core_services_handle, FSEventStreamStop);
#undef V
err = 0;
out:
if (err && core_services_handle != NULL) {
dlclose(core_services_handle);
core_services_handle = NULL;
}
if (err && core_foundation_handle != NULL) {
dlclose(core_foundation_handle);
core_foundation_handle = NULL;
}
pthread_mutex_unlock(&global_init_mutex);
return err;
}
/* Runs in UV loop */
static int uv__fsevents_loop_init(uv_loop_t* loop) {
CFRunLoopSourceContext ctx;
uv__cf_loop_state_t* state;
pthread_attr_t attr_storage;
pthread_attr_t* attr;
int err;
if (loop->cf_state != NULL)
return 0;
err = uv__fsevents_global_init();
if (err)
return err;
state = calloc(1, sizeof(*state));
if (state == NULL)
return -ENOMEM;
err = uv_mutex_init(&loop->cf_mutex);
if (err)
goto fail_mutex_init;
err = uv_sem_init(&loop->cf_sem, 0);
if (err)
goto fail_sem_init;
QUEUE_INIT(&loop->cf_signals);
err = uv_sem_init(&state->fsevent_sem, 0);
if (err)
goto fail_fsevent_sem_init;
err = uv_mutex_init(&state->fsevent_mutex);
if (err)
goto fail_fsevent_mutex_init;
QUEUE_INIT(&state->fsevent_handles);
state->fsevent_need_reschedule = 0;
state->fsevent_handle_count = 0;
memset(&ctx, 0, sizeof(ctx));
ctx.info = loop;
ctx.perform = uv__cf_loop_cb;
state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
if (state->signal_source == NULL) {
err = -ENOMEM;
goto fail_signal_source_create;
}
/* In the unlikely event that pthread_attr_init() fails, create the thread
* with the default stack size. We'll use a little more address space but
* that in itself is not a fatal error.
*/
attr = &attr_storage;
if (pthread_attr_init(attr))
attr = NULL;
if (attr != NULL)
if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
abort();
loop->cf_state = state;
/* uv_thread_t is an alias for pthread_t. */
err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop);
if (attr != NULL)
pthread_attr_destroy(attr);
if (err)
goto fail_thread_create;
/* Synchronize threads */
uv_sem_wait(&loop->cf_sem);
return 0;
fail_thread_create:
loop->cf_state = NULL;
fail_signal_source_create:
uv_mutex_destroy(&state->fsevent_mutex);
fail_fsevent_mutex_init:
uv_sem_destroy(&state->fsevent_sem);
fail_fsevent_sem_init:
uv_sem_destroy(&loop->cf_sem);
fail_sem_init:
uv_mutex_destroy(&loop->cf_mutex);
fail_mutex_init:
free(state);
return err;
}
/* Runs in UV loop */
void uv__fsevents_loop_delete(uv_loop_t* loop) {
uv__cf_loop_signal_t* s;
uv__cf_loop_state_t* state;
QUEUE* q;
if (loop->cf_state == NULL)
return;
if (uv__cf_loop_signal(loop, NULL) != 0)
abort();
uv_thread_join(&loop->cf_thread);
uv_sem_destroy(&loop->cf_sem);
uv_mutex_destroy(&loop->cf_mutex);
/* Free any remaining data */
while (!QUEUE_EMPTY(&loop->cf_signals)) {
q = QUEUE_HEAD(&loop->cf_signals);
s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
QUEUE_REMOVE(q);
free(s);
}
/* Destroy state */
state = loop->cf_state;
uv_sem_destroy(&state->fsevent_sem);
uv_mutex_destroy(&state->fsevent_mutex);
pCFRelease(state->signal_source);
free(state);
loop->cf_state = NULL;
}
/* Runs in CF thread. This is the CF loop's body */
static void* uv__cf_loop_runner(void* arg) {
uv_loop_t* loop;
uv__cf_loop_state_t* state;
loop = arg;
state = loop->cf_state;
state->loop = pCFRunLoopGetCurrent();
pCFRunLoopAddSource(state->loop,
state->signal_source,
*pkCFRunLoopDefaultMode);
uv_sem_post(&loop->cf_sem);
pCFRunLoopRun();
pCFRunLoopRemoveSource(state->loop,
state->signal_source,
*pkCFRunLoopDefaultMode);
return NULL;
}
/* Runs in CF thread, executed after `uv__cf_loop_signal()` */
static void uv__cf_loop_cb(void* arg) {
uv_loop_t* loop;
uv__cf_loop_state_t* state;
QUEUE* item;
QUEUE split_head;
uv__cf_loop_signal_t* s;
loop = arg;
state = loop->cf_state;
QUEUE_INIT(&split_head);
uv_mutex_lock(&loop->cf_mutex);
if (!QUEUE_EMPTY(&loop->cf_signals)) {
QUEUE* split_pos = QUEUE_HEAD(&loop->cf_signals);
QUEUE_SPLIT(&loop->cf_signals, split_pos, &split_head);
}
uv_mutex_unlock(&loop->cf_mutex);
while (!QUEUE_EMPTY(&split_head)) {
item = QUEUE_HEAD(&split_head);
s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
/* This was a termination signal */
if (s->handle == NULL)
pCFRunLoopStop(state->loop);
else
uv__fsevents_reschedule(s->handle);
QUEUE_REMOVE(item);
free(s);
}
}
/* Runs in UV loop to notify CF thread */
int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__cf_loop_signal_t* item;
uv__cf_loop_state_t* state;
item = malloc(sizeof(*item));
if (item == NULL)
return -ENOMEM;
item->handle = handle;
uv_mutex_lock(&loop->cf_mutex);
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
uv_mutex_unlock(&loop->cf_mutex);
state = loop->cf_state;
assert(state != NULL);
pCFRunLoopSourceSignal(state->signal_source);
pCFRunLoopWakeUp(state->loop);
return 0;
}
/* Runs in UV loop to initialize handle */
int uv__fsevents_init(uv_fs_event_t* handle) {
int err;
uv__cf_loop_state_t* state;
err = uv__fsevents_loop_init(handle->loop);
if (err)
return err;
/* Get absolute path to file */
handle->realpath = realpath(handle->path, NULL);
if (handle->realpath == NULL)
return -errno;
handle->realpath_len = strlen(handle->realpath);
/* Initialize event queue */
QUEUE_INIT(&handle->cf_events);
handle->cf_error = 0;
/*
* Events will occur in other thread.
* Initialize callback for getting them back into event loop's thread
*/
handle->cf_cb = malloc(sizeof(*handle->cf_cb));
if (handle->cf_cb == NULL) {
err = -ENOMEM;
goto fail_cf_cb_malloc;
}
handle->cf_cb->data = handle;
uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
uv_unref((uv_handle_t*) handle->cf_cb);
err = uv_mutex_init(&handle->cf_mutex);
if (err)
goto fail_cf_mutex_init;
/* Insert handle into the list */
state = handle->loop->cf_state;
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
state->fsevent_handle_count++;
state->fsevent_need_reschedule = 1;
uv_mutex_unlock(&state->fsevent_mutex);
/* Reschedule FSEventStream */
assert(handle != NULL);
err = uv__cf_loop_signal(handle->loop, handle);
if (err)
goto fail_loop_signal;
return 0;
fail_loop_signal:
uv_mutex_destroy(&handle->cf_mutex);
fail_cf_mutex_init:
free(handle->cf_cb);
handle->cf_cb = NULL;
fail_cf_cb_malloc:
free(handle->realpath);
handle->realpath = NULL;
handle->realpath_len = 0;
return err;
}
/* Runs in UV loop to de-initialize handle */
int uv__fsevents_close(uv_fs_event_t* handle) {
int err;
uv__cf_loop_state_t* state;
if (handle->cf_cb == NULL)
return -EINVAL;
/* Remove handle from the list */
state = handle->loop->cf_state;
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_REMOVE(&handle->cf_member);
state->fsevent_handle_count--;
state->fsevent_need_reschedule = 1;
uv_mutex_unlock(&state->fsevent_mutex);
/* Reschedule FSEventStream */
assert(handle != NULL);
err = uv__cf_loop_signal(handle->loop, handle);
if (err)
return -err;
/* Wait for deinitialization */
uv_sem_wait(&state->fsevent_sem);
uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) free);
handle->cf_cb = NULL;
/* Free data in queue */
UV__FSEVENTS_PROCESS(handle, {
/* NOP */
});
uv_mutex_destroy(&handle->cf_mutex);
free(handle->realpath);
handle->realpath = NULL;
handle->realpath_len = 0;
return 0;
}
#endif /* TARGET_OS_IPHONE */

View File

@ -27,33 +27,84 @@
#include <string.h>
static void uv__getaddrinfo_work(struct uv__work* w) {
uv_getaddrinfo_t* req = container_of(w, uv_getaddrinfo_t, work_req);
int uv__getaddrinfo_translate_error(int sys_err) {
switch (sys_err) {
case 0: return 0;
#if defined(EAI_ADDRFAMILY)
case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
#endif
#if defined(EAI_AGAIN)
case EAI_AGAIN: return UV_EAI_AGAIN;
#endif
#if defined(EAI_BADFLAGS)
case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
#endif
#if defined(EAI_BADHINTS)
case EAI_BADHINTS: return UV_EAI_BADHINTS;
#endif
#if defined(EAI_CANCELED)
case EAI_CANCELED: return UV_EAI_CANCELED;
#endif
#if defined(EAI_FAIL)
case EAI_FAIL: return UV_EAI_FAIL;
#endif
#if defined(EAI_FAMILY)
case EAI_FAMILY: return UV_EAI_FAMILY;
#endif
#if defined(EAI_MEMORY)
case EAI_MEMORY: return UV_EAI_MEMORY;
#endif
#if defined(EAI_NODATA)
case EAI_NODATA: return UV_EAI_NODATA;
#endif
#if defined(EAI_NONAME)
# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
case EAI_NONAME: return UV_EAI_NONAME;
# endif
#endif
#if defined(EAI_OVERFLOW)
case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
#endif
#if defined(EAI_PROTOCOL)
case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
#endif
#if defined(EAI_SERVICE)
case EAI_SERVICE: return UV_EAI_SERVICE;
#endif
#if defined(EAI_SOCKTYPE)
case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
#endif
#if defined(EAI_SYSTEM)
case EAI_SYSTEM: return -errno;
#endif
}
assert(!"unknown EAI_* error code");
abort();
return 0; /* Pacify compiler. */
}
req->retcode = getaddrinfo(req->hostname,
req->service,
req->hints,
&req->res);
static void uv__getaddrinfo_work(struct uv__work* w) {
uv_getaddrinfo_t* req;
int err;
req = container_of(w, uv_getaddrinfo_t, work_req);
err = getaddrinfo(req->hostname, req->service, req->hints, &req->res);
req->retcode = uv__getaddrinfo_translate_error(err);
}
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
uv_getaddrinfo_t* req = container_of(w, uv_getaddrinfo_t, work_req);
struct addrinfo *res = req->res;
#if defined(__sun)
size_t hostlen;
if (req->hostname)
hostlen = strlen(req->hostname);
else
hostlen = 0;
#endif
req->res = NULL;
uv_getaddrinfo_t* req;
struct addrinfo *res;
req = container_of(w, uv_getaddrinfo_t, work_req);
uv__req_unregister(req->loop, req);
/* see initialization in uv_getaddrinfo() */
res = req->res;
req->res = NULL;
/* See initialization in uv_getaddrinfo(). */
if (req->hints)
free(req->hints);
else if (req->service)
@ -67,27 +118,9 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
req->service = NULL;
req->hostname = NULL;
if (req->retcode == 0) {
/* OK */
#if defined(EAI_NODATA) /* FreeBSD deprecated EAI_NODATA */
} else if (req->retcode == EAI_NONAME || req->retcode == EAI_NODATA) {
#else
} else if (req->retcode == EAI_NONAME) {
#endif
uv__set_sys_error(req->loop, ENOENT); /* FIXME compatibility hack */
#if defined(__sun)
} else if (req->retcode == EAI_MEMORY && hostlen >= MAXHOSTNAMELEN) {
uv__set_sys_error(req->loop, ENOENT);
#endif
} else {
req->loop->last_err.code = UV_EADDRINFO;
req->loop->last_err.sys_errno_ = req->retcode;
}
if (status == -UV_ECANCELED) {
if (status == -ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_ECANCELED;
uv__set_artificial_error(req->loop, UV_ECANCELED);
req->retcode = UV_EAI_CANCELED;
}
req->cb(req, req->retcode, res);
@ -107,7 +140,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
char* buf;
if (req == NULL || cb == NULL || (hostname == NULL && service == NULL))
return uv__set_artificial_error(loop, UV_EINVAL);
return -EINVAL;
hostname_len = hostname ? strlen(hostname) + 1 : 0;
service_len = service ? strlen(service) + 1 : 0;
@ -115,7 +148,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
buf = malloc(hostname_len + service_len + hints_len);
if (buf == NULL)
return uv__set_artificial_error(loop, UV_ENOMEM);
return -ENOMEM;
uv__req_init(loop, req, UV_GETADDRINFO);
req->loop = loop;

View File

@ -0,0 +1,114 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "uv.h"
#include "internal.h"
static void uv__getnameinfo_work(struct uv__work* w) {
uv_getnameinfo_t* req;
int err;
socklen_t salen;
req = container_of(w, uv_getnameinfo_t, work_req);
if (req->storage.ss_family == AF_INET)
salen = sizeof(struct sockaddr_in);
else if (req->storage.ss_family == AF_INET6)
salen = sizeof(struct sockaddr_in6);
else
abort();
err = getnameinfo((struct sockaddr*) &req->storage,
salen,
req->host,
sizeof(req->host),
req->service,
sizeof(req->service),
req->flags);
req->retcode = uv__getaddrinfo_translate_error(err);
}
static void uv__getnameinfo_done(struct uv__work* w, int status) {
uv_getnameinfo_t* req;
char* host;
char* service;
req = container_of(w, uv_getnameinfo_t, work_req);
uv__req_unregister(req->loop, req);
host = service = NULL;
if (status == -ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
} else if (req->retcode == 0) {
host = req->host;
service = req->service;
}
req->getnameinfo_cb(req, req->retcode, host, service);
}
/*
* Entry point for getnameinfo
* return 0 if a callback will be made
* return error code if validation fails
*/
int uv_getnameinfo(uv_loop_t* loop,
uv_getnameinfo_t* req,
uv_getnameinfo_cb getnameinfo_cb,
const struct sockaddr* addr,
int flags) {
if (req == NULL || getnameinfo_cb == NULL || addr == NULL)
return UV_EINVAL;
if (addr->sa_family == AF_INET) {
memcpy(&req->storage,
addr,
sizeof(struct sockaddr_in));
} else if (addr->sa_family == AF_INET6) {
memcpy(&req->storage,
addr,
sizeof(struct sockaddr_in6));
} else {
return UV_EINVAL;
}
uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
req->getnameinfo_cb = getnameinfo_cb;
req->flags = flags;
req->type = UV_GETNAMEINFO;
req->loop = loop;
req->retcode = 0;
uv__work_submit(loop,
&req->work_req,
uv__getnameinfo_work,
uv__getnameinfo_done);
return 0;
}

View File

@ -26,6 +26,8 @@
#include <assert.h>
#include <stdlib.h> /* abort */
#include <string.h> /* strrchr */
#include <fcntl.h> /* O_CLOEXEC, may be */
#if defined(__STRICT_ANSI__)
# define inline __inline
@ -38,9 +40,14 @@
#if defined(__sun)
# include <sys/port.h>
# include <port.h>
# define futimes(fd, tv) futimesat(fd, (void*)0, tv)
#endif /* __sun */
#if defined(_AIX)
#define reqevents events
#define rtnevents revents
#include <sys/poll.h>
#endif /* _AIX */
#if defined(__APPLE__) && !TARGET_OS_IPHONE
# include <CoreServices/CoreServices.h>
#endif
@ -66,6 +73,21 @@
} \
while (0)
/* The __clang__ and __INTEL_COMPILER checks are superfluous because they
* define __GNUC__. They are here to convey to you, dear reader, that these
* macros are enabled when compiling with clang or icc.
*/
#if defined(__clang__) || \
defined(__GNUC__) || \
defined(__INTEL_COMPILER) || \
defined(__SUNPRO_C)
# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
#else
# define UV_DESTRUCTOR(declaration) declaration
# define UV_UNUSED(declaration) declaration
#endif
#if defined(__linux__)
# define UV__POLLIN UV__EPOLLIN
# define UV__POLLOUT UV__EPOLLOUT
@ -73,7 +95,7 @@
# define UV__POLLHUP UV__EPOLLHUP
#endif
#if defined(__sun)
#if defined(__sun) || defined(_AIX)
# define UV__POLLIN POLLIN
# define UV__POLLOUT POLLOUT
# define UV__POLLERR POLLERR
@ -96,6 +118,16 @@
# define UV__POLLHUP 8
#endif
#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
/*
* It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
* Try using fixed value const and give up, if it doesn't work
*/
# define O_CLOEXEC 0x00100000
#endif
typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
/* handle flags */
enum {
UV_CLOSING = 0x01, /* uv_close() called but not finished. */
@ -106,16 +138,33 @@ enum {
UV_STREAM_READABLE = 0x20, /* The stream is readable */
UV_STREAM_WRITABLE = 0x40, /* The stream is writable */
UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */
UV_TCP_NODELAY = 0x100, /* Disable Nagle. */
UV_TCP_KEEPALIVE = 0x200, /* Turn on keep-alive. */
UV_TCP_SINGLE_ACCEPT = 0x400 /* Only accept() when idle. */
UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */
UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */
UV_TCP_NODELAY = 0x400, /* Disable Nagle. */
UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */
UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */
UV_HANDLE_IPV6 = 0x2000 /* Handle is bound to a IPv6 socket. */
};
typedef enum {
UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
} uv_clocktype_t;
struct uv__stream_queued_fds_s {
unsigned int size;
unsigned int offset;
int fds[1];
};
/* core */
int uv__nonblock(int fd, int set);
int uv__close(int fd);
int uv__cloexec(int fd, int set);
int uv__socket(int domain, int type, int protocol);
int uv__dup(int fd);
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
void uv__make_close_pending(uv_handle_t* handle);
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
@ -133,16 +182,10 @@ int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb);
void uv__async_stop(uv_loop_t* loop, struct uv__async* wa);
/* loop */
int uv__loop_init(uv_loop_t* loop, int default_loop);
void uv__loop_delete(uv_loop_t* loop);
void uv__run_idle(uv_loop_t* loop);
void uv__run_check(uv_loop_t* loop);
void uv__run_prepare(uv_loop_t* loop);
/* error */
uv_err_code uv_translate_sys_error(int sys_errno);
void uv_fatal_error(const int errorno, const char* syscall);
/* stream */
void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream,
uv_handle_type type);
@ -153,6 +196,8 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd);
#endif /* defined(__APPLE__) */
void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
int uv__accept(int sockfd);
int uv__dup2_cloexec(int oldfd, int newfd);
int uv__open_cloexec(const char* path, int flags);
/* tcp */
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
@ -171,15 +216,8 @@ void uv__signal_close(uv_signal_t* handle);
void uv__signal_global_once_init(void);
void uv__signal_loop_cleanup(uv_loop_t* loop);
/* thread pool */
void uv__work_submit(uv_loop_t* loop,
struct uv__work *w,
void (*work)(struct uv__work *w),
void (*done)(struct uv__work *w, int status));
void uv__work_done(uv_async_t* handle, int status);
/* platform specific */
uint64_t uv__hrtime(void);
uint64_t uv__hrtime(uv_clocktype_t type);
int uv__kqueue_init(uv_loop_t* loop);
int uv__platform_loop_init(uv_loop_t* loop, int default_loop);
void uv__platform_loop_delete(uv_loop_t* loop);
@ -199,10 +237,11 @@ void uv__tcp_close(uv_tcp_t* handle);
void uv__timer_close(uv_timer_t* handle);
void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle);
uv_handle_type uv__handle_type(int fd);
#if defined(__APPLE__)
int uv___stream_fd(uv_stream_t* handle);
#define uv__stream_fd(handle) (uv___stream_fd((uv_stream_t*) (handle)))
int uv___stream_fd(const uv_stream_t* handle);
#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle)))
#else
#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
#endif /* defined(__APPLE__) */
@ -217,12 +256,10 @@ int uv__make_socketpair(int fds[2], int flags);
int uv__make_pipe(int fds[2], int flags);
#if defined(__APPLE__)
typedef void (*cf_loop_signal_cb)(void*);
void uv__cf_loop_signal(uv_loop_t* loop, cf_loop_signal_cb cb, void* arg);
int uv__fsevents_init(uv_fs_event_t* handle);
int uv__fsevents_close(uv_fs_event_t* handle);
void uv__fsevents_loop_delete(uv_loop_t* loop);
/* OSX < 10.7 has no file events, polyfill them */
#ifndef MAC_OS_X_VERSION_10_7
@ -244,19 +281,32 @@ static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
#endif /* defined(__APPLE__) */
__attribute__((unused))
static void uv__req_init(uv_loop_t* loop, uv_req_t* req, uv_req_type type) {
UV_UNUSED(static void uv__req_init(uv_loop_t* loop,
uv_req_t* req,
uv_req_type type)) {
req->type = type;
uv__req_register(loop, req);
}
#define uv__req_init(loop, req, type) \
uv__req_init((loop), (uv_req_t*)(req), (type))
__attribute__((unused))
static void uv__update_time(uv_loop_t* loop) {
loop->time = uv__hrtime() / 1000000;
UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
/* Use a fast time source if available. We only need millisecond precision.
*/
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
}
UV_UNUSED(static char* uv__basename_r(const char* path)) {
char* s;
s = strrchr(path, '/');
if (s == NULL)
return (char*) path;
return s + 1;
}
#ifdef HAVE_DTRACE
#include "uv-dtrace.h"
#else

View File

@ -39,9 +39,8 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
int uv__kqueue_init(uv_loop_t* loop) {
loop->backend_fd = kqueue();
if (loop->backend_fd == -1)
return -1;
return -errno;
uv__cloexec(loop->backend_fd, 1);
@ -55,7 +54,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
struct timespec spec;
unsigned int nevents;
unsigned int revents;
ngx_queue_t* q;
QUEUE* q;
uint64_t base;
uint64_t diff;
uv__io_t* w;
@ -68,18 +67,18 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int i;
if (loop->nfds == 0) {
assert(ngx_queue_empty(&loop->watcher_queue));
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
nevents = 0;
while (!ngx_queue_empty(&loop->watcher_queue)) {
q = ngx_queue_head(&loop->watcher_queue);
ngx_queue_remove(q);
ngx_queue_init(q);
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = ngx_queue_data(q, uv__io_t, watcher_queue);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
@ -286,6 +285,11 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
uv_fs_event_t* handle;
struct kevent ev;
int events;
const char* path;
#if defined(F_GETPATH)
/* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
char pathbuf[MAXPATHLEN];
#endif
handle = container_of(w, uv_fs_event_t, event_watcher);
@ -294,7 +298,16 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
else
events = UV_RENAME;
handle->cb(handle, NULL, events, 0);
path = NULL;
#if defined(F_GETPATH)
/* Also works when the file has been unlinked from the file system. Passing
* in the path when the file has been deleted is arguably a little strange
* but it's consistent with what the inotify backend does.
*/
if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
path = uv__basename_r(pathbuf);
#endif
handle->cb(handle, path, events, 0);
if (handle->event_watcher.fd == -1)
return;
@ -310,31 +323,37 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
}
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
int flags) {
const char* path,
unsigned int flags) {
#if defined(__APPLE__)
struct stat statbuf;
#endif /* defined(__APPLE__) */
int fd;
/* TODO open asynchronously - but how do we report back errors? */
if ((fd = open(filename, O_RDONLY)) == -1) {
uv__set_sys_error(loop, errno);
return -1;
}
if (uv__is_active(handle))
return -EINVAL;
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
uv__handle_start(handle); /* FIXME shouldn't start automatically */
/* TODO open asynchronously - but how do we report back errors? */
fd = open(path, O_RDONLY);
if (fd == -1)
return -errno;
uv__handle_start(handle);
uv__io_init(&handle->event_watcher, uv__fs_event, fd);
handle->filename = strdup(filename);
handle->path = strdup(path);
handle->cb = cb;
#if defined(__APPLE__)
/* Nullify field to perform checks later */
handle->cf_eventstream = NULL;
handle->cf_cb = NULL;
handle->realpath = NULL;
handle->realpath_len = 0;
handle->cf_flags = flags;
@ -350,25 +369,35 @@ int uv_fs_event_init(uv_loop_t* loop,
fallback:
#endif /* defined(__APPLE__) */
uv__io_start(loop, &handle->event_watcher, UV__POLLIN);
uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
return 0;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
return 0;
uv__handle_stop(handle);
#if defined(__APPLE__)
if (uv__fsevents_close(handle))
#endif /* defined(__APPLE__) */
{
uv__io_close(handle->loop, &handle->event_watcher);
}
free(handle->path);
handle->path = NULL;
uv__close(handle->event_watcher.fd);
handle->event_watcher.fd = -1;
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
#if defined(__APPLE__)
if (uv__fsevents_close(handle))
uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN);
#else
uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN);
#endif /* defined(__APPLE__) */
uv__handle_stop(handle);
free(handle->filename);
handle->filename = NULL;
close(handle->event_watcher.fd);
handle->event_watcher.fd = -1;
uv_fs_event_stop(handle);
}

View File

@ -37,17 +37,28 @@
#include <time.h>
#define HAVE_IFADDRS_H 1
#ifdef __UCLIBC__
# if __UCLIBC_MAJOR__ < 0 || __UCLIBC_MINOR__ < 9 || __UCLIBC_SUBLEVEL__ < 32
# undef HAVE_IFADDRS_H
# endif
#endif
#ifdef HAVE_IFADDRS_H
# include <ifaddrs.h>
#endif
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
#ifdef HAVE_IFADDRS_H
# if defined(__ANDROID__)
# include "android-ifaddrs.h"
# else
# include <ifaddrs.h>
# endif
# include <sys/socket.h>
# include <net/ethernet.h>
# include <linux/if_packet.h>
#endif /* HAVE_IFADDRS_H */
/* Available from 2.6.32 onwards. */
#ifndef CLOCK_MONOTONIC_COARSE
# define CLOCK_MONOTONIC_COARSE 6
#endif
/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
* include that file because it conflicts with <time.h>. We'll just have to
@ -83,7 +94,7 @@ int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
loop->inotify_watchers = NULL;
if (fd == -1)
return -1;
return -errno;
return 0;
}
@ -92,13 +103,14 @@ int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->inotify_fd == -1) return;
uv__io_stop(loop, &loop->inotify_read_watcher, UV__POLLIN);
close(loop->inotify_fd);
uv__close(loop->inotify_fd);
loop->inotify_fd = -1;
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct uv__epoll_event* events;
struct uv__epoll_event dummy;
uintptr_t i;
uintptr_t nfds;
@ -106,13 +118,20 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
if (events != NULL)
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].data == fd)
events[i].data = -1;
/* Remove the file descriptor from the epoll.
* This avoids a problem where the same file description remains open
* in another process, causing repeated junk epoll events.
*
* We pass in a dummy epoll_event, to work around a bug in old kernels.
*/
if (loop->backend_fd >= 0)
uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
}
@ -120,7 +139,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
struct uv__epoll_event events[1024];
struct uv__epoll_event* pe;
struct uv__epoll_event e;
ngx_queue_t* q;
QUEUE* q;
uv__io_t* w;
uint64_t base;
uint64_t diff;
@ -132,16 +151,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int i;
if (loop->nfds == 0) {
assert(ngx_queue_empty(&loop->watcher_queue));
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
while (!ngx_queue_empty(&loop->watcher_queue)) {
q = ngx_queue_head(&loop->watcher_queue);
ngx_queue_remove(q);
ngx_queue_init(q);
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = ngx_queue_data(q, uv__io_t, watcher_queue);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
@ -294,10 +313,36 @@ update_timeout:
}
uint64_t uv__hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
uint64_t uv__hrtime(uv_clocktype_t type) {
static clock_t fast_clock_id = -1;
struct timespec t;
clock_t clock_id;
/* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
* millisecond granularity or better. CLOCK_MONOTONIC_COARSE is
* serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
* decide to make a costly system call.
*/
/* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
* when it has microsecond granularity or better (unlikely).
*/
if (type == UV_CLOCK_FAST && fast_clock_id == -1) {
if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 &&
t.tv_nsec <= 1 * 1000 * 1000) {
fast_clock_id = CLOCK_MONOTONIC_COARSE;
} else {
fast_clock_id = CLOCK_MONOTONIC;
}
}
clock_id = CLOCK_MONOTONIC;
if (type == UV_CLOCK_FAST)
clock_id = fast_clock_id;
if (clock_gettime(clock_id, &t))
return 0; /* Not really possible. */
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
}
@ -315,12 +360,13 @@ void uv_loadavg(double avg[3]) {
int uv_exepath(char* buffer, size_t* size) {
ssize_t n;
if (!buffer || !size) {
return -1;
}
if (buffer == NULL || size == NULL)
return -EINVAL;
n = readlink("/proc/self/exe", buffer, *size - 1);
if (n <= 0) return -1;
if (n == -1)
return -errno;
buffer[n] = '\0';
*size = n;
@ -338,7 +384,7 @@ uint64_t uv_get_total_memory(void) {
}
uv_err_t uv_resident_set_memory(size_t* rss) {
int uv_resident_set_memory(size_t* rss) {
char buf[1024];
const char* s;
ssize_t n;
@ -351,15 +397,15 @@ uv_err_t uv_resident_set_memory(size_t* rss) {
while (fd == -1 && errno == EINTR);
if (fd == -1)
return uv__new_sys_error(errno);
return -errno;
do
n = read(fd, buf, sizeof(buf) - 1);
while (n == -1 && errno == EINTR);
SAVE_ERRNO(close(fd));
uv__close(fd);
if (n == -1)
return uv__new_sys_error(errno);
return -errno;
buf[n] = '\0';
s = strchr(buf, ' ');
@ -388,14 +434,14 @@ uv_err_t uv_resident_set_memory(size_t* rss) {
goto err;
*rss = val * getpagesize();
return uv_ok_;
return 0;
err:
return uv__new_artificial_error(UV_EINVAL);
return -EINVAL;
}
uv_err_t uv_uptime(double* uptime) {
int uv_uptime(double* uptime) {
static volatile int no_clock_boottime;
struct timespec now;
int r;
@ -413,17 +459,17 @@ uv_err_t uv_uptime(double* uptime) {
}
if (r)
return uv__new_sys_error(errno);
return -errno;
*uptime = now.tv_sec;
*uptime += (double)now.tv_nsec / 1000000000.0;
return uv_ok_;
return 0;
}
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int numcpus;
uv_cpu_info_t* ci;
int err;
*cpu_infos = NULL;
*count = 0;
@ -434,16 +480,15 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
ci = calloc(numcpus, sizeof(*ci));
if (ci == NULL)
return uv__new_sys_error(ENOMEM);
return -ENOMEM;
if (read_models(numcpus, ci)) {
SAVE_ERRNO(uv_free_cpu_info(ci, numcpus));
return uv__new_sys_error(errno);
}
err = read_models(numcpus, ci);
if (err == 0)
err = read_times(numcpus, ci);
if (read_times(numcpus, ci)) {
SAVE_ERRNO(uv_free_cpu_info(ci, numcpus));
return uv__new_sys_error(errno);
if (err) {
uv_free_cpu_info(ci, numcpus);
return err;
}
/* read_models() on x86 also reads the CPU speed from /proc/cpuinfo.
@ -455,7 +500,7 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
*cpu_infos = ci;
*count = numcpus;
return uv_ok_;
return 0;
}
@ -499,7 +544,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
defined(__x86_64__)
fp = fopen("/proc/cpuinfo", "r");
if (fp == NULL)
return -1;
return -errno;
while (fgets(buf, sizeof(buf), fp)) {
if (model_idx < numcpus) {
@ -508,7 +553,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
model = strndup(model, strlen(model) - 1); /* Strip newline. */
if (model == NULL) {
fclose(fp);
return -1;
return -ENOMEM;
}
ci[model_idx++].model = model;
continue;
@ -527,7 +572,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
model = strndup(model, strlen(model) - 1); /* Strip newline. */
if (model == NULL) {
fclose(fp);
return -1;
return -ENOMEM;
}
ci[model_idx++].model = model;
continue;
@ -557,7 +602,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
while (model_idx < numcpus) {
model = strndup(inferred_model, strlen(inferred_model));
if (model == NULL)
return -1;
return -ENOMEM;
ci[model_idx++].model = model;
}
@ -585,7 +630,7 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
fp = fopen("/proc/stat", "r");
if (fp == NULL)
return -1;
return -errno;
if (!fgets(buf, sizeof(buf), fp))
abort();
@ -672,24 +717,24 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
}
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
int uv_interface_addresses(uv_interface_address_t** addresses,
int* count) {
#ifndef HAVE_IFADDRS_H
return uv__new_artificial_error(UV_ENOSYS);
return -ENOSYS;
#else
struct ifaddrs *addrs, *ent;
char ip[INET6_ADDRSTRLEN];
uv_interface_address_t* address;
int i;
struct sockaddr_ll *sll;
if (getifaddrs(&addrs) != 0) {
return uv__new_sys_error(errno);
}
if (getifaddrs(&addrs))
return -errno;
*count = 0;
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) ||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family == PF_PACKET)) {
continue;
@ -698,48 +743,67 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
(*count)++;
}
*addresses = (uv_interface_address_t*)
malloc(*count * sizeof(uv_interface_address_t));
if (!(*addresses)) {
return uv__new_artificial_error(UV_ENOMEM);
}
*addresses = malloc(*count * sizeof(**addresses));
if (!(*addresses))
return -ENOMEM;
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
bzero(&ip, sizeof (ip));
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
continue;
}
if (ent->ifa_addr == NULL) {
if (ent->ifa_addr == NULL)
continue;
}
/*
* On Linux getifaddrs returns information related to the raw underlying
* devices. We're not interested in this information.
* devices. We're not interested in this information yet.
*/
if (ent->ifa_addr->sa_family == PF_PACKET) {
if (ent->ifa_addr->sa_family == PF_PACKET)
continue;
}
address->name = strdup(ent->ifa_name);
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6 *)ent->ifa_addr);
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
} else {
address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr);
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
address->is_internal = ent->ifa_flags & IFF_LOOPBACK ? 1 : 0;
if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
}
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
address++;
}
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family != PF_PACKET)) {
continue;
}
address = *addresses;
for (i = 0; i < (*count); i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {
sll = (struct sockaddr_ll*)ent->ifa_addr;
memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
}
address++;
}
}
freeifaddrs(addrs);
return uv_ok_;
return 0;
#endif
}

View File

@ -34,7 +34,7 @@
struct watcher_list {
RB_ENTRY(watcher_list) entry;
ngx_queue_t watchers;
QUEUE watchers;
char* path;
int wd;
};
@ -45,13 +45,6 @@ struct watcher_root {
#define CAST(p) ((struct watcher_root*)(p))
/* Don't look aghast, this is exactly how glibc's basename() works. */
static char* basename_r(const char* path) {
char* s = strrchr(path, '/');
return s ? (s + 1) : (char*)path;
}
static int compare_watchers(const struct watcher_list* a,
const struct watcher_list* b) {
if (a->wd < b->wd) return -1;
@ -69,20 +62,27 @@ static void uv__inotify_read(uv_loop_t* loop,
static int new_inotify_fd(void) {
int err;
int fd;
fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
if (fd != -1)
return fd;
if (errno != ENOSYS)
return -1;
return -errno;
if ((fd = uv__inotify_init()) == -1)
return -1;
fd = uv__inotify_init();
if (fd == -1)
return -errno;
if (uv__cloexec(fd, 1) || uv__nonblock(fd, 1)) {
SAVE_ERRNO(close(fd));
return -1;
err = uv__cloexec(fd, 1);
if (err == 0)
err = uv__nonblock(fd, 1);
if (err) {
uv__close(fd);
return err;
}
return fd;
@ -90,15 +90,16 @@ static int new_inotify_fd(void) {
static int init_inotify(uv_loop_t* loop) {
int err;
if (loop->inotify_fd != -1)
return 0;
loop->inotify_fd = new_inotify_fd();
if (loop->inotify_fd == -1) {
uv__set_sys_error(loop, errno);
return -1;
}
err = new_inotify_fd();
if (err < 0)
return err;
loop->inotify_fd = err;
uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
uv__io_start(loop, &loop->inotify_read_watcher, UV__POLLIN);
@ -119,11 +120,11 @@ static void uv__inotify_read(uv_loop_t* loop,
const struct uv__inotify_event* e;
struct watcher_list* w;
uv_fs_event_t* h;
ngx_queue_t* q;
QUEUE* q;
const char* path;
ssize_t size;
const char *p;
/* needs to be large enough for sizeof(inotify_event) + strlen(filename) */
/* needs to be large enough for sizeof(inotify_event) + strlen(path) */
char buf[4096];
while (1) {
@ -156,10 +157,10 @@ static void uv__inotify_read(uv_loop_t* loop,
* for modifications. Repurpose the filename for API compatibility.
* I'm not convinced this is a good thing, maybe it should go.
*/
path = e->len ? (const char*) (e + 1) : basename_r(w->path);
path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path);
ngx_queue_foreach(q, &w->watchers) {
h = ngx_queue_data(q, uv_fs_event_t, watchers);
QUEUE_FOREACH(q, &w->watchers) {
h = QUEUE_DATA(q, uv_fs_event_t, watchers);
h->cb(h, path, events, 0);
}
}
@ -167,17 +168,27 @@ static void uv__inotify_read(uv_loop_t* loop,
}
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* path,
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
int flags) {
const char* path,
unsigned int flags) {
struct watcher_list* w;
int events;
int err;
int wd;
size_t pathsz;
if (init_inotify(loop)) return -1;
if (uv__is_active(handle))
return -EINVAL;
err = init_inotify(handle->loop);
if (err)
return err;
events = UV__IN_ATTRIB
| UV__IN_CREATE
@ -188,30 +199,27 @@ int uv_fs_event_init(uv_loop_t* loop,
| UV__IN_MOVED_FROM
| UV__IN_MOVED_TO;
wd = uv__inotify_add_watch(loop->inotify_fd, path, events);
wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events);
if (wd == -1)
return uv__set_sys_error(loop, errno);
return -errno;
w = find_watcher(loop, wd);
w = find_watcher(handle->loop, wd);
if (w)
goto no_insert;
pathsz = strlen(path) + 1;
w = malloc(sizeof(*w) + pathsz);
w = malloc(sizeof(*w) + strlen(path) + 1);
if (w == NULL)
return uv__set_sys_error(loop, ENOMEM);
return -ENOMEM;
w->wd = wd;
uv_strlcpy((char*)(w + 1), path, pathsz);
w->path = (char*)(w + 1);
ngx_queue_init(&w->watchers);
RB_INSERT(watcher_root, CAST(&loop->inotify_watchers), w);
w->path = strcpy((char*)(w + 1), path);
QUEUE_INIT(&w->watchers);
RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
no_insert:
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
uv__handle_start(handle); /* FIXME shouldn't start automatically */
ngx_queue_insert_tail(&w->watchers, &handle->watchers);
handle->filename = w->path;
uv__handle_start(handle);
QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers);
handle->path = w->path;
handle->cb = cb;
handle->wd = wd;
@ -219,21 +227,31 @@ no_insert:
}
void uv__fs_event_close(uv_fs_event_t* handle) {
int uv_fs_event_stop(uv_fs_event_t* handle) {
struct watcher_list* w;
if (!uv__is_active(handle))
return 0;
w = find_watcher(handle->loop, handle->wd);
assert(w != NULL);
handle->wd = -1;
handle->filename = NULL;
handle->path = NULL;
uv__handle_stop(handle);
ngx_queue_remove(&handle->watchers);
QUEUE_REMOVE(&handle->watchers);
if (ngx_queue_empty(&w->watchers)) {
if (QUEUE_EMPTY(&w->watchers)) {
/* No watchers left for this path. Clean up. */
RB_REMOVE(watcher_root, CAST(&handle->loop->inotify_watchers), w);
uv__inotify_rm_watch(handle->loop->inotify_fd, w->wd);
free(w);
}
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
}

View File

@ -199,6 +199,36 @@
# endif
#endif /* __NR_utimensat */
#ifndef __NR_preadv
# if defined(__x86_64__)
# define __NR_preadv 295
# elif defined(__i386__)
# define __NR_preadv 333
# elif defined(__arm__)
# define __NR_preadv (UV_SYSCALL_BASE + 361)
# endif
#endif /* __NR_preadv */
#ifndef __NR_pwritev
# if defined(__x86_64__)
# define __NR_pwritev 296
# elif defined(__i386__)
# define __NR_pwritev 334
# elif defined(__arm__)
# define __NR_pwritev (UV_SYSCALL_BASE + 362)
# endif
#endif /* __NR_pwritev */
#ifndef __NR_dup3
# if defined(__x86_64__)
# define __NR_dup3 292
# elif defined(__i386__)
# define __NR_dup3 330
# elif defined(__arm__)
# define __NR_dup3 (UV_SYSCALL_BASE + 358)
# endif
#endif /* __NR_pwritev */
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
#if defined(__i386__)
@ -386,3 +416,30 @@ int uv__utimesat(int dirfd,
return errno = ENOSYS, -1;
#endif
}
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
#if defined(__NR_preadv)
return syscall(__NR_preadv, fd, iov, iovcnt, offset);
#else
return errno = ENOSYS, -1;
#endif
}
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
#if defined(__NR_pwritev)
return syscall(__NR_pwritev, fd, iov, iovcnt, offset);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__dup3(int oldfd, int newfd, int flags) {
#if defined(__NR_dup3)
return syscall(__NR_dup3, oldfd, newfd, flags);
#else
return errno = ENOSYS, -1;
#endif
}

View File

@ -28,6 +28,7 @@
#include <stdint.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#if defined(__alpha__)
@ -146,5 +147,8 @@ int uv__utimesat(int dirfd,
const char* path,
const struct timespec times[2],
int flags);
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
int uv__dup3(int oldfd, int newfd, int flags);
#endif /* UV_LINUX_SYSCALL_H_ */

View File

@ -31,9 +31,8 @@
\
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
if (uv__is_active(handle)) return 0; \
if (cb == NULL) \
return uv__set_artificial_error(handle->loop, UV_EINVAL); \
ngx_queue_insert_head(&handle->loop->name##_handles, &handle->queue); \
if (cb == NULL) return -EINVAL; \
QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
handle->name##_cb = cb; \
uv__handle_start(handle); \
return 0; \
@ -41,17 +40,17 @@
\
int uv_##name##_stop(uv_##name##_t* handle) { \
if (!uv__is_active(handle)) return 0; \
ngx_queue_remove(&handle->queue); \
QUEUE_REMOVE(&handle->queue); \
uv__handle_stop(handle); \
return 0; \
} \
\
void uv__run_##name(uv_loop_t* loop) { \
uv_##name##_t* h; \
ngx_queue_t* q; \
ngx_queue_foreach(q, &loop->name##_handles) { \
h = ngx_queue_data(q, uv_##name##_t, queue); \
h->name##_cb(h, 0); \
QUEUE* q; \
QUEUE_FOREACH(q, &loop->name##_handles) { \
h = QUEUE_DATA(q, uv_##name##_t, queue); \
h->name##_cb(h); \
} \
} \
\

View File

@ -22,34 +22,106 @@
#include "uv.h"
#include "tree.h"
#include "internal.h"
#include "heap-inl.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int uv__loop_init(uv_loop_t* loop, int default_loop);
static void uv__loop_close(uv_loop_t* loop);
int uv__loop_init(uv_loop_t* loop, int default_loop) {
static uv_loop_t default_loop_struct;
static uv_loop_t* default_loop_ptr;
uv_loop_t* uv_default_loop(void) {
if (default_loop_ptr != NULL)
return default_loop_ptr;
if (uv__loop_init(&default_loop_struct, /* default_loop? */ 1))
return NULL;
default_loop_ptr = &default_loop_struct;
return default_loop_ptr;
}
int uv_loop_init(uv_loop_t* loop) {
return uv__loop_init(loop, /* default_loop? */ 0);
}
int uv_loop_close(uv_loop_t* loop) {
QUEUE* q;
uv_handle_t* h;
if (!QUEUE_EMPTY(&(loop)->active_reqs))
return -EBUSY;
QUEUE_FOREACH(q, &loop->handle_queue) {
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
if (!(h->flags & UV__HANDLE_INTERNAL))
return -EBUSY;
}
uv__loop_close(loop);
#ifndef NDEBUG
memset(loop, -1, sizeof(*loop));
#endif
if (loop == default_loop_ptr)
default_loop_ptr = NULL;
return 0;
}
uv_loop_t* uv_loop_new(void) {
uv_loop_t* loop;
loop = malloc(sizeof(*loop));
if (loop == NULL)
return NULL;
if (uv_loop_init(loop)) {
free(loop);
return NULL;
}
return loop;
}
void uv_loop_delete(uv_loop_t* loop) {
uv_loop_t* default_loop;
int err;
default_loop = default_loop_ptr;
err = uv_loop_close(loop);
assert(err == 0);
if (loop != default_loop)
free(loop);
}
static int uv__loop_init(uv_loop_t* loop, int default_loop) {
unsigned int i;
int err;
uv__signal_global_once_init();
memset(loop, 0, sizeof(*loop));
RB_INIT(&loop->timer_handles);
ngx_queue_init(&loop->wq);
ngx_queue_init(&loop->active_reqs);
ngx_queue_init(&loop->idle_handles);
ngx_queue_init(&loop->async_handles);
ngx_queue_init(&loop->check_handles);
ngx_queue_init(&loop->prepare_handles);
ngx_queue_init(&loop->handle_queue);
heap_init((struct heap*) &loop->timer_heap);
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->active_reqs);
QUEUE_INIT(&loop->idle_handles);
QUEUE_INIT(&loop->async_handles);
QUEUE_INIT(&loop->check_handles);
QUEUE_INIT(&loop->prepare_handles);
QUEUE_INIT(&loop->handle_queue);
loop->nfds = 0;
loop->watchers = NULL;
loop->nwatchers = 0;
ngx_queue_init(&loop->pending_queue);
ngx_queue_init(&loop->watcher_queue);
QUEUE_INIT(&loop->pending_queue);
QUEUE_INIT(&loop->watcher_queue);
loop->closing_handles = NULL;
loop->time = uv__hrtime() / 1000000;
uv__update_time(loop);
uv__async_init(&loop->async_watcher);
loop->signal_pipefd[0] = -1;
loop->signal_pipefd[1] = -1;
@ -59,15 +131,19 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
loop->timer_counter = 0;
loop->stop_flag = 0;
if (uv__platform_loop_init(loop, default_loop))
return -1;
err = uv__platform_loop_init(loop, default_loop);
if (err)
return err;
uv_signal_init(loop, &loop->child_watcher);
uv__handle_unref(&loop->child_watcher);
loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++)
ngx_queue_init(loop->process_handles + i);
QUEUE_INIT(loop->process_handles + i);
if (uv_rwlock_init(&loop->cloexec_lock))
abort();
if (uv_mutex_init(&loop->wq_mutex))
abort();
@ -82,29 +158,36 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
}
void uv__loop_delete(uv_loop_t* loop) {
static void uv__loop_close(uv_loop_t* loop) {
uv__signal_loop_cleanup(loop);
uv__platform_loop_delete(loop);
uv__async_stop(loop, &loop->async_watcher);
if (loop->emfile_fd != -1) {
close(loop->emfile_fd);
uv__close(loop->emfile_fd);
loop->emfile_fd = -1;
}
if (loop->backend_fd != -1) {
close(loop->backend_fd);
uv__close(loop->backend_fd);
loop->backend_fd = -1;
}
uv_mutex_lock(&loop->wq_mutex);
assert(ngx_queue_empty(&loop->wq) && "thread pool work queue not empty!");
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
assert(!uv__has_active_reqs(loop));
uv_mutex_unlock(&loop->wq_mutex);
uv_mutex_destroy(&loop->wq_mutex);
/*
* Note that all thread pool stuff is finished at this point and
* it is safe to just destroy rw lock
*/
uv_rwlock_destroy(&loop->cloexec_lock);
#if 0
assert(ngx_queue_empty(&loop->pending_queue));
assert(ngx_queue_empty(&loop->watcher_queue));
assert(QUEUE_EMPTY(&loop->pending_queue));
assert(QUEUE_EMPTY(&loop->watcher_queue));
assert(loop->nfds == 0);
#endif

View File

@ -34,9 +34,11 @@
#include <fcntl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <uvm/uvm_extern.h>
#include <unistd.h>
#include <time.h>
@ -56,7 +58,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
uint64_t uv__hrtime(void) {
uint64_t uv__hrtime(uv_clocktype_t type) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
@ -81,9 +83,8 @@ int uv_exepath(char* buffer, size_t* size) {
size_t cb;
pid_t mypid;
if (!buffer || !size) {
return -1;
}
if (buffer == NULL || size == NULL)
return -EINVAL;
mypid = getpid();
mib[0] = CTL_KERN;
@ -92,10 +93,8 @@ int uv_exepath(char* buffer, size_t* size) {
mib[3] = KERN_PROC_ARGV;
cb = *size;
if (sysctl(mib, 4, buffer, &cb, NULL, 0) == -1) {
*size = 0;
return -1;
}
if (sysctl(mib, 4, buffer, &cb, NULL, 0))
return -errno;
*size = strlen(buffer);
return 0;
@ -107,9 +106,8 @@ uint64_t uv_get_free_memory(void) {
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_UVMEXP};
if (sysctl(which, 2, &info, &size, NULL, 0) == -1) {
return -1;
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
}
@ -125,9 +123,8 @@ uint64_t uv_get_total_memory(void) {
#endif
size_t size = sizeof(info);
if (sysctl(which, 2, &info, &size, NULL, 0) == -1) {
return -1;
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
return (uint64_t) info;
}
@ -139,17 +136,17 @@ char** uv_setup_args(int argc, char** argv) {
}
uv_err_t uv_set_process_title(const char* title) {
int uv_set_process_title(const char* title) {
if (process_title) free(process_title);
process_title = strdup(title);
setproctitle("%s", title);
return uv_ok_;
return 0;
}
uv_err_t uv_get_process_title(char* buffer, size_t size) {
int uv_get_process_title(char* buffer, size_t size) {
if (process_title) {
strncpy(buffer, process_title, size);
} else {
@ -158,11 +155,11 @@ uv_err_t uv_get_process_title(char* buffer, size_t size) {
}
}
return uv_ok_;
return 0;
}
uv_err_t uv_resident_set_memory(size_t* rss) {
int uv_resident_set_memory(size_t* rss) {
kvm_t *kd = NULL;
struct kinfo_proc2 *kinfo = NULL;
pid_t pid;
@ -184,32 +181,31 @@ uv_err_t uv_resident_set_memory(size_t* rss) {
kvm_close(kd);
return uv_ok_;
return 0;
error:
if (kd) kvm_close(kd);
return uv__new_sys_error(errno);
return -EPERM;
}
uv_err_t uv_uptime(double* uptime) {
int uv_uptime(double* uptime) {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, 2, &info, &size, NULL, 0) == -1) {
return uv__new_sys_error(errno);
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
now = time(NULL);
*uptime = (double)(now - info.tv_sec);
return uv_ok_;
return 0;
}
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
unsigned int multiplier = ((uint64_t)1000L / ticks);
unsigned int cur = 0;
@ -222,37 +218,34 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int i;
size = sizeof(model);
if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) == -1 &&
sysctlbyname("hw.model", &model, &size, NULL, 0) == -1) {
return uv__new_sys_error(errno);
if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
sysctlbyname("hw.model", &model, &size, NULL, 0)) {
return -errno;
}
size = sizeof(numcpus);
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0) == -1) {
return uv__new_sys_error(errno);
}
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
return -errno;
*count = numcpus;
/* Only i386 and amd64 have machdep.tsc_freq */
size = sizeof(cpuspeed);
if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0) == -1) {
if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
cpuspeed = 0;
}
size = numcpus * CPUSTATES * sizeof(*cp_times);
cp_times = malloc(size);
if (cp_times == NULL) {
return uv__new_artificial_error(UV_ENOMEM);
}
if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0) == -1) {
return uv__new_sys_error(errno);
}
if (cp_times == NULL)
return -ENOMEM;
if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
return -errno;
*cpu_infos = malloc(numcpus * sizeof(**cpu_infos));
if (!(*cpu_infos)) {
free(cp_times);
free(*cpu_infos);
return uv__new_artificial_error(UV_ENOMEM);
return -ENOMEM;
}
for (i = 0; i < numcpus; i++) {
@ -267,9 +260,10 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cur += CPUSTATES;
}
free(cp_times);
return uv_ok_;
return 0;
}
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
int i;
@ -281,20 +275,20 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
}
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifaddrs *addrs;
struct ifaddrs *ent;
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifaddrs *addrs, *ent;
uv_interface_address_t* address;
int i;
struct sockaddr_dl *sa_addr;
if (getifaddrs(&addrs) != 0) {
return uv__new_sys_error(errno);
}
if (getifaddrs(&addrs))
return -errno;
*count = 0;
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) ||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family != PF_INET)) {
continue;
@ -304,41 +298,62 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses, int* count)
*addresses = malloc(*count * sizeof(**addresses));
if (!(*addresses)) {
return uv__new_artificial_error(UV_ENOMEM);
}
if (!(*addresses))
return -ENOMEM;
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
continue;
}
if (ent->ifa_addr == NULL) {
if (ent->ifa_addr == NULL)
continue;
}
if (ent->ifa_addr->sa_family != PF_INET) {
if (ent->ifa_addr->sa_family != PF_INET)
continue;
}
address->name = strdup(ent->ifa_name);
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6 *)ent->ifa_addr);
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
} else {
address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr);
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK) ? 1 : 0;
if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
}
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
address++;
}
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family != AF_LINK)) {
continue;
}
address = *addresses;
for (i = 0; i < (*count); i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
}
address++;
}
}
freeifaddrs(addrs);
return uv_ok_;
return 0;
}

View File

@ -28,6 +28,10 @@
#include <sys/time.h>
#include <sys/sysctl.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <errno.h>
#include <fcntl.h>
#include <kvm.h>
@ -52,7 +56,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
uint64_t uv__hrtime(void) {
uint64_t uv__hrtime(uv_clocktype_t type) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
@ -79,16 +83,17 @@ int uv_exepath(char* buffer, size_t* size) {
size_t argsbuf_size = 100U;
size_t exepath_size;
pid_t mypid;
int status = -1;
int err;
if (buffer == NULL || size == NULL)
return -EINVAL;
if (!buffer || !size) {
goto out;
}
mypid = getpid();
for (;;) {
if ((argsbuf_tmp = realloc(argsbuf, argsbuf_size)) == NULL) {
err = -ENOMEM;
argsbuf_tmp = realloc(argsbuf, argsbuf_size);
if (argsbuf_tmp == NULL)
goto out;
}
argsbuf = argsbuf_tmp;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
@ -98,25 +103,28 @@ int uv_exepath(char* buffer, size_t* size) {
break;
}
if (errno != ENOMEM) {
err = -errno;
goto out;
}
argsbuf_size *= 2U;
}
if (argsbuf[0] == NULL) {
err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */
goto out;
}
exepath_size = strlen(argsbuf[0]);
if (exepath_size >= *size) {
err = -EINVAL;
goto out;
}
memcpy(buffer, argsbuf[0], exepath_size + 1U);
*size = exepath_size;
status = 0;
err = 0;
out:
free(argsbuf);
return status;
return err;
}
@ -125,9 +133,8 @@ uint64_t uv_get_free_memory(void) {
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_UVMEXP};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
}
@ -138,9 +145,8 @@ uint64_t uv_get_total_memory(void) {
int which[] = {CTL_HW, HW_PHYSMEM64};
size_t size = sizeof(info);
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
return (uint64_t) info;
}
@ -152,15 +158,15 @@ char** uv_setup_args(int argc, char** argv) {
}
uv_err_t uv_set_process_title(const char* title) {
int uv_set_process_title(const char* title) {
if (process_title) free(process_title);
process_title = strdup(title);
setproctitle(title);
return uv_ok_;
return 0;
}
uv_err_t uv_get_process_title(char* buffer, size_t size) {
int uv_get_process_title(char* buffer, size_t size) {
if (process_title) {
strncpy(buffer, process_title, size);
} else {
@ -169,55 +175,48 @@ uv_err_t uv_get_process_title(char* buffer, size_t size) {
}
}
return uv_ok_;
return 0;
}
uv_err_t uv_resident_set_memory(size_t* rss) {
kvm_t *kd = NULL;
struct kinfo_proc *kinfo = NULL;
pid_t pid;
int nprocs, max_size = sizeof(struct kinfo_proc);
int uv_resident_set_memory(size_t* rss) {
struct kinfo_proc kinfo;
size_t page_size = getpagesize();
size_t size = sizeof(struct kinfo_proc);
int mib[6];
pid = getpid();
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
mib[4] = sizeof(struct kinfo_proc);
mib[5] = 1;
kd = kvm_open(NULL, _PATH_MEM, NULL, O_RDONLY, "kvm_open");
if (kd == NULL) goto error;
if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0)
return -errno;
kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, max_size, &nprocs);
if (kinfo == NULL) goto error;
*rss = kinfo->p_vm_rssize * page_size;
kvm_close(kd);
return uv_ok_;
error:
if (kd) kvm_close(kd);
return uv__new_sys_error(errno);
*rss = kinfo.p_vm_rssize * page_size;
return 0;
}
uv_err_t uv_uptime(double* uptime) {
int uv_uptime(double* uptime) {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return uv__new_sys_error(errno);
}
if (sysctl(which, 2, &info, &size, NULL, 0))
return -errno;
now = time(NULL);
*uptime = (double)(now - info.tv_sec);
return uv_ok_;
return 0;
}
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed;
uint64_t info[CPUSTATES];
@ -229,27 +228,25 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
size = sizeof(model);
if (sysctl(which, 2, &model, &size, NULL, 0) < 0) {
return uv__new_sys_error(errno);
}
if (sysctl(which, 2, &model, &size, NULL, 0))
return -errno;
which[1] = HW_NCPU;
size = sizeof(numcpus);
if (sysctl(which, 2, &numcpus, &size, NULL, 0) < 0) {
return uv__new_sys_error(errno);
}
if (sysctl(which, 2, &numcpus, &size, NULL, 0))
return -errno;
*cpu_infos = (uv_cpu_info_t*)malloc(numcpus * sizeof(uv_cpu_info_t));
if (!(*cpu_infos)) {
return uv__new_artificial_error(UV_ENOMEM);
}
*cpu_infos = malloc(numcpus * sizeof(**cpu_infos));
if (!(*cpu_infos))
return -ENOMEM;
*count = numcpus;
which[1] = HW_CPUSPEED;
size = sizeof(cpuspeed);
if (sysctl(which, 2, &cpuspeed, &size, NULL, 0) < 0) {
free(*cpu_infos);
return uv__new_sys_error(errno);
if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) {
SAVE_ERRNO(free(*cpu_infos));
return -errno;
}
size = sizeof(info);
@ -258,9 +255,9 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
for (i = 0; i < numcpus; i++) {
which[2] = i;
size = sizeof(info);
if (sysctl(which, 3, &info, &size, NULL, 0) < 0) {
free(*cpu_infos);
return uv__new_sys_error(errno);
if (sysctl(which, 3, &info, &size, NULL, 0)) {
SAVE_ERRNO(free(*cpu_infos));
return -errno;
}
cpu_info = &(*cpu_infos)[i];
@ -275,7 +272,7 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cpu_info->speed = cpuspeed;
}
return uv_ok_;
return 0;
}
@ -290,15 +287,96 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
}
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
int uv_interface_addresses(uv_interface_address_t** addresses,
int* count) {
/* TODO: implement */
*addresses = NULL;
struct ifaddrs *addrs, *ent;
uv_interface_address_t* address;
int i;
struct sockaddr_dl *sa_addr;
if (getifaddrs(&addrs) != 0)
return -errno;
*count = 0;
return uv_ok_;
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family != PF_INET)) {
continue;
}
(*count)++;
}
*addresses = malloc(*count * sizeof(**addresses));
if (!(*addresses))
return -ENOMEM;
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
continue;
if (ent->ifa_addr == NULL)
continue;
if (ent->ifa_addr->sa_family != PF_INET)
continue;
address->name = strdup(ent->ifa_name);
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
} else {
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
}
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
address++;
}
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family != AF_LINK)) {
continue;
}
address = *addresses;
for (i = 0; i < (*count); i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
}
address++;
}
}
freeifaddrs(addrs);
return 0;
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; i++) {
free(addresses[i].name);
}
free(addresses);
}

View File

@ -29,8 +29,6 @@
#include <unistd.h>
#include <stdlib.h>
static void uv__pipe_accept(uv_loop_t* loop, uv__io_t* w, unsigned int events);
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
@ -45,44 +43,44 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
struct sockaddr_un saddr;
const char* pipe_fname;
int saved_errno;
int sockfd;
int status;
int bound;
int err;
saved_errno = errno;
pipe_fname = NULL;
sockfd = -1;
status = -1;
bound = 0;
err = -EINVAL;
/* Already bound? */
if (uv__stream_fd(handle) >= 0) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
goto out;
}
if (uv__stream_fd(handle) >= 0)
return -EINVAL;
/* Make a copy of the file name, it outlives this function's scope. */
if ((pipe_fname = strdup(name)) == NULL) {
uv__set_sys_error(handle->loop, ENOMEM);
pipe_fname = strdup(name);
if (pipe_fname == NULL) {
err = -ENOMEM;
goto out;
}
/* We've got a copy, don't touch the original any more. */
name = NULL;
if ((sockfd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
uv__set_sys_error(handle->loop, errno);
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
if (err < 0)
goto out;
}
sockfd = err;
memset(&saddr, 0, sizeof saddr);
uv_strlcpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
saddr.sun_family = AF_UNIX;
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
err = -errno;
/* Convert ENOENT to EACCES for compatibility with Windows. */
uv__set_sys_error(handle->loop, (errno == ENOENT) ? EACCES : errno);
if (err == -ENOENT)
err = -EACCES;
goto out;
}
bound = 1;
@ -90,50 +88,31 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
/* Success. */
handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
handle->io_watcher.fd = sockfd;
status = 0;
return 0;
out:
/* Clean up on error. */
if (status) {
if (bound) {
/* unlink() before close() to avoid races. */
/* unlink() before uv__close() to avoid races. */
assert(pipe_fname != NULL);
unlink(pipe_fname);
}
close(sockfd);
uv__close(sockfd);
free((void*)pipe_fname);
}
errno = saved_errno;
return status;
return err;
}
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
int saved_errno;
int status;
if (uv__stream_fd(handle) == -1)
return -EINVAL;
saved_errno = errno;
status = -1;
if (listen(uv__stream_fd(handle), backlog))
return -errno;
if (uv__stream_fd(handle) == -1) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
goto out;
}
assert(uv__stream_fd(handle) >= 0);
if ((status = listen(uv__stream_fd(handle), backlog)) == -1) {
uv__set_sys_error(handle->loop, errno);
} else {
handle->connection_cb = cb;
handle->io_watcher.cb = uv__pipe_accept;
handle->io_watcher.cb = uv__server_io;
uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN);
}
out:
errno = saved_errno;
return status;
return 0;
}
@ -156,8 +135,11 @@ void uv__pipe_close(uv_pipe_t* handle) {
int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
#if defined(__APPLE__)
if (uv__stream_try_select((uv_stream_t*) handle, &fd))
return -1;
int err;
err = uv__stream_try_select((uv_stream_t*) handle, &fd);
if (err)
return err;
#endif /* defined(__APPLE__) */
return uv__stream_open((uv_stream_t*)handle,
@ -171,21 +153,23 @@ void uv_pipe_connect(uv_connect_t* req,
const char* name,
uv_connect_cb cb) {
struct sockaddr_un saddr;
int saved_errno;
int new_sock;
int err;
int r;
saved_errno = errno;
new_sock = (uv__stream_fd(handle) == -1);
err = -1;
err = -EINVAL;
if (new_sock)
if ((handle->io_watcher.fd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
if (new_sock) {
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
if (err < 0)
goto out;
handle->io_watcher.fd = err;
}
memset(&saddr, 0, sizeof saddr);
uv_strlcpy(saddr.sun_path, name, sizeof(saddr.sun_path));
strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
saddr.sun_family = AF_UNIX;
do {
@ -194,68 +178,99 @@ void uv_pipe_connect(uv_connect_t* req,
}
while (r == -1 && errno == EINTR);
if (r == -1)
if (errno != EINPROGRESS)
if (r == -1 && errno != EINPROGRESS) {
err = -errno;
goto out;
}
if (new_sock)
if (uv__stream_open((uv_stream_t*)handle,
uv__stream_fd(handle),
UV_STREAM_READABLE | UV_STREAM_WRITABLE))
goto out;
uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT);
err = 0;
if (new_sock) {
err = uv__stream_open((uv_stream_t*)handle,
uv__stream_fd(handle),
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
}
if (err == 0)
uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT);
out:
handle->delayed_error = err ? errno : 0; /* Passed to callback. */
handle->delayed_error = err;
handle->connect_req = req;
uv__req_init(handle->loop, req, UV_CONNECT);
req->handle = (uv_stream_t*)handle;
req->cb = cb;
ngx_queue_init(&req->queue);
QUEUE_INIT(&req->queue);
/* Force callback to run on next tick in case of error. */
if (err != 0)
if (err)
uv__io_feed(handle->loop, &handle->io_watcher);
/* Mimic the Windows pipe implementation, always
* return 0 and let the callback handle errors.
*/
errno = saved_errno;
}
/* TODO merge with uv__server_io()? */
static void uv__pipe_accept(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
uv_pipe_t* pipe;
int saved_errno;
int sockfd;
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
struct sockaddr_un sa;
socklen_t addrlen;
int err;
saved_errno = errno;
pipe = container_of(w, uv_pipe_t, io_watcher);
assert(pipe->type == UV_NAMED_PIPE);
sockfd = uv__accept(uv__stream_fd(pipe));
if (sockfd == -1) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
uv__set_sys_error(pipe->loop, errno);
pipe->connection_cb((uv_stream_t*)pipe, -1);
}
} else {
pipe->accepted_fd = sockfd;
pipe->connection_cb((uv_stream_t*)pipe, 0);
if (pipe->accepted_fd == sockfd) {
/* The user hasn't called uv_accept() yet */
uv__io_stop(pipe->loop, &pipe->io_watcher, UV__POLLIN);
}
addrlen = sizeof(sa);
memset(&sa, 0, addrlen);
err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen);
if (err < 0) {
*len = 0;
return -errno;
}
errno = saved_errno;
if (sa.sun_path[0] == 0)
/* Linux abstract namespace */
addrlen -= offsetof(struct sockaddr_un, sun_path);
else
addrlen = strlen(sa.sun_path) + 1;
if (addrlen > *len) {
*len = addrlen;
return UV_ENOBUFS;
}
memcpy(buf, sa.sun_path, addrlen);
*len = addrlen;
return 0;
}
void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
}
int uv_pipe_pending_count(uv_pipe_t* handle) {
uv__stream_queued_fds_t* queued_fds;
if (!handle->ipc)
return 0;
if (handle->accepted_fd == -1)
return 0;
if (handle->queued_fds == NULL)
return 1;
queued_fds = handle->queued_fds;
return queued_fds->offset + 1;
}
uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
if (!handle->ipc)
return UV_UNKNOWN_HANDLE;
if (handle->accepted_fd == -1)
return UV_UNKNOWN_HANDLE;
else
return uv__handle_type(handle->accepted_fd);
}

View File

@ -36,8 +36,7 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
if (events & UV__POLLERR) {
uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
uv__handle_stop(handle);
uv__set_sys_error(handle->loop, EBADF);
handle->poll_cb(handle, -1, 0);
handle->poll_cb(handle, -EBADF, 0);
return;
}

View File

@ -40,78 +40,82 @@
extern char **environ;
#endif
#ifdef __linux__
# include <grp.h>
#endif
static ngx_queue_t* uv__process_queue(uv_loop_t* loop, int pid) {
static QUEUE* uv__process_queue(uv_loop_t* loop, int pid) {
assert(pid > 0);
return loop->process_handles + pid % ARRAY_SIZE(loop->process_handles);
}
static uv_process_t* uv__process_find(uv_loop_t* loop, int pid) {
uv_process_t* handle;
ngx_queue_t* h;
ngx_queue_t* q;
h = uv__process_queue(loop, pid);
ngx_queue_foreach(q, h) {
handle = ngx_queue_data(q, uv_process_t, queue);
if (handle->pid == pid) return handle;
}
return NULL;
}
static void uv__chld(uv_signal_t* handle, int signum) {
uv_process_t* process;
uv_loop_t* loop;
int exit_status;
int term_signal;
unsigned int i;
int status;
pid_t pid;
QUEUE pending;
QUEUE* h;
QUEUE* q;
assert(signum == SIGCHLD);
for (;;) {
QUEUE_INIT(&pending);
loop = handle->loop;
for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++) {
h = loop->process_handles + i;
q = QUEUE_HEAD(h);
while (q != h) {
process = QUEUE_DATA(q, uv_process_t, queue);
q = QUEUE_NEXT(q);
do
pid = waitpid(-1, &status, WNOHANG);
pid = waitpid(process->pid, &status, WNOHANG);
while (pid == -1 && errno == EINTR);
if (pid == 0)
return;
continue;
if (pid == -1) {
if (errno == ECHILD)
return; /* XXX stop signal watcher? */
else
if (errno != ECHILD)
abort();
continue;
}
process = uv__process_find(handle->loop, pid);
if (process == NULL)
continue; /* XXX bug? abort? */
process->status = status;
QUEUE_REMOVE(&process->queue);
QUEUE_INSERT_TAIL(&pending, &process->queue);
}
while (!QUEUE_EMPTY(&pending)) {
q = QUEUE_HEAD(&pending);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
process = QUEUE_DATA(q, uv_process_t, queue);
uv__handle_stop(process);
if (process->exit_cb == NULL)
continue;
exit_status = 0;
if (WIFEXITED(process->status))
exit_status = WEXITSTATUS(process->status);
term_signal = 0;
if (WIFEXITED(status))
exit_status = WEXITSTATUS(status);
if (WIFSIGNALED(status))
term_signal = WTERMSIG(status);
if (process->errorno) {
uv__set_sys_error(process->loop, process->errorno);
exit_status = -1; /* execve() failed */
}
if (WIFSIGNALED(process->status))
term_signal = WTERMSIG(process->status);
process->exit_cb(process, exit_status, term_signal);
}
}
}
@ -129,7 +133,7 @@ int uv__make_socketpair(int fds[2], int flags) {
* Anything else is a genuine error.
*/
if (errno != EINVAL)
return -1;
return -errno;
no_cloexec = 1;
@ -137,7 +141,7 @@ skip:
#endif
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
return -1;
return -errno;
uv__cloexec(fds[0], 1);
uv__cloexec(fds[1], 1);
@ -162,7 +166,7 @@ int uv__make_pipe(int fds[2], int flags) {
return 0;
if (errno != ENOSYS)
return -1;
return -errno;
no_pipe2 = 1;
@ -170,7 +174,7 @@ skip:
#endif
if (pipe(fds))
return -1;
return -errno;
uv__cloexec(fds[0], 1);
uv__cloexec(fds[1], 1);
@ -200,10 +204,9 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
case UV_CREATE_PIPE:
assert(container->data.stream != NULL);
if (container->data.stream->type != UV_NAMED_PIPE) {
errno = EINVAL;
return -1;
}
if (container->data.stream->type != UV_NAMED_PIPE)
return -EINVAL;
else
return uv__make_socketpair(fds, 0);
case UV_INHERIT_FD:
@ -213,17 +216,15 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
else
fd = uv__stream_fd(container->data.stream);
if (fd == -1) {
errno = EINVAL;
return -1;
}
if (fd == -1)
return -EINVAL;
fds[1] = fd;
return 0;
default:
assert(0 && "Unexpected flags");
return -1;
return -EINVAL;
}
}
@ -236,7 +237,7 @@ static int uv__process_open_stream(uv_stdio_container_t* container,
if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
return 0;
if (close(pipefds[1]))
if (uv__close(pipefds[1]))
if (errno != EINTR && errno != EINPROGRESS)
abort();
@ -275,7 +276,7 @@ static void uv__write_int(int fd, int val) {
}
static void uv__process_child_init(uv_process_options_t options,
static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd) {
@ -283,7 +284,7 @@ static void uv__process_child_init(uv_process_options_t options,
int use_fd;
int fd;
if (options.flags & UV_PROCESS_DETACHED)
if (options->flags & UV_PROCESS_DETACHED)
setsid();
for (fd = 0; fd < stdio_count; fd++) {
@ -301,8 +302,7 @@ static void uv__process_child_init(uv_process_options_t options,
close_fd = use_fd;
if (use_fd == -1) {
uv__write_int(error_fd, errno);
perror("failed to open stdio");
uv__write_int(error_fd, -errno);
_exit(127);
}
}
@ -316,8 +316,8 @@ static void uv__process_child_init(uv_process_options_t options,
if (fd <= 2)
uv__nonblock(fd, 0);
if (close_fd != -1)
close(close_fd);
if (close_fd >= stdio_count)
uv__close(close_fd);
}
for (fd = 0; fd < stdio_count; fd++) {
@ -327,74 +327,84 @@ static void uv__process_child_init(uv_process_options_t options,
close(use_fd);
}
if (options.cwd && chdir(options.cwd)) {
uv__write_int(error_fd, errno);
perror("chdir()");
if (options->cwd != NULL && chdir(options->cwd)) {
uv__write_int(error_fd, -errno);
_exit(127);
}
if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
uv__write_int(error_fd, errno);
perror("setgid()");
if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
/* When dropping privileges from root, the `setgroups` call will
* remove any extraneous groups. If we don't call this, then
* even though our uid has dropped, we may still have groups
* that enable us to do super-user things. This will fail if we
* aren't root, so don't bother checking the return value, this
* is just done as an optimistic privilege dropping function.
*/
SAVE_ERRNO(setgroups(0, NULL));
}
if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
uv__write_int(error_fd, -errno);
_exit(127);
}
if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
uv__write_int(error_fd, errno);
perror("setuid()");
if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
uv__write_int(error_fd, -errno);
_exit(127);
}
if (options.env) {
environ = options.env;
if (options->env != NULL) {
environ = options->env;
}
execvp(options.file, options.args);
uv__write_int(error_fd, errno);
perror("execvp()");
execvp(options->file, options->args);
uv__write_int(error_fd, -errno);
_exit(127);
}
int uv_spawn(uv_loop_t* loop,
uv_process_t* process,
const uv_process_options_t options) {
const uv_process_options_t* options) {
int signal_pipe[2] = { -1, -1 };
int (*pipes)[2];
int stdio_count;
ngx_queue_t* q;
QUEUE* q;
ssize_t r;
pid_t pid;
int err;
int exec_errorno;
int i;
assert(options.file != NULL);
assert(!(options.flags & ~(UV_PROCESS_DETACHED |
assert(options->file != NULL);
assert(!(options->flags & ~(UV_PROCESS_DETACHED |
UV_PROCESS_SETGID |
UV_PROCESS_SETUID |
UV_PROCESS_WINDOWS_HIDE |
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
ngx_queue_init(&process->queue);
QUEUE_INIT(&process->queue);
stdio_count = options.stdio_count;
stdio_count = options->stdio_count;
if (stdio_count < 3)
stdio_count = 3;
err = -ENOMEM;
pipes = malloc(stdio_count * sizeof(*pipes));
if (pipes == NULL) {
errno = ENOMEM;
if (pipes == NULL)
goto error;
}
for (i = 0; i < stdio_count; i++) {
pipes[i][0] = -1;
pipes[i][1] = -1;
}
for (i = 0; i < options.stdio_count; i++)
if (uv__process_init_stdio(options.stdio + i, pipes[i]))
for (i = 0; i < options->stdio_count; i++) {
err = uv__process_init_stdio(options->stdio + i, pipes[i]);
if (err)
goto error;
}
/* This pipe is used by the parent to wait until
* the child has called `execve()`. We need this
@ -416,16 +426,21 @@ int uv_spawn(uv_loop_t* loop,
* marked close-on-exec. Then, after the call to `fork()`,
* the parent polls the read end until it EOFs or errors with EPIPE.
*/
if (uv__make_pipe(signal_pipe, 0))
err = uv__make_pipe(signal_pipe, 0);
if (err)
goto error;
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
/* Acquire write lock to prevent opening new fds in worker threads */
uv_rwlock_wrlock(&loop->cloexec_lock);
pid = fork();
if (pid == -1) {
close(signal_pipe[0]);
close(signal_pipe[1]);
err = -errno;
uv_rwlock_wrunlock(&loop->cloexec_lock);
uv__close(signal_pipe[0]);
uv__close(signal_pipe[1]);
goto error;
}
@ -434,48 +449,56 @@ int uv_spawn(uv_loop_t* loop,
abort();
}
close(signal_pipe[1]);
/* Release lock in parent process */
uv_rwlock_wrunlock(&loop->cloexec_lock);
uv__close(signal_pipe[1]);
process->errorno = 0;
process->status = 0;
exec_errorno = 0;
do
r = read(signal_pipe[0], &process->errorno, sizeof(process->errorno));
r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
while (r == -1 && errno == EINTR);
if (r == 0)
; /* okay, EOF */
else if (r == sizeof(process->errorno))
else if (r == sizeof(exec_errorno))
; /* okay, read errorno */
else if (r == -1 && errno == EPIPE)
; /* okay, got EPIPE */
else
abort();
close(signal_pipe[0]);
uv__close(signal_pipe[0]);
for (i = 0; i < options->stdio_count; i++) {
err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0);
if (err == 0)
continue;
while (i--)
uv__process_close_stream(options->stdio + i);
for (i = 0; i < options.stdio_count; i++) {
if (uv__process_open_stream(options.stdio + i, pipes[i], i == 0)) {
while (i--) uv__process_close_stream(options.stdio + i);
goto error;
}
/* Only activate this handle if exec() happened successfully */
if (exec_errorno == 0) {
q = uv__process_queue(loop, pid);
QUEUE_INSERT_TAIL(q, &process->queue);
uv__handle_start(process);
}
q = uv__process_queue(loop, pid);
ngx_queue_insert_tail(q, &process->queue);
process->pid = pid;
process->exit_cb = options.exit_cb;
uv__handle_start(process);
process->exit_cb = options->exit_cb;
free(pipes);
return 0;
return exec_errorno;
error:
uv__set_sys_error(process->loop, errno);
if (pipes != NULL) {
for (i = 0; i < stdio_count; i++) {
if (i < options.stdio_count)
if (options.stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
if (i < options->stdio_count)
if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
continue;
if (pipes[i][0] != -1)
close(pipes[i][0]);
@ -485,35 +508,25 @@ error:
free(pipes);
}
return -1;
return err;
}
int uv_process_kill(uv_process_t* process, int signum) {
int r = kill(process->pid, signum);
if (r) {
uv__set_sys_error(process->loop, errno);
return -1;
} else {
return 0;
}
return uv_kill(process->pid, signum);
}
uv_err_t uv_kill(int pid, int signum) {
int r = kill(pid, signum);
if (r) {
return uv__new_sys_error(errno);
} else {
return uv_ok_;
}
int uv_kill(int pid, int signum) {
if (kill(pid, signum))
return -errno;
else
return 0;
}
void uv__process_close(uv_process_t* handle) {
/* TODO stop signal watcher when this is the last handle */
ngx_queue_remove(&handle->queue);
QUEUE_REMOVE(&handle->queue);
uv__handle_stop(handle);
}

View File

@ -74,30 +74,29 @@ char** uv_setup_args(int argc, char** argv) {
}
uv_err_t uv_set_process_title(const char* title) {
int uv_set_process_title(const char* title) {
if (process_title.len == 0)
return uv_ok_;
return 0;
/* No need to terminate, byte after is always '\0'. */
strncpy(process_title.str, title, process_title.len);
uv__set_process_title(title);
return uv_ok_;
return 0;
}
uv_err_t uv_get_process_title(char* buffer, size_t size) {
int uv_get_process_title(char* buffer, size_t size) {
if (process_title.len > 0)
strncpy(buffer, process_title.str, size);
else if (size > 0)
buffer[0] = '\0';
return uv_ok_;
return 0;
}
__attribute__((destructor))
static void free_args_mem(void) {
UV_DESTRUCTOR(static void free_args_mem(void)) {
free(args_mem); /* Keep valgrind happy. */
args_mem = NULL;
}

View File

@ -0,0 +1,103 @@
/* Copyright (c) 2013, Sony Mobile Communications AB
* Copyright (c) 2012, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Android versions < 4.1 have a broken pthread_sigmask.
* Note that this block of code must come before any inclusion of
* pthread-fixes.h so that the real pthread_sigmask can be referenced.
* */
#include <errno.h>
#include <pthread.h>
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
static int workaround;
if (workaround) {
return sigprocmask(how, set, oset);
} else if (pthread_sigmask(how, set, oset)) {
if (errno == EINVAL && sigprocmask(how, set, oset) == 0) {
workaround = 1;
return 0;
} else {
return -1;
}
} else {
return 0;
}
}
/*Android doesn't provide pthread_barrier_t for now.*/
#ifndef PTHREAD_BARRIER_SERIAL_THREAD
#include "pthread-fixes.h"
int pthread_barrier_init(pthread_barrier_t* barrier,
const void* barrier_attr,
unsigned count) {
barrier->count = count;
pthread_mutex_init(&barrier->mutex, NULL);
pthread_cond_init(&barrier->cond, NULL);
return 0;
}
int pthread_barrier_wait(pthread_barrier_t* barrier) {
/* Lock the mutex*/
pthread_mutex_lock(&barrier->mutex);
/* Decrement the count. If this is the first thread to reach 0, wake up
waiters, unlock the mutex, then return PTHREAD_BARRIER_SERIAL_THREAD.*/
if (--barrier->count == 0) {
/* First thread to reach the barrier */
pthread_cond_broadcast(&barrier->cond);
pthread_mutex_unlock(&barrier->mutex);
return PTHREAD_BARRIER_SERIAL_THREAD;
}
/* Otherwise, wait for other threads until the count reaches 0, then
return 0 to indicate this is not the first thread.*/
do {
pthread_cond_wait(&barrier->cond, &barrier->mutex);
} while (barrier->count > 0);
pthread_mutex_unlock(&barrier->mutex);
return 0;
}
int pthread_barrier_destroy(pthread_barrier_t *barrier) {
barrier->count = 0;
pthread_cond_destroy(&barrier->cond);
pthread_mutex_destroy(&barrier->mutex);
return 0;
}
#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */
int pthread_yield(void) {
sched_yield();
return 0;
}

View File

@ -37,7 +37,7 @@ typedef struct {
RB_HEAD(uv__signal_tree_s, uv_signal_s);
static int uv__signal_unlock();
static int uv__signal_unlock(void);
static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events);
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
static void uv__signal_stop(uv_signal_t* handle);
@ -116,7 +116,7 @@ static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
}
inline static uv_signal_t* uv__signal_first_handle(int signum) {
static uv_signal_t* uv__signal_first_handle(int signum) {
/* This function must be called with the signal lock held. */
uv_signal_t lookup;
uv_signal_t* handle;
@ -174,7 +174,7 @@ static void uv__signal_handler(int signum) {
}
static uv_err_t uv__signal_register_handler(int signum) {
static int uv__signal_register_handler(int signum) {
/* When this function is called, the signal lock must be held. */
struct sigaction sa;
@ -186,9 +186,9 @@ static uv_err_t uv__signal_register_handler(int signum) {
/* XXX save old action so we can restore it later on? */
if (sigaction(signum, &sa, NULL))
return uv__new_sys_error(errno);
return -errno;
return uv_ok_;
return 0;
}
@ -209,12 +209,15 @@ static void uv__signal_unregister_handler(int signum) {
static int uv__signal_loop_once_init(uv_loop_t* loop) {
int err;
/* Return if already initialized. */
if (loop->signal_pipefd[0] != -1)
return 0;
if (uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK))
return -1;
err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
if (err)
return err;
uv__io_init(&loop->signal_io_watcher,
uv__signal_event,
@ -226,34 +229,37 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
void uv__signal_loop_cleanup(uv_loop_t* loop) {
ngx_queue_t* q;
QUEUE* q;
/* Stop all the signal watchers that are still attached to this loop. This
* ensures that the (shared) signal tree doesn't contain any invalid entries
* entries, and that signal handlers are removed when appropriate.
*/
ngx_queue_foreach(q, &loop->handle_queue) {
uv_handle_t* handle = ngx_queue_data(q, uv_handle_t, handle_queue);
QUEUE_FOREACH(q, &loop->handle_queue) {
uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
if (handle->type == UV_SIGNAL)
uv__signal_stop((uv_signal_t*) handle);
}
if (loop->signal_pipefd[0] != -1) {
close(loop->signal_pipefd[0]);
uv__close(loop->signal_pipefd[0]);
loop->signal_pipefd[0] = -1;
}
if (loop->signal_pipefd[1] != -1) {
close(loop->signal_pipefd[1]);
uv__close(loop->signal_pipefd[1]);
loop->signal_pipefd[1] = -1;
}
}
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
if (uv__signal_loop_once_init(loop))
return uv__set_sys_error(loop, errno);
int err;
err = uv__signal_loop_once_init(loop);
if (err)
return err;
uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
handle->signum = 0;
@ -280,6 +286,7 @@ void uv__signal_close(uv_signal_t* handle) {
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
sigset_t saved_sigmask;
int err;
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
@ -287,10 +294,8 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
* signum is otherwise invalid then uv__signal_register will find out
* eventually.
*/
if (signum == 0) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
return -1;
}
if (signum == 0)
return -EINVAL;
/* Short circuit: if the signal watcher is already watching {signum} don't
* go through the process of deregistering and registering the handler.
@ -313,12 +318,11 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
* any of the loops), it's time to try and register a handler for it here.
*/
if (uv__signal_first_handle(signum) == NULL) {
uv_err_t err = uv__signal_register_handler(signum);
if (err.code != UV_OK) {
err = uv__signal_register_handler(signum);
if (err) {
/* Registering the signal handler failed. Must be an invalid signal. */
handle->loop->last_err = err;
uv__signal_unlock_and_unblock(&saved_sigmask);
return -1;
return err;
}
}
@ -334,7 +338,9 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
}
static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
static void uv__signal_event(uv_loop_t* loop,
uv__io_t* w,
unsigned int events) {
uv__signal_msg_t* msg;
uv_signal_t* handle;
char buf[sizeof(uv__signal_msg_t) * 32];
@ -342,6 +348,7 @@ static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events)
int r;
bytes = 0;
end = 0;
do {
r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);

View File

@ -0,0 +1,53 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef UV_SPINLOCK_H_
#define UV_SPINLOCK_H_
#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */
#include "atomic-ops.h"
#define UV_SPINLOCK_INITIALIZER { 0 }
typedef struct {
int lock;
} uv_spinlock_t;
UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock));
UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock));
UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock));
UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock));
UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) {
ACCESS_ONCE(int, spinlock->lock) = 0;
}
UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) {
while (!uv_spinlock_trylock(spinlock)) cpu_relax();
}
UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) {
ACCESS_ONCE(int, spinlock->lock) = 0;
}
UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) {
/* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing.
* Not really critical until we have locks that are (frequently) contended
* for by several threads.
*/
return 0 == cmpxchgi(&spinlock->lock, 0, 1);
}
#endif /* UV_SPINLOCK_H_ */

View File

@ -32,6 +32,7 @@
# include <ifaddrs.h>
#endif
#include <net/if.h>
#include <net/if_dl.h>
#include <sys/loadavg.h>
#include <sys/time.h>
@ -62,13 +63,22 @@
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
int err;
int fd;
loop->fs_fd = -1;
loop->backend_fd = port_create();
loop->backend_fd = -1;
if (loop->backend_fd == -1)
return -1;
fd = port_create();
if (fd == -1)
return -errno;
uv__cloexec(loop->backend_fd, 1);
err = uv__cloexec(fd, 1);
if (err) {
uv__close(fd);
return err;
}
loop->backend_fd = fd;
return 0;
}
@ -76,12 +86,12 @@ int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->fs_fd != -1) {
close(loop->fs_fd);
uv__close(loop->fs_fd);
loop->fs_fd = -1;
}
if (loop->backend_fd != -1) {
close(loop->backend_fd);
uv__close(loop->backend_fd);
loop->backend_fd = -1;
}
}
@ -110,7 +120,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
struct port_event events[1024];
struct port_event* pe;
struct timespec spec;
ngx_queue_t* q;
QUEUE* q;
uv__io_t* w;
uint64_t base;
uint64_t diff;
@ -122,16 +132,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int fd;
if (loop->nfds == 0) {
assert(ngx_queue_empty(&loop->watcher_queue));
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
while (!ngx_queue_empty(&loop->watcher_queue)) {
q = ngx_queue_head(&loop->watcher_queue);
ngx_queue_remove(q);
ngx_queue_init(q);
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = ngx_queue_data(q, uv__io_t, watcher_queue);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0))
@ -215,9 +225,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
w->cb(loop, w, pe->portev_events);
nevents++;
if (w != loop->watchers[fd])
continue; /* Disabled by callback. */
/* Events Ports operates in oneshot mode, rearm timer on next run. */
if (w->pevents != 0 && ngx_queue_empty(&w->watcher_queue))
ngx_queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
@ -254,7 +267,7 @@ update_timeout:
}
uint64_t uv__hrtime(void) {
uint64_t uv__hrtime(uv_clocktype_t type) {
return gethrtime();
}
@ -268,21 +281,17 @@ int uv_exepath(char* buffer, size_t* size) {
ssize_t res;
char buf[128];
if (buffer == NULL)
return (-1);
if (buffer == NULL || size == NULL)
return -EINVAL;
if (size == NULL)
return (-1);
(void) snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
res = readlink(buf, buffer, *size - 1);
if (res < 0)
return (res);
if (res == -1)
return -errno;
buffer[res] = '\0';
*size = res;
return (0);
return 0;
}
@ -303,19 +312,19 @@ void uv_loadavg(double avg[3]) {
#if defined(PORT_SOURCE_FILE)
static int uv__fs_event_rearm(uv_fs_event_t* handle) {
static int uv__fs_event_rearm(uv_fs_event_t *handle) {
if (handle->fd == -1)
return 0;
return -EBADF;
if (port_associate(handle->loop->fs_fd,
PORT_SOURCE_FILE,
(uintptr_t) &handle->fo,
FILE_ATTRIB | FILE_MODIFIED,
handle) == -1) {
uv__set_sys_error(handle->loop, errno);
return -1;
return -errno;
}
handle->fd = PORT_LOADED;
return 0;
}
@ -352,7 +361,7 @@ static void uv__fs_event_read(uv_loop_t* loop,
if ((r == -1 && errno == ETIME) || n == 0)
break;
handle = (uv_fs_event_t *)pe.portev_user;
handle = (uv_fs_event_t*) pe.portev_user;
assert((r == 0) && "unexpected port_get() error");
events = 0;
@ -364,72 +373,102 @@ static void uv__fs_event_read(uv_loop_t* loop,
handle->fd = PORT_FIRED;
handle->cb(handle, NULL, events, 0);
if (handle->fd != PORT_DELETED)
if (uv__fs_event_rearm(handle) != 0)
handle->cb(handle, NULL, 0, -1);
if (handle->fd != PORT_DELETED) {
r = uv__fs_event_rearm(handle);
if (r != 0)
handle->cb(handle, NULL, 0, r);
}
}
while (handle->fd != PORT_DELETED);
}
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
uv_fs_event_cb cb,
int flags) {
int portfd;
int first_run = 0;
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
}
if (loop->fs_fd == -1) {
if ((portfd = port_create()) == -1) {
uv__set_sys_error(loop, errno);
return -1;
}
loop->fs_fd = portfd;
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
const char* path,
unsigned int flags) {
int portfd;
int first_run;
int err;
if (uv__is_active(handle))
return -EINVAL;
first_run = 0;
if (handle->loop->fs_fd == -1) {
portfd = port_create();
if (portfd == -1)
return -errno;
handle->loop->fs_fd = portfd;
first_run = 1;
}
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
handle->filename = strdup(filename);
uv__handle_start(handle);
handle->path = strdup(path);
handle->fd = PORT_UNUSED;
handle->cb = cb;
memset(&handle->fo, 0, sizeof handle->fo);
handle->fo.fo_name = handle->filename;
if (uv__fs_event_rearm(handle) != 0)
return -1;
uv__handle_start(handle); /* FIXME shouldn't start automatically */
handle->fo.fo_name = handle->path;
err = uv__fs_event_rearm(handle);
if (err != 0)
return err;
if (first_run) {
uv__io_init(&loop->fs_event_watcher, uv__fs_event_read, portfd);
uv__io_start(loop, &loop->fs_event_watcher, UV__POLLIN);
uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
uv__io_start(handle->loop, &handle->loop->fs_event_watcher, UV__POLLIN);
}
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
return 0;
if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
port_dissociate(handle->loop->fs_fd, PORT_SOURCE_FILE, (uintptr_t)&handle->fo);
port_dissociate(handle->loop->fs_fd,
PORT_SOURCE_FILE,
(uintptr_t) &handle->fo);
}
handle->fd = PORT_DELETED;
free(handle->filename);
handle->filename = NULL;
free(handle->path);
handle->path = NULL;
handle->fo.fo_name = NULL;
uv__handle_stop(handle);
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
}
#else /* !defined(PORT_SOURCE_FILE) */
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
return -ENOSYS;
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
int flags) {
uv__set_sys_error(loop, ENOSYS);
return -1;
const char* filename,
unsigned int flags) {
return -ENOSYS;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
return -ENOSYS;
}
@ -445,105 +484,103 @@ char** uv_setup_args(int argc, char** argv) {
}
uv_err_t uv_set_process_title(const char* title) {
return uv_ok_;
int uv_set_process_title(const char* title) {
return 0;
}
uv_err_t uv_get_process_title(char* buffer, size_t size) {
int uv_get_process_title(char* buffer, size_t size) {
if (size > 0) {
buffer[0] = '\0';
}
return uv_ok_;
return 0;
}
uv_err_t uv_resident_set_memory(size_t* rss) {
int uv_resident_set_memory(size_t* rss) {
psinfo_t psinfo;
uv_err_t err;
int err;
int fd;
fd = open("/proc/self/psinfo", O_RDONLY);
if (fd == -1)
return uv__new_sys_error(errno);
return -errno;
err = uv_ok_;
if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo))
/* FIXME(bnoordhuis) Handle EINTR. */
err = -EINVAL;
if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
*rss = (size_t)psinfo.pr_rssize * 1024;
else
err = uv__new_sys_error(EINVAL);
close(fd);
err = 0;
}
uv__close(fd);
return err;
}
uv_err_t uv_uptime(double* uptime) {
int uv_uptime(double* uptime) {
kstat_ctl_t *kc;
kstat_t *ksp;
kstat_named_t *knp;
long hz = sysconf(_SC_CLK_TCK);
if ((kc = kstat_open()) == NULL)
return uv__new_sys_error(errno);
ksp = kstat_lookup(kc, (char *)"unix", 0, (char *)"system_misc");
kc = kstat_open();
if (kc == NULL)
return -EPERM;
ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
if (kstat_read(kc, ksp, NULL) == -1) {
*uptime = -1;
} else {
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"clk_intr");
knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr");
*uptime = knp->value.ul / hz;
}
kstat_close(kc);
return uv_ok_;
return 0;
}
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int lookup_instance;
kstat_ctl_t *kc;
kstat_t *ksp;
kstat_named_t *knp;
uv_cpu_info_t* cpu_info;
if ((kc = kstat_open()) == NULL) {
return uv__new_sys_error(errno);
}
kc = kstat_open();
if (kc == NULL)
return -EPERM;
/* Get count of cpus */
lookup_instance = 0;
while ((ksp = kstat_lookup(kc, (char *)"cpu_info", lookup_instance, NULL))) {
while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
lookup_instance++;
}
*cpu_infos = (uv_cpu_info_t*)
malloc(lookup_instance * sizeof(uv_cpu_info_t));
*cpu_infos = malloc(lookup_instance * sizeof(**cpu_infos));
if (!(*cpu_infos)) {
return uv__new_artificial_error(UV_ENOMEM);
kstat_close(kc);
return -ENOMEM;
}
*count = lookup_instance;
cpu_info = *cpu_infos;
lookup_instance = 0;
while ((ksp = kstat_lookup(kc, (char *)"cpu_info", lookup_instance, NULL))) {
while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
if (kstat_read(kc, ksp, NULL) == -1) {
cpu_info->speed = 0;
cpu_info->model = NULL;
} else {
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"clock_MHz");
knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
assert(knp->data_type == KSTAT_DATA_INT32 ||
knp->data_type == KSTAT_DATA_INT64);
cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
: knp->value.i64;
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"brand");
knp = kstat_data_lookup(ksp, (char*) "brand");
assert(knp->data_type == KSTAT_DATA_STRING);
cpu_info->model = strdup(KSTAT_NAMED_STR_PTR(knp));
}
@ -554,7 +591,11 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cpu_info = *cpu_infos;
lookup_instance = 0;
while ((ksp = kstat_lookup(kc, (char *)"cpu", lookup_instance, (char *)"sys"))){
for (;;) {
ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
if (ksp == NULL)
break;
if (kstat_read(kc, ksp, NULL) == -1) {
cpu_info->cpu_times.user = 0;
@ -563,19 +604,19 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cpu_info->cpu_times.idle = 0;
cpu_info->cpu_times.irq = 0;
} else {
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_user");
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
assert(knp->data_type == KSTAT_DATA_UINT64);
cpu_info->cpu_times.user = knp->value.ui64;
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_kernel");
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
assert(knp->data_type == KSTAT_DATA_UINT64);
cpu_info->cpu_times.sys = knp->value.ui64;
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_idle");
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
assert(knp->data_type == KSTAT_DATA_UINT64);
cpu_info->cpu_times.idle = knp->value.ui64;
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"intr");
knp = kstat_data_lookup(ksp, (char*) "intr");
assert(knp->data_type == KSTAT_DATA_UINT64);
cpu_info->cpu_times.irq = knp->value.ui64;
cpu_info->cpu_times.nice = 0;
@ -587,7 +628,7 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
kstat_close(kc);
return uv_ok_;
return 0;
}
@ -602,24 +643,24 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
}
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
int* count) {
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
#ifdef SUNOS_NO_IFADDRS
return uv__new_artificial_error(UV_ENOSYS);
return -ENOSYS;
#else
struct ifaddrs *addrs, *ent;
char ip[INET6_ADDRSTRLEN];
uv_interface_address_t* address;
struct sockaddr_dl* sa_addr;
struct ifaddrs* addrs;
struct ifaddrs* ent;
int i;
if (getifaddrs(&addrs) != 0) {
return uv__new_sys_error(errno);
}
if (getifaddrs(&addrs))
return -errno;
*count = 0;
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) ||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family == PF_PACKET)) {
continue;
@ -628,42 +669,61 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
(*count)++;
}
*addresses = (uv_interface_address_t*)
malloc(*count * sizeof(uv_interface_address_t));
if (!(*addresses)) {
return uv__new_artificial_error(UV_ENOMEM);
}
*addresses = malloc(*count * sizeof(**addresses));
if (!(*addresses))
return -ENOMEM;
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
memset(&ip, 0, sizeof(ip));
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
continue;
}
if (ent->ifa_addr == NULL) {
if (ent->ifa_addr == NULL)
continue;
}
address->name = strdup(ent->ifa_name);
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6 *)ent->ifa_addr);
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
} else {
address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr);
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
address->is_internal = ent->ifa_flags & IFF_PRIVATE || ent->ifa_flags &
IFF_LOOPBACK ? 1 : 0;
if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
}
address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
(ent->ifa_flags & IFF_LOOPBACK));
address++;
}
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family != AF_LINK)) {
continue;
}
address = *addresses;
for (i = 0; i < (*count); i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
}
address++;
}
}
freeifaddrs(addrs);
return uv_ok_;
return 0;
#endif /* SUNOS_NO_IFADDRS */
}

View File

@ -36,63 +36,90 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
int sockfd;
int err;
if (uv__stream_fd(handle) != -1)
return 0;
sockfd = uv__socket(domain, SOCK_STREAM, 0);
err = uv__socket(domain, SOCK_STREAM, 0);
if (err < 0)
return err;
sockfd = err;
if (sockfd == -1)
return uv__set_sys_error(handle->loop, errno);
if (uv__stream_open((uv_stream_t*)handle, sockfd, flags)) {
close(sockfd);
return -1;
err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
if (err) {
uv__close(sockfd);
return err;
}
return 0;
}
static int uv__bind(uv_tcp_t* tcp,
int domain,
struct sockaddr* addr,
int addrsize) {
int uv__tcp_bind(uv_tcp_t* tcp,
const struct sockaddr* addr,
unsigned int addrlen,
unsigned int flags) {
int err;
int on;
if (maybe_new_socket(tcp, domain, UV_STREAM_READABLE|UV_STREAM_WRITABLE))
return -1;
/* Cannot set IPv6-only mode on non-IPv6 socket. */
if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
return -EINVAL;
err = maybe_new_socket(tcp,
addr->sa_family,
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
if (err)
return err;
on = 1;
if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
return uv__set_sys_error(tcp->loop, errno);
return -errno;
#ifdef IPV6_V6ONLY
if (addr->sa_family == AF_INET6) {
on = (flags & UV_TCP_IPV6ONLY) != 0;
if (setsockopt(tcp->io_watcher.fd,
IPPROTO_IPV6,
IPV6_V6ONLY,
&on,
sizeof on) == -1) {
return -errno;
}
}
#endif
errno = 0;
if (bind(tcp->io_watcher.fd, addr, addrsize) && errno != EADDRINUSE)
return uv__set_sys_error(tcp->loop, errno);
if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE)
return -errno;
tcp->delayed_error = -errno;
if (addr->sa_family == AF_INET6)
tcp->flags |= UV_HANDLE_IPV6;
tcp->delayed_error = errno;
return 0;
}
static int uv__connect(uv_connect_t* req,
int uv__tcp_connect(uv_connect_t* req,
uv_tcp_t* handle,
struct sockaddr* addr,
socklen_t addrlen,
const struct sockaddr* addr,
unsigned int addrlen,
uv_connect_cb cb) {
int err;
int r;
assert(handle->type == UV_TCP);
if (handle->connect_req)
return uv__set_sys_error(handle->loop, EALREADY);
if (handle->connect_req != NULL)
return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */
if (maybe_new_socket(handle,
err = maybe_new_socket(handle,
addr->sa_family,
UV_STREAM_READABLE|UV_STREAM_WRITABLE)) {
return -1;
}
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
if (err)
return err;
handle->delayed_error = 0;
@ -108,15 +135,15 @@ static int uv__connect(uv_connect_t* req,
* error. Solaris wants to report immediately--other unixes want to
* wait.
*/
handle->delayed_error = errno;
handle->delayed_error = -errno;
else
return uv__set_sys_error(handle->loop, errno);
return -errno;
}
uv__req_init(handle->loop, req, UV_CONNECT);
req->cb = cb;
req->handle = (uv_stream_t*) handle;
ngx_queue_init(&req->queue);
QUEUE_INIT(&req->queue);
handle->connect_req = req;
uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
@ -128,22 +155,6 @@ static int uv__connect(uv_connect_t* req,
}
int uv__tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr) {
return uv__bind(handle,
AF_INET,
(struct sockaddr*)&addr,
sizeof(struct sockaddr_in));
}
int uv__tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) {
return uv__bind(handle,
AF_INET6,
(struct sockaddr*)&addr,
sizeof(struct sockaddr_in6));
}
int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
return uv__stream_open((uv_stream_t*)handle,
sock,
@ -151,85 +162,56 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
}
int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name,
int uv_tcp_getsockname(const uv_tcp_t* handle,
struct sockaddr* name,
int* namelen) {
socklen_t socklen;
int saved_errno;
int rv = 0;
/* Don't clobber errno. */
saved_errno = errno;
if (handle->delayed_error)
return handle->delayed_error;
if (handle->delayed_error) {
uv__set_sys_error(handle->loop, handle->delayed_error);
rv = -1;
goto out;
}
if (uv__stream_fd(handle) < 0) {
uv__set_sys_error(handle->loop, EINVAL);
rv = -1;
goto out;
}
if (uv__stream_fd(handle) < 0)
return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
/* sizeof(socklen_t) != sizeof(int) on some systems. */
socklen = (socklen_t)*namelen;
socklen = (socklen_t) *namelen;
if (getsockname(uv__stream_fd(handle), name, &socklen) == -1) {
uv__set_sys_error(handle->loop, errno);
rv = -1;
} else {
*namelen = (int)socklen;
}
if (getsockname(uv__stream_fd(handle), name, &socklen))
return -errno;
out:
errno = saved_errno;
return rv;
*namelen = (int) socklen;
return 0;
}
int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name,
int uv_tcp_getpeername(const uv_tcp_t* handle,
struct sockaddr* name,
int* namelen) {
socklen_t socklen;
int saved_errno;
int rv = 0;
/* Don't clobber errno. */
saved_errno = errno;
if (handle->delayed_error)
return handle->delayed_error;
if (handle->delayed_error) {
uv__set_sys_error(handle->loop, handle->delayed_error);
rv = -1;
goto out;
}
if (uv__stream_fd(handle) < 0) {
uv__set_sys_error(handle->loop, EINVAL);
rv = -1;
goto out;
}
if (uv__stream_fd(handle) < 0)
return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
/* sizeof(socklen_t) != sizeof(int) on some systems. */
socklen = (socklen_t)*namelen;
socklen = (socklen_t) *namelen;
if (getpeername(uv__stream_fd(handle), name, &socklen) == -1) {
uv__set_sys_error(handle->loop, errno);
rv = -1;
} else {
*namelen = (int)socklen;
}
if (getpeername(uv__stream_fd(handle), name, &socklen))
return -errno;
out:
errno = saved_errno;
return rv;
*namelen = (int) socklen;
return 0;
}
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
static int single_accept = -1;
int err;
if (tcp->delayed_error)
return uv__set_sys_error(tcp->loop, tcp->delayed_error);
return tcp->delayed_error;
if (single_accept == -1) {
const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
@ -239,11 +221,12 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
if (single_accept)
tcp->flags |= UV_TCP_SINGLE_ACCEPT;
if (maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE))
return -1;
err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
if (err)
return err;
if (listen(tcp->io_watcher.fd, backlog))
return uv__set_sys_error(tcp->loop, errno);
return -errno;
tcp->connection_cb = cb;
@ -255,56 +238,29 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
}
int uv__tcp_connect(uv_connect_t* req,
uv_tcp_t* handle,
struct sockaddr_in addr,
uv_connect_cb cb) {
int saved_errno;
int status;
saved_errno = errno;
status = uv__connect(req, handle, (struct sockaddr*)&addr, sizeof addr, cb);
errno = saved_errno;
return status;
}
int uv__tcp_connect6(uv_connect_t* req,
uv_tcp_t* handle,
struct sockaddr_in6 addr,
uv_connect_cb cb) {
int saved_errno;
int status;
saved_errno = errno;
status = uv__connect(req, handle, (struct sockaddr*)&addr, sizeof addr, cb);
errno = saved_errno;
return status;
}
int uv__tcp_nodelay(int fd, int on) {
return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
return -errno;
return 0;
}
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
return -1;
return -errno;
#ifdef TCP_KEEPIDLE
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
return -1;
return -errno;
#endif
/* Solaris/SmartOS, if you don't support keep-alive,
* then don't advertise it in your system headers...
*/
/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
#if defined(TCP_KEEPALIVE) && !defined(__sun)
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
return -1;
return -errno;
#endif
return 0;
@ -312,9 +268,13 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
if (uv__stream_fd(handle) != -1)
if (uv__tcp_nodelay(uv__stream_fd(handle), on))
return -1;
int err;
if (uv__stream_fd(handle) != -1) {
err = uv__tcp_nodelay(uv__stream_fd(handle), on);
if (err)
return err;
}
if (on)
handle->flags |= UV_TCP_NODELAY;
@ -326,9 +286,13 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
if (uv__stream_fd(handle) != -1)
if (uv__tcp_keepalive(uv__stream_fd(handle), on, delay))
return -1;
int err;
if (uv__stream_fd(handle) != -1) {
err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
if (err)
return err;
}
if (on)
handle->flags |= UV_TCP_KEEPALIVE;

Some files were not shown because too many files have changed in this diff Show More