Skip to content
Commits on Source (11)
_build
src/unix/lwt_config
*.flag
# OPAM 2.0 local switches.
_opam
# NPM.
node_modules/
package-lock.json
# package-lock.json should probably be committed once we know what we're doing.
# Coverage analysis.
bisect*.out
_coverage/
# For local work, tests, etc.
scratch/
# Autogenerated by jbuider
.merlin
*.install
# BuckleScript output.
lib/
# Wikidoc output.
/docs/api/
# Junk from packaging tests.
*.cm*
*.o
a.out
language: c
matrix:
include:
- os: osx
env: COMPILER=4.08.1 LIBEV=no
- os: linux
env: COMPILER=4.08.1 COVERAGE=yes
- os: linux
env: COMPILER=4.02.3 LIBEV=no
- os: linux
env: COMPILER=4.03.0
- os: linux
env: COMPILER=4.04.2
- os: linux
env: COMPILER=4.05.0
- os: linux
env: COMPILER=4.06.1
- os: linux
env: COMPILER=4.07.1
- os: linux
env: COMPILER=ocaml-variants.4.07.1+flambda
- os: linux
env: COMPILER=ocaml-variants.4.09.0+beta1 REPOSITORIES=--repositories=default,beta=git+https://github.com/ocaml/ocaml-beta-repository.git
allow_failures:
- env: COMPILER=ocaml-variants.4.09.0+beta1 REPOSITORIES=--repositories=default,beta=git+https://github.com/ocaml/ocaml-beta-repository.git
fast_finish: true
env:
global:
- LWT_FORCE_LIBEV_BY_DEFAULT=yes
- LWT_STRESS_TEST=true
script: bash -e src/util/travis.sh
cache:
directories:
- $HOME/.opam
- ./_opam
notifications:
email:
recipients:
- antonbachin@yahoo.com
on_success: always
on_failure: always
===== 4.3.0 (2019-08-20) =====
====== Planned to break in 5.0.0 ======
For general discussion of breakage in Lwt 5.0.0, see #584. See #293 about how
Lwt announces and does breaking changes.*
* The signature of Lwt.async will change from (unit -> 'a Lwt.t) -> unit to
(unit -> unit Lwt.t) -> unit (#603, prompted @cfcs).
* Lwt_unix.send_msg and Lwt_unix.recv_msg will be changed to take
Lwt_unix.IO_vectors.t instead of Lwt_unix.io_vectors (#702, prompted
Marcello Seri).
* Nesting calls to Lwt_main.run will be forbidden, and will raise an
Failure. Most programs don't do this (#609, prompted François-René Rideau).
* configure.ml will be removed in favor of an improved discover.ml This
affects only users who are configuring Lwt as part of a manual installation
(i.e., not users of opam or esy). See discover.ml for usage (#700).
* Lwt_unix.async_method will have no effect. In practice, it already does
nothing, and has almost no users (#572).
====== Additions ======
* Lwt_process: allow setting working directory for new processes (#694, Thomas
Leonard).
* PPX: use OCaml 4.08 ASTs to support latest features (#697).
* Lwt_io.NumberIO: use compiler intrinsics for better performance (#178,
requested Mauricio Fernandez).
====== Bugs fixed ======
* Race condition in Lwt_react.S.limit (4e592eb).
* Use fallback rule during configuration (#693, Hongchang Wu).
* Fix typos (#688, #692, @Fourchaux).
===== 4.2.1 (2019-04-02) =====
====== Bug fixed ======
* Detect libev correctly when building under esy (#679, Antonio Nuno
Monteiro).
===== 4.2.0 (2019-03-25) =====
====== Additions ======
* Lwt.both (#668, Brendan Long, Jeremy Yallop).
* ppx_let support with open Lwt.Infix (#667, Brendan Long).
* Lwt_stream.of_seq (#646, Hezekiah Carty).
* Lwt_io.is_closed (#635, Andreas Garnaes).
* Lwt_unix.IO_vectors.byte_count (#645, Raphaël Proust).
* Support for higher baud rates in Lwt_unix.tcgetattr and Lwt_unix.tcsetattr
(#678, Frédéric Fortier).
* Replacement functions in Lwt_main for deprecated functions based on
Lwt_sequence (#660).
====== Bugs fixed ======
* 4.08 compatibility (#658).
* Stack overflow in Lwt_stream.iter_p (#432, Varun Kohli).
* Incorrect bounds check in Lwt_bytes.mincore (#627, Cédric Le Moigne).
* Lwt_bytes.mincore will not be available in future releases of OpenBSD (#663,
Kenneth Westerback).
* Missing header in the Android build (#652, Justus Matthiesen).
* Build broken on MSVC (98303de, 85535f7, Dmitry Bely).
* Build broken on OpenBSD (#672, Christopher Zimmermann).
* Lwt_io.of_bytes produces a channel with inaccurate positions (#636, Nathan
Rebours).
* Lwt_io._.read_int behaves incorrectly on 32-bit systems (#671, reported
Dmitry Bely).
* Inaccurate locations for errors related to ;%lwt (#602, @kandu).
* (_ : t) not recognized as a catch-all pattern by the PPX (#640, Florian
Angeletti).
* Race condition in Lwt_react.E.limit (#606, Avni Fatehpuria).
* Premature deallocation in Lwt_react.E.with_finaliser and
Lwt_react.S.with_finaliser (#626, El-Hassan Wanas).
====== Miscellaneous ======
* New tests for Lwt_bytes, portions of Lwt_unix (#619, #621, #628, #630, #673,
Cédric Le Moigne, Anurag Soni).
* Test suite improvements (#656, Dave Parfitt).
* Clarifications for documentation of Lwt.try_bind, Lwt.pick (#648, #650,
Bikal Lem).
* Fixed documentation of Lwt_io.read_line (#657, Yoni Levy).
* Fixed some typos (#611, #613, Rich Neswold).
===== 4.1.0 (2018-06-26) =====
====== Additions ======
* Change license to MIT (#560).
* Lwt_fmt, an Lwt-aware version of Format (#548, Gabriel Radanne).
* Lwt_io.establish_server_with_client_socket (#586).
====== Bugs fixed ======
* Lwt_stream.iter_n: rename ?max_threads argument to ?max_concurrency (#581,
Hezekiah Carty).
* PPX: reject match expressions that have only exception cases (#597, Raphaël
Proust).
====== Miscellaneous ======
* Improvements to Lwt_pool docs (#575, Bobby Priambodo).
* Restore all PPX tests (#590, Jess Smith).
===== 4.0.1 (2018-04-13) =====
====== Bugs fixed ======
* Race condition in worker thread management in Lwt_unix (#569, diagnosed Gabe
Levi).
* Hang in Lwt_unix.read on Windows (#574, #569, 86a6baf, diagnosed Gabe Levi).
* Docs: note that Lwt_io.open_file for writing truncates the file by default
(#570, reported Tóth Róbert).
===== 4.0.0 (2018-03-30) =====
====== Breaking ======
These changes were announced in Lwt 3.1.0 and Lwt 3.2.0. See #453 about smooth
upgrade paths.
* Delete package lwt.ppx. The PPX syntax is in package lwt_ppx since Lwt 3.2.0
(#338).
* Remove >> syntax from the PPX (#495).
* Delete modules Lwt_log, Lwt_daemon, Lwt_log_core, and package lwt.log. These
are in package lwt_log since Lwt 3.2.0, but it is recommended to use
Logs_lwt from the logs library instead (#484, initiated Hannes Mehnert).
* Delete package lwt.preemptive. It is an alias for lwt.unix since Lwt 3.2.0
(#487).
* Delete package lwt.syntax. The Camlp4 syntax is in package lwt_camlp4 since
Lwt 3.2.0 (#370).
* Delete module Lwt_chan, a predecessor of Lwt_io (#441).
* Delete package lwt.simple-top, a predecessor of utop (#371).
* Make resolvers (Lwt.u) contravariant (#458).
====== Planned to break in 5.0.0 ======
* Lwt.pick will raise Invalid_argument on the empty list, instead of returning
a forever-pending promise. Also applies to Lwt.choose, Lwt.npick,
Lwt.nchoose, and Lwt.nchoose_split (#562, Tim Reinke, prompted Hezekiah
Carty).
* Remove translation of [%lwt ...] to Lwt.catch from the PPX (#527).
* Remove -no-debug option from the PPX (#528).
* Remove Lwt_log support from the PPX (#520).
====== Bugs fixed ======
* Lwt_io.file_length now fails with EISDIR when used on a directory (#563,
requested Cedric Cellier).
* Lwt_react.E.limit and Lwt_react.S.limit now working more correctly (#566,
@Freyr666).
====== Miscellaneous ======
* Documentation improvements (#561, Jason Evans).
===== 3.3.0 (2018-03-07) =====
====== Bugs fixed ======
* Restore backtrace support (#554, #556, Gabe Levi).
* Serious logic error that could cause Lwt to hang or crash (#549, reported
@koen-struyve).
* All Lwt_list functions are now tail-recursive (#538, Joseph Thomas).
====== Additions ======
* Support ;%lwt syntax in the PPX (#307, Hezekiah Carty).
* Lwt_stream.iter_n (#312, Hezekiah Carty).
====== Miscellaneous ======
* Testing improvements (#536, #541, @cedlemo).
* Documentation improvements (#544, #546, #547, #553, #559, Daniil Baturin,
Jason Evans, Jess Smith, Milo Turner).
===== 3.2.1 (2018-01-11) =====
Lwt 3.2.1 is released because it still packages lwt.ppx, a deprecated copy of
package lwt_ppx, and the two packages should be kept in sync.
====== Deprecations ======
* All PPX options are deprecated and should not be used (#534).
* The [%lwt ...] PPX syntax should be replaced by Lwt.catch (#534).
====== Fixes ======
* Clean up PPX -help usage message output (#525, Zan Doye).
====== Miscellaneous ======
* More thorough testing (#512, #535, Joseph Thomas).
* Clarification of the C binding (#521, @cedlemo).
===== 3.2.0 (2017-12-19) =====
====== Additions ======
* Lwt_mvar.take_available, Lwt_mvar.is_empty (#459, Hezekiah Carty).
* Lwt_io.open_temp_file, Lwt_io.with_temp_file (#467, Joe Thomas).
* New reference documentation for module Lwt (#469).
* Lwt_pool.clear and ?dispose argument for Lwt_pool.create (#483,
Hezekiah Carty).
* Lwt_pool.wait_queue_length (#493, Jerome Vouillon).
====== Bugs fixed ======
* Lwt.npick never worked (#447, Zack Coker).
* Lwt_pool.use now always calls ?validate on elements (#461, Joe Thomas).
* Better locations generated by the PPX (#470, Fabian Hemmer).
* Keep worker thread count accurate in Lwt_unix when pthread_create fails
(#493, @koen-struyve).
* Leaked exceptions in Lwt_list (#499).
* Memory leak in Lwt_unix.getnameinfo (#503, Hannes Mehnert).
====== Planned to break in 4.0.0 ======
See #453 for details and instructions about planned breakage in Lwt 4.0.0.
* The semantics of Lwt will be adjusted for better exception and stack safety
(#500).
* The PPX will be factored out into its own opam package, lwt_ppx. This
package is installable from opam now, as of Lwt 3.2.0 (#338).
* Similarly, the deprecated Camlp4 syntax will be factored out into
lwt_camlp4, which is installable from opam now (#370).
* Modules Lwt_log, Lwt_log_core, Lwt_log_rules, and Lwt_daemon are being
deprecated and factored out into opam package lwt_log, also installable from
opam now. Use the logs library for logging, in particular module Logs_lwt.
Direct daemonization is deprecated on most platforms (#484, Hannes Mehnert).
* The >> construct from the PPX will be deleted (#471, Raphaël Proust).
* Package lwt.preemptive is being merged into lwt.unix. In 3.2.0,
lwt.preemptive becomes an alias for lwt.unix, and the package name
lwt.preemptive will be deleted in 4.0.0 (#487).
====== Deprecations ======
* Lwt.waiter_of_wakener should not be used, as it can lead to soundness bugs
in future (but not current) Lwt (#458).
* Lwt_sequence was deprecated in Lwt 2.6.0, but it now has a warning attached,
as do Lwt.add_task_r and Lwt.add_task_l, which use it (#361).
* Use of the following functions is discouraged, but they have not yet
received deprecation warnings: Lwt.with_value, Lwt.cancel, Lwt.state,
Lwt.ignore_result (#359, #469).
====== Miscellaneous ======
* Replace references to Camlp4 in the manual with the PPX (#457, Bobby
Priambodo).
* More tests for Lwt_pool (#464, Joe Thomas).
* Expect tests for the PPX (#474, Fabian Hemmer).
===== 3.1.0 (2017-07-19) =====
====== Additions ======
* Port to Jbuilder (#374, Andrew Ray).
* Lwt_io.establish_server_with_client_address (#346, Rudi Grinberg).
* Lwt_unix.getcwd (#403, Raphaël Proust).
====== Planned to break in 4.0.0 ======
* Delete lwt.simple-top (#371).
* Delete Lwt_chan (#441).
====== Fixes ======
* Make Lwt_log functions tail-recursive (#348, Jan Doms).
* Make more of Lwt_list tail-recursive (#347, Jan Doms).
* Improve string messages in exceptions (#368, #382, Jan Doms, Raphaël
Proust).
* Don't call Unix.set_nonblock or Unix.clear_nonblock unnecessarily on
some fds (#356, David Sheets).
* Lwt_unix.sleep and Lwt_unix.timeout returning too early when using
libev (#433, Stijn Devriendt).
* Lwt_sequence.fold_r iterating the wrong way in some cases (#405,
Stijn Devriendt).
* Build conflicts in some cases due to duplicate cst_to_constr
function (#362, Jérémie Dimino).
* Don't use deprecated readdir_r system call (#430, Raphaël Proust).
====== Miscellaneous ======
* The Lwt core, lwt.ml, has been thoroughly refactored and commented
(#354, reviewed Gabriel Radanne, Edwin Török, Raphaël Proust, Jan
Doms, Fabian Hemmer, Sebastien Mondet, Simon Cruanes, Anil
Madhavapeddy, Pierre Chambart, and many others).
* Lots of tests for most of the Lwt core (#339, #389, #392, #440,
#448, #450, Joseph Thomas, Ryan Slade).
* Documentation fixes (including by Joseph Thomas, Raphaël Proust,
Richard Degenne, Stavros Polymenis).
* Contributing documentation (#379).
* Massively adjust whitespace for legibility (#400, #409, #416,
Richard Degenne).
* Improvements to CI (Etienne Millon, Raphael Rafatpanah, Zack Coker,
Yotam Barnoy).
* The additional packages lwt_ssl, lwt_react, lwt_glib get new minor
releases, the change being new Jbuilder build systems (#374, Andrew
Ray).
===== 3.0.0 (2017-04-10) =====
====== Breaking ======
* These changes were originally announced in release 2.7.0 (#308).
* Lwt_engine.libev now has an optional argument for selecting the libev back
end (#269, #294, Jeremy Yallop).
* Lwt_io.establish_server has been changed to make it more difficult to leak
file descriptors (#258, #260).
* Lwt_io.shutdown_server now evaluates to a promise, which completes when the
listening socket's close(2) operation completes (#259).
* Lwt_unix.bind now evaluates to a promise, because the bind(2) system call
can block for Unix domain sockets (#296, requested David Sheets).
* ocamlfind packages lwt.react, lwt.ssl, lwt.glib are replaced by lwt_react,
lwt_ssl, lwt_glib. These have been separate OPAM packages, under those
names, since 2.7.0 (#301).
===== 2.7.1 (2017-04-08) =====
====== Fixes ======
......@@ -131,7 +450,7 @@
* Improve wildcard detection in the ppx (#198)
* Fix Lwt_stream: bounded_push#close wake the reader (#201)
* Fix infinite loop with Lwt_stream.choose (#214)
* Fix lazyness failure with Lwt_io.common#close (#207)
* Fix laziness failure with Lwt_io.common#close (#207)
===== 2.5.1 (2015-12-07) =====
......@@ -347,7 +666,7 @@
* {{{Lwt_unix}}} now use libev instead of select
* Add thread local storage support to {{{Lwt}}}
* Add backtrace support to {{{Lwt}}}. Now {{{Lwt}}} exceptions can
be recored by using the syntax extension with the {{{-lwt-debug}}}
be recorded by using the syntax extension with the {{{-lwt-debug}}}
command line switch.
* Allow blocking system calls to be executed in parallels
* Change the type of many functions of {{{Lwt_unix}}}, which now
......@@ -397,7 +716,7 @@
* Allow to use {{{select}}} on arbitrary high file descriptors
* More commands and features in {{{Lwt_read_line}}}:
** Handle "undo" command
** New controlable read-lines instances
** New controllable read-lines instances
** More edition commands
** Completion as you type
** Backward search
......
Copyright (c) 1999-2019, the Authors of Lwt (docs/AUTHORS)
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.
# Makefile
# --------
# Copyright : (c) 2012, Jérémie Dimino <jeremie@dimino.org>
# Licence : BSD3
#
# Generic Makefile for oasis project
# Suppress duplicate topdirs.cmi warnings.
OCAMLFIND_IGNORE_DUPS_IN = $(shell ocamlfind query compiler-libs)
export OCAMLFIND_IGNORE_DUPS_IN
# Set to setup.exe for the release
SETUP := setup.exe
# Default rule
.PHONY: default
default: build
# Setup for the development version
setup-dev.exe: _oasis setup.ml
grep -v '^#' setup.ml > setup_dev.ml
ocamlfind ocamlopt -o $@ -linkpkg -package ocamlbuild,oasis.dynrun setup_dev.ml || \
ocamlfind ocamlc -o $@ -linkpkg -package ocamlbuild,oasis.dynrun setup_dev.ml || true
rm -f setup_dev.*
# Setup for the release
setup.exe: setup.ml
ocamlopt.opt -o $@ $< || ocamlopt -o $@ $< || ocamlc -o $@ $<
rm -f setup.cmx setup.cmi setup.o setup.obj setup.cmo
setup: $(SETUP)
build: $(SETUP) setup.data
./$(SETUP) -build $(BUILDFLAGS)
doc: $(SETUP) setup.data build
./$(SETUP) -doc $(DOCFLAGS)
doc-api: $(SETUP) setup.data build
./$(SETUP) -build lwt-api.docdir/index.html
test: $(SETUP) setup.data build clean-coverage
./$(SETUP) -test $(TESTFLAGS)
all: $(SETUP)
./$(SETUP) -all $(ALLFLAGS)
install: $(SETUP) setup.data
./$(SETUP) -install $(INSTALLFLAGS)
uninstall: $(SETUP) setup.data
./$(SETUP) -uninstall $(UNINSTALLFLAGS)
reinstall: $(SETUP) setup.data
./$(SETUP) -reinstall $(REINSTALLFLAGS)
clean: $(SETUP) clean-coverage
./$(SETUP) -clean $(CLEANFLAGS)
distclean: $(SETUP)
./$(SETUP) -distclean $(DISTCLEANFLAGS)
rm -rf setup*.exe
clean-coverage:
rm -rf bisect*.out
# build the usual development packages
.PHONY: build
build:
dune build
# run unit tests for package lwt
.PHONY: test
test: build
dune runtest -j 1 --no-buffer
# Install dependencies needed during development.
.PHONY : dev-deps
dev-deps :
opam install . --deps-only --yes
# Use Dune+odoc to generate static html documentation.
# Currently requires ocaml 4.03.0 to install odoc.
.PHONY: doc
doc:
dune build @doc
# Build HTML documentation with ocamldoc
.PHONY: doc-api-html
doc-api-html: build
$(MAKE) -C docs api/html/index.html
# Build wiki documentation with wikidoc
# requires ocaml 4.03.0 and pinning the repo
# https://github.com/ocsigen/wikidoc
.PHONY: doc-api-wiki
doc-api-wiki: build
$(MAKE) -C docs api/wiki/index.wiki
# Packaging tests. These are run with Lwt installed by OPAM, typically during
# CI. To run locally, run the install-for-packaging-test target first.
.PHONY: packaging-test
packaging-test:
ocamlfind query lwt
for TEST in `ls -d test/packaging/*/*` ; \
do \
$(MAKE) -wC $$TEST || exit 1 ; \
echo ; \
echo ; \
done
.PHONY: install-for-packaging-test
install-for-packaging-test: clean
opam pin add --yes --no-action lwt .
opam pin add --yes --no-action lwt_ppx .
opam pin add --yes --no-action lwt_react .
opam reinstall --yes lwt lwt_ppx lwt_react
.PHONY: uninstall-after-packaging-test
uninstall-after-packaging-test:
opam remove --yes lwt lwt_ppx lwt_react
opam pin remove --yes lwt
opam pin remove --yes lwt_ppx
opam pin remove --yes lwt_react
# ppx_let integration test.
.PHONY : ppx_let-test
ppx_let-test :
dune build test/ppx_let/test.exe
dune exec test/ppx_let/test.exe
.PHONY : ppx_let-test-deps
ppx_let-test-deps :
opam install --yes --unset-root ppx_let
.PHONY: clean
clean:
dune clean
find . -name '.merlin' | xargs rm -f
rm -fr docs/api
rm -f src/jbuild-ignore src/unix/lwt_config
for TEST in `ls -d test/packaging/*/*` ; \
do \
$(MAKE) -wC $$TEST clean ; \
done
rm -rf _coverage/
configure: $(SETUP)
./$(SETUP) -configure $(CONFIGUREFLAGS)
BISECT_FILES_PATTERN := _build/default/test/*/bisect*.out
setup.data: $(SETUP)
./$(SETUP) -configure $(CONFIGUREFLAGS)
coverage: test
bisect-ppx-report -I _build/ -html _coverage/ bisect*.out
bisect-ppx-report -text - -summary-only bisect*.out
.PHONY: coverage
coverage: clean
BISECT_ENABLE=yes $(MAKE) build
BISECT_ENABLE=yes dune runtest -j 1 --no-buffer
bisect-ppx-report \
-I _build/default/ --html _coverage/ \
--text - --summary-only \
$(BISECT_FILES_PATTERN)
@echo See _coverage/index.html
.PHONY: default setup build doc test all install uninstall reinstall clean distclean configure coverage
# Lwt &nbsp;&nbsp; [![version 2.7.1][version]][releases] [![LGPL][license-img]][copying] [![Gitter chat][gitter-img]][gitter] [![Travis status][travis-img]][travis] [![AppVeyor status][appveyor-img]][appveyor]
# Lwt &nbsp;&nbsp; [![version 4.3.0][version]][releases] [![Gitter chat][gitter-img]][gitter] [![Travis status][travis-img]][travis] [![AppVeyor status][appveyor-img]][appveyor]
[version]: https://img.shields.io/badge/version-2.7.1-blue.svg
[version]: https://img.shields.io/badge/version-4.3.0-blue.svg
[releases]: https://github.com/ocsigen/lwt/releases
[license-img]: https://img.shields.io/badge/license-LGPL-blue.svg
[gitter-img]: https://img.shields.io/badge/chat-on_gitter-lightgrey.svg
[travis]: https://travis-ci.org/ocsigen/lwt/branches
[travis-img]: https://img.shields.io/travis/ocsigen/lwt/master.svg?label=travis
......@@ -25,7 +24,7 @@ if the request is not completed in five seconds:
let () =
let request =
let%lwt addresses = Lwt_unix.getaddrinfo "google.com" "80" [] in
let google = (List.hd addresses).Lwt_unix.ai_addr in
let google = Lwt_unix.((List.hd addresses).ai_addr) in
Lwt_io.(with_connection google (fun (incoming, outgoing) ->
let%lwt () = write outgoing "GET / HTTP/1.1\r\n" in
......@@ -43,7 +42,7 @@ let () =
| Some response -> print_string response
| None -> prerr_endline "Request timed out"; exit 1
(* ocamlfind opt -package lwt.unix -package lwt.ppx -linkpkg -o request example.ml
(* ocamlfind opt -package lwt.unix -package lwt_ppx -linkpkg -o request example.ml
./request *)
```
......@@ -56,74 +55,142 @@ the visible OCaml code is run in a single thread, but Lwt internally uses a
combination of worker threads and non-blocking file descriptors to resolve in
parallel the promises that do I/O.
<br/>
### Overview
Lwt compiles to native code on Linux, macOS, Windows, and other systems. It's
also routinely compiled to JavaScript for the front end and Node, by js_of_ocaml
and BuckleScript.
In Lwt,
- The [core library `Lwt`][core] provides promises...
- ...and a few pure-OCaml helpers, such as promise-friendly [mutexes][mutex],
[condition variables][cond], and [mvars][mvar].
- There is a big Unix binding, [`Lwt_unix`][unix] that binds almost every Unix
system call. A higher-level module [`Lwt_io`][io] provides nice I/O channels.
- [`Lwt_process`][process] is for subprocess handling.
- [`Lwt_preemptive`][preemptive] spawns system threads.
- The [PPX syntax][ppx] allows using all of the above without going crazy!
- There are also some other helpers, such as [`Lwt_react`][react] for reactive
programming. See the table of contents on the linked manual pages!
[core]: https://ocsigen.org/lwt/api/Lwt
[cond]: https://ocsigen.org/lwt/api/Lwt_condition
[mutex]: https://ocsigen.org/lwt/api/Lwt_mutex
[mvar]: https://ocsigen.org/lwt/api/Lwt_mvar
[unix]: https://ocsigen.org/lwt/api/Lwt_unix
[io]: https://ocsigen.org/lwt/api/Lwt_io
[process]: https://ocsigen.org/lwt/api/Lwt_process
[preemptive]: https://ocsigen.org/lwt/api/Lwt_preemptive
[ppx]: https://ocsigen.org/lwt/api/Ppx_lwt
[react]: https://ocsigen.org/lwt/api/Lwt_react
<br/>
## Installing
```
opam install lwt
```
1. Use your system package manager to install a development libev package.
It is often called `libev-dev` or `libev-devel`.
2. `opam install conf-libev lwt`
<br/>
## Documentation
The manual can be found [here][manual]. There are also some examples available
in [`doc/examples`][examples].
We are currently working on improving the Lwt documentation (drastically; we are
rewriting the manual). In the meantime:
- The current manual can be found [here][manual].
- Mirage has a nicely-written [Lwt tutorial][mirage-tutorial].
- An example of a [simple server][counter-server] written in Lwt.
- [Concurrent Programming with Lwt][rwo-lwt] is a nice source of Lwt examples.
They are translations of code from the excellent Real World OCaml, but are
just as useful if you are not reading the book.
*Note: much of the current manual refers to `'a Lwt.t` as "lightweight threads"
or just "threads." This will be fixed in the new manual. `'a Lwt.t` is a
promise, and has nothing to do with system or preemptive threads.*
*Note: much of the manual still refers to `'a Lwt.t` as "lightweight threads" or
just "threads." This will be fixed in the new manual. `'a Lwt.t` is a promise,
and has nothing to do with system or preemptive threads.*
[manual]: http://ocsigen.org/lwt/
[rwo-lwt]: https://github.com/dkim/rwo-lwt#readme
[mirage-tutorial]: https://mirage.io/wiki/tutorial-lwt
[counter-server]: http://www.baturin.org/code/lwt-counter-server/
[manual]: http://ocsigen.org/lwt/manual/
[examples]: https://github.com/ocsigen/lwt/tree/master/doc/examples
<br/>
## Contact
Open an [issue][issues], visit [Gitter][gitter] chat, [email][email] the
maintainer, or ask in [#ocaml][irc]. If you think enough people will be
interested in the answer, it is also possible to ask on [Stack Overflow][so].
Open an [issue][issues], visit [Gitter][gitter] chat, ask in [#ocaml][irc],
on [discuss.ocaml.org][discourse], or on [Stack Overflow][so]. Please do ask!
Even apparently simple questions often end up educating other users, not to
mention enlightening the maintainers!
Subscribe to the [announcements issue][announcements] to get news about Lwt
releases. It is less noisy than watching the whole repository. Announcements are
also made in [/r/ocaml][reddit] and on the [OCaml mailing list][caml-list].
Release announcements are made in [/r/ocaml][reddit], and on
[discuss.ocaml.org][discourse]. Watching the repo for "Releases only" is also an
option.
[issues]: https://github.com/ocsigen/lwt/issues/new
[gitter]: https://gitter.im/ocaml-lwt/Lobby
[email]: mailto:antonbachin@yahoo.com
[irc]: http://webchat.freenode.net/?channels=#ocaml
[so]: http://stackoverflow.com/questions/ask?tags=ocaml,lwt,ocaml-lwt
[announcements]: https://github.com/ocsigen/lwt/issues/309
[reddit]: https://www.reddit.com/r/ocaml/
[caml-list]: https://sympa.inria.fr/sympa/arc/caml-list
[discourse]: https://discuss.ocaml.org/c/lwt
[issues]: https://github.com/ocsigen/lwt/issues/new
<br/>
## Contributing
Lwt is a very mature library, but there is considerable room for improvement.
Contributions are welcome. To clone the source and install a development
version,
```
opam source --dev-repo --pin lwt
```
This will also install the development dependency OASIS.
A list of [project suggestions][projects] and a [roadmap][roadmap] can be found
on the wiki.
- We maintain [easy starter issues][easy-issues]. These are thoroughly explained
and hyperlinked. We hope that this makes working on Lwt accessible even to
relative OCaml beginners :)
- [`CONTRIBUTING.md`][contributing-md] contains tips for working on the code,
such as how to check the code out, how review works, etc. There is also a
high-level outline of the code base.
- The overall development plan can be found in the [roadmap][roadmap].
- [Ask](#contact) us anything, whether it's about working on Lwt, or any
question at all about it :)
- The [documentation](#documentation) always needs proofreading and fixes.
- Despite a lot of progress, Lwt still needs [more tests][testing-issues].
- You are welcome to pick up any other [issue][issues-and-prs], review a PR, add
your opinion, etc.
- Any feedback is welcome, including how to make contributing easier!
[issues-and-prs]: https://github.com/ocsigen/lwt/issues?utf8=%E2%9C%93&q=is%3Aopen
[all-issues]: https://github.com/ocsigen/lwt/issues
[roadmap]: https://github.com/ocsigen/lwt/wiki/Roadmap
[easy-issues]: https://github.com/ocsigen/lwt/labels/easy
[contributing-md]: https://github.com/ocsigen/lwt/blob/master/docs/CONTRIBUTING.md#readme
[testing-issues]: https://github.com/ocsigen/lwt/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Aeasy%20test
[projects]: https://github.com/ocsigen/lwt/wiki/Plan#projects
[roadmap]: https://github.com/ocsigen/lwt/wiki/Plan#roadmap
<br/>
## License
Lwt is released under the LGPL, with the OpenSSL linking exception. See
[`COPYING`][copying].
[copying]: https://github.com/ocsigen/lwt/blob/master/doc/COPYING
## Libraries to use with Lwt
- [alcotest](https://github.com/mirage/alcotest/)
unit testing
- [angstrom](https://github.com/inhabitedtype/angstrom)
parser combinators
- [cohttp](https://github.com/mirage/ocaml-cohttp) — HTTP client and server
- [cstruct](https://github.com/mirage/ocaml-cstruct)
interop with C-like structures
- [ezjsonm](https://github.com/mirage/ezjsonm)
JSON parsing and output
- [faraday](https://github.com/inhabitedtype/faraday)
serialization combinators
- [logs](https://github.com/dbuenzli/logs)
logging
- [lwt-parallel](https://github.com/ivg/parallel)
distributed computing
- [mwt](https://github.com/hcarty/mwt) — preemptive (system) thread pools
- [opium](https://github.com/rgrinberg/opium)
web framework
This diff is collapsed.
version: "{build}"
shallow_clone: true
environment:
global:
ARCH: x86_64
LWT_FORCE_LIBEV_BY_DEFAULT: yes
# Uncomment to debug build with RDP. Alternatively, create the file
# appveyor-debug in the repository root. The latter option avoids
# invalidating the AppVeyor dependency cache.
# LWT_APPVEYOR_DEBUG: yes
install:
- 'IF EXIST C:\projects\lwt\appveyor-debug (SET LWT_APPVEYOR_DEBUG=yes)'
- 'IF "%ARCH%"=="x86" (SET CYGSH=C:\Cygwin\bin\bash -lc) ELSE (SET CYGSH=C:\Cygwin64\bin\bash -lc)'
- 'IF "%ARCH%"=="x86" (SET CYGSETUP=C:\Cygwin\setup-x86) ELSE (SET CYGSETUP=C:\Cygwin64\setup-x86_64)'
- 'IF "%LWT_APPVEYOR_DEBUG%"=="yes" (%CYGSETUP% -q -P nano)'
- '%CYGSETUP% -q -P rsync -P patch -P diffutils -P make -P unzip -P m4'
- 'IF "%LIBEV%"=="yes" (%CYGSETUP% -q -P libev-devel)'
- '%CYGSH% "wget https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam64.tar.xz"'
- '%CYGSH% "tar -xf opam64.tar.xz"'
- '%CYGSH% "bash opam64/install.sh"'
- '%CYGSH% "opam init default https://github.com/fdopen/opam-repository-mingw.git#opam2 -c ocaml-variants.4.07.1+mingw64c --disable-sandboxing --yes --auto-setup"'
- '%CYGSH% "cd /cygdrive/c/projects/lwt ; src/util/appveyor-install.sh"'
build_script:
- '%CYGSH% "cd /cygdrive/c/projects/lwt ; src/util/appveyor-build.sh"'
cache:
- '..\opam-cache-%SYSTEM%-%COMPILER%-%LIBEV%.tar -> lwt*.opam, appveyor.yml, src\util\appveyor*.sh'
on_finish:
- ps: 'if ($env:LWT_APPVEYOR_DEBUG -eq "yes") { $blockRdp = $true; iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1")) }'
This diff is collapsed.
The Ocsigen application core, and other portions of the official Ocsigen
distribution not explicitly licensed otherwise, are licensed under
the GNU LESSER GENERAL PUBLIC LICENSE with openssl linking exception
-- see the 'COPYING' file in this directory for details.
all:
ocamlbuild -use-ocamlfind -classic-display -package lwt.unix,lwt.glib,lwt.ppx,lablgtk2 connect.byte
(* Lightweight thread library for OCaml
* http://www.ocsigen.org/lwt
* Program Connect
* Copyright (C) 2011 Jérémie Dimino
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, with linking exceptions;
* either version 2.1 of the License, or (at your option) any later
* version. See COPYING file for details.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*)
(* A simple graphical telnet. *)
open Lwt.Infix
(* +-----------------------------------------------------------------+
| Utils |
+-----------------------------------------------------------------+ *)
let show_error fmt =
Printf.ksprintf
(fun message ->
let dialog = GWindow.message_dialog ~message_type:`ERROR ~buttons:GWindow.Buttons.ok ~message () in
ignore (dialog#connect#response (function
| `DELETE_EVENT -> ()
| `OK -> dialog#destroy ()));
dialog#show ())
fmt
(* +-----------------------------------------------------------------+
| Connection |
+-----------------------------------------------------------------+ *)
(* Either [None] if we are not connected, either [Some (ic, oc,
thread)] if we are connected. In this last case [thread] is the
thread reading data from the connection. *)
let connection = ref None
(* Read continously data from [ic] and write them to [view]. *)
let read ic (view : GText.view) =
let rec loop () =
match%lwt Lwt_io.read_line_opt ic with
| Some line ->
view#buffer#insert ~iter:view#buffer#end_iter ~tag_names:["recv"] (line ^ "\n");
loop ()
| None ->
view#buffer#insert ~iter:view#buffer#end_iter "end of connection\n";
Lwt_io.close ic
in
try%lwt
loop ()
with Unix.Unix_error (error, _, _) ->
show_error "reading error: %s" (Unix.error_message error);
Lwt.return_unit
(* Function called when the user active the [connect] menu
item. [view] is the text view used to display data received from
the connection. *)
let connect (view : GText.view) =
(* Create a popup for asking the address and port to connect to. *)
let dialog = GWindow.dialog ~title:"connection" () in
dialog#add_button_stock `OK `OK;
dialog#add_button_stock `CANCEL `CANCEL;
let hbox = GPack.hbox ~packing:dialog#vbox#add () in
ignore (GMisc.label ~packing:hbox#add ~text:"host: " ());
let host = GEdit.entry ~packing:hbox#add ~text:"127.0.0.1" () in
ignore (GMisc.label ~packing:hbox#add ~text:" port: " ());
let port = GEdit.spin_button ~digits:0 ~numeric:true ~packing:hbox#add () in
port#adjustment#set_bounds ~lower:0. ~upper:(float max_int) ~step_incr:1. ();
(* Thread waiting for the popup to be closed. *)
let waiter, wakener = Lwt.wait () in
(* Wakeup the thread when the popup is closed. *)
ignore (dialog#connect#response (Lwt.wakeup wakener));
dialog#show ();
ignore (
match%lwt waiter with
| `DELETE_EVENT ->
Lwt.return_unit
| `CANCEL ->
dialog#destroy ();
Lwt.return_unit
| `OK ->
let host = host#text and port = int_of_float port#value in
dialog#destroy ();
try%lwt
(* Resolve the address. *)
let%lwt entry = Lwt_unix.gethostbyname host in
if Array.length entry.Unix.h_addr_list = 0 then begin
show_error "no address found for host %S" host;
Lwt.return_unit
end else begin
let%lwt ic, oc = Lwt_io.open_connection (Unix.ADDR_INET (entry.Unix.h_addr_list.(0), port)) in
(* Close the previous connection. *)
let%lwt () =
match !connection with
| None ->
Lwt.return_unit
| Some (ic, oc, thread) ->
Lwt.cancel thread;
try%lwt
Lwt_io.close ic <&> Lwt_io.close oc
with Unix.Unix_error (error, _, _) ->
show_error "cannot close the connection: %s" (Unix.error_message error);
Lwt.return_unit
in
(* Clear the buffer. *)
view#buffer#delete view#buffer#start_iter view#buffer#end_iter;
connection := Some (ic, oc, read ic view);
Lwt.return_unit
end
with
| Unix.Unix_error (error, _, _) ->
show_error "cannot establish the connection: %s" (Unix.error_message error);
Lwt.return_unit
| Not_found ->
show_error "host %S not found" host;
Lwt.return_unit
)
(* Send some data. *)
let write (view : GText.view) (entry : GEdit.entry) =
let text = entry#text in
entry#set_text "";
match !connection with
| Some (ic, oc, thread) ->
view#buffer#insert ~iter:view#buffer#end_iter ~tag_names:["send"] (text ^ "\n");
ignore (
try%lwt
Lwt_io.write_line oc text
with Unix.Unix_error (error, _, _) ->
show_error "cannot send line: %s" (Unix.error_message error);
Lwt.return_unit
)
| None ->
show_error "not connected"
(* +-----------------------------------------------------------------+
| Entry point |
+-----------------------------------------------------------------+ *)
let%lwt () =
(* Initializes GTK. *)
ignore (GMain.init ~setlocale:false ());
(* Integrate Lwt with Glib. *)
Lwt_glib.install ();
(* Create the UI. *)
let window = GWindow.window ~title:"simple graphical telnet in OCaml with Lwt" ~allow_shrink:true ~width:640 ~height:480 () in
let vbox = GPack.vbox ~packing:window#add () in
(* Create the menu. *)
let menu = GMenu.menu_bar ~packing:(vbox#pack ~expand:false) () in
let menu_file = GMenu.menu ~packing:(GMenu.menu_item ~label:"File" ~packing:menu#add ())#set_submenu () in
let menu_connect = GMenu.image_menu_item ~label:"Connect" ~packing:menu_file#add ~stock:`CONNECT () in
ignore (GMenu.separator_item ~packing:menu_file#add ());
let menu_quit = GMenu.image_menu_item ~label:"Quit" ~packing:menu_file#add ~stock:`QUIT () in
(* The text view displaying inputs and outputs. *)
let view =
GText.view
~editable:false
~packing:(GBin.scrolled_window
~hpolicy:`AUTOMATIC
~vpolicy:`AUTOMATIC
~packing:(GBin.frame
~label:"log"
~packing:vbox#add
())#add
())#add
()
in
ignore (view#buffer#create_tag ~name:"send" [`FOREGROUND "blue"]);
ignore (view#buffer#create_tag ~name:"recv" [`FOREGROUND "#007f00"]);
let hbox = GPack.hbox ~packing:(GBin.frame ~label:"input" ~packing:(vbox#pack ~expand:false) ())#add () in
(* The entry for user input. *)
let entry = GEdit.entry ~packing:hbox#add () in
let send = GButton.button ~label:"send" ~packing:(hbox#pack ~expand:false) () in
(* Try to use a monospace font. *)
(try
view#misc#modify_font_by_name "Monospace";
entry#misc#modify_font_by_name "Monospace"
with _ ->
());
(* Thread waiting for the main window to be closed. *)
let waiter, wakener = Lwt.wait () in
(* Setup callbacks. *)
ignore (window#connect#destroy (Lwt.wakeup wakener));
ignore (menu_quit#connect#activate (Lwt.wakeup wakener));
ignore (menu_connect#connect#activate (fun () -> connect view));
ignore (entry#connect#activate (fun () -> write view entry));
ignore (send#connect#clicked (fun () -> write view entry));
window#show ();
(* Wait for the main window to be closed. *)
waiter
(* Lightweight thread library for OCaml
* http://www.ocsigen.org/lwt
* Program Logging
* Copyright (C) 2011 Jérémie Dimino
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, with linking exceptions;
* either version 2.1 of the License, or (at your option) any later
* version. See COPYING file for details.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*)
(* This example illustrate the use of the Lwt_log module from
lwt.unix. *)
(* The logging section for this module: *)
let section = Lwt_log.Section.make "test"
let%lwt () =
(* Enable all logging levels superior from [Info] to [Fatal]: *)
Lwt_log.Section.set_level section Lwt_log.Info;
(* A message with the default logger: *)
let%lwt () = Lwt_log.log ~section ~level:Lwt_log.Info "this message will appear only on stderr" in
(* Same as begore, but using [Lwt_log.info]: *)
let%lwt () = Lwt_log.info ~section "this one too" in
(* A message to a custom logger, logging simultaneously to [stderr]
and to the system logger daemon: *)
let logger =
Lwt_log.broadcast
[Lwt_log.channel ~close_mode:`Keep ~channel:Lwt_io.stderr ();
Lwt_log.syslog ~facility:`User ()]
in
let%lwt () = Lwt_log.info ~section ~logger "this message will appear on stderr and in '/var/log/user.log'" in
(* Logging of exceptions: *)
Printexc.record_backtrace true;
let f () : unit = raise Exit in
let g () = f () in
let h () = g () in
let%lwt () =
try
h ();
Lwt.return_unit
with exn ->
Lwt_log.error ~section ~exn "h failed with"
in
let logger = Lwt_log.channel ~template:"$(name): $(section): $(loc-file): $(loc-line): $(loc-column): $(message)" ~close_mode:`Keep ~channel:Lwt_io.stderr () in
Lwt_log.info ~section ~logger "this message will appear with a location"
(* Lightweight thread library for OCaml
* http://www.ocsigen.org/lwt
* Program Parallelize
* Copyright (C) 2011 Jérémie Dimino
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, with linking exceptions;
* either version 2.1 of the License, or (at your option) any later
* version. See COPYING file for details.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*)
(* Reads commands from standard input and launch them in parallel,
using as many processes as the number of CPUs. *)
open Lwt.Infix
(* Reads one command, launch it and waits for when it termination,
then start again: *)
let rec launch () =
match%lwt Lwt_io.read_line_opt Lwt_io.stdin with
| None ->
Lwt.return_unit
| Some line ->
let%lwt _ = Lwt_process.exec (Lwt_process.shell line) in
launch ()
(* Creates the initial <N> threads, where <N> is the number of
CPUs: *)
let rec create_threads = function
| 0 ->
Lwt.return_unit
| n ->
launch () <&> create_threads (n - 1)
(* Counts the number of CPUs using "/proc/cpuinfo": *)
let cpus_count () =
Lwt_stream.fold (fun _ n -> succ n)
(Lwt_stream.filter
(fun line ->
try
Scanf.sscanf line "processor :" true
with _ ->
false)
(Lwt_io.lines_of_file "/proc/cpuinfo")) 0
let%lwt () = cpus_count () >>= create_threads
(* Lightweight thread library for OCaml
* http://www.ocsigen.org/lwt
* Program Relay
* Copyright (C) 2011 Jérémie Dimino
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, with linking exceptions;
* either version 2.1 of the License, or (at your option) any later
* version. See COPYING file for details.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*)
(* Relay data from an address to another. *)
(* +-----------------------------------------------------------------+
| Relaying |
+-----------------------------------------------------------------+ *)
(* Write exactly [len] bytes from [buf] at [ofs]. *)
let rec write_exactly fd buf ofs len =
let%lwt n = Lwt_bytes.write fd buf ofs len in
if n = len then
(* Everything has been written, do nothing. *)
Lwt.return_unit
else
(* Write remaining data. *)
write_exactly fd buf (ofs + n) (len - n)
(* Copy continously data from [in_fd] to [out_fd]. *)
let relay in_fd out_fd =
(* Queue of data received but not yet written. *)
let queue = Queue.create () in
(* Condition used to signal the writer that some data are
available. *)
let cond = Lwt_condition.create () in
(* Boolean which tells whether the input socket has been closed. *)
let end_of_input = ref false in
(* Write continously data received to [out_fd]. *)
let rec loop_write () =
if Queue.is_empty queue then
if !end_of_input then
(* End of input reached, exit. *)
Lwt.return_unit
else
(* There is no data pending, wait for some. *)
let%lwt () = Lwt_condition.wait cond in
loop_write ()
else
let (buf, len) = Queue.take queue in
let%lwt () = write_exactly out_fd buf 0 len in
loop_write ()
in
(* Start the writer. *)
let writer = loop_write () in
(* Read continously from [in_fd]. *)
let rec loop_read () =
let buf = Lwt_bytes.create 8192 in
match%lwt Lwt_bytes.read in_fd buf 0 8192 with
| 0 ->
(* If we read nothing, this means that the connection has
been closed. *)
(* Mark the end of input has reached. *)
end_of_input := true;
(* Singal the writer in case it is waiting for data. *)
Lwt_condition.signal cond ();
(* Wait for it to terminate. *)
writer
| n ->
(* Otherwise, send data to the writer. *)
Queue.add (buf, n) queue;
(* Singal the writer in case it is waiting for data. *)
Lwt_condition.signal cond ();
loop_read ()
in
(* Wait for either the reader to terminate or the writer to fail. *)
Lwt.pick [writer; loop_read ()]
(* +-----------------------------------------------------------------+
| Entry point |
+-----------------------------------------------------------------+ *)
let usage () =
prerr_endline "usage: relay <source-address>:<source-port> <destination-address>:<destination-port>";
exit 2
(* Convert a string of the form "<host>:<port>" to an internet address
object. *)
let addr_of_string str =
(* Split the host and the port. *)
let idx = try String.index str ':' with Not_found -> usage () in
let host = String.sub str 0 idx and port = String.sub str (idx + 1) (String.length str - idx - 1) in
(* Parse the port. *)
let port = try int_of_string port with Failure _ -> usage () in
(* Request the address of the host. *)
let%lwt entry = Lwt_unix.gethostbyname host in
if Array.length entry.Unix.h_addr_list = 0 then begin
Printf.eprintf "no address found for host %S\n" host;
exit 1
end;
Lwt.return (Unix.ADDR_INET (entry.Unix.h_addr_list.(0), port))
let%lwt () =
if Array.length Sys.argv <> 3 then usage ();
try%lwt
(* Resolve addresses. *)
let%lwt src_addr = addr_of_string Sys.argv.(1) and dst_addr = addr_of_string Sys.argv.(2) in
(* Initialize the listening address. *)
let sock = Lwt_unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
Lwt_unix.setsockopt sock Unix.SO_REUSEADDR true;
let%lwt () = Lwt_unix.Versioned.bind_2 sock src_addr in
Lwt_unix.listen sock 1024;
ignore (Lwt_log.notice "waiting for connection");
(* Wait for a connection. *)
let%lwt fd1, _ = Lwt_unix.accept sock in
ignore (Lwt_log.notice "connection received, start relayling");
(* Closes the no-more used listening socket. *)
let%lwt () = Lwt_unix.close sock in
(* Connect to the destination port. *)
let fd2 = Lwt_unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
let%lwt () = Lwt_unix.connect fd2 dst_addr in
(* Start relaying. *)
let%lwt () = Lwt.pick [relay fd1 fd2; relay fd2 fd1] in
ignore (Lwt_log.notice "done relayling");
Lwt.return_unit
with exn ->
ignore (Lwt_log.error ~exn "something went wrong");
exit 1
Monadic promises and concurrent I/O
A promise is a value that may become determined in the future.
Lwt provides typed, composable promises. Promises that are resolved by I/O are
resolved by Lwt in parallel.
Meanwhile, OCaml code, including code creating and waiting on promises, runs in
a single thread by default. This reduces the need for locks or other
synchronization primitives. Code can be run in parallel on an opt-in basis.
GLib integration for Lwt
Helpers for using React with Lwt
Lwt-friendly OpenSSL bindings
Copyright (c) 1999-2008 Jérôme Vouillon
Laboratoire PPS - CNRS Université Paris Diderot
2005 Nataliya Guts, Vincent Balat
Laboratoire PPS - CNRS Université Paris Diderot
2008 Stéphane Glondu
2009 Mauricio Fernandez
2009, 2010 Pierre Chambart
2009-2012 Jérémie Dimino
Laboratoire PPS - CNRS Université Paris Diderot
2014 Peter Zotov
2014, 2018 Gabriel Radanne
2015 Nicolas Ojeda Bar
2016 Simon Cruanes
2016-2018 Anton Bachin
2017 Joseph Thomas
2017 Andrew Ray