mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-28 11:40:11 +03:00
This commit is contained in:
commit
9a68a111bf
24
Makefile
24
Makefile
@ -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
|
||||
|
38
outside/libuv/.gitignore
vendored
38
outside/libuv/.gitignore
vendored
@ -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
|
@ -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>
|
@ -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)
|
@ -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)
|
||||
— API documentation in the form of detailed header comments.
|
||||
* [An Introduction to libuv](http://nikhilm.github.com/uvbook/) — 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.
|
@ -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)
|
@ -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 $@
|
@ -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_ */
|
@ -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);
|
||||
}
|
@ -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");
|
||||
}
|
@ -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 */
|
||||
}
|
@ -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();
|
||||
}
|
@ -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 */
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
63
outside/libuv_0.11/.gitignore
vendored
Normal 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
|
34
outside/libuv_0.11/.mailmap
Normal file
34
outside/libuv_0.11/.mailmap
Normal 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>
|
@ -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>
|
166
outside/libuv_0.11/CONTRIBUTING.md
Normal file
166
outside/libuv_0.11/CONTRIBUTING.md
Normal 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
1380
outside/libuv_0.11/ChangeLog
Normal file
File diff suppressed because it is too large
Load Diff
@ -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.
|
336
outside/libuv_0.11/Makefile.am
Normal file
336
outside/libuv_0.11/Makefile.am
Normal 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
|
84
outside/libuv_0.11/Makefile.mingw
Normal file
84
outside/libuv_0.11/Makefile.mingw
Normal 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 $@ $<
|
146
outside/libuv_0.11/README.md
Normal file
146
outside/libuv_0.11/README.md
Normal 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)
|
||||
— API documentation in the form of detailed header comments.
|
||||
* [An Introduction to libuv](http://nikhilm.github.com/uvbook/)
|
||||
— 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.
|
||||
* [libuv-dox](https://github.com/thlorenz/libuv-dox)
|
||||
— 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
|
20
outside/libuv_0.11/android-configure
Executable file
20
outside/libuv_0.11/android-configure
Executable 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
46
outside/libuv_0.11/autogen.sh
Executable 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
|
@ -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
|
@ -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' ],
|
||||
}],
|
57
outside/libuv_0.11/configure.ac
Normal file
57
outside/libuv_0.11/configure.ac
Normal 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
|
@ -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)
|
BIN
outside/libuv_0.11/img/banner.png
Normal file
BIN
outside/libuv_0.11/img/banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
152
outside/libuv_0.11/img/logos.svg
Normal file
152
outside/libuv_0.11/img/logos.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 64 KiB |
54
outside/libuv_0.11/include/android-ifaddrs.h
Normal file
54
outside/libuv_0.11/include/android-ifaddrs.h
Normal 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
|
72
outside/libuv_0.11/include/pthread-fixes.h
Normal file
72
outside/libuv_0.11/include/pthread-fixes.h
Normal 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 */
|
32
outside/libuv_0.11/include/uv-aix.h
Normal file
32
outside/libuv_0.11/include/uv-aix.h
Normal 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 */
|
@ -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 \
|
402
outside/libuv_0.11/include/uv-errno.h
Normal file
402
outside/libuv_0.11/include/uv-errno.h
Normal 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_ */
|
@ -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 */
|
37
outside/libuv_0.11/include/uv-threadpool.h
Normal file
37
outside/libuv_0.11/include/uv-threadpool.h
Normal 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_ */
|
@ -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;
|
38
outside/libuv_0.11/include/uv-version.h
Normal file
38
outside/libuv_0.11/include/uv-version.h
Normal 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 */
|
@ -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
11
outside/libuv_0.11/libuv.pc.in
Normal file
11
outside/libuv_0.11/libuv.pc.in
Normal 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
2
outside/libuv_0.11/m4/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Ignore libtoolize-generated files.
|
||||
*.m4
|
@ -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
|
@ -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/
|
53
outside/libuv_0.11/samples/socks5-proxy/LICENSE
Normal file
53
outside/libuv_0.11/samples/socks5-proxy/LICENSE
Normal 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.
|
46
outside/libuv_0.11/samples/socks5-proxy/build.gyp
Normal file
46
outside/libuv_0.11/samples/socks5-proxy/build.gyp
Normal 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']
|
||||
}]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
737
outside/libuv_0.11/samples/socks5-proxy/client.c
Normal file
737
outside/libuv_0.11/samples/socks5-proxy/client.c
Normal 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);
|
||||
}
|
139
outside/libuv_0.11/samples/socks5-proxy/defs.h
Normal file
139
outside/libuv_0.11/samples/socks5-proxy/defs.h
Normal 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_ */
|
131
outside/libuv_0.11/samples/socks5-proxy/getopt.c
Normal file
131
outside/libuv_0.11/samples/socks5-proxy/getopt.c
Normal 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 */
|
||||
}
|
99
outside/libuv_0.11/samples/socks5-proxy/main.c
Normal file
99
outside/libuv_0.11/samples/socks5-proxy/main.c
Normal 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);
|
||||
}
|
271
outside/libuv_0.11/samples/socks5-proxy/s5.c
Normal file
271
outside/libuv_0.11/samples/socks5-proxy/s5.c
Normal 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.";
|
||||
}
|
94
outside/libuv_0.11/samples/socks5-proxy/s5.h
Normal file
94
outside/libuv_0.11/samples/socks5-proxy/s5.h
Normal 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_ */
|
241
outside/libuv_0.11/samples/socks5-proxy/server.c
Normal file
241
outside/libuv_0.11/samples/socks5-proxy/server.c
Normal 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;
|
||||
}
|
72
outside/libuv_0.11/samples/socks5-proxy/util.c
Normal file
72
outside/libuv_0.11/samples/socks5-proxy/util.c
Normal 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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
245
outside/libuv_0.11/src/heap-inl.h
Normal file
245
outside/libuv_0.11/src/heap-inl.h
Normal 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_ */
|
@ -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;
|
||||
}
|
92
outside/libuv_0.11/src/queue.h
Normal file
92
outside/libuv_0.11/src/queue.h
Normal 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_ */
|
@ -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);
|
1233
outside/libuv_0.11/src/unix/aix.c
Normal file
1233
outside/libuv_0.11/src/unix/aix.c
Normal file
File diff suppressed because it is too large
Load Diff
702
outside/libuv_0.11/src/unix/android-ifaddrs.c
Normal file
702
outside/libuv_0.11/src/unix/android-ifaddrs.c
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
60
outside/libuv_0.11/src/unix/atomic-ops.h
Normal file
60
outside/libuv_0.11/src/unix/atomic-ops.h
Normal 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_ */
|
@ -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;
|
||||
}
|
||||
}
|
203
outside/libuv_0.11/src/unix/darwin-proctitle.c
Normal file
203
outside/libuv_0.11/src/unix/darwin-proctitle.c
Normal 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 */
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
@ -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);
|
||||
}
|
@ -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;
|
899
outside/libuv_0.11/src/unix/fsevents.c
Normal file
899
outside/libuv_0.11/src/unix/fsevents.c
Normal 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 */
|
@ -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;
|
114
outside/libuv_0.11/src/unix/getnameinfo.c
Normal file
114
outside/libuv_0.11/src/unix/getnameinfo.c
Normal 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;
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
@ -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_ */
|
@ -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); \
|
||||
} \
|
||||
} \
|
||||
\
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
103
outside/libuv_0.11/src/unix/pthread-fixes.c
Normal file
103
outside/libuv_0.11/src/unix/pthread-fixes.c
Normal 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;
|
||||
}
|
@ -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);
|
53
outside/libuv_0.11/src/unix/spinlock.h
Normal file
53
outside/libuv_0.11/src/unix/spinlock.h
Normal 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_ */
|
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user