diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 166bc72afa..c41b1de015 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -116,3 +116,24 @@ jobs: - run: nix-build -A hs.urbit-king.components.exes.urbit-king --arg enableStatic true - run: nix-build -A hs-checks - run: nix-build shell.nix + + mingw: + runs-on: windows-latest + defaults: + run: + shell: C:\msys64\msys2_shell.cmd -mingw64 -defterm -no-start -here -c ". <(cygpath '{0}')" + working-directory: ./pkg/urbit + + steps: + - uses: actions/checkout@v2 + with: + lfs: true + + # echo suppresses pacman prompt + - run: echo|./configure + env: + CACHIX_CACHE: locpyl-tidnyd-test1 + CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} + + - run: make build/urbit build/urbit-worker + - run: build/urbit -l -d -B ../../bin/solid.pill -F bus && curl -f --data '{"source":{"dojo":"+hood/exit"},"sink":{"app":"hood"}}' http://localhost:12321 diff --git a/.gitignore b/.gitignore index e79759dc67..e6c572d9b3 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ release/ dist/ out/ work/ +pkg/*/*.a *.o # Landscape Dev diff --git a/bin/solid.pill b/bin/solid.pill index 034ca34273..7bac0f38e7 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d7b7cf24e56ab078cf1dcb82e4e7744f188c5221c08772d6cfb15f59ce81aaa5 -size 11198219 +oid sha256:88acd8aa1aae3d11579ada954b6e0b06c940de7856d22017cc1a1442de97fcf3 +size 13650762 diff --git a/nix/sources-pmnsh.json b/nix/sources-pmnsh.json new file mode 100644 index 0000000000..cd3e8a30fc --- /dev/null +++ b/nix/sources-pmnsh.json @@ -0,0 +1,90 @@ +{ + "curl": { + "branch": "master", + "description": "A command line tool and library for transferring data with URL syntax", + "homepage": "http://curl.se/", + "pmnsh": { + "include": "include", + "lib": "lib/.libs", + "prepare": "autoreconf -vfi && ./configure --disable-shared --disable-ldap --disable-rtsp --without-brotli --without-libidn2 --without-libpsl --without-nghttp2 --with-openssl", + "make": "-C lib libcurl.la" + }, + "owner": "curl", + "repo": "curl", + "rev": "curl-7_77_0", + "type": "tarball", + "url": "https://github.com/curl/curl/archive/curl-7_77_0.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "lmdb": { + "branch": "mdb.master", + "description": "LMDB library", + "homepage": "http://www.lmdb.tech/", + "pmnsh": { + "strip": 2, + "make": "liblmdb.a" + }, + "owner": "LMDB", + "repo": "lmdb", + "rev": "48a7fed59a8aae623deff415dda27097198ca0c1", + "type": "tarball", + "url": "https://github.com/LMDB/lmdb/archive/48a7fed59a8aae623deff415dda27097198ca0c1.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "secp256k1": { + "branch": "master", + "description": "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.", + "homepage": null, + "pmnsh": { + "include": "include", + "lib": ".libs", + "prepare": "./autogen.sh && ./configure --disable-shared --enable-module-recovery CFLAGS=-DSECP256K1_API=", + "make": "libsecp256k1.la" + }, + "owner": "bitcoin-core", + "repo": "secp256k1", + "rev": "26de4dfeb1f1436dae1fcf17f57bdaa43540f940", + "type": "tarball", + "url": "https://github.com/bitcoin-core/secp256k1/archive/26de4dfeb1f1436dae1fcf17f57bdaa43540f940.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "uv": { + "branch": "v1.x", + "description": "Cross-platform asynchronous I/O", + "homepage": "http://libuv.org/", + "pmnsh": { + "include": "include", + "lib": ".libs", + "prepare": "./autogen.sh && ./configure --disable-shared", + "make": "libuv.la", + "compat": { + "m1brew": false + } + }, + "owner": "libuv", + "repo": "libuv", + "rev": "v1.40.0", + "type": "tarball", + "url": "https://github.com/libuv/libuv/archive/v1.40.0.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "ent": { + "pmnsh": { + "prepare": "./configure" + } + }, + "ge-additions": { + "pmnsh": { + "make": "CFLAGS=-I../ed25519" + } + }, + "libaes_siv": { + "pmnsh": { + "compat": { + "m1brew": { + "make": "CFLAGS=$(pkg-config --cflags openssl)" + } + } + } + } +} diff --git a/nix/sources.json b/nix/sources.json index b9c176227f..adb772dc2f 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -3,18 +3,26 @@ "branch": "master", "description": "With argon2u. Based off https://github.com/P-H-C/phc-winner-argon2", "homepage": "", + "pmnsh": { + "include": ["include", "src/blake2"], + "make": "libargon2.a" + }, "owner": "urbit", "repo": "argon2", - "rev": "4da94a611ee62bad87ab2b131ffda3bcc0723d9c", - "sha256": "0bqq1hg367l4jkb6cqhxlblpvdbwz3l586qsfakwzfd9wdvnm3yc", + "rev": "a4c1e3f7138c2e577376beb99f964cf71e1c8b1b", + "sha256": "1j8a15fx2kn5aa3scmb5qnsfk627kfvsq5ppz9j0pv2d1xck527x", "type": "tarball", - "url": "https://github.com/urbit/argon2/archive/4da94a611ee62bad87ab2b131ffda3bcc0723d9c.tar.gz", + "url": "https://github.com/urbit/argon2/archive/a4c1e3f7138c2e577376beb99f964cf71e1c8b1b.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "ed25519": { "branch": "master", "description": "Submodule included by Urbit", "homepage": null, + "pmnsh": { + "strip": 1, + "make": "all" + }, "owner": "urbit", "repo": "ed25519", "rev": "76385f2ebbbc9580a9c236952d68d11d73a6135c", @@ -24,15 +32,25 @@ "url_template": "https://github.com///archive/.tar.gz" }, "h2o": { - "branch": "v2.2.x", + "branch": "master", "description": "H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server", "homepage": "https://h2o.examp1e.net", + "pmnsh": { + "include": "include", + "prepare": "cmake .", + "make": "libh2o", + "compat": { + "mingw": { + "prepare": "cmake -G\"MSYS Makefiles\" ." + } + } + }, "owner": "h2o", "repo": "h2o", - "rev": "7359e98d78d018a35f5da7523feac69f64eddb4b", + "rev": "v2.2.6", "sha256": "0qni676wqvxx0sl0pw9j0ph7zf2krrzqc1zwj73mgpdnsr8rsib7", "type": "tarball", - "url": "https://github.com/h2o/h2o/archive/7359e98d78d018a35f5da7523feac69f64eddb4b.tar.gz", + "url": "https://github.com/h2o/h2o/archive/v2.2.6.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "hackage.nix": { @@ -63,6 +81,9 @@ "branch": "master", "description": null, "homepage": null, + "pmnsh": { + "make": "libscrypt.a CFLAGS_EXTRA=-ffast-math" + }, "owner": "urbit", "repo": "libscrypt", "rev": "029693ff1cbe4f69d3a2da87d0f4f034f92cc0c2", @@ -75,6 +96,9 @@ "branch": "master", "description": null, "homepage": null, + "pmnsh": { + "make": "static" + }, "owner": "urbit", "repo": "murmur3", "rev": "71a75d57ca4e7ca0f7fc2fd84abd93595b0624ca", @@ -111,6 +135,19 @@ "branch": "master", "description": null, "homepage": null, + "pmnsh": { + "include": "source/include", + "compat": { + "m1brew": { + "lib": "build/template-FAST_INT64", + "make": "-C build/template-FAST_INT64 libsoftfloat3.a" + }, + "mingw": { + "lib": "build/Win64-MinGW-w64", + "make": "-C build/Win64-MinGW-w64 libsoftfloat3.a" + } + } + }, "owner": "urbit", "repo": "berkeley-softfloat-3", "rev": "ec4c7e31b32e07aad80e52f65ff46ac6d6aad986", diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index c06b86e50e..73f4f86358 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -875,7 +875,7 @@ %ge (dy-run-generator (dy-cage p.p.p.bil) q.p.bil) %sa =+ .^(=dais:clay cb+(en-beam he-beak /[p.bil])) - (dy-hand p.bil bunt:dais) + (dy-hand p.bil *vale:dais) :: %as =/ cag=cage (dy-cage p.q.bil) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index e4cbca335a..6c7f778f01 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -1,6 +1,5 @@ :: graph-store [landscape] :: -:: /+ store=graph-store, sigs=signatures, res=resource, default-agent, dbug, verb ~% %graph-store-top ..part ~ |% @@ -724,7 +723,7 @@ :+ %add-nodes [ship term] %- ~(gas by *(map index:store node:store)) - %+ turn (tap:orm `graph:store`(subset:orm p.u.graph start end)) + %+ turn (tap:orm `graph:store`(lot:orm p.u.graph start end)) |= [=atom =node:store] ^- [index:store node:store] [~[atom] node] @@ -775,7 +774,7 @@ %+ turn =- ?.(older (slag (safe-sub (lent -) count) -) (scag count -)) %- tap:orm - %+ subset:orm u.graph + %+ lot:orm u.graph =/ idx (snag (dec (lent index)) index) ?:(older [`idx ~] [~ `idx]) @@ -826,7 +825,7 @@ :+ %add-nodes [ship term] %- ~(gas by *(map index:store node:store)) - %+ turn (tap:orm `graph:store`(subset:orm p.children.u.node end start)) + %+ turn (tap:orm `graph:store`(lot:orm p.children.u.node end start)) |= [=atom =node:store] ^- [index:store node:store] [(snoc index atom) node] @@ -840,7 +839,7 @@ =/ update-log=(unit update-log:store) (~(get by update-logs) [ship term]) ?~ update-log [~ ~] :: orm-log is ordered backwards, so swap start and end - ``noun+!>((subset:orm-log u.update-log end start)) + ``noun+!>((lot:orm-log u.update-log end start)) :: [%x %update-log @ @ ~] =/ =ship (slav %p i.t.t.path) @@ -858,7 +857,7 @@ %+ biff m-update-log |= =update-log:store =/ result=(unit [=time =update:store]) - (peek:orm-log:store update-log) + (pry:orm-log:store update-log) (bind result |=([=time update:store] time)) == :: diff --git a/pkg/arvo/app/hark-graph-hook.hoon b/pkg/arvo/app/hark-graph-hook.hoon index 828025d3d9..4e7de53d80 100644 --- a/pkg/arvo/app/hark-graph-hook.hoon +++ b/pkg/arvo/app/hark-graph-hook.hoon @@ -256,7 +256,7 @@ =/ graph=graph:graph-store :: graph in subscription is bunted (get-graph-mop:gra rid) =/ node=(unit node:graph-store) - (bind (peek:orm:graph-store graph) |=([@ =node:graph-store] node)) + (bind (pry:orm:graph-store graph) |=([@ =node:graph-store] node)) =/ assoc=(unit association:metadata) (peek-association:met %graph rid) =^ cards state diff --git a/pkg/arvo/gen/hood/fuse.hoon b/pkg/arvo/gen/hood/fuse.hoon new file mode 100644 index 0000000000..870b38d2aa --- /dev/null +++ b/pkg/arvo/gen/hood/fuse.hoon @@ -0,0 +1,15 @@ +:: Kiln: Fuse local desk from (optionally-)foreign sources +:: +:::: /hoon/fuse/hood/gen + :: +/* help-text %txt /gen/hood/fuse/help/txt +=, clay +:: +:::: + :: +:- %say +|= [[now=@da eny=@uvJ bec=beak] [arg=[?(~ [des=desk bas=beak con=(list [beak germ]) ~])]] ~] +:- %kiln-fuse +?~ arg + ((slog (turn `wain`help-text |=(=@t leaf+(trip t)))) ~) +[des bas con]:arg diff --git a/pkg/arvo/gen/hood/fuse/help.txt b/pkg/arvo/gen/hood/fuse/help.txt new file mode 100644 index 0000000000..9e18eb80e9 --- /dev/null +++ b/pkg/arvo/gen/hood/fuse/help.txt @@ -0,0 +1,8 @@ +Usage: + + |fuse %destination-desk base-beak ~[[source-beak %some-germ] [another-beak %another-germ]] + +A fuse replaces the contents of %destination-desk with the merge of the +specified beaks according to their merge strategies. This has no dependence +on the previous state of %destination-desk so any commits/work there will +be overwritten. diff --git a/pkg/arvo/gen/tally.hoon b/pkg/arvo/gen/tally.hoon index 9040da1d04..7935400362 100644 --- a/pkg/arvo/gen/tally.hoon +++ b/pkg/arvo/gen/tally.hoon @@ -1,5 +1,5 @@ /- gr=group, md=metadata-store, ga=graph-store -/+ re=resource +/+ re=resource, graph=graph-store !: :- %say |= $: [now=@da eny=@uvJ =beak] @@ -86,9 +86,9 @@ %+ scry update:ga [%x %graph-store /graph/(scot %p entity.r)/[name.r]/noun] ?> ?=(%add-graph -.q.upd) - =/ mo ((ordered-map atom node:ga) gth) + =* mo orm:graph =/ week=(list [@da node:ga]) - (tap:mo (subset:mo graph.q.upd ~ `(sub now ~d7))) + (tap:mo (lot:mo graph.q.upd ~ `(sub now ~d7))) :- (lent week) %~ wyt in %+ roll week diff --git a/pkg/arvo/lib/hood/kiln.hoon b/pkg/arvo/lib/hood/kiln.hoon index 0e7f719eb2..79b07a668a 100644 --- a/pkg/arvo/lib/hood/kiln.hoon +++ b/pkg/arvo/lib/hood/kiln.hoon @@ -55,6 +55,12 @@ cas=case :: gim=?(%auto germ) :: == ++$ kiln-fuse + $@ ~ + $: syd=desk + bas=beak + con=(list [beak germ]) + == -- |= [bowl:gall state] ?> =(src our) @@ -381,6 +387,11 @@ ?~ +< abet abet:abet:(merge:(work syd) ali sud cas gim) :: +++ poke-fuse + |= k=kiln-fuse + ?~ k abet + abet:(emit [%pass /kiln/fuse/[syd.k] %arvo %c [%fuse syd.k bas.k con.k]]) +:: ++ poke-cancel |= a=@tas abet:(emit %pass /cancel %arvo %c [%drop a]) @@ -430,6 +441,7 @@ %kiln-info =;(f (f !<(_+<.f vase)) poke-info) %kiln-label =;(f (f !<(_+<.f vase)) poke-label) %kiln-merge =;(f (f !<(_+<.f vase)) poke-merge) + %kiln-fuse =;(f (f !<(_+<.f vase)) poke-fuse) %kiln-mount =;(f (f !<(_+<.f vase)) poke-mount) %kiln-ota =;(f (f !<(_+<.f vase)) poke:update) %kiln-ota-info =;(f (f !<(_+<.f vase)) poke-ota-info) @@ -489,6 +501,8 @@ ++ take |=(way=wire ?>(?=([@ ~] way) (work i.way))) :: general handler ++ take-mere :: |= [way=wire are=(each (set path) (pair term tang))] + ?. ?=([@ ~] way) + abet abet:abet:(mere:(take way) are) :: ++ take-coup-fancy :: diff --git a/pkg/arvo/lib/language-server/parser.hoon b/pkg/arvo/lib/language-server/parser.hoon index d4f5002fb6..cf57790926 100644 --- a/pkg/arvo/lib/language-server/parser.hoon +++ b/pkg/arvo/lib/language-server/parser.hoon @@ -21,7 +21,10 @@ (most ;~(plug com gaw) taut-rule) :: %+ rune tis - ;~(plug sym ;~(pfix gap fas (more fas urs:ab))) + ;~(plug sym ;~(pfix gap stap)) + :: + %+ rune sig + ;~((glue gap) sym wyde:vast stap) :: %+ rune cen ;~(plug sym ;~(pfix gap ;~(pfix cen sym))) @@ -37,7 +40,7 @@ ;~ (glue gap) sym ;~(pfix cen sym) - ;~(pfix fas (more fas urs:ab)) + stap == :: %+ stag %tssg diff --git a/pkg/arvo/lib/strandio.hoon b/pkg/arvo/lib/strandio.hoon index 7ccbfcbca7..d0574fc73c 100644 --- a/pkg/arvo/lib/strandio.hoon +++ b/pkg/arvo/lib/strandio.hoon @@ -490,7 +490,7 @@ =/ m (strand ,vase) ^- form:m ;< =riot:clay bind:m - (warp ship desk ~ %sing %b case /[mak]) + (warp ship desk ~ %sing %e case /[mak]) ?~ riot (strand-fail %build-nave >arg< ~) ?> =(%nave p.r.u.riot) diff --git a/pkg/arvo/mar/graph/validator/chat.hoon b/pkg/arvo/mar/graph/validator/chat.hoon index 53c10c9f0e..f1a0a16843 100644 --- a/pkg/arvo/mar/graph/validator/chat.hoon +++ b/pkg/arvo/mar/graph/validator/chat.hoon @@ -33,7 +33,7 @@ ++ grab |% ++ noun - |= p=* + |: p=`*`%*(. *indexed-post index.p [0 ~]) =/ ip ;;(indexed-post p) ?> ?=([@ ~] index.p.ip) ip diff --git a/pkg/arvo/mar/graph/validator/link.hoon b/pkg/arvo/mar/graph/validator/link.hoon index d877018648..3f0164c363 100644 --- a/pkg/arvo/mar/graph/validator/link.hoon +++ b/pkg/arvo/mar/graph/validator/link.hoon @@ -49,7 +49,7 @@ ++ grab |% ++ noun - |= p=* + |: p=`*`%*(. *indexed-post index.p [0 0 ~]) =/ ip ;;(indexed-post p) ?+ index.p.ip ~|(index+index.p.ip !!) :: top-level link post; title and url diff --git a/pkg/arvo/mar/graph/validator/post.hoon b/pkg/arvo/mar/graph/validator/post.hoon index a12e62e721..15c9a3f010 100644 --- a/pkg/arvo/mar/graph/validator/post.hoon +++ b/pkg/arvo/mar/graph/validator/post.hoon @@ -43,7 +43,7 @@ :: +noun: validate post :: ++ noun - |= p=* + |: p=`*`%*(. *indexed-post contents.p [%text '']~) =/ ip ;;(indexed-post p) ?> ?=(^ contents.p.ip) ip diff --git a/pkg/arvo/mar/graph/validator/publish.hoon b/pkg/arvo/mar/graph/validator/publish.hoon index c8da4405ca..d19812b3e1 100644 --- a/pkg/arvo/mar/graph/validator/publish.hoon +++ b/pkg/arvo/mar/graph/validator/publish.hoon @@ -58,7 +58,7 @@ :: +noun: validate publish note :: ++ noun - |= p=* + |: p=`*`%*(. *indexed-post index.p [0 ~]) =/ ip ;;(indexed-post p) ?+ index.p.ip !! :: top level post must have no content diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 834cbcf390..d84d3a35cf 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -5452,12 +5452,14 @@ :::: 4k: atom printing :: ++ co + !: ~% %co ..co ~ =< |_ lot=coin ++ rear |=(rom=tape rend(rep rom)) - ++ rent `@ta`(rap 3 rend) + ++ rent ~+ `@ta`(rap 3 rend) ++ rend ^- tape + ~+ ?: ?=(%blob -.lot) ['~' '0' ((v-co 1) (jam p.lot))] ?: ?=(%many -.lot) @@ -5602,18 +5604,17 @@ |= a=dn ?: ?=([%i *] a) (weld ?:(s.a "inf" "-inf") rep) ?: ?=([%n *] a) (weld "nan" rep) - =/ f=(pair tape @) - %. a.a - %+ ed-co(rep ~) [10 1] - |=([a=? b=@ c=tape] [~(d ne b) ?.(a c ['.' c])]) - =. e.a (sum:si e.a (sun:si (dec q.f))) - =/ res - %+ weld p.f - ?~ e.a - rep - %+ weld ?:((syn:si e.a) "e" "e-") - ((d-co 1) (abs:si e.a)) - ?:(s.a res ['-' res]) + =; rep ?:(s.a rep ['-' rep]) + =/ f ((d-co 1) a.a) + =^ e e.a + =/ e=@s (sun:si (lent f)) + =/ sci :(sum:si e.a e -1) + ?: (syn:si (dif:si e.a --3)) [--1 sci] :: 12000 -> 12e3 e>+2 + ?: !(syn:si (dif:si sci -2)) [--1 sci] :: 0.001 -> 1e-3 e<-2 + [(sum:si sci --1) --0] :: 1.234e2 -> '.'@3 -> 123 .4 + =? rep !=(--0 e.a) + :(weld ?:((syn:si e.a) "e" "e-") ((d-co 1) (abs:si e.a))) + (weld (ed-co e f) rep) :: ++ s-co |= esc=(list @) ^- tape @@ -5659,20 +5660,13 @@ :: - used only for @r* floats :: ++ ed-co - |= [[bas=@ min=@] par=$-([? @ tape] tape)] - =| [fir=? cou=@ud] - |= hol=@ - ^- [tape @] - ?: &(=(0 hol) =(0 min)) - [rep cou] - =/ [dar=@ rad=@] (dvr hol bas) - %= $ - min ?:(=(0 min) 0 (dec min)) - hol dar - rep (par &(=(0 dar) !fir) rad rep) - fir | - cou +(cou) - == + |= [exp=@s int=tape] ^- tape + =/ [pos=? dig=@u] [=(--1 (cmp:si exp --0)) (abs:si exp)] + ?. pos + (into (weld (reap +(dig) '0') int) 1 '.') + =/ len (lent int) + ?: (lth dig len) (into int dig '.') + (weld int (reap (sub dig len) '0')) :: :: +ox-co: format '.'-separated digit sequences in numeric base :: @@ -5965,9 +5959,8 @@ :: ++ spat |=(pax=path (crip (spud pax))) :: render path to cord ++ spud |=(pax=path ~(ram re (smyt pax))) :: render path to tape -++ stab :: parse cord to path - =+ fel=;~(pfix fas (more fas urs:ab)) - |=(zep=@t `path`(rash zep fel)) +++ stab |=(zep=@t `path`(rash zep stap)) :: parse cord to path +++ stap ;~(pfix fas (more fas urs:ab)) :: path parser :: :::: 4n: virtualization :: @@ -6627,7 +6620,7 @@ +$ seminoun :: partial noun; blocked subtrees are ~ :: - $~ [[%full ~] ~] + $~ [[%full / ~ ~] ~] [mask=stencil data=noun] :: :: +stencil: noun knowledge map diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index c10dc016d8..b02630eabd 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -762,6 +762,11 @@ her=@p dem=desk cas=case :: source how=germ :: method == :: + $: %fuse :: merge many + des=desk :: target desk + bas=beak :: base desk + con=(list [beak germ]) :: merges + == [%mont pot=term bem=beam] :: mount to unix [%dirk des=desk] :: mark mount dirty [%ogre pot=$@(desk beam)] :: delete mount point @@ -928,6 +933,7 @@ :: /- sur-file :: surface imports from /sur :: /+ lib-file :: library imports from /lib :: /= face /path :: imports built hoon file at path + :: /~ face type /path :: imports built hoon files from directory :: /% face %mark :: imports mark definition from /mar :: /$ face %from %to :: imports mark converter from /mar :: /* face %mark /path :: unbuilt file imports, as mark @@ -936,6 +942,7 @@ $: sur=(list taut) lib=(list taut) raw=(list [face=term =path]) + raz=(list [face=term =spec =path]) maz=(list [face=term =mark]) caz=(list [face=term =mars]) bar=(list [face=term =mark =path]) @@ -955,7 +962,6 @@ $_ ^? |% - ++ bunt *typ ++ diff |~([old=typ new=typ] *dif) ++ form *mark ++ join |~([a=dif b=dif] *(unit (unit dif))) @@ -970,7 +976,6 @@ +$ dais $_ ^| |_ sam=vase - ++ bunt sam ++ diff |~(new=_sam *vase) ++ form *mark ++ join |~([a=vase b=vase] *(unit (unit vase))) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index bd267477e4..fb09a2ebea 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -1944,11 +1944,11 @@ =/ =bone bone.shut-packet :: ?: ?=(%& -.meat.shut-packet) - =+ ?~ dud ~ + =+ ?. &(?=(^ dud) msg.veb) ~ %. ~ - %+ slog - leaf+"ames: {} fragment crashed {}" - ?.(msg.veb ~ tang.u.dud) + %- slog + :_ tang.u.dud + leaf+"ames: {} fragment crashed {}" (run-message-sink bone %hear lane shut-packet ?=(~ dud)) :: Just try again on error, printing trace :: @@ -1967,20 +1967,12 @@ ++ on-memo |= [=bone payload=* valence=?(%plea %boon)] ^+ peer-core - :: if we haven't been trying to talk to %live, reset timer - :: - =? last-contact.qos.peer-state - ?& ?=(%live -.qos.peer-state) - %- ~(all by snd.peer-state) - |= =message-pump-state - =(~ live.packet-pump-state.message-pump-state) - == - now - :: =/ =message-blob (dedup-message (jim payload)) =. peer-core (run-message-pump bone %memo message-blob) :: - ?: &(=(%boon valence) ?=(?(%dead %unborn) -.qos.peer-state)) + ?: ?& =(%boon valence) + (gte now (add ~s30 last-contact.qos.peer-state)) + == check-clog peer-core :: +dedup-message: replace with any existing copy of this message @@ -2535,7 +2527,7 @@ ++ assert ^+ message-pump =/ top-live - (peek:packet-queue:*make-packet-pump live.packet-pump-state.state) + (pry:packet-queue:*make-packet-pump live.packet-pump-state.state) ?. |(?=(~ top-live) (lte current.state message-num.key.u.top-live)) ~| [%strange-current current=current.state key.u.top-live] !! @@ -2603,7 +2595,7 @@ =| acc=(unit static-fragment) ^+ [static-fragment=acc live=live.state] :: - %^ (traverse:packet-queue _acc) live.state acc + %^ (dip:packet-queue _acc) live.state acc |= $: acc=_acc key=live-packet-key val=live-packet-val @@ -2681,7 +2673,7 @@ =/ acc resends=*(list static-fragment) :: - %^ (traverse:packet-queue _acc) live.state acc + %^ (dip:packet-queue _acc) live.state acc |= $: acc=_acc key=live-packet-key val=live-packet-val @@ -2734,7 +2726,7 @@ :: ^+ [acc live=live.state] :: - %^ (traverse:packet-queue _acc) live.state acc + %^ (dip:packet-queue _acc) live.state acc |= $: acc=_acc key=live-packet-key val=live-packet-val @@ -2781,7 +2773,7 @@ :: ^+ [metrics=metrics.state live=live.state] :: - %^ (traverse:packet-queue pump-metrics) live.state acc=metrics.state + %^ (dip:packet-queue pump-metrics) live.state acc=metrics.state |= $: metrics=pump-metrics key=live-packet-key val=live-packet-val @@ -2804,10 +2796,10 @@ :: ++ set-wake ^+ packet-pump - :: if nonempty .live, peek at head to get next wake time + :: if nonempty .live, pry at head to get next wake time :: =/ new-wake=(unit @da) - ?~ head=(peek:packet-queue live.state) + ?~ head=(pry:packet-queue live.state) ~ `(next-expiry:gauge u.head) :: no-op if no change diff --git a/pkg/arvo/sys/vane/behn.hoon b/pkg/arvo/sys/vane/behn.hoon index 3933c22e62..afff958eae 100644 --- a/pkg/arvo/sys/vane/behn.hoon +++ b/pkg/arvo/sys/vane/behn.hoon @@ -186,7 +186,7 @@ =* timers timers.state :: if no timers, cancel existing wakeup timer or no-op :: - =/ first=(unit [date=@da *]) (peek:timer-map timers.state) + =/ first=(unit [date=@da *]) (pry:timer-map timers.state) ?~ first ?~ next-wake event-core @@ -351,7 +351,7 @@ [%timers %next ~] :^ ~ ~ %noun !> ^- (unit @da) - (bind (peek:timer-map timers) head) + (bind (pry:timer-map timers) head) :: [%timers @ ~] ?~ til=(slaw %da i.t.tyl) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index af2f653037..993ac2703a 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -59,6 +59,12 @@ :: +$ cult (jug wove duct) :: +:: State for ongoing %fuse merges. `con` maintains the ordering, +:: `sto` stores the data needed to merge, and `bas` is the base +:: beak for the merge. +:: ++$ melt [bas=beak con=(list [beak germ]) sto=(map beak (unit dome:clay))] +:: :: Domestic desk state. :: :: Includes subscriber list, dome (desk content), possible commit state (for @@ -69,6 +75,7 @@ dom=dome :: desk state per=regs :: read perms per path pew=regs :: write perms per path + fiz=melt :: state for mega merges == :: :: Desk state. @@ -118,11 +125,11 @@ :: Ford cache :: +$ ford-cache - $: files=(map path [res=vase dez=(set path)]) - naves=(map mark [res=vase dez=(set path)]) - marks=(map mark [res=dais dez=(set path)]) - casts=(map mars [res=vase dez=(set path)]) - tubes=(map mars [res=tube dez=(set path)]) + $: files=(map path [res=vase dez=(set [dir=? =path])]) + naves=(map mark [res=vase dez=(set [dir=? =path])]) + marks=(map mark [res=dais dez=(set [dir=? =path])]) + casts=(map mars [res=vase dez=(set [dir=? =path])]) + tubes=(map mars [res=tube dez=(set [dir=? =path])]) == :: $reef-cache: built system files :: @@ -212,6 +219,7 @@ dom=dome :: revision state per=regs :: read perms per path pew=regs :: write perms per path + fiz=melt :: domestic mega merges == :: :: :: Foreign request manager. @@ -303,6 +311,7 @@ $: %c :: to %clay $> $? %info :: internal edit %merg :: merge desks + %fuse :: merge many %pork :: %warp :: %werp :: @@ -428,18 +437,23 @@ :: ++ an |_ nak=ankh - :: +get: produce file at path + :: +dug: produce ankh at path :: - ++ get + ++ dug |= =path - ^- (unit cage) - ?~ path - ?~ fil.nak - ~ - `q.u.fil.nak + ^- (unit ankh) + ?~ path `nak ?~ kid=(~(get by dir.nak) i.path) ~ $(nak u.kid, path t.path) + :: +get: produce file at path + :: + ++ get + |= =path + ^- (unit cage) + ?~ nik=(dug path) ~ + ?~ fil.u.nik ~ + `q.u.fil.u.nik -- ++ with-face |=([face=@tas =vase] vase(p [%face face p.vase])) ++ with-faces @@ -472,7 +486,7 @@ +$ state $: baked=(map path cage) cache=ford-cache - stack=(list (set path)) + stack=(list (set [dir=? =path])) cycle=(set build) == +$ args @@ -493,8 +507,8 @@ :: +pop-stack: pop build stack, copying deps downward :: ++ pop-stack - ^- [(set path) _stack.nub] - =^ top=(set path) stack.nub stack.nub + ^- [(set [dir=? =path]) _stack.nub] + =^ top=(set [dir=? =path]) stack.nub stack.nub =? stack.nub ?=(^ stack.nub) stack.nub(i (~(uni in i.stack.nub) top)) [top stack.nub] @@ -559,7 +573,6 @@ =/ dif diff:deg ^- (nave typ dif) |% - ++ bunt +<.cor ++ diff |= [old=typ new=typ] ^- dif @@ -581,7 +594,6 @@ =/ dif _*diff:grad:cor ^- (nave:clay typ dif) |% - ++ bunt +<.cor ++ diff |=([old=typ new=typ] (diff:~(grad cor old) new)) ++ form form:grad:cor ++ join @@ -622,7 +634,6 @@ :_ nub ^- dais |_ sam=vase - ++ bunt (slap nav limb/%bunt) ++ diff |= new=vase (slam (slap nav limb/%diff) (slop sam new)) @@ -649,7 +660,7 @@ |= diff=vase (slam (slap nav limb/%pact) (slop sam diff)) ++ vale - |= =noun + |: noun=q:(slap nav !,(*hoon *vale)) (slam (slap nav limb/%vale) noun/noun) -- :: +build-cast: produce gate to convert mark .a to, statically typed @@ -805,9 +816,11 @@ =^ res=vase nub (run-pile pile) res :: - ++ build-file - |= =path + ++ build-dependency + |= dep=(each [dir=path fil=path] path) ^- [vase state] + =/ =path + ?:(?=(%| -.dep) p.dep fil.p.dep) ~| %error-building^path ?^ got=(~(get by files.cache.nub) path) =? stack.nub ?=(^ stack.nub) @@ -816,7 +829,9 @@ ?: (~(has in cycle.nub) file+path) ~|(cycle+file+path^stack.nub !!) =. cycle.nub (~(put in cycle.nub) file+path) - =. stack.nub [(sy path ~) stack.nub] + =. stack.nub + =- [(sy - ~) stack.nub] + ?:(?=(%| -.dep) dep [& dir.p.dep]) =^ cag=cage nub (read-file path) ?> =(%hoon p.cag) =/ tex=tape (trip !<(@t q.cag)) @@ -826,11 +841,42 @@ =. files.cache.nub (~(put by files.cache.nub) path [res top]) [res nub] :: + ++ build-file + |= =path + (build-dependency |+path) + :: +build-directory: builds files in top level of a directory + :: + :: this excludes files directly at /path/hoon, + :: instead only including files in the unix-style directory at /path, + :: such as /path/file/hoon, but not /path/more/file/hoon. + :: + ++ build-directory + |= =path + ^- [(map @ta vase) state] + =/ fiz=(list @ta) + =/ nuk=(unit _ankh) (~(dug an ankh) path) + ?~ nuk ~ + %+ murn + ~(tap by dir.u.nuk) + |= [nom=@ta nak=_ankh] + ?. ?=([~ [~ *] *] (~(get by dir.nak) %hoon)) ~ + `nom + :: + =| rez=(map @ta vase) + |- + ?~ fiz + [rez nub] + =* nom=@ta i.fiz + =/ pax=^path (weld path nom %hoon ~) + =^ res nub (build-dependency &+[path pax]) + $(fiz t.fiz, rez (~(put by rez) nom res)) + :: ++ run-pile |= =pile =^ sut=vase nub (run-tauts bud %sur sur.pile) =^ sut=vase nub (run-tauts sut %lib lib.pile) =^ sut=vase nub (run-raw sut raw.pile) + =^ sut=vase nub (run-raz sut raz.pile) =^ sut=vase nub (run-maz sut maz.pile) =^ sut=vase nub (run-caz sut caz.pile) =^ sut=vase nub (run-bar sut bar.pile) @@ -869,7 +915,10 @@ (most ;~(plug com gaw) taut-rule) :: %+ rune tis - ;~(plug sym ;~(pfix gap fas (more fas urs:ab))) + ;~(plug sym ;~(pfix gap stap)) + :: + %+ rune sig + ;~((glue gap) sym wyde:vast stap) :: %+ rune cen ;~(plug sym ;~(pfix gap ;~(pfix cen sym))) @@ -885,7 +934,7 @@ ;~ (glue gap) sym ;~(pfix cen sym) - ;~(pfix fas (more fas urs:ab)) + ;~(pfix stap) == :: %+ stag %tssg @@ -931,6 +980,30 @@ =. p.pin [%face face.i.raw p.pin] $(sut (slop pin sut), raw t.raw) :: + ++ run-raz + |= [sut=vase raz=(list [face=term =spec =path])] + ^- [vase state] + ?~ raz [sut nub] + =^ res=(map @ta vase) nub + (build-directory path.i.raz) + =; pin=vase + =. p.pin [%face face.i.raz p.pin] + $(sut (slop pin sut), raz t.raz) + :: + =/ =type (~(play ut p.sut) [%kttr spec.i.raz]) + :: ensure results nest in the specified type, + :: and produce a homogenous map containing that type. + :: + :- %- ~(play ut p.sut) + [%kttr %make [%wing ~[%map]] ~[[%base %atom %ta] spec.i.raz]] + |- + ?~ res ~ + ?. (~(nest ut type) | p.q.n.res) + ~| [%nest-fail path.i.raz p.n.res] + !! + :- [p.n.res q.q.n.res] + [$(res l.res) $(res r.res)] + :: ++ run-maz |= [sut=vase maz=(list [face=term =mark])] ^- [vase state] @@ -1043,12 +1116,12 @@ ~ =/ rus rus:(~(gut by hoy.ruf) her *rung) %+ ~(gut by rus) syd - [lim=~2000.1.1 ref=`*rind qyx=~ dom=*dome per=~ pew=~] + [lim=~2000.1.1 ref=`*rind qyx=~ dom=*dome per=~ pew=~ fiz=*melt] :: administrative duct, domestic +rede :: :+ ~ `hun.rom.ruf =/ jod (~(gut by dos.rom.ruf) syd *dojo) - [lim=now ref=~ [qyx dom per pew]:jod] + [lim=now ref=~ [qyx dom per pew fiz]:jod] :: =* red=rede ->+ |% @@ -1065,7 +1138,7 @@ :: %= ruf hun.rom (need hun) - dos.rom (~(put by dos.rom.ruf) syd [qyx dom per pew]:red) + dos.rom (~(put by dos.rom.ruf) syd [qyx dom per pew fiz]:red) == :: :: Handle `%sing` requests @@ -1256,6 +1329,24 @@ =/ =path [%question desk (scot %ud index) ~] (emit duct %pass wire %a %plea ship %c path `riff-any`[%1 riff]) :: + ++ foreign-capable + |= =rave + |^ + ?- -.rave + %many & + %sing (good-care care.mood.rave) + %next (good-care care.mood.rave) + %mult + %- ~(all in paths.mool.rave) + |= [=care =path] + (good-care care) + == + :: + ++ good-care + |= =care + (~(has in ^~((silt `(list ^care)`~[%u %w %x %y %z]))) care) + -- + :: :: Create a request that cannot be filled immediately. :: :: If it's a local request, we just put in in `qyx`, setting a timer if it's @@ -1275,6 +1366,10 @@ =. rave ?. ?=([%sing %v *] rave) rave [%many %| [%ud let.dom] case.mood.rave path.mood.rave] + :: + ?. (foreign-capable rave) + ~|([%clay-bad-foreign-request-care rave] !!) + :: =+ inx=nix.u.ref =. +>+.$ =< ?>(?=(^ ref) .) @@ -1582,12 +1677,19 @@ :: ++ invalidate |* [key=mold value=mold] - |= [cache=(map key [value dez=(set path)]) invalid=(set path)] - =/ builds=(list [key value dez=(set path)]) ~(tap by cache) + |= [cache=(map key [value dez=(set [dir=? =path])]) invalid=(set path)] + =/ builds=(list [key value dez=(set [dir=? =path])]) + ~(tap by cache) |- ^+ cache ?~ builds ~ - ?: ?=(^ (~(int in dez.i.builds) invalid)) + ?: %- ~(any in dez.i.builds) + |= [dir=? =path] + ?. dir (~(has in invalid) path) + =+ l=(lent path) + %- ~(any in invalid) + |= i=^path + &(=(path (scag l i)) ?=([@ %hoon ~] (slag l i))) $(builds t.builds) (~(put by $(builds t.builds)) i.builds) :: @@ -1962,32 +2064,178 @@ =/ =wire /merge/[syd]/(scot %p ali-ship)/[ali-desk]/[germ] (emit hen %pass wire %c %warp ali-ship ali-desk `[%sing %v case /]) :: + ++ make-melt + |= [bas=beak con=(list [beak germ])] + ^- melt + :+ bas con + %- ~(gas by *(map beak (unit dome:clay))) + :- [bas *(unit dome:clay)] + (turn con |=(a=[beak germ] [-.a *(unit dome:clay)])) + :: + ++ start-fuse + |= [bas=beak con=(list [beak germ])] + ^+ ..start-fuse + =/ moves=(list move) + %+ turn + [[bas *germ] con] + |= [bec=beak germ] + ^- move + =/ wir=wire /fuse/[syd]/(scot %p p.bec)/[q.bec]/(scot r.bec) + [hen %pass wir %c %warp p.bec q.bec `[%sing %v r.bec /]] + :: + :: We also want to clear the state (fiz) associated with this + :: merge and print a warning if it's non trivial i.e. we're + :: starting a new fuse before the previous one terminated. + :: + =/ err=tang + ?~ con.fiz + ~ + =/ discarded=tang + %+ turn + ~(tap in sto.fiz) + |= [k=beak v=(unit dome:clay)] + ^- tank + =/ received=tape ?~(v "missing" "received") + leaf+"{} {received}" + :_ discarded + leaf+"fusing into {} from {} {} - overwriting prior fuse" + =. fiz (make-melt bas con) + ((slog err) (emil moves)) + :: + ++ take-fuse + |^ + :: + |= [bec=beak =riot] + ^+ ..take-fuse + ?~ riot + :: + :: By setting fiz to *melt the merge is aborted - any further + :: responses we get for the merge will cause take-fuse to crash + :: + =. fiz *melt + ((slog [leaf+"clay: fuse failed, missing {}"]~) ..take-fuse) + ?> (~(has by sto.fiz) bec) + =. fiz + :+ bas.fiz con.fiz + (~(put by sto.fiz) bec `!<(dome:clay q.r.u.riot)) + =/ all-done=flag + %- ~(all by sto.fiz) + |= res=(unit dome:clay) + ^- flag + !=(res ~) + ?. all-done + ..take-fuse + =| rag=rang + =/ clean-state ..take-fuse + =/ initial-dome=dome:clay (need (~(got by sto.fiz) bas.fiz)) + =/ continuation-yaki=yaki + (~(got by hut.ran) (~(got by hit.initial-dome) let.initial-dome)) + =/ parents=(list tako) ~[(~(got by hit.initial-dome) let.initial-dome)] + =/ merges con.fiz + |- + ^+ ..take-fuse + ?~ merges + =/ t=tang [leaf+"{} fused from {} {}" ~] + =. ..take-fuse (done-fuse clean-state %& ~) + (park | [%| continuation-yaki(p (flop parents))] rag) + =/ [bec=beak g=germ] i.merges + =/ ali-dom=dome:clay (need (~(got by sto.fiz) bec)) + =/ result (merge-helper p.bec q.bec g ali-dom `continuation-yaki) + ?- -.result + %| + (done-fuse clean-state %| %fuse-merge-failed p.result) + :: + %& + =/ merge-result=(unit merge-result) +.result + ?~ merge-result + :: + :: This merge was a no-op, just continue + :: + $(merges t.merges) + ?^ conflicts.u.merge-result + :: + :: If there are merge conflicts send the error and abort the merge + :: + (done-fuse clean-state %& conflicts.u.merge-result) + =/ merged-yaki=yaki + ?- -.new.u.merge-result + %| + +.new.u.merge-result + :: + %& + :: + :: Convert the yuki to yaki + :: + =/ yuk=yuki +.new.u.merge-result + =/ lobes=(map path lobe) + %- ~(run by q.yuk) + |= val=(each page lobe) + ^- lobe + ?- -.val + %& (page-to-lobe +.val) + %| +.val + == + (make-yaki p.yuk lobes now) + == + %= $ + continuation-yaki merged-yaki + merges t.merges + hut.ran (~(put by hut.ran) r.merged-yaki merged-yaki) + lat.rag (~(uni by lat.rag) lat.u.merge-result) + parents [(~(got by hit.ali-dom) let.ali-dom) parents] + == + == + :: +done-fuse: restore state after a fuse is attempted, whether it + :: succeeds or fails. + :: + ++ done-fuse + |= [to-restore=_..take-fuse result=(each (set path) (pair term tang))] + ^+ ..take-fuse + =. fiz.to-restore *melt + (done:to-restore result) + -- + :: + ++ done + |= result=(each (set path) (pair term tang)) + ^+ ..merge + (emit hen %give %mere result) + :: ++ merge |= [=ali=ship =ali=desk =germ =riot] ^+ ..merge - |^ ?~ riot - (done %| %ali-unavailable >[ali-ship ali-desk germ]< ~) + (done %| %ali-unavailable ~[>[ali-ship ali-desk germ]<]) =/ ali-dome=dome:clay !<(dome:clay q.r.u.riot) + =/ result=(each (unit merge-result) (pair term tang)) + (merge-helper ali-ship ali-desk germ ali-dome ~) + ?- -.result + %| + (done %| +.result) + :: + %& + =/ mr=(unit merge-result) +.result + ?~ mr + (done %& ~) + =. ..merge (done %& conflicts.u.mr) + (park | new.u.mr ~ lat.u.mr) + == + :: + +$ merge-result [conflicts=(set path) new=yoki lat=(map lobe blob)] + :: + ++ merge-helper + |= [=ali=ship =ali=desk =germ ali-dome=dome:clay continuation-yaki=(unit yaki)] + ^- (each (unit merge-result) [term tang]) + |^ + ^- (each (unit merge-result) [term tang]) =/ ali-yaki=yaki (~(got by hut.ran) (~(got by hit.ali-dome) let.ali-dome)) =/ bob-yaki=(unit yaki) - ?~ let.dom - ~ - (~(get by hut.ran) (~(got by hit.dom) let.dom)) - =/ merge-result (merge-by-germ ali-yaki bob-yaki) - ?: ?=(%| -.merge-result) - (done %| p.merge-result) - ?~ p.merge-result - (done %& ~) - =. ..merge (done %& conflicts.u.p.merge-result) - (park | new.u.p.merge-result ~ lat.u.p.merge-result) - :: - ++ done - |= result=(each (set path) (pair term tang)) - ^+ ..merge - (emit hen %give %mere result) - :: - +$ merge-result [conflicts=(set path) new=yoki lat=(map lobe blob)] + ?~ continuation-yaki + ?~ let.dom + ~ + (~(get by hut.ran) (~(got by hit.dom) let.dom)) + continuation-yaki + (merge-by-germ ali-yaki bob-yaki) + :: ++ merge-by-germ |= [=ali=yaki bob-yaki=(unit yaki)] ^- (each (unit merge-result) [term tang]) @@ -2005,16 +2253,13 @@ ?- germ :: :: If this is a %only-this merge, we check to see if ali's and bob's - :: commits are the same, in which case we're done. Otherwise, we - :: check to see if ali's commit is in the ancestry of bob's, in - :: which case we're done. Otherwise, we create a new commit with - :: bob's data plus ali and bob as parents. + :: commits are the same, in which case we're done. + :: Otherwise, we create a new commit with bob's data plus ali and + :: bob as parents. :: %only-this ?: =(r.ali-yaki r.bob-yaki) &+~ - ?: (~(has in (reachable-takos:ze r.bob-yaki)) r.ali-yaki) - &+~ :* %& ~ conflicts=~ new=&+[[r.bob-yaki r.ali-yaki ~] (to-yuki q.bob-yaki)] @@ -2042,8 +2287,6 @@ %take-this ?: =(r.ali-yaki r.bob-yaki) &+~ - ?: (~(has in (reachable-takos:ze r.bob-yaki)) r.ali-yaki) - &+~ =/ new-data (~(uni by q.ali-yaki) q.bob-yaki) :* %& ~ conflicts=~ @@ -2313,7 +2556,7 @@ =+ (slag (dec (lent path)) path) ?~(- %$ i.-) =/ =dais (get-dais mark) - =/ res=(unit (unit vase)) (~(join dais bunt:dais) q.cal q.cob) + =/ res=(unit (unit vase)) (~(join dais *vale:dais) q.cal q.cob) ?~ res `[form:dais q.cob] ?~ u.res @@ -2665,6 +2908,9 @@ ++ start-request |= [for=(unit [ship @ud]) rav=rave] ^+ ..start-request + ?: &(?=(^ for) !(foreign-capable rav)) + ~& [%bad-foreign-request-care from=for rav] + ..start-request =^ [new-sub=(unit rove) sub-results=(list sub-result)] fod.dom (try-fill-sub for (rave-to-rove rav)) =. ..start-request (send-sub-results sub-results [hen ~ ~]) @@ -2721,14 +2967,23 @@ %r ~| %no-cages-please-they-are-just-way-too-big !! %s ~| %please-dont-get-your-takos-over-a-network !! %t ~| %requesting-foreign-directory-is-vaporware !! - %u ~| %prolly-poor-idea-to-get-rang-over-network !! %v ~| %weird-shouldnt-get-v-request-from-network !! - %z `(validate-z r.rand) + %u `(validate-u r.rand) %w `(validate-w r.rand) %x (validate-x [p.p q.p q r]:rand) %y `[p.r.rand !>(;;(arch q.r.rand))] + %z `(validate-z r.rand) == :: + :: Make sure the incoming data is a %u response + :: + ++ validate-u + |= =page + ^- cage + ?> ?=(%flag p.page) + :- p.page + !> ;;(? q.page) + :: :: Make sure the incoming data is a %w response :: ++ validate-w @@ -2749,7 +3004,11 @@ =/ vale-result %- mule |. %- wrap:fusion - (page-to-cage:(ford:fusion static-ford-args) peg) + :: Use %home's marks to validate, so we don't have to build the + :: foreign hoon/zuse + :: + =/ args %*(static-ford-args . dom dom:(~(got by dos.rom) %home)) + (page-to-cage:(ford:fusion args) peg) ?: ?=(%| -.vale-result) %- (slog >%validate-x-failed< p.vale-result) ~ @@ -2762,7 +3021,7 @@ ^- cage ?> ?=(%uvi p.page) :- p.page - !>(;;(@uvI q.page)) + !> ;;(@uvI q.page) -- :: :: Respond to backfill request @@ -3391,12 +3650,29 @@ |- ?: =(b let.dom) hit.dom + :: del everything after b $(hit.dom (~(del by hit.dom) let.dom), let.dom (dec let.dom)) b ?: =(0 b) [~ ~] - (data-twixt-takos =(0 ver) (~(get by hit.dom) a) (aeon-to-tako b)) - :: + =/ excludes=(set tako) + =| acc=(set tako) + =/ lower=@ud 1 + |- + :: a should be excluded, so wait until we're past it + ?: =(lower +(a)) + acc + =/ res=(set tako) (reachable-takos (~(got by hit.dom) lower)) + $(acc (~(uni in acc) res), lower +(lower)) + =/ includes=(set tako) + =| acc=(set tako) + =/ upper=@ud b + |- + ?: =(upper a) + acc + =/ res=(set tako) (reachable-takos (~(got by hit.dom) upper)) + $(acc (~(uni in acc) res), upper (dec upper)) + [(~(run in (~(dif in includes) excludes)) tako-to-yaki) ~] :: Traverse parentage and find all ancestor hashes :: ++ reachable-takos :: reachable @@ -3415,30 +3691,6 @@ =. s ^$(p i.p.y) $(p.y t.p.y) :: - :: Gets the data between two commit hashes, assuming the first is an - :: ancestor of the second. - :: - :: Get all the takos before `a`, then get all takos before `b` except the - :: ones we found before `a`. Then convert the takos to yakis and also get - :: all the data in all the yakis. - :: - :: What happens if you run an %init merge on a desk that already - :: had a commit? - :: - ++ data-twixt-takos - |= [plops=? a=(unit tako) b=tako] - ^- [(set yaki) (set plop)] - =+ old=?~(a ~ (reachable-takos u.a)) - =/ yal=(set tako) - %- silt - %+ skip - ~(tap in (reachable-takos b)) - |=(tak=tako (~(has in old) tak)) - :- (silt (turn ~(tap in yal) tako-to-yaki)) - ?. plops - ~ - (silt (turn ~(tap in (new-lobes (new-lobes ~ old) yal)) lobe-to-blob)) - :: :: Get all the lobes that are referenced in `a` except those that are :: already in `b`. :: @@ -3528,11 +3780,11 @@ [[~ ~] fod.dom] =/ cached=(unit [=vase *]) (~(get by naves.fod.dom) i.path) ?^ cached - :_(fod.dom [~ ~ %& %nave !>(vase.u.cached)]) + :_(fod.dom [~ ~ %& %nave vase.u.cached]) =^ =vase fod.dom %- wrap:fusion (build-nave:(ford:fusion static-ford-args) i.path) - :_(fod.dom [~ ~ %& %nave !>(vase)]) + :_(fod.dom [~ ~ %& %nave vase]) :: ++ read-f !. @@ -3958,12 +4210,14 @@ :: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: =| :: instrument state - $: ver=%7 :: vane version + $: ver=%8 :: vane version ruf=raft :: revision tree == :: |= [now=@da eny=@uvJ rof=roof] :: current invocation +~% %clay-top ..part ~ |% :: ++ call :: handle request + ~/ %clay-call |= $: hen=duct dud=(unit goof) wrapped-task=(hobo task) @@ -4074,6 +4328,14 @@ =/ den ((de now rof hen ruf) our des.req) abet:(start-merge:den her.req dem.req cas.req how.req) [mos ..^$] + :: + %fuse + ?: =(%$ des.req) + ~&(%fuse-no-desk !!) + =^ mos ruf + =/ den ((de now rof hen ruf) our des.req) + abet:(start-fuse:den bas.req con.req) + [mos ..^$] :: %mont =. hez.ruf ?^(hez.ruf hez.ruf `[[%$ %sync ~] ~]) @@ -4202,11 +4464,41 @@ ++ load => |% +$ raft-any - $% [%7 raft-7] + $% [%8 raft-8] + [%7 raft-7] [%6 raft-6] == - +$ raft-7 raft - +$ dojo-7 dojo + +$ raft-8 raft + +$ raft-7 + $: rom=room-7 + hoy=(map ship rung-7) + ran=rang + mon=(map term beam) + hez=(unit duct) + cez=(map @ta crew) + pud=(unit [=desk =yoki]) + == + +$ room-7 + $: hun=duct + dos=(map desk dojo-7) + == + +$ rung-7 + $: rus=(map desk rede-7) + == + +$ dojo-7 + $: qyx=cult + dom=dome + per=regs + pew=regs + == + +$ rede-7 + $: lim=@da + ref=(unit rind) + qyx=cult + dom=dome + per=regs + pew=regs + == +$ ford-cache-7 ford-cache +$ raft-6 $: rom=room-6 :: domestic @@ -4249,7 +4541,8 @@ |= old=raft-any |^ =? old ?=(%6 -.old) 7+(raft-6-to-7 +.old) - ?> ?=(%7 -.old) + =? old ?=(%7 -.old) 8+(raft-7-to-8 +.old) + ?> ?=(%8 -.old) ..^^$(ruf +.old) :: +raft-6-to-7: delete stale ford caches (they could all be invalid) :: @@ -4270,9 +4563,30 @@ |= =rede-6 rede-6(dom dom.rede-6(fod *ford-cache-7)) == + :: +raft-7-to-8: create bunted melts in each dojo/rede + :: + ++ raft-7-to-8 + |= raf=raft-7 + ^- raft-8 + %= raf + dos.rom + %- ~(run by dos.rom.raf) + |= doj=dojo-7 + ^- dojo + [qyx.doj dom.doj per.doj pew.doj *melt] + :: + hoy + %- ~(run by hoy.raf) + |= =rung-7 + %- ~(run by rus.rung-7) + |= r=rede-7 + ^- rede + [lim.r ref.r qyx.r dom.r per.r pew.r *melt] + == -- :: ++ scry :: inspect + ~/ %clay-scry ^- roon |= [lyc=gang car=term bem=beam] ^- (unit (unit cage)) @@ -4334,6 +4648,7 @@ == :: ++ take :: accept response + ~/ %clay-take |= [tea=wire hen=duct dud=(unit goof) hin=sign] ^+ [*(list move) ..^$] ?^ dud @@ -4350,6 +4665,18 @@ abet:(merge:den ali-ship ali-desk germ p.hin) [mos ..^$] :: + ?: ?=([%fuse @ @ @ @ ~] tea) + ?> ?=(%writ +<.hin) + =* syd i.t.tea + =/ ali-ship=@p (slav %p i.t.t.tea) + =* ali-desk=desk i.t.t.t.tea + =/ ali-case (rash i.t.t.t.t.tea nuck:so) + ?> ?=([%$ *] ali-case) + =^ mos ruf + =/ den ((de now rof hen ruf) our i.t.tea) + abet:(take-fuse:den [ali-ship ali-desk (case +.ali-case)] p.hin) + [mos ..^$] + :: ?: ?=([%foreign-warp *] tea) ?> ?=(%writ +<.hin) :_ ..^$ diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index 998bd659a3..8072cbd507 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -215,7 +215,7 @@ ?: =('subscribe' u.maybe-key) %. item %+ pe %subscribe - (ot id+ni ship+(su fed:ag) app+so path+(su ;~(pfix fas (more fas urs:ab))) ~) + (ot id+ni ship+(su fed:ag) app+so path+(su stap) ~) ?: =('unsubscribe' u.maybe-key) %. item %+ pe %unsubscribe @@ -426,10 +426,12 @@ :- ~ %- as-octs:mimes:html %- crip - %- zing + %- zing ^- ^wall + %- zing ^- (list ^wall) %+ turn wall |= t=tape - "{t}\0a" + ^- ^wall + ~[t "\0a"] :: +internal-server-error: 500 page, with a tang :: ++ internal-server-error @@ -1598,6 +1600,7 @@ :: +channel-event-to-sign: attempt to recover a sign from a channel-event :: ++ channel-event-to-sign + ~% %eyre-channel-event-to-sign ..part ~ |= event=channel-event ^- (unit sign:agent:gall) ?. ?=(%fact -.event) `event @@ -1678,6 +1681,7 @@ == :: ++ event-json-to-wall + ~% %eyre-json-to-wall ..part ~ |= [event-id=@ud =json] ^- wall :~ (weld "id: " (format-ud-as-integer event-id)) @@ -2095,6 +2099,7 @@ ~% %http-server ..part ~ |% ++ call + ~/ %eyre-call |= [=duct dud=(unit goof) wrapped-task=(hobo task)] ^- [(list move) _http-server-gate] :: @@ -2297,6 +2302,7 @@ == :: ++ take + ~/ %eyre-take |= [=wire =duct dud=(unit goof) =sign] ^- [(list move) _http-server-gate] ?^ dud @@ -2484,6 +2490,7 @@ :: +scry: request a path in the urbit namespace :: ++ scry + ~/ %eyre-scry ^- roon |= [lyc=gang car=term bem=beam] ^- (unit (unit cage)) diff --git a/pkg/arvo/sys/vane/gall.hoon b/pkg/arvo/sys/vane/gall.hoon index a481307874..690fa615eb 100644 --- a/pkg/arvo/sys/vane/gall.hoon +++ b/pkg/arvo/sys/vane/gall.hoon @@ -646,6 +646,7 @@ :: cleared queue in +load 3-to-4 or +load-4-to-5 :: =? stand ?=(~ stand) + ~& [%gall-missing wire hen] (~(put to *(qeu remote-request)) %missing) ~| [full-wire=full-wire hen=hen stand=stand] =^ rr stand ~(get to stand) diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index eaf098937b..168c15863a 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -3286,7 +3286,7 @@ ++ ship :: string from ship |= a=^ship ^- json - (tape (slag 1 (scow %p a))) + [%n (rap 3 '"' (rsh [3 1] (scot %p a)) '"' ~)] :: :: ++numb:enjs:format ++ numb :: number from unsigned |= a=@u @@ -3458,7 +3458,7 @@ [(rash a fel) b] :: :: ++pa:dejs:format ++ pa :: string as path - (su ;~(pfix fas (more fas urs:ab))) + (su stap) :: :: ++pe:dejs:format ++ pe :: prefix |* [pre=* wit=fist] @@ -5070,36 +5070,54 @@ |= ord=$-([key key] ?) |= a=* =/ b ;;((tree [key=key val=value]) a) - ?> (check-balance:((ordered-map key value) ord) b) + ?> (apt:((on key value) ord) b) b :: -:: $mk-item: constructor for +ordered-map item type :: -++ mk-item |$ [key val] [key=key val=val] -:: +ordered-map: treap with user-specified horizontal order -:: -:: Conceptually smaller items go on the left, so the item with the -:: smallest key can be popped off the head. If $key is `@` and -:: .compare is +lte, then the numerically smallest item is the head. +++ ordered-map on +:: +on: treap with user-specified horizontal order, ordered-map :: :: WARNING: ordered-map will not work properly if two keys can be :: unequal under noun equality but equal via the compare gate :: -++ ordered-map +++ on + ~/ %on |* [key=mold val=mold] => |% - +$ item (mk-item key val) + +$ item [key=key val=val] -- :: +compare: item comparator for horizontal order :: + ~% %comp +>+ ~ |= compare=$-([key key] ?) + ~% %core + ~ |% - :: +check-balance: verify horizontal and vertical orderings + :: +all: apply logical AND boolean test on all values :: - ++ check-balance - =| [l=(unit key) r=(unit key)] - |= a=(tree item) + ++ all + ~/ %all + |= [a=(tree item) b=$-(item ?)] ^- ? + |- + ?~ a + & + ?&((b n.a) $(a l.a) $(a r.a)) + :: +any: apply logical OR boolean test on all values + :: + ++ any + ~/ %any + |= [a=(tree item) b=$-(item ?)] + |- ^- ? + ?~ a + | + ?|((b n.a) $(a l.a) $(a r.a)) + :: +apt: verify horizontal and vertical orderings + :: + ++ apt + ~/ %apt + |= a=(tree item) + =| [l=(unit key) r=(unit key)] + |- ^- ? :: empty tree is valid :: ?~ a %.y @@ -5122,64 +5140,22 @@ :: ?~(r.a %.y &((mor key.n.a key.n.r.a) $(a r.a, r `key.n.a))) == - :: +put: ordered item insert + :: +bap: convert to list, right to left :: - ++ put - |= [a=(tree item) =key =val] - ^- (tree item) - :: base case: replace null with single-item tree - :: - ?~ a [n=[key val] l=~ r=~] - :: base case: overwrite existing .key with new .val - :: - ?: =(key.n.a key) a(val.n val) - :: if item goes on left, recurse left then rebalance vertical order - :: - ?: (compare key key.n.a) - =/ l $(a l.a) - ?> ?=(^ l) - ?: (mor key.n.a key.n.l) - a(l l) - l(r a(l r.l)) - :: item goes on right; recurse right then rebalance vertical order - :: - =/ r $(a r.a) - ?> ?=(^ r) - ?: (mor key.n.a key.n.r) - a(r r) - r(l a(r l.r)) - :: +peek: produce head (smallest item) or null - :: - ++ peek - |= a=(tree item) - ^- (unit item) - :: - ?~ a ~ - ?~ l.a `n.a - $(a l.a) - :: - :: +pop: produce .head (smallest item) and .rest or crash if empty - :: - ++ pop + ++ bap + ~/ %bap |= a=(tree item) - ^- [head=item rest=(tree item)] - :: - ?~ a !! - ?~ l.a [n.a r.a] - :: - =/ l $(a l.a) - :- head.l - :: load .rest.l back into .a and rebalance - :: - ?: |(?=(~ rest.l) (mor key.n.a key.n.rest.l)) - a(l rest.l) - rest.l(r a(r r.rest.l)) + ^- (list item) + =| b=(list item) + |- ^+ b + ?~ a b + $(a r.a, b [n.a $(a l.a)]) :: +del: delete .key from .a if it exists, producing value iff deleted :: ++ del + ~/ %del |= [a=(tree item) =key] ^- [(unit val) (tree item)] - :: ?~ a [~ ~] :: we found .key at the root; delete and rebalance :: @@ -5192,30 +5168,15 @@ [found a(l lef)] =+ [found rig]=$(a r.a) [found a(r rig)] - :: +nip: remove root; for internal use - :: - ++ nip - |= a=(tree item) - ^- (tree item) - :: - ?> ?=(^ a) - :: delete .n.a; merge and balance .l.a and .r.a - :: - |- ^- (tree item) - ?~ l.a r.a - ?~ r.a l.a - ?: (mor key.n.l.a key.n.r.a) - l.a(r $(l.a r.l.a)) - r.a(l $(r.a l.r.a)) - :: +traverse: stateful partial inorder traversal + :: +dip: stateful partial inorder traversal :: :: Mutates .state on each run of .f. Starts at .start key, or if - :: .start is ~, starts at the head (item with smallest key). Stops - :: when .f produces .stop=%.y. Traverses from smaller to larger - :: keys. Each run of .f can replace an item's value or delete the - :: item. + :: .start is ~, starts at the head. Stops when .f produces .stop=%.y. + :: Traverses from left to right keys. + :: Each run of .f can replace an item's value or delete the item. :: - ++ traverse + ++ dip + ~/ %dip |* state=mold |= $: a=(tree item) =state @@ -5274,63 +5235,18 @@ =/ rig main(a r.a) rig(a a(r a.rig)) -- - :: +tap: convert to list, smallest to largest - :: - ++ tap - |= a=(tree item) - ^- (list item) - :: - =| b=(list item) - |- ^+ b - ?~ a b - :: - $(a l.a, b [n.a $(a r.a)]) - :: +bap: convert to list, largest to smallest - :: - ++ bap - |= a=(tree item) - ^- (list item) - :: - =| b=(list item) - |- ^+ b - ?~ a b - :: - $(a r.a, b [n.a $(a l.a)]) :: +gas: put a list of items :: ++ gas + ~/ %gas |= [a=(tree item) b=(list item)] ^- (tree item) - :: ?~ b a $(b t.b, a (put a i.b)) - :: +uni: unify two ordered maps - :: - :: .b takes precedence over .a if keys overlap. - :: - ++ uni - |= [a=(tree item) b=(tree item)] - ^- (tree item) - :: - ?~ b a - ?~ a b - ?: =(key.n.a key.n.b) - :: - [n=n.b l=$(a l.a, b l.b) r=$(a r.a, b r.b)] - :: - ?: (mor key.n.a key.n.b) - :: - ?: (compare key.n.b key.n.a) - $(l.a $(a l.a, r.b ~), b r.b) - $(r.a $(a r.a, l.b ~), b l.b) - :: - ?: (compare key.n.a key.n.b) - $(l.b $(b l.b, r.a ~), a r.a) - $(r.b $(b r.b, l.a ~), a l.a) - :: :: +get: get val at key or return ~ :: ++ get + ~/ %get |= [a=(tree item) b=key] ^- (unit val) ?~ a ~ @@ -5339,11 +5255,24 @@ ?: (compare b key.n.a) $(a l.a) $(a r.a) + :: +got: need value at key + :: + ++ got + |= [a=(tree item) b=key] + ^- val + (need (get a b)) + :: +has: check for key existence :: - :: +subset: take a range excluding start and/or end and all elements + ++ has + ~/ %has + |= [a=(tree item) b=key] + ^- ? + !=(~ (get a b)) + :: +lot: take a subset range excluding start and/or end and all elements :: outside the range :: - ++ subset + ++ lot + ~/ %lot |= $: tre=(tree item) start=(unit key) end=(unit key) @@ -5389,6 +5318,154 @@ $(a (nip a(r ~))) == -- + :: +nip: remove root; for internal use + :: + ++ nip + ~/ %nip + |= a=(tree item) + ^- (tree item) + ?> ?=(^ a) + :: delete .n.a; merge and balance .l.a and .r.a + :: + |- ^- (tree item) + ?~ l.a r.a + ?~ r.a l.a + ?: (mor key.n.l.a key.n.r.a) + l.a(r $(l.a r.l.a)) + r.a(l $(r.a l.r.a)) + :: + :: +pop: produce .head (leftmost item) and .rest or crash if empty + :: + ++ pop + ~/ %pop + |= a=(tree item) + ^- [head=item rest=(tree item)] + ?~ a !! + ?~ l.a [n.a r.a] + =/ l $(a l.a) + :- head.l + :: load .rest.l back into .a and rebalance + :: + ?: |(?=(~ rest.l) (mor key.n.a key.n.rest.l)) + a(l rest.l) + rest.l(r a(r r.rest.l)) + :: +pry: produce head (leftmost item) or null + :: + ++ pry + ~/ %pry + |= a=(tree item) + ^- (unit item) + ?~ a ~ + |- + ?~ l.a `n.a + $(a l.a) + :: +put: ordered item insert + :: + ++ put + ~/ %put + |= [a=(tree item) =key =val] + ^- (tree item) + :: base case: replace null with single-item tree + :: + ?~ a [n=[key val] l=~ r=~] + :: base case: overwrite existing .key with new .val + :: + ?: =(key.n.a key) a(val.n val) + :: if item goes on left, recurse left then rebalance vertical order + :: + ?: (compare key key.n.a) + =/ l $(a l.a) + ?> ?=(^ l) + ?: (mor key.n.a key.n.l) + a(l l) + l(r a(l r.l)) + :: item goes on right; recurse right then rebalance vertical order + :: + =/ r $(a r.a) + ?> ?=(^ r) + ?: (mor key.n.a key.n.r) + a(r r) + r(l a(r l.r)) + :: +ram: produce tail (rightmost item) or null + :: + ++ ram + ~/ %ram + |= a=(tree item) + ^- (unit item) + ?~ a ~ + |- + ?~ r.a `n.a + $(a r.a) + :: +run: apply gate to transform all values in place + :: + ++ run + ~/ %run + |* [a=(tree item) b=$-(val *)] + |- + ?~ a a + [n=[key.n.a (b val.n.a)] l=$(a l.a) r=$(a r.a)] + :: +tab: tabulate a subset excluding start element with a max count + :: + ++ tab + ~/ %tab + |= [a=(tree item) b=(unit key) c=@] + ^- (list item) + |^ + (flop e:(tabulate (del-span a b) b c)) + :: + ++ tabulate + |= [a=(tree item) b=(unit key) c=@] + ^- [d=@ e=(list item)] + ?: ?&(?=(~ b) =(c 0)) + [0 ~] + =| f=[d=@ e=(list item)] + |- ^+ f + ?: ?|(?=(~ a) =(d.f c)) f + =. f $(a l.a) + ?: =(d.f c) f + =. f [+(d.f) [n.a e.f]] + ?:(=(d.f c) f $(a r.a)) + :: + ++ del-span + |= [a=(tree item) b=(unit key)] + ^- (tree item) + ?~ a a + ?~ b a + ?: =(key.n.a u.b) + r.a + ?: (compare key.n.a u.b) + $(a r.a) + a(l $(a l.a)) + -- + :: +tap: convert to list, left to right + :: + ++ tap + ~/ %tap + |= a=(tree item) + ^- (list item) + =| b=(list item) + |- ^+ b + ?~ a b + $(a l.a, b [n.a $(a r.a)]) + :: +uni: unify two ordered maps + :: + :: .b takes precedence over .a if keys overlap. + :: + ++ uni + ~/ %uni + |= [a=(tree item) b=(tree item)] + ^- (tree item) + ?~ b a + ?~ a b + ?: =(key.n.a key.n.b) + [n=n.b l=$(a l.a, b l.b) r=$(a r.a, b r.b)] + ?: (mor key.n.a key.n.b) + ?: (compare key.n.b key.n.a) + $(l.a $(a l.a, r.b ~), b r.b) + $(r.a $(a r.a, l.b ~), b l.b) + ?: (compare key.n.a key.n.b) + $(l.b $(b l.b, r.a ~), a r.a) + $(r.b $(b r.b, l.a ~), a l.a) -- :: :: :::: ++userlib :: (2u) non-vane utils @@ -5535,7 +5612,8 @@ :: :: ++unm:chrono:userlib ++ unm :: Urbit to Unix ms |= a=@da - (div (mul (sub a ~1970.1.1) 1.000) ~s1) + =- (div (mul - 1.000) ~s1) + (sub (add a (div ~s1 2.000)) ~1970.1.1) :: :: ++unt:chrono:userlib ++ unt :: Urbit to Unix time |= a=@da diff --git a/pkg/arvo/tests/sys/vane/clay.hoon b/pkg/arvo/tests/sys/vane/clay.hoon index 636efd3a35..457a810db0 100644 --- a/pkg/arvo/tests/sys/vane/clay.hoon +++ b/pkg/arvo/tests/sys/vane/clay.hoon @@ -23,7 +23,7 @@ =/ src "." %+ expect-eq !> ^- pile:fusion - :* ~ ~ ~ ~ ~ ~ + :* ~ ~ ~ ~ ~ ~ ~ tssg+[%dbug [/sur/foo/hoon [[1 1] [1 2]]] [%cnts ~[[%.y 1]] ~]]~ == !> (parse-pile:(ford):fusion /sur/foo/hoon src) @@ -32,7 +32,7 @@ =/ src "/% moo %mime\0a." %+ expect-eq !> ^- pile:fusion - :* sur=~ lib=~ raw=~ + :* sur=~ lib=~ raw=~ raz=~ maz=[face=%moo mark=%mime]~ caz=~ bar=~ tssg+[%dbug [/sur/foo/hoon [[2 1] [2 2]]] [%cnts ~[[%.y 1]] ~]]~ @@ -43,7 +43,7 @@ =/ src "/$ goo %mime %txt\0a." %+ expect-eq !> ^- pile:fusion - :* sur=~ lib=~ raw=~ maz=~ + :* sur=~ lib=~ raw=~ raz=~ maz=~ caz=[face=%goo from=%mime to=%txt]~ bar=~ tssg+[%dbug [/sur/foo/hoon [[2 1] [2 2]]] [%cnts ~[[%.y 1]] ~]]~ @@ -74,7 +74,7 @@ [`%hood-drum %hood-drum] [`%hood-write %hood-write] == - raw=~ maz=~ caz=~ bar=~ + raw=~ raz=~ maz=~ caz=~ bar=~ tssg+[%dbug [/sur/foo/hoon [[10 1] [10 2]]] [%cnts ~[[%.y 1]] ~]]~ == !> (parse-pile:(ford):fusion /sur/foo/hoon src) @@ -112,10 +112,10 @@ ;: weld %+ expect-eq !>(*mime) - (slap res limb/%bunt) + (slap res !,(*hoon *vale)) :: %+ expect-eq - !> (~(gas in *(set path)) /mar/mime/hoon ~) + !> (~(gas in *(set [? path])) |^/mar/mime/hoon ~) !> dez:(~(got by files.cache.nub) /mar/mime/hoon) == :: @@ -139,10 +139,10 @@ ;: weld %+ expect-eq !>(*@t) - (slap res limb/%bunt) + (slap res !,(*hoon *vale)) :: %+ expect-eq - !> (~(gas in *(set path)) /mar/udon/hoon /lib/cram/hoon ~) + !> (~(gas in *(set [? path])) |^/mar/udon/hoon |^/lib/cram/hoon ~) !> dez:(~(got by files.cache.nub) /mar/udon/hoon) == :: @@ -170,7 +170,7 @@ =/ changes %- my :~ [/mar/mime/hoon &+hoon+mar-mime] - [/lib/foo/hoon &+hoon+'/% moo %mime\0abunt:moo'] + [/lib/foo/hoon &+hoon+'/% moo %mime\0a*vale:moo'] == =/ ford %: ford:fusion @@ -224,7 +224,7 @@ (slap res (ream '(+ [*^ [%bob ~] ~])')) :: %+ expect-eq - !> (~(gas in *(set path)) /gen/hello/hoon ~) + !> (~(gas in *(set [? path])) |^/gen/hello/hoon ~) !> dez:(~(got by files.cache.nub) /gen/hello/hoon) == :: @@ -249,10 +249,10 @@ !>((slab %read %get-our -.res)) :: %+ expect-eq - !> %- ~(gas in *(set path)) - :~ /lib/strandio/hoon - /lib/strand/hoon - /sur/spider/hoon + !> %- ~(gas in *(set [? path])) + :~ [| /lib/strandio/hoon] + [| /lib/strand/hoon] + [| /sur/spider/hoon] == !> dez:(~(got by files.cache.nub) /lib/strandio/hoon) == diff --git a/pkg/arvo/tests/sys/vane/eyre.hoon b/pkg/arvo/tests/sys/vane/eyre.hoon index 0b83d3a843..6710fa2aee 100644 --- a/pkg/arvo/tests/sys/vane/eyre.hoon +++ b/pkg/arvo/tests/sys/vane/eyre.hoon @@ -2353,7 +2353,6 @@ :^ ~ ~ %dais !> ^- dais:clay |_ sam=vase - ++ bunt !! ++ diff !! ++ form !! ++ join !! diff --git a/pkg/arvo/tests/sys/zuse/format.hoon b/pkg/arvo/tests/sys/zuse/format.hoon index 8719ab241e..dddc9ef2e4 100644 --- a/pkg/arvo/tests/sys/zuse/format.hoon +++ b/pkg/arvo/tests/sys/zuse/format.hoon @@ -179,10 +179,15 @@ %+ expect-eq !> [%n '1000'] !> (time ~1970.1.1..0.0.1) + :: timestamps should invert + :: + %+ expect-eq + !> [%n '1001'] + !> (time (from-unix-ms:chrono:userlib 1.001)) :: ship - store ship identity as a string :: %+ expect-eq - !> [%s 'zod'] + !> [%n '"zod"'] !> (ship ~zod) == :: dejs - recursive processing of `json` values diff --git a/pkg/arvo/tests/sys/zuse/ordered-map.hoon b/pkg/arvo/tests/sys/zuse/ordered-map.hoon index 261b8f0851..247b85c91b 100644 --- a/pkg/arvo/tests/sys/zuse/ordered-map.hoon +++ b/pkg/arvo/tests/sys/zuse/ordered-map.hoon @@ -9,6 +9,7 @@ (items-from-keys (gulf 0 6)) :: =/ atom-map ((ordered-map @ud @tas) lte) +=/ gte-atom-map ((ordered-map @ud @tas) gte) :: |% ++ test-ordered-map-gas ^- tang @@ -17,7 +18,7 @@ :: %+ expect-eq !> %.y - !> (check-balance:atom-map a) + !> (apt:atom-map a) :: ++ test-ordered-map-tap ^- tang :: @@ -27,6 +28,72 @@ !> test-items !> (tap:atom-map a) :: +++ test-ordered-map-tab-gte ^- tang + :: + =/ a=(tree [@ud @tas]) (gas:gte-atom-map ~ test-items) + :: + %+ expect-eq + !> (flop test-items) + !> (tab:gte-atom-map a ~ 7) +:: +++ test-ordered-map-tab-gte-starting-from ^- tang + :: + =/ a=(tree [@ud @tas]) (gas:gte-atom-map ~ test-items) + =/ small-test-items=(list [@ud @tas]) + (items-from-keys (gulf 2 5)) + :: + %+ expect-eq + !> (flop small-test-items) + !> (tab:gte-atom-map a [~ 6] 4) +:: +++ test-ordered-map-tab-gte-count ^- tang + :: + =/ a=(tree [@ud @tas]) (gas:gte-atom-map ~ test-items) + =/ small-test-items=(list [@ud @tas]) + (items-from-keys (gulf 4 6)) + :: + %+ expect-eq + !> (flop small-test-items) + !> (tab:gte-atom-map a ~ 3) +:: +++ test-ordered-map-tab ^- tang + :: + =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) + :: + %+ expect-eq + !> test-items + !> (tab:atom-map a ~ 7) +:: +++ test-ordered-map-tab-starting-from ^- tang + :: + =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) + =/ small-test-items=(list [@ud @tas]) + (items-from-keys (gulf 1 4)) + :: + %+ expect-eq + !> small-test-items + !> (tab:atom-map a [~ 0] 4) +:: +++ test-ordered-map-tab-count ^- tang + :: + =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) + =/ small-test-items=(list [@ud @tas]) + (items-from-keys (gulf 0 2)) + :: + %+ expect-eq + !> small-test-items + !> (tab:atom-map a ~ 3) +:: +++ test-ordered-map-tab-more-than-exist ^- tang + :: + =/ specific-test-items=(list [@ud @tas]) + (items-from-keys (gulf 1 6)) + =/ a=(tree [@ud @tas]) (gas:atom-map ~ specific-test-items) + :: + %+ expect-eq + !> specific-test-items + !> (tab:atom-map a [~ 0] 8) +:: ++ test-ordered-map-pop ^- tang :: =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) @@ -35,13 +102,13 @@ !> [[0 %a] (gas:atom-map ~ (items-from-keys (gulf 1 6)))] !> (pop:atom-map a) :: -++ test-ordered-map-peek ^- tang +++ test-ordered-map-pry ^- tang :: =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) :: %+ expect-eq !> `[0 %a] - !> (peek:atom-map a) + !> (pry:atom-map a) :: ++ test-ordered-map-nip ^- tang :: @@ -53,61 +120,61 @@ !> (gas:atom-map ~ ~[[0^%a] [1^%b] [2^%c] [3^%d] [4^%e] [5^%f]]) !> b :: -++ test-ordered-map-subset ^- tang +++ test-ordered-map-lot ^- tang :: =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) :: - =/ b (subset:atom-map a `0 `4) + =/ b (lot:atom-map a `0 `4) :: %+ expect-eq !> (gas:atom-map ~ ~[[1^%b] [2^%c] [3^%d]]) !> b :: -++ test-ordered-map-null-start-subset ^- tang +++ test-ordered-map-null-start-lot ^- tang :: =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) :: - =/ b (subset:atom-map a ~ `5) + =/ b (lot:atom-map a ~ `5) :: %+ expect-eq !> (gas:atom-map ~ ~[[0^%a] [1^%b] [2^%c] [3^%d] [4^%e]]) !> b :: -++ test-ordered-map-null-end-subset ^- tang +++ test-ordered-map-null-end-lot ^- tang :: =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) :: - =/ b (subset:atom-map a `1 ~) + =/ b (lot:atom-map a `1 ~) :: %+ expect-eq !> (gas:atom-map ~ ~[[2^%c] [3^%d] [4^%e] [5^%f] [6^%g]]) !> b :: -++ test-ordered-map-double-null-subset ^- tang +++ test-ordered-map-double-null-lot ^- tang :: =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) :: - =/ b (subset:atom-map a ~ ~) + =/ b (lot:atom-map a ~ ~) :: %+ expect-eq !> (gas:atom-map ~ ~[[0^%a] [1^%b] [2^%c] [3^%d] [4^%e] [5^%f] [6^%g]]) !> b :: -++ test-ordered-map-not-found-start-subset ^- tang +++ test-ordered-map-not-found-start-lot ^- tang :: =/ a=(tree [@ud @tas]) (gas:atom-map ~ ~[[1^%b]]) :: - =/ b (subset:atom-map a `0 ~) + =/ b (lot:atom-map a `0 ~) :: %+ expect-eq !> (gas:atom-map ~ ~[[1^%b]]) !> b :: -++ test-ordered-map-traverse ^- tang +++ test-ordered-map-dip ^- tang :: =/ a=(tree [@ud @tas]) (gas:atom-map ~ test-items) :: - =/ b %- (traverse:atom-map ,(list [@ud @tas])) + =/ b %- (dip:atom-map ,(list [@ud @tas])) :* a state=~ :: @@ -129,11 +196,11 @@ !> -.b == :: -++ test-ordered-map-traverse-delete-all ^- tang +++ test-ordered-map-dip-delete-all ^- tang ;: weld =/ q ((ordered-map ,@ ,~) lte) =/ o (gas:q ~ ~[1/~ 2/~ 3/~]) - =/ b ((traverse:q ,~) o ~ |=([~ key=@ ~] [~ %| ~])) + =/ b ((dip:q ,~) o ~ |=([~ key=@ ~] [~ %| ~])) %+ expect-eq !> [~ ~] !> b @@ -147,7 +214,7 @@ ?:((lth aa ba) %.y ?:((gth aa ba) %.n (lte ab bb))) =/ q ((ordered-map ,[@ @] ,~) compare) =/ o (gas:q ~ c) - =/ b ((traverse:q ,~) o ~ |=([~ key=[@ @] ~] [~ %| ~])) + =/ b ((dip:q ,~) o ~ |=([~ key=[@ @] ~] [~ %| ~])) %+ expect-eq !> [~ ~] !> b diff --git a/pkg/ent/configure b/pkg/ent/configure index 3e98a5108d..8171293f3f 100755 --- a/pkg/ent/configure +++ b/pkg/ent/configure @@ -7,6 +7,7 @@ log () { for impl in ENT_GETENTROPY_UNISTD \ ENT_GETENTROPY_SYSRANDOM \ ENT_GETRANDOM_SYSCALL \ + ENT_GETENTROPY_BCRYPTGENRANDOM \ ENT_DEV_URANDOM do export IMPL=$impl diff --git a/pkg/ent/ent.c b/pkg/ent/ent.c index 7aee7f48d9..e7309ff339 100644 --- a/pkg/ent/ent.c +++ b/pkg/ent/ent.c @@ -57,6 +57,16 @@ int ent_getentropy(void* buf, size_t len) { return 0; } + +// Use `BCryptGenRandom` on Windows //////////////////////////////////////////// + +#elif defined(ENT_GETENTROPY_BCRYPTGENRANDOM) +#include +#include +int ent_getentropy(void* buf, size_t len) { + return BCryptGenRandom(NULL, (PUCHAR)buf, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG); +} + #else -#error "One of these must be set: ENT_DEV_URANDOM, ENT_GETENTROPY_UNISTD, ENT_GETENTROPY_SYSRANDOM, ENT_GETRANDOM_SYSCALL" +#error "One of these must be set: ENT_GETENTROPY_BCRYPTGENRANDOM, ENT_DEV_URANDOM, ENT_GETENTROPY_UNISTD, ENT_GETENTROPY_SYSRANDOM, ENT_GETRANDOM_SYSCALL" #endif diff --git a/pkg/urbit/.gitattributes b/pkg/urbit/.gitattributes index 97a98b07a2..def025cbfc 100644 --- a/pkg/urbit/.gitattributes +++ b/pkg/urbit/.gitattributes @@ -3,3 +3,4 @@ tests export-ignore hashtable_tests export-ignore shell.nix export-ignore +*.patch -text diff --git a/pkg/urbit/.gitignore b/pkg/urbit/.gitignore index 6c94be2f8c..f78b9fecdf 100644 --- a/pkg/urbit/.gitignore +++ b/pkg/urbit/.gitignore @@ -1,3 +1,5 @@ # Configuration Result /config.mk /include/config.h +/include/ca-bundle.h +/include/ivory.h diff --git a/pkg/urbit/Makefile b/pkg/urbit/Makefile index 872c5eb1d3..c079c2af3b 100644 --- a/pkg/urbit/Makefile +++ b/pkg/urbit/Makefile @@ -1,4 +1,5 @@ include config.mk +include $(foreach dir,$(compat),$(wildcard compat/$(dir)/*.mk)) jets = jets/tree.c $(wildcard jets/*/*.c) noun = $(wildcard noun/*.c) @@ -9,7 +10,9 @@ worker = $(wildcard worker/*.c) tests = $(wildcard tests/*.c) bench = $(wildcard bench/*.c) -common = $(jets) $(noun) $(ur) $(vere) +compat := $(foreach dir,$(compat),$(wildcard compat/$(dir)/*.c)) + +common = $(jets) $(noun) $(ur) $(vere) $(compat) headers = $(shell find include -type f) common_objs = $(shell echo $(common) | sed 's/\.c/.o/g') @@ -29,7 +32,7 @@ CFLAGS := $(CFLAGS) ################################################################################ -.PHONY: all test clean mkproper +.PHONY: all test clean mrproper ################################################################################ @@ -74,9 +77,11 @@ build/urbit-worker: $(common_objs) $(worker_objs) @mkdir -p ./build @$(CC) $^ $(LDFLAGS) -o $@ -%.o: %.c $(headers) +# CCDEPS and CCEXTRA are empty except in MingW build, +# which uses them to inject a C source transform step +%.o: %.c $(headers) $(CCDEPS) @echo CC $< - @$(CC) -I./include $(CFLAGS) -c $< -o $@ + @$(CC) -I./include $(CFLAGS) $< $(CCEXTRA) -c -o $@ tags: $(all_srcs) $(headers) ctags $^ diff --git a/pkg/urbit/compat/create-include-files.sh b/pkg/urbit/compat/create-include-files.sh new file mode 100755 index 0000000000..ff45ef7483 --- /dev/null +++ b/pkg/urbit/compat/create-include-files.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# support running off a tarball that doesn't contain binary pills +(( $($1 ../../bin/ivory.pill) > 512 )) || curl -L https://github.com/urbit/urbit/raw/urbit-v$URBIT_VERSION/bin/ivory.pill > ../../bin/ivory.pill + +poor_mans_xxd () { + cch=0 + echo "unsigned char $2[] = {" + while IFS='' read line + do + for i in $line + do + echo -n " 0x$i," + cch=$((cch+1)) + done + echo + done < <(od -An -v -tx1 $1) + echo "};" + echo "unsigned int $2_len = $cch;" +} + +[ -e include/ca-bundle.h ] || poor_mans_xxd $2 include_ca_bundle_crt >include/ca-bundle.h +[ -e include/ivory.h ] || poor_mans_xxd ../../bin/ivory.pill u3_Ivory_pill >include/ivory.h diff --git a/pkg/urbit/compat/m1brew/compat.mk b/pkg/urbit/compat/m1brew/compat.mk new file mode 100644 index 0000000000..5d612ba841 --- /dev/null +++ b/pkg/urbit/compat/m1brew/compat.mk @@ -0,0 +1,14 @@ +# paths to brew packages +CFLAGS := $(CFLAGS) -I/opt/homebrew/include +LDFLAGS := $(LDFLAGS) -L/opt/homebrew/lib +# force linker to use static libraries +LDFLAGS := $(shell compat/m1brew/use-static-libs.sh $(LDFLAGS)) +# add extra osx libraries +LDFLAGS := $(LDFLAGS) -framework SystemConfiguration + +ifdef debug +CFLAGS := $(CFLAGS) -O0 -g +else +# clang hangs on noun/allocate.c if -g is specified with -O3 +CFLAGS := $(CFLAGS) -O3 +endif diff --git a/pkg/urbit/compat/m1brew/ed25519.patch b/pkg/urbit/compat/m1brew/ed25519.patch new file mode 100644 index 0000000000..1dfa957f1d --- /dev/null +++ b/pkg/urbit/compat/m1brew/ed25519.patch @@ -0,0 +1,13 @@ +diff --git a/Makefile b/Makefile +new file mode 100644 +--- /dev/null ++++ b/Makefile +@@ -0,0 +1,8 @@ ++.PHONY: all clean ++ ++all: *.c *.h ++ $(CC) -c -O3 -Wall -Werror *.c ++ $(AR) rcs libed25519.a *.o ++ ++clean: ++ rm -f *.o *.a diff --git a/pkg/urbit/compat/m1brew/ent.patch b/pkg/urbit/compat/m1brew/ent.patch new file mode 100644 index 0000000000..f26edf7a83 --- /dev/null +++ b/pkg/urbit/compat/m1brew/ent.patch @@ -0,0 +1,12 @@ +diff --git a/configure b/configure +--- a/configure ++++ b/configure +@@ -15,7 +15,7 @@ do + log "Trying IMPL=$IMPL" + + if IMPL=$impl make >/dev/null 2>/dev/null +- then sed -i 's|$(error IMPL must be set)|IMPL='"$impl"'|' Makefile ++ then sed -i "" 's|$(error IMPL must be set)|IMPL='"$impl"'|' Makefile + log "IMPL=$IMPL works" + exit 0 + else log "IMPL=$IMPL failed" diff --git a/pkg/urbit/compat/m1brew/libscrypt.patch b/pkg/urbit/compat/m1brew/libscrypt.patch new file mode 100644 index 0000000000..03e88629e8 --- /dev/null +++ b/pkg/urbit/compat/m1brew/libscrypt.patch @@ -0,0 +1,17 @@ +diff --git a/Makefile b/Makefile +index 783c537..3156ee2 100644 +--- a/Makefile ++++ b/Makefile +@@ -12,10 +12,9 @@ LDFLAGS_EXTRA?=-Wl,-z,relro + + all: reference + +-OBJS= crypto_scrypt-nosse.o sha256.o crypto-mcf.o b64.o crypto-scrypt-saltgen.o crypto_scrypt-check.o crypto_scrypt-hash.o slowequals.o ++OBJS= crypto_scrypt-nosse.o sha256.o crypto-mcf.o b64.o slowequals.o + +-libscrypt.so.0: $(OBJS) +- $(CC) $(LDFLAGS) -shared -o libscrypt.so.0 $(OBJS) -lm -lc ++libscrypt.a: $(OBJS) + ar rcs libscrypt.a $(OBJS) + + reference: libscrypt.so.0 main.o crypto_scrypt-hexconvert.o diff --git a/pkg/urbit/compat/m1brew/murmur3.patch b/pkg/urbit/compat/m1brew/murmur3.patch new file mode 100644 index 0000000000..cd83e9fdda --- /dev/null +++ b/pkg/urbit/compat/m1brew/murmur3.patch @@ -0,0 +1,13 @@ +diff --git a/makefile b/makefile +--- a/makefile ++++ b/makefile +@@ -12,5 +12,9 @@ shared: murmur3.c murmur3.h + $(CC) -fPIC -O3 -c murmur3.c + $(CC) -shared -Wl,--export-dynamic murmur3.o -o libmurmur3.so + ++static: murmur3.c murmur3.h ++ $(CC) -fPIC -O3 -c murmur3.c ++ $(AR) rcs libmurmur3.a murmur3.o ++ + clean: + rm -rf example *.o *.so diff --git a/pkg/urbit/compat/m1brew/softfloat3.patch b/pkg/urbit/compat/m1brew/softfloat3.patch new file mode 100644 index 0000000000..888d566f49 --- /dev/null +++ b/pkg/urbit/compat/m1brew/softfloat3.patch @@ -0,0 +1,85 @@ +diff --git a/build/template-FAST_INT64/Makefile b/build/template-FAST_INT64/Makefile +--- a/build/template-FAST_INT64/Makefile ++++ b/build/template-FAST_INT64/Makefile +@@ -34,28 +34,27 @@ + # + #============================================================================= + +-# Edit lines marked with `==>'. See "SoftFloat-source.html". ++SOURCE_DIR ?= ../../source ++SPECIALIZE_TYPE ?= 8086-SSE + +-==> SOURCE_DIR ?= ../../source +-==> SPECIALIZE_TYPE ?= 8086 ++SOFTFLOAT_OPTS ?= \ ++ -DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 \ ++ -DSOFTFLOAT_FAST_DIV64TO32 + +-==> SOFTFLOAT_OPTS ?= \ +-==> -DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 \ +-==> -DSOFTFLOAT_FAST_DIV64TO32 ++DELETE = rm -f ++C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include ++COMPILE_C = \ ++ cc -c -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@ ++MAKELIB = ar crs $@ ++LIBNAME = libsoftfloat3 + +-==> DELETE = rm -f +-==> C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include +-==> COMPILE_C = \ +-==> cc -c -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@ +-==> MAKELIB = ar crs $@ ++OBJ = .o ++LIB = .a + +-==> OBJ = .o +-==> LIB = .a +- +-==> OTHER_HEADERS = ++OTHER_HEADERS = + + .PHONY: all +-all: softfloat$(LIB) ++all: $(LIBNAME)$(LIB) + + OBJS_PRIMITIVES = \ + s_eq128$(OBJ) \ +@@ -381,11 +380,11 @@ $(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c + $(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c + $(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c + +-softfloat$(LIB): $(OBJS_ALL) ++$(LIBNAME)$(LIB): $(OBJS_ALL) + $(DELETE) $@ + $(MAKELIB) $^ + + .PHONY: clean + clean: +- $(DELETE) $(OBJS_ALL) softfloat$(LIB) ++ $(DELETE) $(OBJS_ALL) $(LIBNAME)$(LIB) + +diff --git a/build/template-FAST_INT64/platform.h b/build/template-FAST_INT64/platform.h +--- a/build/template-FAST_INT64/platform.h ++++ b/build/template-FAST_INT64/platform.h +@@ -34,17 +34,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + =============================================================================*/ + +-// Edit lines marked with `==>'. See "SoftFloat-source.html". +- + /*---------------------------------------------------------------------------- + *----------------------------------------------------------------------------*/ +-==> #define LITTLEENDIAN 1 ++#define LITTLEENDIAN 1 + + /*---------------------------------------------------------------------------- + *----------------------------------------------------------------------------*/ +-==> #define INLINE inline ++#define INLINE inline + + /*---------------------------------------------------------------------------- + *----------------------------------------------------------------------------*/ +-==> #define THREAD_LOCAL _Thread_local ++#define THREAD_LOCAL _Thread_local + diff --git a/pkg/urbit/compat/m1brew/use-static-libs.sh b/pkg/urbit/compat/m1brew/use-static-libs.sh new file mode 100755 index 0000000000..7f7cf83a1c --- /dev/null +++ b/pkg/urbit/compat/m1brew/use-static-libs.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -euo pipefail +declare -a ldirs +for i in $@ +do + case $i in + -L*) ldirs+=(${i:2});; + esac +done +for i in $@ +do + case $i in + -l*) + lib=$(find ${ldirs[@]} -name lib${i:2}.a) + if [ "$lib" != "" ] + then + echo $lib + else + echo $i + fi;; + *) echo $i;; + esac +done diff --git a/pkg/urbit/compat/mingw/compat.c b/pkg/urbit/compat/mingw/compat.c new file mode 100644 index 0000000000..0a60b56661 --- /dev/null +++ b/pkg/urbit/compat/mingw/compat.c @@ -0,0 +1,355 @@ +#include "c/portable.h" +#include +#include +#include + +// set default CRT file mode to binary +// note that mingw binmode.o does nothing +#undef _fmode +int _fmode = _O_BINARY; + +// set standard I/O fds to binary too, because +// MSVCRT creates them before MingW sets _fmode +static void __attribute__ ((constructor)) _set_stdio_to_binary() +{ + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); + _setmode(2, _O_BINARY); +} + +// from https://github.com/git/git/blob/master/compat/mingw.c +// ----------------------------------------------------------------------- + +int err_win_to_posix(DWORD winerr) +{ + int error = ENOSYS; + switch(winerr) { + case ERROR_ACCESS_DENIED: error = EACCES; break; + case ERROR_ACCOUNT_DISABLED: error = EACCES; break; + case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break; + case ERROR_ALREADY_ASSIGNED: error = EBUSY; break; + case ERROR_ALREADY_EXISTS: error = EEXIST; break; + case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break; + case ERROR_BAD_COMMAND: error = EIO; break; + case ERROR_BAD_DEVICE: error = ENODEV; break; + case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break; + case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break; + case ERROR_BAD_FORMAT: error = ENOEXEC; break; + case ERROR_BAD_LENGTH: error = EINVAL; break; + case ERROR_BAD_PATHNAME: error = ENOENT; break; + case ERROR_BAD_PIPE: error = EPIPE; break; + case ERROR_BAD_UNIT: error = ENODEV; break; + case ERROR_BAD_USERNAME: error = EINVAL; break; + case ERROR_BROKEN_PIPE: error = EPIPE; break; + case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break; + case ERROR_BUSY: error = EBUSY; break; + case ERROR_BUSY_DRIVE: error = EBUSY; break; + case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break; + case ERROR_CANNOT_MAKE: error = EACCES; break; + case ERROR_CANTOPEN: error = EIO; break; + case ERROR_CANTREAD: error = EIO; break; + case ERROR_CANTWRITE: error = EIO; break; + case ERROR_CRC: error = EIO; break; + case ERROR_CURRENT_DIRECTORY: error = EACCES; break; + case ERROR_DEVICE_IN_USE: error = EBUSY; break; + case ERROR_DEV_NOT_EXIST: error = ENODEV; break; + case ERROR_DIRECTORY: error = EINVAL; break; + case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break; + case ERROR_DISK_CHANGE: error = EIO; break; + case ERROR_DISK_FULL: error = ENOSPC; break; + case ERROR_DRIVE_LOCKED: error = EBUSY; break; + case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break; + case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break; + case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break; + case ERROR_FILE_EXISTS: error = EEXIST; break; + case ERROR_FILE_INVALID: error = ENODEV; break; + case ERROR_FILE_NOT_FOUND: error = ENOENT; break; + case ERROR_GEN_FAILURE: error = EIO; break; + case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break; + case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break; + case ERROR_INVALID_ACCESS: error = EACCES; break; + case ERROR_INVALID_ADDRESS: error = EFAULT; break; + case ERROR_INVALID_BLOCK: error = EFAULT; break; + case ERROR_INVALID_DATA: error = EINVAL; break; + case ERROR_INVALID_DRIVE: error = ENODEV; break; + case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break; + case ERROR_INVALID_FLAGS: error = EINVAL; break; + case ERROR_INVALID_FUNCTION: error = ENOSYS; break; + case ERROR_INVALID_HANDLE: error = EBADF; break; + case ERROR_INVALID_LOGON_HOURS: error = EACCES; break; + case ERROR_INVALID_NAME: error = EINVAL; break; + case ERROR_INVALID_OWNER: error = EINVAL; break; + case ERROR_INVALID_PARAMETER: error = EINVAL; break; + case ERROR_INVALID_PASSWORD: error = EPERM; break; + case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break; + case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break; + case ERROR_INVALID_TARGET_HANDLE: error = EIO; break; + case ERROR_INVALID_WORKSTATION: error = EACCES; break; + case ERROR_IO_DEVICE: error = EIO; break; + case ERROR_IO_INCOMPLETE: error = EINTR; break; + case ERROR_LOCKED: error = EBUSY; break; + case ERROR_LOCK_VIOLATION: error = EACCES; break; + case ERROR_LOGON_FAILURE: error = EACCES; break; + case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break; + case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break; + case ERROR_MORE_DATA: error = EPIPE; break; + case ERROR_NEGATIVE_SEEK: error = ESPIPE; break; + case ERROR_NOACCESS: error = EFAULT; break; + case ERROR_NONE_MAPPED: error = EINVAL; break; + case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break; + case ERROR_NOT_READY: error = EAGAIN; break; + case ERROR_NOT_SAME_DEVICE: error = EXDEV; break; + case ERROR_NO_DATA: error = EPIPE; break; + case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break; + case ERROR_NO_PROC_SLOTS: error = EAGAIN; break; + case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break; + case ERROR_OPEN_FAILED: error = EIO; break; + case ERROR_OPEN_FILES: error = EBUSY; break; + case ERROR_OPERATION_ABORTED: error = EINTR; break; + case ERROR_OUTOFMEMORY: error = ENOMEM; break; + case ERROR_PASSWORD_EXPIRED: error = EACCES; break; + case ERROR_PATH_BUSY: error = EBUSY; break; + case ERROR_PATH_NOT_FOUND: error = ENOENT; break; + case ERROR_PIPE_BUSY: error = EBUSY; break; + case ERROR_PIPE_CONNECTED: error = EPIPE; break; + case ERROR_PIPE_LISTENING: error = EPIPE; break; + case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break; + case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break; + case ERROR_READ_FAULT: error = EIO; break; + case ERROR_SEEK: error = EIO; break; + case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break; + case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break; + case ERROR_SHARING_VIOLATION: error = EACCES; break; + case ERROR_STACK_OVERFLOW: error = ENOMEM; break; + case ERROR_SUCCESS: error = 0; break; + case ERROR_SWAPERROR: error = ENOENT; break; + case ERROR_TOO_MANY_MODULES: error = EMFILE; break; + case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break; + case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break; + case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break; + case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break; + case ERROR_WRITE_FAULT: error = EIO; break; + case ERROR_WRITE_PROTECT: error = EROFS; break; + } + return error; +} + +// from msys2 mingw-packages-dev patches +// ----------------------------------------------------------------------- + +static DWORD __map_mmap_prot_page(const int prot) +{ + DWORD protect = 0; + + if (prot == PROT_NONE) + return protect; + + if ((prot & PROT_EXEC) != 0) + { + protect = ((prot & PROT_WRITE) != 0) ? + PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; + } + else + { + protect = ((prot & PROT_WRITE) != 0) ? + PAGE_READWRITE : PAGE_READONLY; + } + + return protect; +} + +static DWORD __map_mmap_prot_file(const int prot) +{ + DWORD desiredAccess = 0; + + if (prot == PROT_NONE) + return desiredAccess; + + if ((prot & PROT_READ) != 0) + desiredAccess |= FILE_MAP_READ; + if ((prot & PROT_WRITE) != 0) + desiredAccess |= FILE_MAP_WRITE; + if ((prot & PROT_EXEC) != 0) + desiredAccess |= FILE_MAP_EXECUTE; + + return desiredAccess; +} + +void* mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) +{ + HANDLE fm, h; + + void * map = MAP_FAILED; + + const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ? + (DWORD)off : (DWORD)(off & 0xFFFFFFFFL); + const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ? + (DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL); + const DWORD protect = __map_mmap_prot_page(prot); + const DWORD desiredAccess = __map_mmap_prot_file(prot); + + errno = 0; + + if (len == 0 + /* Usupported protection combinations */ + || prot == PROT_EXEC) + { + errno = EINVAL; + return MAP_FAILED; + } + + if ((flags & MAP_ANON) == 0) + { + h = (HANDLE)_get_osfhandle(fildes); + + if (h == INVALID_HANDLE_VALUE) + { + errno = EBADF; + return MAP_FAILED; + } + } + else h = INVALID_HANDLE_VALUE; + + fm = CreateFileMapping(h, NULL, protect, 0, len, NULL); + + if (fm == NULL) + { + errno = err_win_to_posix(GetLastError()); + return MAP_FAILED; + } + + map = MapViewOfFileEx(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len, addr); + errno = err_win_to_posix(GetLastError()); + + CloseHandle(fm); + + if (map == NULL) + return MAP_FAILED; + + if ((flags & MAP_FIXED) != 0 && map != addr) + { + UnmapViewOfFile(map); + errno = EEXIST; + return MAP_FAILED; + } + + return map; +} + +int munmap(void *addr, size_t len) +{ + if (UnmapViewOfFile(addr)) + return 0; + + errno = err_win_to_posix(GetLastError()); + return -1; +} + +int msync(void *addr, size_t len, int flags) +{ + if (FlushViewOfFile(addr, len)) + return 0; + + errno = err_win_to_posix(GetLastError()); + return -1; +} + +// ----------------------------------------------------------------------- + +// vere uses kill() only to kill lockfile owner with SIGTERM or SIGKILL +// Windows does not have signals, so I handle SIGKILL as TerminateProcess() +// and return an error in all other cases +int kill(pid_t pid, int sig) +{ + if (pid > 0 && sig == SIGKILL) { + HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid); + + if (TerminateProcess(h, -1)) { + CloseHandle(h); + return 0; + } + + errno = err_win_to_posix(GetLastError()); + CloseHandle(h); + return -1; + } + + errno = EINVAL; + return -1; +} + +// libgcc built for mingw has included an implementation of mprotect +// via VirtualProtect since olden days, but it takes int rather than size_t +// and therefore fails or does unexpected things for >2GB blocks on 64-bit +// https://github.com/gcc-mirror/gcc/blob/master/libgcc/libgcc2.c +int mprotect (void *addr, size_t len, int prot) +{ + DWORD np, op; + + if (prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) + np = PAGE_EXECUTE_READWRITE; + else if (prot == (PROT_READ | PROT_EXEC)) + np = PAGE_EXECUTE_READ; + else if (prot == (PROT_EXEC)) + np = PAGE_EXECUTE; + else if (prot == (PROT_READ | PROT_WRITE)) + np = PAGE_READWRITE; + else if (prot == (PROT_READ)) + np = PAGE_READONLY; + else if (prot == 0) + np = PAGE_NOACCESS; + else + { + errno = EINVAL; + return -1; + } + + if (VirtualProtect (addr, len, np, &op)) + return 0; + + // NB: return code of ntdll!RtlGetLastNtStatus() is useful + // for diagnosing obscure VirtualProtect failures + errno = err_win_to_posix(GetLastError()); + return -1; +} + +int utimes(const char *path, const struct timeval times[2]) +{ + struct _utimbuf utb = {.actime = times[0].tv_sec, .modtime = times[1].tv_sec}; + return _utime(path, &utb); +} + +int fdatasync(int fildes) +{ + HANDLE h = (HANDLE)_get_osfhandle(fildes); + + if (h == INVALID_HANDLE_VALUE) + { + errno = EBADF; + return -1; + } + + if (FlushFileBuffers(h)) + { + errno = 0; + return 0; + } + else + { + errno = err_win_to_posix(GetLastError()); + return -1; + } +} + +intmax_t mdb_get_filesize(HANDLE han_u) +{ + LARGE_INTEGER li; + GetFileSizeEx(han_u, &li); + return li.QuadPart; +} + +char *realpath(const char *path, char *resolved_path) +{ + // TODO + return strdup(path); +} diff --git a/pkg/urbit/compat/mingw/compat.h b/pkg/urbit/compat/mingw/compat.h new file mode 100644 index 0000000000..21290d7b55 --- /dev/null +++ b/pkg/urbit/compat/mingw/compat.h @@ -0,0 +1,18 @@ +#ifndef _MINGW_IO_H +#define _MINGW_IO_H + +#define mkdir(A, B) mkdir(A) + +char *realpath(const char *path, char *resolved_path); +int fdatasync(int fd); +int utimes(const char *path, const struct timeval times[2]); + +int kill(pid_t pid, int signum); + +#define SIGUSR1 10 +#define SIGALRM 14 +#define SIGVTALRM 26 +#define SIGSTK 31 +#define SIG_COUNT 32 + +#endif//_MINGW_IO_H diff --git a/pkg/urbit/compat/mingw/compat.mk b/pkg/urbit/compat/mingw/compat.mk new file mode 100644 index 0000000000..f4254c188d --- /dev/null +++ b/pkg/urbit/compat/mingw/compat.mk @@ -0,0 +1,15 @@ +# increase default thread stack size and link Windows implibs +LDFLAGS := $(LDFLAGS) -static -Wl,--stack,67108864 -lbcrypt -lntdll -lws2_32 +# libcurl +CFLAGS := $(CFLAGS) -DCURL_STATICLIB +LDFLAGS := $(LDFLAGS) -lzstd -lcrypt32 +# libh2o +CFLAGS := $(CFLAGS) -DH2O_NO_UNIX_SOCKETS +# libuv +LDFLAGS := $(LDFLAGS) -luserenv -liphlpapi -lpsapi + +ifdef debug +CFLAGS := $(CFLAGS) -O0 -g +else +CFLAGS := $(CFLAGS) -O3 -g +endif diff --git a/pkg/urbit/compat/mingw/ctrlc.c b/pkg/urbit/compat/mingw/ctrlc.c new file mode 100644 index 0000000000..9be57981b9 --- /dev/null +++ b/pkg/urbit/compat/mingw/ctrlc.c @@ -0,0 +1,7 @@ +#include + +// initialize msvcrt signals early, otherwise Ctrl-C does nothing +static void __attribute__ ((constructor)) _init_crt_signals() +{ + signal(SIGINT, SIG_DFL); +} diff --git a/pkg/urbit/compat/mingw/daemon.c b/pkg/urbit/compat/mingw/daemon.c new file mode 100644 index 0000000000..0220cb75ae --- /dev/null +++ b/pkg/urbit/compat/mingw/daemon.c @@ -0,0 +1,116 @@ +#include "all.h" +#include "vere/vere.h" + +/* _dup_std_handle(): creates an inheritable duplicate of a standard handle. +*/ +static BOOL +_dup_std_handle(HANDLE* new_u, DWORD typ_u) +{ + DWORD dum_u; + HANDLE han_u = GetStdHandle(typ_u); + BOOL con_u = GetConsoleMode(han_u, &dum_u); + if ( con_u ) { + han_u = (HANDLE)_get_osfhandle(open(c3_dev_null, O_RDWR, 0)); + } + + if ( !DuplicateHandle(GetCurrentProcess(), han_u, GetCurrentProcess(), new_u, 0, TRUE, DUPLICATE_SAME_ACCESS) ) { + fprintf(stderr, "vere: DuplicateHandle(%d): %d\r\n", typ_u, GetLastError()); + exit(1); + } + + return con_u; +} + +/* _on_boot_completed_cb: invoked when the ship has finished booting. +*/ +static void _on_boot_completed_cb() { + HANDLE hin_u = GetStdHandle(STD_INPUT_HANDLE); + SetEvent(hin_u); + CloseHandle(hin_u); +} + +/* u3_daemon_init(): platform-specific daemon mode initialization. +*/ +void +u3_daemon_init() +{ + // detect if this process is the child daemon process + // + if ( ResetEvent(GetStdHandle(STD_INPUT_HANDLE)) ) { + u3_Host.bot_f = _on_boot_completed_cb; + return; + } + + STARTUPINFOW psi_u; + ZeroMemory(&psi_u, sizeof(psi_u)); + psi_u.cb = sizeof(psi_u); + psi_u.dwFlags = STARTF_USESTDHANDLES; + + // duplicate standard output and error handles for the child process, + // replacing any raw console handles with handles to /dev/null + // print a warning if raw console output detected + // + // On Windows, console handles become invalid once the console is + // detached. This will cause urbit terminal output to fail. libuv + // provides no way of changing the handle of an open uv_pipe_handle, + // and Windows has no equivalent of dup2() for handles, so I cannot + // substitute a /dev/null handle once the terminal is initialized. + // It is possible to create an anonymous pipe and have the child + // process take over its drain end after it signals that the ship + // has booted, but -d is intended for background operation anyway + // and does not seem to warrant the added complexity. + // + if ( _dup_std_handle(&psi_u.hStdOutput, STD_OUTPUT_HANDLE) | + _dup_std_handle(&psi_u.hStdError, STD_ERROR_HANDLE) ) + { + fprintf(stderr, "vere: -d used from a Windows console without redirection\r\n" + " no output from the daemon process will be visible\r\n"); + fflush(stderr); + } + + // create an event for the child process to signal + // the parent that the ship has finished booting + // pass the handle as "stdin" (otherwise unused with -d) + // + SECURITY_ATTRIBUTES sa_u = {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE}; + if ( !(psi_u.hStdInput = CreateEvent(&sa_u, TRUE, FALSE, NULL)) ) { + fprintf(stderr, "vere: CreateEvent: %d\r\n", GetLastError()); + exit(1); + } + + // create the child process with the same command line as parent + // it will start, re-parse the command line, and call u3_daemon_init + // + PROCESS_INFORMATION ppi_u; + if ( !CreateProcessW(NULL, _wcsdup(GetCommandLineW()), NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &psi_u, &ppi_u) ) { + fprintf(stderr, "vere: CreateProcess: %d\r\n", GetLastError()); + exit(1); + } + + CloseHandle(ppi_u.hThread); + + // wait for the child process to exit or to signal the event + // + DWORD exi_u; + HANDLE han_u[2] = {ppi_u.hProcess, psi_u.hStdInput}; + switch ( WaitForMultipleObjects(2, han_u, FALSE, INFINITE) ) { + case WAIT_OBJECT_0: + // the child process exited prematurely, propagate its exit code + // + if ( GetExitCodeProcess(ppi_u.hProcess, &exi_u) ) { + exit(exi_u); + } + + fprintf(stderr, "vere: GetExitCodeProcess: %d\r\n", GetLastError()); + exit(1); + + case WAIT_OBJECT_0 + 1: + // the child process has finished booting, exit normally + // + exit(0); + + default: + fprintf(stderr, "vere: WaitForMultipleObjects: %d\r\n", GetLastError()); + exit(1); + } +} diff --git a/pkg/urbit/compat/mingw/ed25519.patch b/pkg/urbit/compat/mingw/ed25519.patch new file mode 100644 index 0000000000..1dfa957f1d --- /dev/null +++ b/pkg/urbit/compat/mingw/ed25519.patch @@ -0,0 +1,13 @@ +diff --git a/Makefile b/Makefile +new file mode 100644 +--- /dev/null ++++ b/Makefile +@@ -0,0 +1,8 @@ ++.PHONY: all clean ++ ++all: *.c *.h ++ $(CC) -c -O3 -Wall -Werror *.c ++ $(AR) rcs libed25519.a *.o ++ ++clean: ++ rm -f *.o *.a diff --git a/pkg/urbit/compat/mingw/h2o.patch b/pkg/urbit/compat/mingw/h2o.patch new file mode 100644 index 0000000000..1bfc90e4ad --- /dev/null +++ b/pkg/urbit/compat/mingw/h2o.patch @@ -0,0 +1,1834 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 5a04e1426..9ddad60d1 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -69,6 +69,18 @@ OPTION(WITH_BUNDLED_SSL "whether or not to use the bundled libressl" ${WITH_BUND + + OPTION(WITHOUT_LIBS "skip building libs even when possible" OFF) + OPTION(BUILD_SHARED_LIBS "whether to build a shared library" OFF) ++OPTION(WITHOUT_FASTCGI "don't include fastcgi" OFF) ++OPTION(WITHOUT_MEMCACHED "don't include memcached" OFF) ++ ++IF (MINGW) ++ SET(WITHOUT_FASTCGI "ON") ++ SET(WITHOUT_MEMCACHED "ON") ++ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_POSIX_C_SOURCE -DO_CLOEXEC=0 -DH2O_NO_UNIX_SOCKETS") ++ENDIF (MINGW) ++ ++IF (WITHOUT_MEMCACHED) ++ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DH2O_NO_MEMCACHED") ++ENDIF (WITHOUT_MEMCACHED) + + FIND_PROGRAM(RUBY ruby) + FIND_PROGRAM(BISON bison) +@@ -228,16 +240,7 @@ SET(PICOTLS_SOURCE_FILES + deps/picotls/lib/openssl.c) + + SET(LIB_SOURCE_FILES +- deps/cloexec/cloexec.c + deps/libgkc/gkc.c +- deps/libyrmcds/close.c +- deps/libyrmcds/connect.c +- deps/libyrmcds/recv.c +- deps/libyrmcds/send.c +- deps/libyrmcds/send_text.c +- deps/libyrmcds/socket.c +- deps/libyrmcds/strerror.c +- deps/libyrmcds/text_mode.c + deps/picohttpparser/picohttpparser.c + + lib/common/cache.c +@@ -245,7 +248,6 @@ SET(LIB_SOURCE_FILES + lib/common/filecache.c + lib/common/hostinfo.c + lib/common/http1client.c +- lib/common/memcached.c + lib/common/memory.c + lib/common/multithread.c + lib/common/serverutil.c +@@ -272,7 +274,6 @@ SET(LIB_SOURCE_FILES + lib/handler/compress/gzip.c + lib/handler/errordoc.c + lib/handler/expires.c +- lib/handler/fastcgi.c + lib/handler/file.c + lib/handler/headers.c + lib/handler/mimemap.c +@@ -290,7 +291,6 @@ SET(LIB_SOURCE_FILES + lib/handler/configurator/compress.c + lib/handler/configurator/errordoc.c + lib/handler/configurator/expires.c +- lib/handler/configurator/fastcgi.c + lib/handler/configurator/file.c + lib/handler/configurator/headers.c + lib/handler/configurator/proxy.c +@@ -314,6 +314,33 @@ SET(LIB_SOURCE_FILES + lib/http2/stream.c + lib/http2/http2_debug_state.c) + ++IF (NOT MINGW) ++ SET(LIB_SOURCE_FILES ++ ${LIB_SOURCE_FILES} ++ deps/cloexec/cloexec.c) ++ENDIF (NOT MINGW) ++ ++IF (NOT WITHOUT_FASTCGI) ++ SET(LIB_SOURCE_FILES ++ ${LIB_SOURCE_FILES} ++ lib/handler/fastcgi.c ++ lib/handler/configurator/fastcgi.c) ++ENDIF (NOT WITHOUT_FASTCGI) ++ ++IF (NOT WITHOUT_MEMCACHED) ++ SET(LIB_SOURCE_FILES ++ ${LIB_SOURCE_FILES} ++ deps/libyrmcds/close.c ++ deps/libyrmcds/connect.c ++ deps/libyrmcds/recv.c ++ deps/libyrmcds/send.c ++ deps/libyrmcds/send_text.c ++ deps/libyrmcds/socket.c ++ deps/libyrmcds/strerror.c ++ deps/libyrmcds/text_mode.c ++ lib/common/memcached.c) ++ENDIF (NOT WITHOUT_MEMCACHED) ++ + SET(UNIT_TEST_SOURCE_FILES + ${LIB_SOURCE_FILES} + ${LIBYAML_SOURCE_FILES} +diff --git a/examples/libh2o/http1client.c b/examples/libh2o/http1client.c +index bcf9b94b2..592376759 100644 +--- a/examples/libh2o/http1client.c ++++ b/examples/libh2o/http1client.c +@@ -134,6 +134,11 @@ h2o_http1client_head_cb on_connect(h2o_http1client_t *client, const char *errstr + + int main(int argc, char **argv) + { ++#ifdef _WIN32 ++ WSADATA wsaData; ++ WSAStartup(MAKEWORD(2, 0), &wsaData); ++#endif ++ + h2o_multithread_queue_t *queue; + h2o_multithread_receiver_t getaddr_receiver; + h2o_timeout_t io_timeout; +diff --git a/examples/libh2o/simple.c b/examples/libh2o/simple.c +index bb72bf60c..be7045d1c 100644 +--- a/examples/libh2o/simple.c ++++ b/examples/libh2o/simple.c +@@ -21,11 +21,15 @@ + */ + #include + #include +-#include + #include + #include + #include ++#ifdef _WIN32 ++#include ++#else ++#include + #include ++#endif + #include + #include "h2o.h" + #include "h2o/http1.h" +@@ -219,7 +223,12 @@ int main(int argc, char **argv) + { + h2o_hostconf_t *hostconf; + ++#ifdef _WIN32 ++ WSADATA wsaData; ++ WSAStartup(MAKEWORD(2, 0), &wsaData); ++#else + signal(SIGPIPE, SIG_IGN); ++#endif + + h2o_config_init(&config); + hostconf = h2o_config_register_host(&config, h2o_iovec_init(H2O_STRLIT("default")), 65535); +diff --git a/include/h2o.h b/include/h2o.h +index 57877bd12..84822b792 100644 +--- a/include/h2o.h ++++ b/include/h2o.h +@@ -32,7 +32,11 @@ extern "C" { + #include + #include + #include ++#ifdef _WIN32 ++#include ++#else + #include ++#endif + #include + #include + #include +diff --git a/include/h2o/configurator.h b/include/h2o/configurator.h +index d1a2e2515..d59d070dd 100644 +--- a/include/h2o/configurator.h ++++ b/include/h2o/configurator.h +@@ -145,7 +145,7 @@ int h2o_configurator_apply_commands(h2o_configurator_context_t *ctx, yoml_t *nod + * emits configuration error + */ + void h2o_configurator_errprintf(h2o_configurator_command_t *cmd, yoml_t *node, const char *reason, ...) +- __attribute__((format(printf, 3, 4))); ++ __attribute__((format(gnu_printf, 3, 4))); + /** + * interprets the configuration value using sscanf, or prints an error upon failure + * @param configurator configurator +@@ -154,7 +154,7 @@ void h2o_configurator_errprintf(h2o_configurator_command_t *cmd, yoml_t *node, c + * @return 0 if successful, -1 if not + */ + int h2o_configurator_scanf(h2o_configurator_command_t *cmd, yoml_t *node, const char *fmt, ...) +- __attribute__((format(scanf, 3, 4))); ++ __attribute__((format(gnu_scanf, 3, 4))); + /** + * interprets the configuration value and returns the index of the matched string within the candidate strings, or prints an error + * upon failure +diff --git a/include/h2o/filecache.h b/include/h2o/filecache.h +index a000c4c6d..494f61fb1 100644 +--- a/include/h2o/filecache.h ++++ b/include/h2o/filecache.h +@@ -61,6 +61,7 @@ void h2o_filecache_destroy(h2o_filecache_t *cache); + void h2o_filecache_clear(h2o_filecache_t *cache); + + h2o_filecache_ref_t *h2o_filecache_open_file(h2o_filecache_t *cache, const char *path, int oflag); ++ssize_t h2o_filecache_read_file(h2o_filecache_ref_t *ref, void *buf, size_t count, off_t offset); + void h2o_filecache_close_file(h2o_filecache_ref_t *ref); + struct tm *h2o_filecache_get_last_modified(h2o_filecache_ref_t *ref, char *outbuf); + size_t h2o_filecache_get_etag(h2o_filecache_ref_t *ref, char *outbuf); +diff --git a/include/h2o/hostinfo.h b/include/h2o/hostinfo.h +index 14ac30c6c..b39fea520 100644 +--- a/include/h2o/hostinfo.h ++++ b/include/h2o/hostinfo.h +@@ -22,13 +22,16 @@ + #ifndef h2o__hostinfo_h + #define h2o__hostinfo_h + +-#include ++#ifdef _WIN32 ++#include ++#else + #include + #include + #include + #include + #include + #include ++#endif + #include "h2o/multithread.h" + + typedef struct st_h2o_hostinfo_getaddr_req_t h2o_hostinfo_getaddr_req_t; +diff --git a/include/h2o/memory.h b/include/h2o/memory.h +index 10c137c88..354fa4359 100644 +--- a/include/h2o/memory.h ++++ b/include/h2o/memory.h +@@ -78,8 +78,19 @@ typedef struct st_h2o_buffer_prototype_t h2o_buffer_prototype_t; + * buffer structure compatible with iovec + */ + typedef struct st_h2o_iovec_t { ++#ifdef __MINGW32__ ++#define H2O_IOVEC_NULL {0, NULL} ++#define H2O_IOVEC_EMPTY {0, ""} ++#define H2O_IOVEC_STRLIT(s) {sizeof(s) - 1, (s)} ++ unsigned int len; ++ char *base; ++#else ++#define H2O_IOVEC_NULL {NULL} ++#define H2O_IOVEC_EMPTY {"", 0} ++#define H2O_IOVEC_STRLIT(s) {(s), sizeof(s) - 1} + char *base; + size_t len; ++#endif + } h2o_iovec_t; + + typedef struct st_h2o_mem_recycle_t { +diff --git a/include/h2o/socket.h b/include/h2o/socket.h +index 58ada8509..268dd8a2e 100644 +--- a/include/h2o/socket.h ++++ b/include/h2o/socket.h +@@ -27,7 +27,11 @@ extern "C" { + #endif + + #include ++#ifdef _WIN32 ++#include ++#else + #include ++#endif + #include + #include "h2o/cache.h" + #include "h2o/memory.h" +diff --git a/include/h2o/socketpool.h b/include/h2o/socketpool.h +index cc4161df4..f1c4eb3c3 100644 +--- a/include/h2o/socketpool.h ++++ b/include/h2o/socketpool.h +@@ -26,8 +26,10 @@ + extern "C" { + #endif + ++#ifndef _WIN32 + #include + #include ++#endif + #include + #include "h2o/linklist.h" + #include "h2o/multithread.h" +diff --git a/include/h2o/url.h b/include/h2o/url.h +index 231c9a263..6a707a567 100644 +--- a/include/h2o/url.h ++++ b/include/h2o/url.h +@@ -22,7 +22,9 @@ + #ifndef h2o__url_h + #define h2o__url_h + ++#ifndef H2O_NO_UNIX_SOCKETS + #include ++#endif + #include "h2o/memory.h" + + typedef struct st_h2o_url_scheme_t { +@@ -92,11 +94,13 @@ static h2o_iovec_t h2o_url_stringify(h2o_mem_pool_t *pool, const h2o_url_t *url) + * copies a URL object (null-terminates all the string elements) + */ + void h2o_url_copy(h2o_mem_pool_t *pool, h2o_url_t *dest, const h2o_url_t *src); ++#ifndef H2O_NO_UNIX_SOCKETS + /** + * extracts sockaddr_un from host and returns NULL (or returns an error string if failed) + */ + const char *h2o_url_host_to_sun(h2o_iovec_t host, struct sockaddr_un *sa); + extern const char *h2o_url_host_to_sun_err_is_not_unix_socket; ++#endif + + /* inline definitions */ + +diff --git a/lib/common/file.c b/lib/common/file.c +index 3cf5ac5d1..d3e0048b6 100644 +--- a/lib/common/file.c ++++ b/lib/common/file.c +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include "h2o/file.h" + +@@ -33,7 +32,7 @@ h2o_iovec_t h2o_file_read(const char *fn) + { + int fd; + struct stat st; +- h2o_iovec_t ret = {NULL}; ++ h2o_iovec_t ret = H2O_IOVEC_NULL; + + /* open */ + if ((fd = open(fn, O_RDONLY | O_CLOEXEC)) == -1) +@@ -64,5 +63,5 @@ Error: + if (fd != -1) + close(fd); + free(ret.base); +- return (h2o_iovec_t){NULL}; ++ return (h2o_iovec_t)H2O_IOVEC_NULL; + } +diff --git a/lib/common/filecache.c b/lib/common/filecache.c +index 747a1ffa6..e37e1f498 100644 +--- a/lib/common/filecache.c ++++ b/lib/common/filecache.c +@@ -136,6 +136,24 @@ Exit: + return ref; + } + ++ssize_t h2o_filecache_read_file(h2o_filecache_ref_t *ref, void *buf, size_t count, off_t offset) ++{ ++ #ifdef _WIN32 ++ // h2o reads from h2o_filecache_ref_t.fd only with pread (comment it out to verify) ++ // this allows me to ignore the existence of the file pointer position maintained ++ // by Windows I/O manager and use NtReadFile() without opening extra file handles ++ /* ++ #include ++ IO_STATUS_BLOCK sb; ++ LARGE_INTEGER li; ++ NTSTATUS s = NtReadFile(_get_osfhandle(fd), NULL, NULL, NULL, &sb, buf, count, &li, NULL); ++ */ ++ return -1; ++ #else ++ return pread(ref->fd, buf, count, offset); ++ #endif ++} ++ + void h2o_filecache_close_file(h2o_filecache_ref_t *ref) + { + if (--ref->_refcnt != 0) +diff --git a/lib/common/http1client.c b/lib/common/http1client.c +index 8547ea817..a9de3d67d 100644 +--- a/lib/common/http1client.c ++++ b/lib/common/http1client.c +@@ -19,12 +19,18 @@ + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ ++#ifdef _WIN32 ++#include ++#else + #include + #include + #include + #include ++#endif + #include ++#ifndef H2O_NO_UNIX_SOCKETS + #include ++#endif + #include "picohttpparser.h" + #include "h2o.h" + +@@ -535,6 +541,7 @@ void h2o_http1client_connect(h2o_http1client_t **_client, void *data, h2o_http1c + return; + } + } ++ #ifndef _WIN32 + { /* directly call connect(2) if `host` refers to an UNIX-domain socket */ + struct sockaddr_un sa; + const char *to_sa_err; +@@ -547,6 +554,7 @@ void h2o_http1client_connect(h2o_http1client_t **_client, void *data, h2o_http1c + return; + } + } ++ #endif + /* resolve destination and then connect */ + client->_getaddr_req = + h2o_hostinfo_getaddr(ctx->getaddr_receiver, host, h2o_iovec_init(serv, sprintf(serv, "%u", (unsigned)port)), AF_UNSPEC, +diff --git a/lib/common/memory.c b/lib/common/memory.c +index ba9f2dba2..3a505d8ea 100644 +--- a/lib/common/memory.c ++++ b/lib/common/memory.c +@@ -27,7 +27,9 @@ + #include + #include + #include ++#ifndef _WIN32 + #include ++#endif + #include + #include "h2o/memory.h" + +@@ -190,20 +192,24 @@ void h2o_mem_link_shared(h2o_mem_pool_t *pool, void *p) + link_shared(pool, H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p)); + } + ++#ifndef _WIN32 + static size_t topagesize(size_t capacity) + { + size_t pagesize = getpagesize(); + return (offsetof(h2o_buffer_t, _buf) + capacity + pagesize - 1) / pagesize * pagesize; + } ++#endif + + void h2o_buffer__do_free(h2o_buffer_t *buffer) + { + /* caller should assert that the buffer is not part of the prototype */ + if (buffer->capacity == buffer->_prototype->_initial_buf.capacity) { + h2o_mem_free_recycle(&buffer->_prototype->allocator, buffer); ++ #ifndef _WIN32 + } else if (buffer->_fd != -1) { + close(buffer->_fd); + munmap((void *)buffer, topagesize(buffer->capacity)); ++ #endif + } else { + free(buffer); + } +@@ -240,6 +246,7 @@ h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **_inbuf, size_t min_guarantee) + do { + new_capacity *= 2; + } while (new_capacity - inbuf->size < min_guarantee); ++ #ifndef _WIN32 + if (inbuf->_prototype->mmap_settings != NULL && inbuf->_prototype->mmap_settings->threshold <= new_capacity) { + size_t new_allocsize = topagesize(new_capacity); + int fd; +@@ -287,7 +294,9 @@ h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **_inbuf, size_t min_guarantee) + inbuf->capacity = new_capacity; + inbuf->bytes = newp->_buf + offset; + } +- } else { ++ } else ++ #endif ++ { + h2o_buffer_t *newp = h2o_mem_alloc(offsetof(h2o_buffer_t, _buf) + new_capacity); + newp->size = inbuf->size; + newp->bytes = newp->_buf; +@@ -306,10 +315,12 @@ h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **_inbuf, size_t min_guarantee) + + return ret; + ++#ifndef _WIN32 + MapError: + ret.base = NULL; + ret.len = 0; + return ret; ++#endif + } + + void h2o_buffer_consume(h2o_buffer_t **_inbuf, size_t delta) +diff --git a/lib/common/multithread.c b/lib/common/multithread.c +index b4e8ba836..9a3dbe7d4 100644 +--- a/lib/common/multithread.c ++++ b/lib/common/multithread.c +@@ -22,7 +22,6 @@ + */ + #include + #include +-#include "cloexec.h" + #include "h2o/multithread.h" + + struct st_h2o_multithread_queue_t { +@@ -73,6 +72,7 @@ pthread_mutex_t h2o_conn_id_mutex = PTHREAD_MUTEX_INITIALIZER; + #if H2O_USE_LIBUV + #else + ++#include "cloexec.h" + #include + #include + #include +diff --git a/lib/common/serverutil.c b/lib/common/serverutil.c +index 8226f6efc..a599e7412 100644 +--- a/lib/common/serverutil.c ++++ b/lib/common/serverutil.c +@@ -21,26 +21,30 @@ + */ + #include + #include ++#ifndef _WIN32 + #include +-#include + #include +-#include + #include ++#include ++#if !defined(_SC_NPROCESSORS_ONLN) ++#include ++#endif ++#endif ++#include ++#include + #include + #include + #include + #include +-#include + #include +-#if !defined(_SC_NPROCESSORS_ONLN) +-#include +-#endif +-#include "cloexec.h" + #include "h2o/memory.h" + #include "h2o/serverutil.h" + #include "h2o/socket.h" + #include "h2o/string_.h" +- ++#if !H2O_USE_LIBUV ++#include "cloexec.h" ++#endif ++#if 0 + void h2o_set_signal_handler(int signo, void (*cb)(int signo)) + { + struct sigaction action; +@@ -137,6 +141,7 @@ static char **build_spawn_env(void) + return newenv; + } + ++#ifndef _WIN32 + pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int cloexec_mutex_is_locked) + { + #if defined(__linux__) +@@ -235,6 +240,7 @@ Error: + + #endif + } ++#endif + + int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status) + { +@@ -315,3 +321,4 @@ size_t h2o_numproc(void) + return 1; + #endif + } ++#endif +\ No newline at end of file +diff --git a/lib/common/socket.c b/lib/common/socket.c +index 5b1c37e04..86ebbd8b4 100644 +--- a/lib/common/socket.c ++++ b/lib/common/socket.c +@@ -23,11 +23,18 @@ + #include + #include + #include ++#ifdef _WIN32 ++#include ++#include ++#else + #include + #include + #include ++#endif + #include ++#ifndef H2O_NO_UNIX_SOCKETS + #include ++#endif + #include + #include + #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +@@ -861,12 +868,7 @@ int h2o_socket_compare_address(struct sockaddr *x, struct sockaddr *y) + + CMP(x->sa_family, y->sa_family); + +- if (x->sa_family == AF_UNIX) { +- struct sockaddr_un *xun = (void *)x, *yun = (void *)y; +- int r = strcmp(xun->sun_path, yun->sun_path); +- if (r != 0) +- return r; +- } else if (x->sa_family == AF_INET) { ++ if (x->sa_family == AF_INET) { + struct sockaddr_in *xin = (void *)x, *yin = (void *)y; + CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr)); + CMP(ntohs(xin->sin_port), ntohs(yin->sin_port)); +@@ -878,6 +880,13 @@ int h2o_socket_compare_address(struct sockaddr *x, struct sockaddr *y) + CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port)); + CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo); + CMP(xin6->sin6_scope_id, yin6->sin6_scope_id); ++ #ifndef H2O_NO_UNIX_SOCKETS ++ } else if (x->sa_family == AF_UNIX) { ++ struct sockaddr_un *xun = (void *)x, *yun = (void *)y; ++ int r = strcmp(xun->sun_path, yun->sun_path); ++ if (r != 0) ++ return r; ++ #endif + } else { + assert(!"unknown sa_family"); + } +@@ -1015,7 +1024,7 @@ static void on_handshake_complete(h2o_socket_t *sock, const char *err) + + static void proceed_handshake(h2o_socket_t *sock, const char *err) + { +- h2o_iovec_t first_input = {NULL}; ++ h2o_iovec_t first_input = H2O_IOVEC_NULL; + int ret = 0; + + sock->_cb.write = NULL; +diff --git a/lib/common/socketpool.c b/lib/common/socketpool.c +index da69933f7..730d3d22f 100644 +--- a/lib/common/socketpool.c ++++ b/lib/common/socketpool.c +@@ -21,12 +21,18 @@ + */ + #include + #include ++#ifdef _WIN32 ++#include ++#else + #include ++#include + #include + #include ++#endif + #include ++#ifndef H2O_NO_UNIX_SOCKETS + #include +-#include ++#endif + #include "h2o/hostinfo.h" + #include "h2o/linklist.h" + #include "h2o/socketpool.h" +@@ -110,11 +116,15 @@ void h2o_socketpool_init_by_address(h2o_socketpool_t *pool, struct sockaddr *sa, + assert(salen <= sizeof(pool->peer.sockaddr.bytes)); + + if ((host_len = h2o_socket_getnumerichost(sa, salen, host)) == SIZE_MAX) { ++ #ifndef H2O_NO_UNIX_SOCKETS + if (sa->sa_family != AF_UNIX) + h2o_fatal("failed to convert a non-unix socket address to a numerical representation"); + /* use the sockaddr_un::sun_path as the SNI indicator (is that the right thing to do?) */ + strcpy(host, ((struct sockaddr_un *)sa)->sun_path); + host_len = strlen(host); ++ #else ++ h2o_fatal("failed to convert a socket address to a numerical representation"); ++ #endif + } + + common_init(pool, H2O_SOCKETPOOL_TYPE_SOCKADDR, h2o_iovec_init(host, host_len), is_ssl, capacity); +diff --git a/lib/common/string.c b/lib/common/string.c +index 3c068f3ad..2c33624b7 100644 +--- a/lib/common/string.c ++++ b/lib/common/string.c +@@ -441,16 +441,21 @@ const char *h2o_next_token(h2o_iovec_t *iter, int separator, size_t *element_len + *iter = h2o_iovec_init(cur, end - cur); + *element_len = token_end - token_start; + if (value != NULL) +- *value = (h2o_iovec_t){NULL}; ++ *value = (h2o_iovec_t)H2O_IOVEC_NULL; + return token_start; + + FindValue: + *iter = h2o_iovec_init(cur, end - cur); + *element_len = token_end - token_start; +- if ((value->base = (char *)h2o_next_token(iter, separator, &value->len, NULL)) == NULL) { +- *value = (h2o_iovec_t){"", 0}; +- } else if (h2o_memis(value->base, value->len, H2O_STRLIT(","))) { +- *value = (h2o_iovec_t){"", 0}; ++ ++ size_t tmp; ++ if ((value->base = (char *)h2o_next_token(iter, separator, &tmp, NULL)) == NULL) { ++ *value = (h2o_iovec_t)H2O_IOVEC_EMPTY; ++ return token_start; ++ } ++ value->len = tmp; ++ if (h2o_memis(value->base, value->len, H2O_STRLIT(","))) { ++ *value = (h2o_iovec_t)H2O_IOVEC_EMPTY; + iter->base -= 1; + iter->len += 1; + } +@@ -499,7 +504,7 @@ h2o_iovec_t h2o_htmlescape(h2o_mem_pool_t *pool, const char *src, size_t len) + /* escape and return the result if necessary */ + if (add_size != 0) { + /* allocate buffer and fill in the chars that are known not to require escaping */ +- h2o_iovec_t escaped = {h2o_mem_alloc_pool(pool, len + add_size + 1), 0}; ++ h2o_iovec_t escaped = h2o_iovec_init(h2o_mem_alloc_pool(pool, len + add_size + 1), 0); + /* fill-in the rest */ + for (s = src; s != end; ++s) { + switch (*s) { +@@ -529,7 +534,7 @@ h2o_iovec_t h2o_htmlescape(h2o_mem_pool_t *pool, const char *src, size_t len) + + h2o_iovec_t h2o_concat_list(h2o_mem_pool_t *pool, h2o_iovec_t *list, size_t count) + { +- h2o_iovec_t ret = {NULL, 0}; ++ h2o_iovec_t ret = H2O_IOVEC_NULL; + size_t i; + + /* calc the length */ +diff --git a/lib/common/url.c b/lib/common/url.c +index d65d18fb5..9b9ec85bb 100644 +--- a/lib/common/url.c ++++ b/lib/common/url.c +@@ -19,15 +19,21 @@ + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ ++#ifdef _WIN32 ++#include ++#else + #include ++#endif + #include ++#ifndef H2O_NO_UNIX_SOCKETS + #include ++#endif + #include "h2o/memory.h" + #include "h2o/string_.h" + #include "h2o/url.h" + +-const h2o_url_scheme_t H2O_URL_SCHEME_HTTP = {{H2O_STRLIT("http")}, 80}; +-const h2o_url_scheme_t H2O_URL_SCHEME_HTTPS = {{H2O_STRLIT("https")}, 443}; ++const h2o_url_scheme_t H2O_URL_SCHEME_HTTP = {H2O_IOVEC_STRLIT("http"), 80}; ++const h2o_url_scheme_t H2O_URL_SCHEME_HTTPS = {H2O_IOVEC_STRLIT("https"), 443}; + + static int decode_hex(int ch) + { +@@ -277,8 +283,8 @@ int h2o_url_parse_relative(const char *url, size_t url_len, h2o_url_t *parsed) + return parse_authority_and_path(p + 2, url_end, parsed); + + /* reset authority, host, port, and set path */ +- parsed->authority = (h2o_iovec_t){NULL}; +- parsed->host = (h2o_iovec_t){NULL}; ++ parsed->authority = (h2o_iovec_t)H2O_IOVEC_NULL; ++ parsed->host = (h2o_iovec_t)H2O_IOVEC_NULL; + parsed->_port = 65535; + parsed->path = h2o_iovec_init(p, url_end - p); + +@@ -324,7 +330,7 @@ h2o_iovec_t h2o_url_resolve(h2o_mem_pool_t *pool, const h2o_url_t *base, const h + h2o_url_resolve_path(&base_path, &relative_path); + } else { + assert(relative->path.len == 0); +- relative_path = (h2o_iovec_t){NULL}; ++ relative_path = (h2o_iovec_t)H2O_IOVEC_NULL; + } + + Build: +@@ -388,6 +394,7 @@ void h2o_url_copy(h2o_mem_pool_t *pool, h2o_url_t *dest, const h2o_url_t *src) + dest->_port = src->_port; + } + ++#ifndef H2O_NO_UNIX_SOCKETS + const char *h2o_url_host_to_sun(h2o_iovec_t host, struct sockaddr_un *sa) + { + #define PREFIX "unix:" +@@ -407,3 +414,4 @@ const char *h2o_url_host_to_sun(h2o_iovec_t host, struct sockaddr_un *sa) + } + + const char *h2o_url_host_to_sun_err_is_not_unix_socket = "supplied name does not look like an unix-domain socket"; ++#endif +diff --git a/lib/core/config.c b/lib/core/config.c +index ce1d32018..267708723 100644 +--- a/lib/core/config.c ++++ b/lib/core/config.c +@@ -246,7 +246,7 @@ h2o_hostconf_t *h2o_config_register_host(h2o_globalconf_t *config, h2o_iovec_t h + /* create hostconf */ + hostconf = create_hostconf(config); + hostconf->authority.host = host_lc; +- host_lc = (h2o_iovec_t){NULL}; ++ host_lc = (h2o_iovec_t)H2O_IOVEC_NULL; + hostconf->authority.port = port; + if (hostconf->authority.port == 65535) { + hostconf->authority.hostport = hostconf->authority.host; +diff --git a/lib/core/context.c b/lib/core/context.c +index 8d1101381..f472adbe6 100644 +--- a/lib/core/context.c ++++ b/lib/core/context.c +@@ -23,7 +23,6 @@ + #include + #include + #include "h2o.h" +-#include "h2o/memcached.h" + + void h2o_context_init_pathconf_context(h2o_context_t *ctx, h2o_pathconf_t *pathconf) + { +@@ -194,7 +193,9 @@ void h2o_context_update_timestamp_cache(h2o_context_t *ctx) + if (ctx->_timestamp_cache.value != NULL) + h2o_mem_release_shared(ctx->_timestamp_cache.value); + ctx->_timestamp_cache.value = h2o_mem_alloc_shared(NULL, sizeof(h2o_timestamp_string_t), NULL); +- gmtime_r(&ctx->_timestamp_cache.tv_at.tv_sec, &gmt); ++ /* work around pointer type collision in MingW */ ++ time_t tmp = ctx->_timestamp_cache.tv_at.tv_sec; ++ gmtime_r(&tmp, &gmt); + h2o_time2str_rfc1123(ctx->_timestamp_cache.value->rfc1123, &gmt); + h2o_time2str_log(ctx->_timestamp_cache.value->log, ctx->_timestamp_cache.tv_at.tv_sec); + } +diff --git a/lib/core/logconf.c b/lib/core/logconf.c +index 4d79736cc..74c198ce7 100644 +--- a/lib/core/logconf.c ++++ b/lib/core/logconf.c +@@ -597,8 +597,11 @@ char *h2o_log_request(h2o_logconf_t *logconf, h2o_req_t *req, size_t *len, char + goto EmitNull; + { + size_t bufsz, len; +- if (localt.tm_year == 0) +- localtime_r(&req->processed_at.at.tv_sec, &localt); ++ if (localt.tm_year == 0) { ++ /* work around pointer type collision in MingW */ ++ time_t tmp = req->processed_at.at.tv_sec; ++ localtime_r(&tmp, &localt); ++ } + for (bufsz = 128;; bufsz *= 2) { + RESERVE(bufsz); + if ((len = strftime(pos, bufsz, element->data.name.base, &localt)) != 0) +diff --git a/lib/core/proxy.c b/lib/core/proxy.c +index edb4baf9d..448dc103d 100644 +--- a/lib/core/proxy.c ++++ b/lib/core/proxy.c +@@ -19,10 +19,14 @@ + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +-#include + #include + #include ++#ifdef _WIN32 ++#include ++#else ++#include + #include ++#endif + #include "picohttpparser.h" + #include "h2o.h" + #include "h2o/http1.h" +@@ -79,7 +83,7 @@ static h2o_iovec_t rewrite_location(h2o_mem_pool_t *pool, const char *location, + h2o_iovec_init(loc_parsed.path.base + match->path.len, loc_parsed.path.len - match->path.len)); + + NoRewrite: +- return (h2o_iovec_t){NULL}; ++ return (h2o_iovec_t)H2O_IOVEC_NULL; + } + + static h2o_iovec_t build_request_merge_headers(h2o_mem_pool_t *pool, h2o_iovec_t merged, h2o_iovec_t added, int seperator) +@@ -136,7 +140,7 @@ static h2o_iovec_t build_request(h2o_req_t *req, int keepalive, int is_websocket + char remote_addr[NI_MAXHOST]; + struct sockaddr_storage ss; + socklen_t sslen; +- h2o_iovec_t cookie_buf = {NULL}, xff_buf = {NULL}, via_buf = {NULL}; ++ h2o_iovec_t cookie_buf = H2O_IOVEC_NULL, xff_buf = H2O_IOVEC_NULL, via_buf = H2O_IOVEC_NULL; + int preserve_x_forwarded_proto = req->conn->ctx->globalconf->proxy.preserve_x_forwarded_proto; + int emit_x_forwarded_headers = req->conn->ctx->globalconf->proxy.emit_x_forwarded_headers; + int emit_via_header = req->conn->ctx->globalconf->proxy.emit_via_header; +@@ -202,7 +206,7 @@ static h2o_iovec_t build_request(h2o_req_t *req, int keepalive, int is_websocket + assert(offset <= buf.len); + if (req->entity.base != NULL || req_requires_content_length(req)) { + RESERVE(sizeof("content-length: " H2O_UINT64_LONGEST_STR) - 1); +- offset += sprintf(buf.base + offset, "content-length: %zu\r\n", req->entity.len); ++ offset += sprintf(buf.base + offset, "content-length: %zu\r\n", (size_t)req->entity.len); + } + + /* rewrite headers if necessary */ +diff --git a/lib/core/request.c b/lib/core/request.c +index 96aabb22d..65810ed91 100644 +--- a/lib/core/request.c ++++ b/lib/core/request.c +@@ -22,7 +22,9 @@ + #include + #include + #include ++#ifndef _WIN32 + #include ++#endif + #include "h2o.h" + + #ifndef IOV_MAX +@@ -595,10 +597,16 @@ void h2o_req_log_error(h2o_req_t *req, const char *module, const char *fmt, ...) + p += 3; + } + *p++ = ':'; ++ #ifdef _WIN32 ++ write(2, prefix, p - prefix); ++ write(2, errbuf, errlen); ++ write(2, "\n", 1); ++ #else + /* use writev(2) to emit error atomically */ + struct iovec vecs[] = {{prefix, p - prefix}, {errbuf, errlen}, {"\n", 1}}; + H2O_BUILD_ASSERT(sizeof(vecs) / sizeof(vecs[0]) < IOV_MAX); + writev(2, vecs, sizeof(vecs) / sizeof(vecs[0])); ++ #endif + } + } + +@@ -611,8 +619,8 @@ void h2o_send_redirect(h2o_req_t *req, int status, const char *reason, const cha + } + + static h2o_generator_t generator = {NULL, NULL}; +- static const h2o_iovec_t body_prefix = {H2O_STRLIT("Moved

The document has moved here")}; ++ static const h2o_iovec_t body_prefix = H2O_IOVEC_STRLIT("Moved

The document has moved here"); + + /* build and send response */ + h2o_iovec_t bufs[3]; +diff --git a/lib/core/token_table.h b/lib/core/token_table.h +index ae26aa6c4..fa74f1e08 100644 +--- a/lib/core/token_table.h ++++ b/lib/core/token_table.h +@@ -21,68 +21,68 @@ + */ + + /* DO NOT EDIT! generated by tokens.pl */ +-h2o_token_t h2o__tokens[] = {{{H2O_STRLIT(":authority")}, 1, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT(":method")}, 2, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT(":path")}, 4, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT(":scheme")}, 6, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT(":status")}, 8, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("accept")}, 19, 0, 0, 0, 0, 1, 0}, +- {{H2O_STRLIT("accept-charset")}, 15, 0, 0, 0, 0, 1, 0}, +- {{H2O_STRLIT("accept-encoding")}, 16, 0, 0, 0, 0, 1, 0}, +- {{H2O_STRLIT("accept-language")}, 17, 0, 0, 0, 0, 1, 0}, +- {{H2O_STRLIT("accept-ranges")}, 18, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("access-control-allow-origin")}, 20, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("age")}, 21, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("allow")}, 22, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("authorization")}, 23, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("cache-control")}, 24, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("cache-digest")}, 0, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("connection")}, 0, 1, 1, 0, 1, 0, 0}, +- {{H2O_STRLIT("content-disposition")}, 25, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("content-encoding")}, 26, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("content-language")}, 27, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("content-length")}, 28, 0, 0, 1, 0, 0, 0}, +- {{H2O_STRLIT("content-location")}, 29, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("content-range")}, 30, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("content-type")}, 31, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("cookie")}, 32, 0, 0, 0, 0, 0, 1}, +- {{H2O_STRLIT("date")}, 33, 0, 1, 0, 0, 0, 0}, +- {{H2O_STRLIT("etag")}, 34, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("expect")}, 35, 0, 0, 1, 0, 0, 0}, +- {{H2O_STRLIT("expires")}, 36, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("from")}, 37, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("host")}, 38, 0, 0, 1, 1, 0, 0}, +- {{H2O_STRLIT("http2-settings")}, 0, 1, 0, 0, 1, 0, 0}, +- {{H2O_STRLIT("if-match")}, 39, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("if-modified-since")}, 40, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("if-none-match")}, 41, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("if-range")}, 42, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("if-unmodified-since")}, 43, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("keep-alive")}, 0, 1, 1, 0, 0, 0, 0}, +- {{H2O_STRLIT("last-modified")}, 44, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("link")}, 45, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("location")}, 46, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("max-forwards")}, 47, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("proxy-authenticate")}, 48, 1, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("proxy-authorization")}, 49, 1, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("range")}, 50, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("referer")}, 51, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("refresh")}, 52, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("retry-after")}, 53, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("server")}, 54, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("set-cookie")}, 55, 0, 0, 0, 0, 0, 1}, +- {{H2O_STRLIT("strict-transport-security")}, 56, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("te")}, 0, 1, 0, 0, 1, 0, 0}, +- {{H2O_STRLIT("transfer-encoding")}, 57, 1, 1, 1, 1, 0, 0}, +- {{H2O_STRLIT("upgrade")}, 0, 1, 1, 1, 1, 0, 0}, +- {{H2O_STRLIT("user-agent")}, 58, 0, 0, 0, 0, 1, 0}, +- {{H2O_STRLIT("vary")}, 59, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("via")}, 60, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("www-authenticate")}, 61, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("x-compress-hint")}, 0, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("x-forwarded-for")}, 0, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("x-reproxy-url")}, 0, 0, 0, 0, 0, 0, 0}, +- {{H2O_STRLIT("x-traffic")}, 0, 0, 0, 0, 0, 0, 0}}; ++h2o_token_t h2o__tokens[] = {{H2O_IOVEC_STRLIT(":authority"), 1, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT(":method"), 2, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT(":path"), 4, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT(":scheme"), 6, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT(":status"), 8, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("accept"), 19, 0, 0, 0, 0, 1, 0}, ++ {H2O_IOVEC_STRLIT("accept-charset"), 15, 0, 0, 0, 0, 1, 0}, ++ {H2O_IOVEC_STRLIT("accept-encoding"), 16, 0, 0, 0, 0, 1, 0}, ++ {H2O_IOVEC_STRLIT("accept-language"), 17, 0, 0, 0, 0, 1, 0}, ++ {H2O_IOVEC_STRLIT("accept-ranges"), 18, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("access-control-allow-origin"), 20, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("age"), 21, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("allow"), 22, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("authorization"), 23, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("cache-control"), 24, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("cache-digest"), 0, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("connection"), 0, 1, 1, 0, 1, 0, 0}, ++ {H2O_IOVEC_STRLIT("content-disposition"), 25, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("content-encoding"), 26, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("content-language"), 27, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("content-length"), 28, 0, 0, 1, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("content-location"), 29, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("content-range"), 30, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("content-type"), 31, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("cookie"), 32, 0, 0, 0, 0, 0, 1}, ++ {H2O_IOVEC_STRLIT("date"), 33, 0, 1, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("etag"), 34, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("expect"), 35, 0, 0, 1, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("expires"), 36, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("from"), 37, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("host"), 38, 0, 0, 1, 1, 0, 0}, ++ {H2O_IOVEC_STRLIT("http2-settings"), 0, 1, 0, 0, 1, 0, 0}, ++ {H2O_IOVEC_STRLIT("if-match"), 39, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("if-modified-since"), 40, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("if-none-match"), 41, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("if-range"), 42, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("if-unmodified-since"), 43, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("keep-alive"), 0, 1, 1, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("last-modified"), 44, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("link"), 45, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("location"), 46, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("max-forwards"), 47, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("proxy-authenticate"), 48, 1, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("proxy-authorization"), 49, 1, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("range"), 50, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("referer"), 51, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("refresh"), 52, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("retry-after"), 53, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("server"), 54, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("set-cookie"), 55, 0, 0, 0, 0, 0, 1}, ++ {H2O_IOVEC_STRLIT("strict-transport-security"), 56, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("te"), 0, 1, 0, 0, 1, 0, 0}, ++ {H2O_IOVEC_STRLIT("transfer-encoding"), 57, 1, 1, 1, 1, 0, 0}, ++ {H2O_IOVEC_STRLIT("upgrade"), 0, 1, 1, 1, 1, 0, 0}, ++ {H2O_IOVEC_STRLIT("user-agent"), 58, 0, 0, 0, 0, 1, 0}, ++ {H2O_IOVEC_STRLIT("vary"), 59, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("via"), 60, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("www-authenticate"), 61, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("x-compress-hint"), 0, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("x-forwarded-for"), 0, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("x-reproxy-url"), 0, 0, 0, 0, 0, 0, 0}, ++ {H2O_IOVEC_STRLIT("x-traffic"), 0, 0, 0, 0, 0, 0, 0}}; + size_t h2o__num_tokens = 62; + + const h2o_token_t *h2o_lookup_token(const char *name, size_t len) +diff --git a/lib/core/util.c b/lib/core/util.c +index 50d2b2493..13c363ee1 100644 +--- a/lib/core/util.c ++++ b/lib/core/util.c +@@ -63,6 +63,7 @@ static void free_accept_data(struct st_h2o_accept_data_t *data) + free(data); + } + ++#ifndef H2O_NO_MEMCACHED + static struct { + h2o_memcached_context_t *memc; + unsigned expiration; +@@ -97,15 +98,18 @@ void h2o_accept_setup_async_ssl_resumption(h2o_memcached_context_t *memc, unsign + async_resumption_context.expiration = expiration; + h2o_socket_ssl_async_resumption_init(async_resumption_get, async_resumption_new); + } ++#endif + + void on_accept_timeout(h2o_timeout_entry_t *entry) + { + /* TODO log */ + struct st_h2o_accept_data_t *data = H2O_STRUCT_FROM_MEMBER(struct st_h2o_accept_data_t, timeout, entry); ++ #ifndef H2O_NO_MEMCACHED + if (data->async_resumption_get_req != NULL) { + h2o_memcached_cancel_get(async_resumption_context.memc, data->async_resumption_get_req); + data->async_resumption_get_req = NULL; + } ++ #endif + h2o_socket_t *sock = data->sock; + free_accept_data(data); + h2o_socket_close(sock); +@@ -158,7 +162,11 @@ static ssize_t parse_proxy_line(char *src, size_t len, struct sockaddr *sa, sock + + char *p = src, *end = p + len; + void *addr; ++ #if _WIN32 ++ u_short *port; ++ #else + in_port_t *port; ++ #endif + + /* "PROXY "*/ + EXPECT_CHAR('P'); +@@ -369,7 +377,7 @@ static void push_one_path(h2o_mem_pool_t *pool, h2o_iovec_vector_t *paths_to_pus + } + + /* check scheme and authority if given URL contains either of the two, or if base is specified */ +- h2o_url_t base = {input_scheme, input_authority, {NULL}, base_path, 65535}; ++ h2o_url_t base = {input_scheme, input_authority, H2O_IOVEC_NULL, base_path, 65535}; + if (base_scheme != NULL) { + base.scheme = base_scheme; + base.authority = *base_authority; +@@ -528,7 +536,7 @@ h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t pre + if (req->path.base[0] != '/' && next_unnormalized == 1) { + next_unnormalized = 0; + } +- parts[num_parts++] = (h2o_iovec_t){req->path.base + next_unnormalized, req->path.len - next_unnormalized}; ++ parts[num_parts++] = h2o_iovec_init(req->path.base + next_unnormalized, req->path.len - next_unnormalized); + } + } + +@@ -536,10 +544,7 @@ h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t pre + } + + /* h2-14 and h2-16 are kept for backwards compatibility, as they are often used */ +-#define ALPN_ENTRY(s) \ +- { \ +- H2O_STRLIT(s) \ +- } ++#define ALPN_ENTRY(s) H2O_IOVEC_STRLIT(s) + #define ALPN_PROTOCOLS_CORE ALPN_ENTRY("h2"), ALPN_ENTRY("h2-16"), ALPN_ENTRY("h2-14") + #define NPN_PROTOCOLS_CORE \ + "\x02" \ +@@ -549,10 +554,10 @@ h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t pre + "\x05" \ + "h2-14" + +-static const h2o_iovec_t http2_alpn_protocols[] = {ALPN_PROTOCOLS_CORE, {NULL}}; ++static const h2o_iovec_t http2_alpn_protocols[] = {ALPN_PROTOCOLS_CORE, H2O_IOVEC_NULL}; + const h2o_iovec_t *h2o_http2_alpn_protocols = http2_alpn_protocols; + +-static const h2o_iovec_t alpn_protocols[] = {ALPN_PROTOCOLS_CORE, {H2O_STRLIT("http/1.1")}, {NULL}}; ++static const h2o_iovec_t alpn_protocols[] = {ALPN_PROTOCOLS_CORE, H2O_IOVEC_STRLIT("http/1.1"), H2O_IOVEC_NULL}; + const h2o_iovec_t *h2o_alpn_protocols = alpn_protocols; + + const char *h2o_http2_npn_protocols = NPN_PROTOCOLS_CORE; +diff --git a/lib/handler/access_log.c b/lib/handler/access_log.c +index 4a7704174..d56c21add 100644 +--- a/lib/handler/access_log.c ++++ b/lib/handler/access_log.c +@@ -22,12 +22,16 @@ + #include + #include + #include ++#include ++#include ++#ifdef _WIN32 ++#include ++#else + #include + #include + #include +-#include +-#include + #include ++#endif + #include + #include "h2o.h" + #include "h2o/serverutil.h" +@@ -73,6 +77,7 @@ int h2o_access_log_open_log(const char *path) + { + int fd; + ++ #ifndef _WIN32 + if (path[0] == '|') { + int pipefds[2]; + pid_t pid; +@@ -96,7 +101,9 @@ int h2o_access_log_open_log(const char *path) + /* close the read side of the pipefds and return the write side */ + close(pipefds[0]); + fd = pipefds[1]; +- } else { ++ } else ++ #endif ++ { + if ((fd = open(path, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0644)) == -1) { + fprintf(stderr, "failed to open log file:%s:%s\n", path, strerror(errno)); + return -1; +diff --git a/lib/handler/configurator/headers_util.c b/lib/handler/configurator/headers_util.c +index c05b9b7c2..56e47842e 100644 +--- a/lib/handler/configurator/headers_util.c ++++ b/lib/handler/configurator/headers_util.c +@@ -87,7 +87,7 @@ static int on_config_header_unset(h2o_configurator_command_t *cmd, h2o_configura + h2o_configurator_errprintf(cmd, node, "invalid header name"); + return -1; + } +- if (add_cmd(cmd, node, H2O_HEADERS_CMD_UNSET, name, (h2o_iovec_t){NULL}, self->get_commands(self->child)) != 0) { ++ if (add_cmd(cmd, node, H2O_HEADERS_CMD_UNSET, name, (h2o_iovec_t)H2O_IOVEC_NULL, self->get_commands(self->child)) != 0) { + if (!h2o_iovec_is_token(name)) + free(name->base); + return -1; +diff --git a/lib/handler/file.c b/lib/handler/file.c +index 5d7c7a2a4..c0bc486ec 100644 +--- a/lib/handler/file.c ++++ b/lib/handler/file.c +@@ -128,7 +128,7 @@ static void do_proceed(h2o_generator_t *_self, h2o_req_t *req) + rlen = self->bytesleft; + if (rlen > MAX_BUF_SIZE) + rlen = MAX_BUF_SIZE; +- while ((rret = pread(self->file.ref->fd, self->buf, rlen, self->file.off)) == -1 && errno == EINTR) ++ while ((rret = h2o_filecache_read_file(self->file.ref, self->buf, rlen, self->file.off)) == -1 && errno == EINTR) + ; + if (rret == -1) { + h2o_send(req, NULL, 0, H2O_SEND_STATE_ERROR); +@@ -177,7 +177,7 @@ static void do_multirange_proceed(h2o_generator_t *_self, h2o_req_t *req) + rlen = self->bytesleft; + if (rlen + used_buf > MAX_BUF_SIZE) + rlen = MAX_BUF_SIZE - used_buf; +- while ((rret = pread(self->file.ref->fd, self->buf + used_buf, rlen, self->file.off)) == -1 && errno == EINTR) ++ while ((rret = h2o_filecache_read_file(self->file.ref, self->buf + used_buf, rlen, self->file.off)) == -1 && errno == EINTR) + ; + if (rret == -1) + goto Error; +@@ -213,7 +213,7 @@ static h2o_send_state_t do_pull(h2o_generator_t *_self, h2o_req_t *req, h2o_iove + + if (self->bytesleft < buf->len) + buf->len = self->bytesleft; +- while ((rret = pread(self->file.ref->fd, buf->base, buf->len, self->file.off)) == -1 && errno == EINTR) ++ while ((rret = h2o_filecache_read_file(self->file.ref, buf->base, buf->len, self->file.off)) == -1 && errno == EINTR) + ; + if (rret <= 0) { + buf->len = 0; +@@ -237,7 +237,7 @@ static struct st_h2o_sendfile_generator_t *create_generator(h2o_req_t *req, cons + { + struct st_h2o_sendfile_generator_t *self; + h2o_filecache_ref_t *fileref; +- h2o_iovec_t content_encoding = (h2o_iovec_t){NULL}; ++ h2o_iovec_t content_encoding = H2O_IOVEC_NULL; + unsigned gunzip = 0; + + *is_dir = 0; +diff --git a/lib/handler/proxy.c b/lib/handler/proxy.c +index 1d87225e1..7de3c4ec5 100644 +--- a/lib/handler/proxy.c ++++ b/lib/handler/proxy.c +@@ -19,7 +19,9 @@ + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ ++#ifndef H2O_NO_UNIX_SOCKETS + #include ++#endif + #include "h2o.h" + #include "h2o/socketpool.h" + +@@ -136,29 +138,37 @@ static void on_handler_dispose(h2o_handler_t *_self) + + void h2o_proxy_register_reverse_proxy(h2o_pathconf_t *pathconf, h2o_url_t *upstream, h2o_proxy_config_vars_t *config) + { +- struct sockaddr_un sa; ++ #ifndef H2O_NO_UNIX_SOCKETS + const char *to_sa_err; ++ #endif + struct rp_handler_t *self = (void *)h2o_create_handler(pathconf, sizeof(*self)); + self->super.on_context_init = on_context_init; + self->super.on_context_dispose = on_context_dispose; + self->super.dispose = on_handler_dispose; + self->super.on_req = on_req; +- to_sa_err = h2o_url_host_to_sun(upstream->host, &sa); + if (config->keepalive_timeout != 0) { + self->sockpool = h2o_mem_alloc(sizeof(*self->sockpool)); + int is_ssl = upstream->scheme == &H2O_URL_SCHEME_HTTPS; ++ #ifndef H2O_NO_UNIX_SOCKETS ++ struct sockaddr_un sa; ++ to_sa_err = h2o_url_host_to_sun(upstream->host, &sa); + if (to_sa_err == h2o_url_host_to_sun_err_is_not_unix_socket) { ++ #endif + h2o_socketpool_init_by_hostport(self->sockpool, upstream->host, h2o_url_get_port(upstream), is_ssl, + SIZE_MAX /* FIXME */); ++ #ifndef H2O_NO_UNIX_SOCKETS + } else { + assert(to_sa_err == NULL); + h2o_socketpool_init_by_address(self->sockpool, (void *)&sa, sizeof(sa), is_ssl, SIZE_MAX /* FIXME */); + } ++ #endif + } + h2o_url_copy(NULL, &self->upstream, upstream); ++ #ifndef H2O_NO_UNIX_SOCKETS + if (to_sa_err) { + h2o_strtolower(self->upstream.host.base, self->upstream.host.len); + } ++ #endif + self->config = *config; + if (self->config.ssl_ctx != NULL) + SSL_CTX_up_ref(self->config.ssl_ctx); +diff --git a/lib/handler/redirect.c b/lib/handler/redirect.c +index c8b9c5086..9eb5d4552 100644 +--- a/lib/handler/redirect.c ++++ b/lib/handler/redirect.c +@@ -68,7 +68,7 @@ static void redirect_internally(h2o_redirect_handler_t *self, h2o_req_t *req, h2 + break; + default: + method = h2o_iovec_init(H2O_STRLIT("GET")); +- req->entity = (h2o_iovec_t){NULL}; ++ req->entity = (h2o_iovec_t)H2O_IOVEC_NULL; + break; + } + +diff --git a/lib/handler/reproxy.c b/lib/handler/reproxy.c +index 369386d27..2639045c6 100644 +--- a/lib/handler/reproxy.c ++++ b/lib/handler/reproxy.c +@@ -47,7 +47,7 @@ static void on_setup_ostream(h2o_filter_t *self, h2o_req_t *req, h2o_ostream_t * + break; + default: + method = h2o_iovec_init(H2O_STRLIT("GET")); +- req->entity = (h2o_iovec_t){NULL}; ++ req->entity = (h2o_iovec_t)H2O_IOVEC_NULL; + break; + } + +diff --git a/lib/handler/status.c b/lib/handler/status.c +index 93befed3b..95f9ce823 100644 +--- a/lib/handler/status.c ++++ b/lib/handler/status.c +@@ -95,7 +95,7 @@ static void send_response(struct st_h2o_status_collector_t *collector) + h2o_iovec_t resp[nr_resp]; + + memset(resp, 0, sizeof(resp[0]) * nr_resp); +- resp[cur_resp++] = (h2o_iovec_t){H2O_STRLIT("{\n")}; ++ resp[cur_resp++] = h2o_iovec_init(H2O_STRLIT("{\n")); + + int coma_removed = 0; + for (i = 0; i < req->conn->ctx->globalconf->statuses.size; i++) { +@@ -110,7 +110,7 @@ static void send_response(struct st_h2o_status_collector_t *collector) + coma_removed = 1; + } + } +- resp[cur_resp++] = (h2o_iovec_t){H2O_STRLIT("\n}\n")}; ++ resp[cur_resp++] = h2o_iovec_init(H2O_STRLIT("\n}\n")); + + req->res.status = 200; + h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/plain; charset=utf-8")); +@@ -213,7 +213,7 @@ static int on_req(h2o_handler_t *_self, h2o_req_t *req) + } else if (h2o_memis(local_path.base, local_path.len, H2O_STRLIT("/json"))) { + int ret; + /* "/json" maps to the JSON API */ +- h2o_iovec_t status_list = {NULL, 0}; /* NULL means we'll show all statuses */ ++ h2o_iovec_t status_list = H2O_IOVEC_NULL; /* NULL means we'll show all statuses */ + if (req->query_at != SIZE_MAX && (req->path.len - req->query_at > 6)) { + if (h2o_memis(&req->path.base[req->query_at], 6, "?show=", 6)) { + status_list = h2o_iovec_init(&req->path.base[req->query_at + 6], req->path.len - req->query_at - 6); +diff --git a/lib/handler/status/durations.c b/lib/handler/status/durations.c +index f011107bf..0e45e3eed 100644 +--- a/lib/handler/status/durations.c ++++ b/lib/handler/status/durations.c +@@ -203,5 +203,5 @@ void h2o_duration_stats_register(h2o_globalconf_t *conf) + } + + h2o_status_handler_t durations_status_handler = { +- {H2O_STRLIT("durations")}, durations_status_init, durations_status_per_thread, durations_status_final, ++ H2O_IOVEC_STRLIT("durations"), durations_status_init, durations_status_per_thread, durations_status_final, + }; +diff --git a/lib/handler/status/events.c b/lib/handler/status/events.c +index e6ed0b7c6..64fb6546f 100644 +--- a/lib/handler/status/events.c ++++ b/lib/handler/status/events.c +@@ -108,5 +108,5 @@ static h2o_iovec_t events_status_final(void *priv, h2o_globalconf_t *gconf, h2o_ + } + + h2o_status_handler_t events_status_handler = { +- {H2O_STRLIT("events")}, events_status_init, events_status_per_thread, events_status_final, ++ H2O_IOVEC_STRLIT("events"), events_status_init, events_status_per_thread, events_status_final, + }; +diff --git a/lib/handler/status/requests.c b/lib/handler/status/requests.c +index 4854e4a1f..56c28c36c 100644 +--- a/lib/handler/status/requests.c ++++ b/lib/handler/status/requests.c +@@ -123,7 +123,7 @@ static void *requests_status_init(void) + /* log format compilation error is an internal logic flaw, therefore we need not send the details to the client */ + fprintf(stderr, "[lib/handler/status/requests.c] failed to compile log format: %s", errbuf); + +- rsc->req_data = (h2o_iovec_t){NULL}; ++ rsc->req_data = (h2o_iovec_t)H2O_IOVEC_NULL; + pthread_mutex_init(&rsc->mutex, NULL); + + return rsc; +@@ -131,7 +131,7 @@ static void *requests_status_init(void) + + static h2o_iovec_t requests_status_final(void *priv, h2o_globalconf_t *gconf, h2o_req_t *req) + { +- h2o_iovec_t ret = {NULL}; ++ h2o_iovec_t ret = H2O_IOVEC_NULL; + struct st_requests_status_ctx_t *rsc = priv; + + if (rsc->logconf != NULL) { +@@ -147,5 +147,5 @@ static h2o_iovec_t requests_status_final(void *priv, h2o_globalconf_t *gconf, h2 + } + + h2o_status_handler_t requests_status_handler = { +- {H2O_STRLIT("requests")}, requests_status_init, requests_status_per_thread, requests_status_final, ++ H2O_IOVEC_STRLIT("requests"), requests_status_init, requests_status_per_thread, requests_status_final, + }; +diff --git a/lib/http1.c b/lib/http1.c +index 98c4e55ab..b765b8aae 100644 +--- a/lib/http1.c ++++ b/lib/http1.c +@@ -323,7 +323,7 @@ static ssize_t fixup_request(struct st_h2o_http1_conn_t *conn, struct phr_header + h2o_iovec_t *expect) + { + ssize_t entity_header_index; +- h2o_iovec_t connection = {NULL, 0}, host = {NULL, 0}, upgrade = {NULL, 0}; ++ h2o_iovec_t connection = H2O_IOVEC_NULL, host = H2O_IOVEC_NULL, upgrade = H2O_IOVEC_NULL; + + expect->base = NULL; + expect->len = 0; +@@ -406,12 +406,12 @@ static void send_bad_request_on_complete(h2o_socket_t *sock, const char *err) + + static void send_bad_request(struct st_h2o_http1_conn_t *conn) + { +- const static h2o_iovec_t resp = {H2O_STRLIT("HTTP/1.1 400 Bad Request\r\n" ++ const static h2o_iovec_t resp = H2O_IOVEC_STRLIT("HTTP/1.1 400 Bad Request\r\n" + "Content-Type: text/plain; charset=utf-8\r\n" + "Connection: close\r\n" + "Content-Length: 11\r\n" + "\r\n" +- "Bad Request")}; ++ "Bad Request"); + + assert(conn->req.version == 0 && "request has not been parsed successfully"); + assert(conn->req.http1_is_persistent == 0); +@@ -421,7 +421,7 @@ static void send_bad_request(struct st_h2o_http1_conn_t *conn) + + static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) + { +- size_t inreqlen = conn->sock->input->size < H2O_MAX_REQLEN ? conn->sock->input->size : H2O_MAX_REQLEN; ++ size_t methodlen, pathlen, inreqlen = conn->sock->input->size < H2O_MAX_REQLEN ? conn->sock->input->size : H2O_MAX_REQLEN; + int reqlen, minor_version; + struct phr_header headers[H2O_MAX_HEADERS]; + size_t num_headers = H2O_MAX_HEADERS; +@@ -433,8 +433,10 @@ static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) + conn->req.timestamps.request_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); + + reqlen = phr_parse_request(conn->sock->input->bytes, inreqlen, (const char **)&conn->req.input.method.base, +- &conn->req.input.method.len, (const char **)&conn->req.input.path.base, &conn->req.input.path.len, ++ &methodlen, (const char **)&conn->req.input.path.base, &pathlen, + &minor_version, headers, &num_headers, conn->_prevreqlen); ++ conn->req.input.method.len = methodlen; ++ conn->req.input.path.len = pathlen; + conn->_prevreqlen = inreqlen; + + switch (reqlen) { +@@ -455,7 +457,7 @@ static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) + return; + } + if (expect.base != NULL) { +- static const h2o_iovec_t res = {H2O_STRLIT("HTTP/1.1 100 Continue\r\n\r\n")}; ++ static const h2o_iovec_t res = H2O_IOVEC_STRLIT("HTTP/1.1 100 Continue\r\n\r\n"); + h2o_socket_write(conn->sock, (void *)&res, 1, on_continue_sent); + /* processing of the incoming entity is postponed until the 100 response is sent */ + h2o_socket_read_stop(conn->sock); +@@ -477,7 +479,7 @@ static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) + /* upgrade to HTTP/2 if the request starts with: PRI * HTTP/2 */ + if (conn->super.ctx->globalconf->http1.upgrade_to_http2) { + /* should check up to the first octet that phr_parse_request returns an error */ +- static const h2o_iovec_t HTTP2_SIG = {H2O_STRLIT("PRI * HTTP/2")}; ++ static const h2o_iovec_t HTTP2_SIG = H2O_IOVEC_STRLIT("PRI * HTTP/2"); + if (conn->sock->input->size >= HTTP2_SIG.len && memcmp(conn->sock->input->bytes, HTTP2_SIG.base, HTTP2_SIG.len) == 0) { + h2o_accept_ctx_t accept_ctx = {conn->super.ctx, conn->super.hosts}; + h2o_socket_t *sock = conn->sock; +@@ -638,7 +640,7 @@ static size_t flatten_headers(char *buf, h2o_req_t *req, const char *connection) + * - https://www.igvita.com/2013/05/01/deploying-webp-via-accept-content-negotiation/ + */ + if (is_msie(req)) { +- static h2o_header_t cache_control_private = {&H2O_TOKEN_CACHE_CONTROL->buf, NULL, {H2O_STRLIT("private")}}; ++ static h2o_header_t cache_control_private = {&H2O_TOKEN_CACHE_CONTROL->buf, NULL, H2O_IOVEC_STRLIT("private")}; + header = &cache_control_private; + } + } +@@ -660,11 +662,11 @@ static size_t flatten_headers(char *buf, h2o_req_t *req, const char *connection) + + static void proceed_pull(struct st_h2o_http1_conn_t *conn, size_t nfilled) + { +- h2o_iovec_t buf = {conn->_ostr_final.pull.buf, nfilled}; ++ h2o_iovec_t buf = h2o_iovec_init(conn->_ostr_final.pull.buf, nfilled); + h2o_send_state_t send_state; + + if (buf.len < MAX_PULL_BUF_SZ) { +- h2o_iovec_t cbuf = {buf.base + buf.len, MAX_PULL_BUF_SZ - buf.len}; ++ h2o_iovec_t cbuf = h2o_iovec_init(buf.base + buf.len, MAX_PULL_BUF_SZ - buf.len); + send_state = h2o_pull(&conn->req, conn->_ostr_final.pull.cb, &cbuf); + if (send_state == H2O_SEND_STATE_ERROR) { + conn->req.http1_is_persistent = 0; +diff --git a/lib/http2/casper.c b/lib/http2/casper.c +index 56e00d71f..e5c9a0ed7 100644 +--- a/lib/http2/casper.c ++++ b/lib/http2/casper.c +@@ -56,7 +56,7 @@ h2o_http2_casper_t *h2o_http2_casper_create(unsigned capacity_bits, unsigned rem + memset(&casper->keys, 0, sizeof(casper->keys)); + casper->capacity_bits = capacity_bits; + casper->remainder_bits = remainder_bits; +- casper->cookie_cache = (h2o_iovec_t){NULL}; ++ casper->cookie_cache = (h2o_iovec_t)H2O_IOVEC_NULL; + + return casper; + } +@@ -89,7 +89,7 @@ int h2o_http2_casper_lookup(h2o_http2_casper_t *casper, const char *path, size_t + + /* we need to set a new value */ + free(casper->cookie_cache.base); +- casper->cookie_cache = (h2o_iovec_t){NULL}; ++ casper->cookie_cache = (h2o_iovec_t)H2O_IOVEC_NULL; + h2o_vector_reserve(NULL, &casper->keys, casper->keys.size + 1); + memmove(casper->keys.entries + i + 1, casper->keys.entries + i, (casper->keys.size - i) * sizeof(casper->keys.entries[0])); + ++casper->keys.size; +@@ -99,7 +99,7 @@ int h2o_http2_casper_lookup(h2o_http2_casper_t *casper, const char *path, size_t + + void h2o_http2_casper_consume_cookie(h2o_http2_casper_t *casper, const char *cookie, size_t cookie_len) + { +- h2o_iovec_t binary = {NULL}; ++ h2o_iovec_t binary = H2O_IOVEC_NULL; + uint64_t tiny_keys_buf[128], *keys = tiny_keys_buf; + + /* check the name of the cookie */ +@@ -177,7 +177,7 @@ h2o_iovec_t h2o_http2_casper_get_cookie(h2o_http2_casper_t *casper) + return casper->cookie_cache; + + if (casper->keys.size == 0) +- return (h2o_iovec_t){NULL}; ++ return (h2o_iovec_t)H2O_IOVEC_NULL; + + /* encode as binary */ + char tiny_bin_buf[128], *bin_buf = tiny_bin_buf; +diff --git a/lib/http2/connection.c b/lib/http2/connection.c +index 2f8cad620..c7ba5d6b2 100644 +--- a/lib/http2/connection.c ++++ b/lib/http2/connection.c +@@ -27,7 +27,7 @@ + #include "h2o/http2.h" + #include "h2o/http2_internal.h" + +-static const h2o_iovec_t CONNECTION_PREFACE = {H2O_STRLIT("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")}; ++static const h2o_iovec_t CONNECTION_PREFACE = H2O_IOVEC_STRLIT("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"); + + const h2o_http2_priority_t h2o_http2_default_priority = { + 0, /* exclusive */ +@@ -43,7 +43,7 @@ const h2o_http2_settings_t H2O_HTTP2_SETTINGS_HOST = { + 16384 /* max_frame_size */ + }; + +-static const h2o_iovec_t SETTINGS_HOST_BIN = {H2O_STRLIT("\x00\x00\x0c" /* frame size */ ++static const h2o_iovec_t SETTINGS_HOST_BIN = H2O_IOVEC_STRLIT("\x00\x00\x0c"/* frame size */ + "\x04" /* settings frame */ + "\x00" /* no flags */ + "\x00\x00\x00\x00" /* stream id */ +@@ -51,7 +51,7 @@ static const h2o_iovec_t SETTINGS_HOST_BIN = {H2O_STRLIT("\x00\x00\x0c" /* f + "\x00\x00\x00\x64" /* max_concurrent_streams = 100 */ + "\x00\x04" + "\x01\x00\x00\x00" /* initial_window_size = 16777216 */ +- )}; ++ ); + + static __thread h2o_buffer_prototype_t wbuf_buffer_prototype = {{16}, {H2O_HTTP2_DEFAULT_OUTBUF_SIZE}}; + +@@ -103,7 +103,7 @@ static void graceful_shutdown_resend_goaway(h2o_timeout_entry_t *entry) + for (node = ctx->http2._conns.next; node != &ctx->http2._conns; node = node->next) { + h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _conns, node); + if (conn->state < H2O_HTTP2_CONN_STATE_HALF_CLOSED) { +- enqueue_goaway(conn, H2O_HTTP2_ERROR_NONE, (h2o_iovec_t){NULL}); ++ enqueue_goaway(conn, H2O_HTTP2_ERROR_NONE, (h2o_iovec_t)H2O_IOVEC_NULL); + do_close_stragglers = 1; + } + } +@@ -135,7 +135,7 @@ static void initiate_graceful_shutdown(h2o_context_t *ctx) + h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _conns, node); + if (conn->state < H2O_HTTP2_CONN_STATE_HALF_CLOSED) { + h2o_http2_encode_goaway_frame(&conn->_write.buf, INT32_MAX, H2O_HTTP2_ERROR_NONE, +- (h2o_iovec_t){H2O_STRLIT("graceful shutdown")}); ++ (h2o_iovec_t)H2O_IOVEC_STRLIT("graceful shutdown")); + h2o_http2_conn_request_write(conn); + } + } +@@ -876,7 +876,7 @@ static int parse_input(h2o_http2_conn_t *conn) + } else if (ret < 0) { + if (ret != H2O_HTTP2_ERROR_PROTOCOL_CLOSE_IMMEDIATELY) { + enqueue_goaway(conn, (int)ret, +- err_desc != NULL ? (h2o_iovec_t){(char *)err_desc, strlen(err_desc)} : (h2o_iovec_t){NULL}); ++ err_desc != NULL ? h2o_iovec_init((char *)err_desc, strlen(err_desc)) : (h2o_iovec_t)H2O_IOVEC_NULL); + } + return close_connection(conn); + } +@@ -1046,7 +1046,7 @@ void do_emit_writereq(h2o_http2_conn_t *conn) + + if (conn->_write.buf->size != 0) { + /* write and wait for completion */ +- h2o_iovec_t buf = {conn->_write.buf->bytes, conn->_write.buf->size}; ++ h2o_iovec_t buf = h2o_iovec_init(conn->_write.buf->bytes, conn->_write.buf->size); + h2o_socket_write(conn->sock, &buf, 1, on_write_complete); + conn->_write.buf_in_flight = conn->_write.buf; + h2o_buffer_init(&conn->_write.buf, &wbuf_buffer_prototype); +@@ -1290,7 +1290,7 @@ static void push_path(h2o_req_t *src_req, const char *abspath, size_t abspath_le + h2o_http2_stream_prepare_for_request(conn, stream); + + /* setup request */ +- stream->req.input.method = (h2o_iovec_t){H2O_STRLIT("GET")}; ++ stream->req.input.method = (h2o_iovec_t)H2O_IOVEC_STRLIT("GET"); + stream->req.input.scheme = src_stream->req.input.scheme; + stream->req.input.authority = + h2o_strdup(&stream->req.pool, src_stream->req.input.authority.base, src_stream->req.input.authority.len); +diff --git a/lib/http2/hpack.c b/lib/http2/hpack.c +index 4adb15cd7..f4e4679e2 100644 +--- a/lib/http2/hpack.c ++++ b/lib/http2/hpack.c +@@ -902,7 +902,7 @@ void h2o_hpack_flatten_response(h2o_buffer_t **buf, h2o_hpack_header_table_t *he + if (server_name->len) { + dst = encode_header(header_table, dst, &H2O_TOKEN_SERVER->buf, server_name); + } +- h2o_iovec_t date_value = {ts->str->rfc1123, H2O_TIMESTR_RFC1123_LEN}; ++ h2o_iovec_t date_value = h2o_iovec_init(ts->str->rfc1123, H2O_TIMESTR_RFC1123_LEN); + dst = encode_header(header_table, dst, &H2O_TOKEN_DATE->buf, &date_value); + #endif + size_t i; +diff --git a/lib/http2/hpack_static_table.h b/lib/http2/hpack_static_table.h +index 4c1243103..fae748537 100644 +--- a/lib/http2/hpack_static_table.h ++++ b/lib/http2/hpack_static_table.h +@@ -23,65 +23,65 @@ + /* automatically generated by tokens.pl */ + + static const struct st_h2o_hpack_static_table_entry_t h2o_hpack_static_table[61] = { +- { H2O_TOKEN_AUTHORITY, { H2O_STRLIT("") } }, +- { H2O_TOKEN_METHOD, { H2O_STRLIT("GET") } }, +- { H2O_TOKEN_METHOD, { H2O_STRLIT("POST") } }, +- { H2O_TOKEN_PATH, { H2O_STRLIT("/") } }, +- { H2O_TOKEN_PATH, { H2O_STRLIT("/index.html") } }, +- { H2O_TOKEN_SCHEME, { H2O_STRLIT("http") } }, +- { H2O_TOKEN_SCHEME, { H2O_STRLIT("https") } }, +- { H2O_TOKEN_STATUS, { H2O_STRLIT("200") } }, +- { H2O_TOKEN_STATUS, { H2O_STRLIT("204") } }, +- { H2O_TOKEN_STATUS, { H2O_STRLIT("206") } }, +- { H2O_TOKEN_STATUS, { H2O_STRLIT("304") } }, +- { H2O_TOKEN_STATUS, { H2O_STRLIT("400") } }, +- { H2O_TOKEN_STATUS, { H2O_STRLIT("404") } }, +- { H2O_TOKEN_STATUS, { H2O_STRLIT("500") } }, +- { H2O_TOKEN_ACCEPT_CHARSET, { H2O_STRLIT("") } }, +- { H2O_TOKEN_ACCEPT_ENCODING, { H2O_STRLIT("gzip, deflate") } }, +- { H2O_TOKEN_ACCEPT_LANGUAGE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_ACCEPT_RANGES, { H2O_STRLIT("") } }, +- { H2O_TOKEN_ACCEPT, { H2O_STRLIT("") } }, +- { H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN, { H2O_STRLIT("") } }, +- { H2O_TOKEN_AGE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_ALLOW, { H2O_STRLIT("") } }, +- { H2O_TOKEN_AUTHORIZATION, { H2O_STRLIT("") } }, +- { H2O_TOKEN_CACHE_CONTROL, { H2O_STRLIT("") } }, +- { H2O_TOKEN_CONTENT_DISPOSITION, { H2O_STRLIT("") } }, +- { H2O_TOKEN_CONTENT_ENCODING, { H2O_STRLIT("") } }, +- { H2O_TOKEN_CONTENT_LANGUAGE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_CONTENT_LENGTH, { H2O_STRLIT("") } }, +- { H2O_TOKEN_CONTENT_LOCATION, { H2O_STRLIT("") } }, +- { H2O_TOKEN_CONTENT_RANGE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_CONTENT_TYPE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_COOKIE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_DATE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_ETAG, { H2O_STRLIT("") } }, +- { H2O_TOKEN_EXPECT, { H2O_STRLIT("") } }, +- { H2O_TOKEN_EXPIRES, { H2O_STRLIT("") } }, +- { H2O_TOKEN_FROM, { H2O_STRLIT("") } }, +- { H2O_TOKEN_HOST, { H2O_STRLIT("") } }, +- { H2O_TOKEN_IF_MATCH, { H2O_STRLIT("") } }, +- { H2O_TOKEN_IF_MODIFIED_SINCE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_IF_NONE_MATCH, { H2O_STRLIT("") } }, +- { H2O_TOKEN_IF_RANGE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_IF_UNMODIFIED_SINCE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_LAST_MODIFIED, { H2O_STRLIT("") } }, +- { H2O_TOKEN_LINK, { H2O_STRLIT("") } }, +- { H2O_TOKEN_LOCATION, { H2O_STRLIT("") } }, +- { H2O_TOKEN_MAX_FORWARDS, { H2O_STRLIT("") } }, +- { H2O_TOKEN_PROXY_AUTHENTICATE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_PROXY_AUTHORIZATION, { H2O_STRLIT("") } }, +- { H2O_TOKEN_RANGE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_REFERER, { H2O_STRLIT("") } }, +- { H2O_TOKEN_REFRESH, { H2O_STRLIT("") } }, +- { H2O_TOKEN_RETRY_AFTER, { H2O_STRLIT("") } }, +- { H2O_TOKEN_SERVER, { H2O_STRLIT("") } }, +- { H2O_TOKEN_SET_COOKIE, { H2O_STRLIT("") } }, +- { H2O_TOKEN_STRICT_TRANSPORT_SECURITY, { H2O_STRLIT("") } }, +- { H2O_TOKEN_TRANSFER_ENCODING, { H2O_STRLIT("") } }, +- { H2O_TOKEN_USER_AGENT, { H2O_STRLIT("") } }, +- { H2O_TOKEN_VARY, { H2O_STRLIT("") } }, +- { H2O_TOKEN_VIA, { H2O_STRLIT("") } }, +- { H2O_TOKEN_WWW_AUTHENTICATE, { H2O_STRLIT("") } } ++ { H2O_TOKEN_AUTHORITY, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_METHOD, H2O_IOVEC_STRLIT("GET") }, ++ { H2O_TOKEN_METHOD, H2O_IOVEC_STRLIT("POST") }, ++ { H2O_TOKEN_PATH, H2O_IOVEC_STRLIT("/") }, ++ { H2O_TOKEN_PATH, H2O_IOVEC_STRLIT("/index.html") }, ++ { H2O_TOKEN_SCHEME, H2O_IOVEC_STRLIT("http") }, ++ { H2O_TOKEN_SCHEME, H2O_IOVEC_STRLIT("https") }, ++ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("200") }, ++ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("204") }, ++ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("206") }, ++ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("304") }, ++ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("400") }, ++ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("404") }, ++ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("500") }, ++ { H2O_TOKEN_ACCEPT_CHARSET, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_ACCEPT_ENCODING, H2O_IOVEC_STRLIT("gzip, deflate") }, ++ { H2O_TOKEN_ACCEPT_LANGUAGE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_ACCEPT_RANGES, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_ACCEPT, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_AGE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_ALLOW, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_AUTHORIZATION, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_CACHE_CONTROL, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_CONTENT_DISPOSITION, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_CONTENT_ENCODING, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_CONTENT_LANGUAGE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_CONTENT_LENGTH, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_CONTENT_LOCATION, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_CONTENT_RANGE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_CONTENT_TYPE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_COOKIE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_DATE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_ETAG, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_EXPECT, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_EXPIRES, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_FROM, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_HOST, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_IF_MATCH, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_IF_MODIFIED_SINCE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_IF_NONE_MATCH, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_IF_RANGE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_IF_UNMODIFIED_SINCE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_LAST_MODIFIED, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_LINK, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_LOCATION, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_MAX_FORWARDS, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_PROXY_AUTHENTICATE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_PROXY_AUTHORIZATION, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_RANGE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_REFERER, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_REFRESH, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_RETRY_AFTER, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_SERVER, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_SET_COOKIE, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_STRICT_TRANSPORT_SECURITY, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_TRANSFER_ENCODING, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_USER_AGENT, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_VARY, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_VIA, H2O_IOVEC_STRLIT("") }, ++ { H2O_TOKEN_WWW_AUTHENTICATE, H2O_IOVEC_STRLIT("") } + }; +diff --git a/lib/http2/http2_debug_state.c b/lib/http2/http2_debug_state.c +index 3ef8de37f..e9245ddcd 100644 +--- a/lib/http2/http2_debug_state.c ++++ b/lib/http2/http2_debug_state.c +@@ -62,7 +62,7 @@ static const char *get_debug_state_string(h2o_http2_stream_t *stream) + return NULL; + } + +-__attribute__((format(printf, 3, 4))) static void append_chunk(h2o_mem_pool_t *pool, h2o_iovec_vector_t *chunks, const char *fmt, ++__attribute__((format(gnu_printf, 3, 4))) static void append_chunk(h2o_mem_pool_t *pool, h2o_iovec_vector_t *chunks, const char *fmt, + ...) + { + va_list args; +diff --git a/misc/tokens.pl b/misc/tokens.pl +index 1fcf173fa..1407f6681 100755 +--- a/misc/tokens.pl ++++ b/misc/tokens.pl +@@ -94,7 +94,7 @@ print $fh render_mt(<< 'EOT', \@tokens, LICENSE)->as_string; + /* DO NOT EDIT! generated by tokens.pl */ + h2o_token_t h2o__tokens[] = { + ? for my $i (0..$#$tokens) { +- { { H2O_STRLIT("[$i][0] ?>") }, [$i][$_] } (1..$#{$tokens->[$i]})) ?> } ++ { H2O_IOVEC_STRLIT("[$i][0] ?>"), [$i][$_] } (1..$#{$tokens->[$i]})) ?> } + ? } + }; + size_t h2o__num_tokens = ; +@@ -135,7 +135,7 @@ print $fh render_mt(<< 'EOT', \@hpack, LICENSE)->as_string; + + static const struct st_h2o_hpack_static_table_entry_t h2o_hpack_static_table[] = { + ? for my $i (0..$#$entries) { +- { [$i][0]) ?>, { H2O_STRLIT("[$i][1] || "" ?>") } } ++ { [$i][0]) ?>, H2O_IOVEC_STRLIT("[$i][1] || "" ?>") } + ? } + }; + EOT +diff --git a/src/main.c b/src/main.c +index af0867f29..7c801755d 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -43,7 +43,9 @@ + #include + #include + #include ++#ifndef H2O_NO_UNIX_SOCKETS + #include ++#endif + #include + #include + #include +@@ -886,6 +888,7 @@ Found: + return conf.server_starter.fds[i]; + } + ++#ifndef H2O_NO_UNIX_SOCKETS + static int open_unix_listener(h2o_configurator_command_t *cmd, yoml_t *node, struct sockaddr_un *sa) + { + struct stat st; +@@ -948,6 +951,7 @@ ErrorExit: + close(fd); + return -1; + } ++#endif + + static int open_tcp_listener(h2o_configurator_command_t *cmd, yoml_t *node, const char *hostname, const char *servname, int domain, + int type, int protocol, struct sockaddr *addr, socklen_t addrlen) +@@ -1067,6 +1071,7 @@ static int on_config_listen(h2o_configurator_command_t *cmd, h2o_configurator_co + return -1; + } + ++ #ifndef H2O_NO_UNIX_SOCKETS + if (strcmp(type, "unix") == 0) { + + /* unix socket */ +@@ -1110,7 +1115,9 @@ static int on_config_listen(h2o_configurator_command_t *cmd, h2o_configurator_co + if (listener->hosts != NULL && ctx->hostconf != NULL) + h2o_append_to_null_terminated_list((void *)&listener->hosts, ctx->hostconf); + +- } else if (strcmp(type, "tcp") == 0) { ++ } else ++ #endif ++ if (strcmp(type, "tcp") == 0) { + + /* TCP socket */ + struct addrinfo hints, *res, *ai; +@@ -1712,11 +1719,13 @@ static char **build_server_starter_argv(const char *h2o_cmd, const char *config_ + sprintf(newarg, "--port=%s:%s", host, serv); + } + } break; ++ #ifndef H2O_NO_UNIX_SOCKETS + case AF_UNIX: { + struct sockaddr_un *sa = (void *)&conf.listeners[i]->addr; + newarg = h2o_mem_alloc(sizeof("--path=") + strlen(sa->sun_path)); + sprintf(newarg, "--path=%s", sa->sun_path); + } break; ++ #endif + } + h2o_vector_reserve(NULL, &args, args.size + 1); + args.entries[args.size++] = newarg; diff --git a/pkg/urbit/compat/mingw/libscrypt.patch b/pkg/urbit/compat/mingw/libscrypt.patch new file mode 100644 index 0000000000..03e88629e8 --- /dev/null +++ b/pkg/urbit/compat/mingw/libscrypt.patch @@ -0,0 +1,17 @@ +diff --git a/Makefile b/Makefile +index 783c537..3156ee2 100644 +--- a/Makefile ++++ b/Makefile +@@ -12,10 +12,9 @@ LDFLAGS_EXTRA?=-Wl,-z,relro + + all: reference + +-OBJS= crypto_scrypt-nosse.o sha256.o crypto-mcf.o b64.o crypto-scrypt-saltgen.o crypto_scrypt-check.o crypto_scrypt-hash.o slowequals.o ++OBJS= crypto_scrypt-nosse.o sha256.o crypto-mcf.o b64.o slowequals.o + +-libscrypt.so.0: $(OBJS) +- $(CC) $(LDFLAGS) -shared -o libscrypt.so.0 $(OBJS) -lm -lc ++libscrypt.a: $(OBJS) + ar rcs libscrypt.a $(OBJS) + + reference: libscrypt.so.0 main.o crypto_scrypt-hexconvert.o diff --git a/pkg/urbit/compat/mingw/lmdb.patch b/pkg/urbit/compat/mingw/lmdb.patch new file mode 100644 index 0000000000..e023a71330 --- /dev/null +++ b/pkg/urbit/compat/mingw/lmdb.patch @@ -0,0 +1,74 @@ +diff --git a/mdb.c b/mdb.c +--- a/mdb.c ++++ b/mdb.c +@@ -1707,28 +1707,27 @@ static char *const mdb_errstr[] = { + "MDB_PROBLEM: Unexpected problem - txn should abort", + }; + +-char * +-mdb_strerror(int err) ++void ++mdb_logerror(FILE* f, int err, const char* fmt, ...) + { +-#ifdef _WIN32 +- /** HACK: pad 4KB on stack over the buf. Return system msgs in buf. +- * This works as long as no function between the call to mdb_strerror +- * and the actual use of the message uses more than 4K of stack. +- */ +-#define MSGSIZE 1024 +-#define PADSIZE 4096 +- char buf[MSGSIZE+PADSIZE], *ptr = buf; +-#endif ++ va_list ap; ++ va_start(ap, fmt); ++ vfprintf(f, fmt, ap); ++ va_end(ap); ++ + int i; + if (!err) +- return ("Successful return: 0"); ++ { ++ fprintf(stderr, ": %s\r\n", "Successful return: 0"); ++ return; ++ } + + if (err >= MDB_KEYEXIST && err <= MDB_LAST_ERRCODE) { + i = err - MDB_KEYEXIST; +- return mdb_errstr[i]; ++ fprintf(stderr, ": %s\r\n", mdb_errstr[i]); ++ return; + } + +-#ifdef _WIN32 + /* These are the C-runtime error codes we use. The comment indicates + * their numeric value, and the Win32 error they would correspond to + * if the error actually came from a Win32 API. A major mess, we should +@@ -1742,18 +1741,20 @@ mdb_strerror(int err) + case EBUSY: /* 16, CURRENT_DIRECTORY */ + case EINVAL: /* 22, BAD_COMMAND */ + case ENOSPC: /* 28, OUT_OF_PAPER */ +- return strerror(err); ++ fprintf(stderr, ": %s\r\n", strerror(err)); + default: + ; + } +- buf[0] = 0; +- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | ++ LPSTR ptr; ++ if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | ++ FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS, +- NULL, err, 0, ptr, MSGSIZE, (va_list *)buf+MSGSIZE); +- return ptr; +-#else +- return strerror(err); +-#endif ++ NULL, err, 0, (LPSTR)&ptr, sizeof (LPSTR), NULL)) ++ { ++ fprintf(stderr, ": %s\r\n", ptr); ++ LocalFree(ptr); ++ } else ++ fprintf(stderr, ": <%d>\r\n", err); + } + + /** assert(3) variant in cursor context */ diff --git a/pkg/urbit/compat/mingw/mman.h b/pkg/urbit/compat/mingw/mman.h new file mode 100644 index 0000000000..965fecfd8c --- /dev/null +++ b/pkg/urbit/compat/mingw/mman.h @@ -0,0 +1,26 @@ +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); +int munmap(void *addr, size_t length); +int msync(void *addr, size_t length, int flags); +int mprotect(void *addr, size_t len, int prot); + +#define PROT_NONE 0x00 /* No access. */ +#define PROT_READ 0x01 /* Pages can be read. */ +#define PROT_WRITE 0x02 /* Pages can be written. */ +#define PROT_EXEC 0x04 /* Pages can be executed. */ + +#define MAP_FILE 0x0001 /* Mapped from a file or device. */ +#define MAP_ANON 0x0002 /* Allocated from anonymous virtual memory. */ +#define MAP_TYPE 0x000f /* Mask for type field. */ +#define MAP_SHARED 0x0010 /* Share changes. */ +#define MAP_PRIVATE 0x0000 /* Changes private; copy pages on write. */ +#define MAP_FIXED 0x0100 /* Map address must be exactly as requested. */ +#define MAP_FAILED ((void *) -1) + +#define MS_ASYNC 1 /* Sync memory asynchronously. */ +#define MS_SYNC 0 /* Synchronous memory sync. */ +#define MS_INVALIDATE 2 /* Invalidate the caches. */ + +#endif//_SYS_MMAN_H diff --git a/pkg/urbit/compat/mingw/murmur3.patch b/pkg/urbit/compat/mingw/murmur3.patch new file mode 100644 index 0000000000..cd83e9fdda --- /dev/null +++ b/pkg/urbit/compat/mingw/murmur3.patch @@ -0,0 +1,13 @@ +diff --git a/makefile b/makefile +--- a/makefile ++++ b/makefile +@@ -12,5 +12,9 @@ shared: murmur3.c murmur3.h + $(CC) -fPIC -O3 -c murmur3.c + $(CC) -shared -Wl,--export-dynamic murmur3.o -o libmurmur3.so + ++static: murmur3.c murmur3.h ++ $(CC) -fPIC -O3 -c murmur3.c ++ $(AR) rcs libmurmur3.a murmur3.o ++ + clean: + rm -rf example *.o *.so diff --git a/pkg/urbit/compat/mingw/ptty.c b/pkg/urbit/compat/mingw/ptty.c new file mode 100644 index 0000000000..063db564c5 --- /dev/null +++ b/pkg/urbit/compat/mingw/ptty.c @@ -0,0 +1,152 @@ +/* compat/mingw/ptty.c +** +*/ +#include "all.h" +#include "vere/vere.h" +#include + +/* _ptty_get_type(): detects tty type. +*/ +static DWORD +_ptty_get_type(int fd) +{ + HANDLE h = (HANDLE)_get_osfhandle(fd); + if (h == INVALID_HANDLE_VALUE) + return FILE_TYPE_UNKNOWN; + + DWORD t = GetFileType(h); + if (t != FILE_TYPE_PIPE) + return t ; + + // https://github.com/fusesource/jansi-native/commit/461068c67a38647d2890e96250636fc0117074f5 + ULONG result; + BYTE buffer[1024]; + POBJECT_NAME_INFORMATION nameinfo = (POBJECT_NAME_INFORMATION) buffer; + PWSTR name; + + /* get pipe name */ + if (!NT_SUCCESS(NtQueryObject(h, ObjectNameInformation, buffer, sizeof(buffer) - sizeof(WCHAR), &result))) + return FILE_TYPE_UNKNOWN; + + name = nameinfo->Name.Buffer; + name[nameinfo->Name.Length] = 0; + + // check for popular terminal emulators + // that use named pipes to communicate with subprocesses + if (wcsstr(name, L"\\ConEmu") || + (wcsstr(name, L"msys-") || wcsstr(name, L"cygwin-")) && wcsstr(name, L"-pty")) + return FILE_TYPE_PIPE; + + return FILE_TYPE_UNKNOWN; +} + +/* _ttyf_nop(): stub function. +*/ +static c3_o +_ttyf_nop(u3_utty* uty_u) +{ + return c3y; +} + +/* _ttyf_start_raw_input(): ends raw input on the tty. +*/ +static c3_o +_ttyf_set_normal(u3_utty* uty_u) +{ + c3_i e; + if ( 0 != (e = uv_tty_set_mode(&uty_u->pin_u.tty_u, UV_TTY_MODE_NORMAL)) ) { + fprintf(stderr, "uv_tty_set_mode(UV_TTY_MODE_NORMAL) -> %d\r\n", e); + return c3n; + } + return c3y; +} + +/* _ttyf_start_raw_input(): sets the tty to raw input. +*/ +static c3_o +_ttyf_set_raw(u3_utty* uty_u) +{ + c3_i e; + if ( 0 != (e = uv_tty_set_mode(&uty_u->pin_u.tty_u, UV_TTY_MODE_RAW)) ) { + fprintf(stderr, "uv_tty_set_mode(UV_TTY_MODE_RAW) -> %d\r\n", e); + return c3n; + } + return c3y; +} + +/* _ttyf_get_winsize(): gets the tty window size. +*/ +static c3_o +_ttyf_get_winsize(u3_utty* uty_u, c3_l* col_l, c3_l* row_l) +{ + c3_i col_i, row_i; + if ( 0 != uv_tty_get_winsize(&uty_u->pop_u.tty_u, &col_i, &row_i) ) { + return c3n; + } + + *col_l = col_i; + *row_l = row_i; + return c3y; +} + +/* _ttyf_get_winsize(): gets the tty window size. +*/ +static c3_o +_ttyf_nop_winsize(u3_utty* uty_u, c3_l* col_l, c3_l* row_l) +{ + return c3n; +} + +/* u3_ptty_init(): initialize platform-specific tty. +*/ +u3_utty* +u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c) +{ + DWORD pip_l = _ptty_get_type(0); + DWORD pop_l = _ptty_get_type(1); + if ( pip_l == FILE_TYPE_UNKNOWN || pop_l == FILE_TYPE_UNKNOWN) { + *err_c = "not a tty"; + return NULL; + } + + if ( pip_l != pop_l ) { + *err_c = "partly redirected"; + return NULL; + } + + c3_i e; + u3_utty* uty_u = c3_calloc(sizeof(u3_utty)); + if ( pip_l == FILE_TYPE_CHAR ) { + if ( 0 == (e = uv_tty_init(lup_u, &uty_u->pin_u.tty_u, 0, 0)) && + 0 == (e = uv_tty_init(lup_u, &uty_u->pop_u.tty_u, 1, 0)) ) + { + SetConsoleOutputCP(CP_UTF8); + uty_u->sta_f = _ttyf_set_raw; + uty_u->sto_f = _ttyf_set_normal; + uty_u->wsz_f = _ttyf_get_winsize; + } + } else { + if ( 0 == (e = uv_pipe_init(lup_u, &uty_u->pin_u.pop_u, 0)) && + 0 == (e = uv_pipe_init(lup_u, &uty_u->pop_u.pop_u, 0)) && + 0 == (e = uv_pipe_open(&uty_u->pin_u.pop_u, 0)) && + 0 == (e = uv_pipe_open(&uty_u->pop_u.pop_u, 1)) ) + { + fprintf(stderr, "vere: running interactive in a terminal emulator is experimental\r\n" + " use -t to disable interactivity or use native Windows console\r\n") ; + uty_u->sta_f = _ttyf_nop; + uty_u->sto_f = _ttyf_nop; + uty_u->wsz_f = _ttyf_nop_winsize; + } + } + + if ( e ) { + *err_c = uv_strerror(e); + c3_free(uty_u); + return NULL; + } + + uty_u->fid_i = 1; + uty_u->hij_f = _ttyf_nop; + uty_u->loj_f = _ttyf_nop; + return uty_u; +} diff --git a/pkg/urbit/compat/mingw/rsignal.c b/pkg/urbit/compat/mingw/rsignal.c new file mode 100644 index 0000000000..b49dff5153 --- /dev/null +++ b/pkg/urbit/compat/mingw/rsignal.c @@ -0,0 +1,167 @@ +#include "all.h" +#include "rsignal.h" +#include + +int err_win_to_posix(DWORD winerr); + +// The current implementation of rsignal_ is single-threaded, +// but it can be extended to multi-threaded by replacing these +// static variables with a thread id-based hash map. +// +static __p_sig_fn_t _fns[SIG_COUNT]; +static volatile DWORD _tid; +static HANDLE _hvt; + +void rsignal_install_handler(int sig, __p_sig_fn_t fn) +{ + if (sig < 0 || sig >= SIG_COUNT) + return; + + DWORD newtid = GetCurrentThreadId(); + DWORD oldtid = InterlockedExchange(&_tid, newtid); + if (oldtid != 0 && oldtid != newtid) { + fprintf(stderr, "\r\nrsignal_install_handler: %u -> %u\r\n", oldtid, newtid); + return; + } + + __p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], fn); + if (fn != 0 && oldfn != 0 && oldfn != fn) { + fprintf(stderr, "\r\nrsignal_install_handler: %p -> %p\r\n", oldfn, fn); + } +} + +void rsignal_deinstall_handler(int sig) +{ + rsignal_install_handler(sig, 0); +} + +void rsignal_raise(int sig) +{ + if (sig < 0 || sig >= SIG_COUNT) + return; + + __p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], 0); + if (oldfn == 0) + return; + + if (_tid == GetCurrentThreadId()) { + oldfn(sig); + return; + } + + HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, _tid); + if (!hthread) { + fprintf(stderr, "\r\nrsignal_raise: OpenThread(%u): %d\r\n", _tid, GetLastError()); + return; + } + + if (SuspendThread(hthread) < 0) { + fprintf(stderr, "\r\nrsignal_raise: SuspendThread(%u): %d\r\n", _tid, GetLastError()); + goto cleanup; + } + + oldfn(sig); + + if (!ResumeThread(hthread)) { + fprintf(stderr, "\r\nrsignal_raise: ResumeThread(%u): %d\r\n", _tid, GetLastError()); + + // abort because the main thread is stuck + abort(); + } + +cleanup: + CloseHandle(hthread); +} + +static void _rsignal_vt_cb(PVOID param, BOOLEAN timedOut) +{ + rsignal_raise(SIGVTALRM); +} + +int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out) +{ + if (in == 0) { + errno = EFAULT; + return -1; + } + + if (type != ITIMER_VIRTUAL || out != 0) { + errno = ENOTSUP; + return -1; + } + + if (_hvt != NULL) { + DeleteTimerQueueTimer(NULL, _hvt, NULL); + _hvt = NULL; + } + + if (timerisset(&in->it_value) && !CreateTimerQueueTimer(&_hvt, NULL, _rsignal_vt_cb, NULL, + in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000, + in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000, 0)) + { + errno = err_win_to_posix(GetLastError()); + return -1; + } else { + return 0; + } +} + +// direct import from ntdll.dll +extern DWORD64 __imp_KiUserExceptionDispatcher; + +static void _rsignal_longjmp(intptr_t* builtin_jb) +{ + __builtin_longjmp(builtin_jb, 1); +} + +void rsignal_post_longjmp(DWORD tid, intptr_t* builtin_jb) +{ + HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid); + if (!hthread) { + fprintf(stderr, "\r\nrsignal: OpenThread(%u): %d\r\n", tid, GetLastError()); + return; + } + + CONTEXT context; + context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + if (!GetThreadContext(hthread, &context)) { + fprintf(stderr, "\r\nrsignal: GetThreadContext(%u): %d\r\n", tid, GetLastError()); + goto cleanup; + } + + // see if the thread is currently handling a structured exception + // if so, let the handler (usually the libsigsegv handler) finish + // and set up the the signal to run at the exception resume point + // otherwise, passing a parameter to fn is completely unreliable + // + DWORD64 kibase; + PRUNTIME_FUNCTION ki = RtlLookupFunctionEntry(__imp_KiUserExceptionDispatcher, &kibase, NULL); + CONTEXT c = context; + while (1) + { + DWORD64 base, frame; + PRUNTIME_FUNCTION f = RtlLookupFunctionEntry(c.Rip, &base, NULL); + if (!f) break; + if (f == ki) + { + // KiUserExceptionDispatcher has a "bare" frame + // with $rsp pointing to the CONTEXT structure + // + ((PCONTEXT)c.Rsp)->Rip = (DWORD64)_rsignal_longjmp; + ((PCONTEXT)c.Rsp)->Rcx = (DWORD64)builtin_jb; + goto cleanup; + } + PVOID handler_data; + RtlVirtualUnwind(0, base, c.Rip, f, &c, &handler_data, &frame, NULL); + } + + context.Rip = (DWORD64)_rsignal_longjmp; + context.Rcx = (DWORD64)builtin_jb; + if (!SetThreadContext(hthread, &context)) { + fprintf(stderr, "\r\nrsignal: SetThreadContext(%u): %d\r\n", tid, GetLastError()); + goto cleanup; + } + +cleanup: + CloseHandle(hthread); +} diff --git a/pkg/urbit/compat/mingw/rsignal.h b/pkg/urbit/compat/mingw/rsignal.h new file mode 100644 index 0000000000..5af8e2dcd7 --- /dev/null +++ b/pkg/urbit/compat/mingw/rsignal.h @@ -0,0 +1,24 @@ +#ifndef _RSIGNAL_H +#define _RSIGNAL_H + +typedef struct { + jmp_buf jb; + unsigned long tid; +} rsignal_jmpbuf; + +#define rsignal_setjmp(buf) (buf.tid = GetCurrentThreadId(), setjmp(buf.jb)) +#define rsignal_longjmp(buf, val) if (buf.tid != GetCurrentThreadId()) {buf.jb.retval = (val); rsignal_post_longjmp(buf.tid, buf.jb.buffer);} else longjmp(buf.jb, val) + +void rsignal_raise(int sig); +void rsignal_install_handler(int sig, __p_sig_fn_t fn); +void rsignal_deinstall_handler(int sig); +void rsignal_post_longjmp(unsigned long tid, intptr_t* builtin_jb); + +#define ITIMER_VIRTUAL 1 +struct itimerval { + struct timeval it_value, it_interval; +}; + +int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out); + +#endif//_RSIGNAL_H diff --git a/pkg/urbit/compat/mingw/seh_handler.c b/pkg/urbit/compat/mingw/seh_handler.c new file mode 100644 index 0000000000..ecf59f0a40 --- /dev/null +++ b/pkg/urbit/compat/mingw/seh_handler.c @@ -0,0 +1,25 @@ +#include "all.h" +#include "rsignal.h" +#include "vere/vere.h" + +/* _mingw_exception_filter: replaces libsigsegv on MingW +*/ +EXCEPTION_DISPOSITION _mingw_exception_filter( + IN PEXCEPTION_RECORD ExceptionRecord, + IN ULONG64 EstablisherFrame, + IN OUT PCONTEXT ContextRecord, + IN OUT PDISPATCHER_CONTEXT DispatcherContext) +{ + if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && + ExceptionRecord->ExceptionInformation[0] == 1 && + u3e_fault((void*)ExceptionRecord->ExceptionInformation[1], 1)) + { + return ExceptionContinueExecution; + } + + if (ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { + rsignal_raise(SIGSTK); + } + + return ExceptionContinueSearch; +} diff --git a/pkg/urbit/compat/mingw/seh_handler_decorator.cc b/pkg/urbit/compat/mingw/seh_handler_decorator.cc new file mode 100644 index 0000000000..acc97efcc3 --- /dev/null +++ b/pkg/urbit/compat/mingw/seh_handler_decorator.cc @@ -0,0 +1,65 @@ +#include +#include + +enum { INIT, CPAR, DQ, DQS, SQ, SQS }; +char line[1 << 16]; + +/* seh_handler_decorator: registers u3_exception_handler for all functions in given source file +*/ +int main(int argc, const char* argv[]) +{ + if (argc != 2) + return 1; + + int c, state = INIT, curly = 0, emit = 0; + + while (fgets(line, sizeof(line), stdin)) + { + if (line[0] == '#') + { + emit = !!strstr(line, argv[1]); + fputs(line, stdout); + } + else + for (int i = 0; line[i]; i++) + { + switch (state) { + case INIT: + case CPAR: + switch (line[i]) { + case ' ': + case '\t': + case '\n': + case '\r': + case '\f': break; + case '{': curly++; if (emit && curly == 1 && state == CPAR) goto emit_handler; goto reset; + case '}': curly--; goto reset; + case '"': state = DQ; break; + case '\'': state = SQ; break; + case ')': state = CPAR; break; + reset: + default: state = INIT; break; + } break; + case DQ: + switch (line[i]) { + case '\\': state = DQS; break; + case '"': state = INIT; break; + } break; + case DQS: state = DQ; break; + case SQ: + switch (line[i]) { + case '\\': state = SQS; break; + case '\'': state = INIT; break; + } break; + case SQS: state = SQ; break; + } + fputc(line[i], stdout); + continue; + emit_handler: + fputs("{__asm__(\".seh_handler _mingw_exception_filter,@except\\n\");", stdout); + state = INIT; + } + } + + return 0; +} diff --git a/pkg/urbit/compat/mingw/seh_handler_decorator.mk b/pkg/urbit/compat/mingw/seh_handler_decorator.mk new file mode 100644 index 0000000000..aa2a4c37de --- /dev/null +++ b/pkg/urbit/compat/mingw/seh_handler_decorator.mk @@ -0,0 +1,24 @@ +# This include file injects a step that transforms vere C source to register +# a SEH exception handler for each function that is declared in a .c file. +# It inserts a .seh_handler directive into each function body with __asm__. +# This directive affects the x64 unwind tables (.pdata and .xdata sections) +# emitted by the compiler. +# +# See gas/config/obj-coff-seh.h in binutils source for .seh_handler, and +# https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64 +# for a description of how stack unwinding and SEH work in x64 Windows. +# +# When this file sets CCEXTRA, the first invocation of $(CC) in Makefile +# writes preprocessor output to stdout (-E -o -), which is piped to a simple +# parser that inserts __asm__ statements to each function in the .c file +# being compiled. The second invocation of $(CC) reads transformed source +# from stdin (-x cpp-output -). $< argument to $(sehdexe) tells the parser +# which .c file is being compiled. + +sehdexe := build/seh_handler_decorator.exe +CCDEPS := $(CCDEPS) $(sehdexe) +CCEXTRA = -E -o -|$(sehdexe) $<|$(CC) $(CFLAGS) -x cpp-output - + +$(sehdexe): compat/mingw/seh_handler_decorator.cc + @mkdir -p ./build + @$(CC) $< -o $@ diff --git a/pkg/urbit/compat/mingw/setjmp.h b/pkg/urbit/compat/mingw/setjmp.h new file mode 100644 index 0000000000..497636872d --- /dev/null +++ b/pkg/urbit/compat/mingw/setjmp.h @@ -0,0 +1,15 @@ +#ifndef _MINGW_SETJMP_H +#define _MINGW_SETJMP_H + +// msvcrt setjmp/longjmp are broken on 64-bit systems, use gcc builtins +typedef struct jmp_buf { + intptr_t buffer[5]; + int retval; +} jmp_buf; + +#define _setjmp setjmp +#define _longjmp longjmp +#define longjmp(buf, val) {buf.retval = (val); __builtin_longjmp(buf.buffer, 1);} +#define setjmp(buf) (__builtin_setjmp(buf.buffer) ? (buf.retval) : 0) + +#endif//_MINGW_SETJMP_H diff --git a/pkg/urbit/compat/mingw/softfloat3.patch b/pkg/urbit/compat/mingw/softfloat3.patch new file mode 100644 index 0000000000..9f0c5c5e7b --- /dev/null +++ b/pkg/urbit/compat/mingw/softfloat3.patch @@ -0,0 +1,36 @@ +diff --git a/build/Win64-MinGW-w64/Makefile b/build/Win64-MinGW-w64/Makefile +--- a/build/Win64-MinGW-w64/Makefile ++++ b/build/Win64-MinGW-w64/Makefile +@@ -46,7 +46,8 @@ C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include + COMPILE_C = \ + x86_64-w64-mingw32-gcc -c -Werror-implicit-function-declaration \ + -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@ +-MAKELIB = x86_64-w64-mingw32-ar crs $@ ++MAKELIB = x86_64-w64-mingw32-gcc-ar crs $@ ++LIBNAME = libsoftfloat3 + + OBJ = .o + LIB = .a +@@ -54,7 +55,7 @@ LIB = .a + OTHER_HEADERS = $(SOURCE_DIR)/include/opts-GCC.h + + .PHONY: all +-all: softfloat$(LIB) ++all: $(LIBNAME)$(LIB) + + OBJS_PRIMITIVES = \ + s_eq128$(OBJ) \ +@@ -380,11 +381,11 @@ $(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c + $(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c + $(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c + +-softfloat$(LIB): $(OBJS_ALL) ++$(LIBNAME)$(LIB): $(OBJS_ALL) + $(DELETE) $@ + $(MAKELIB) $^ + + .PHONY: clean + clean: +- $(DELETE) $(OBJS_ALL) softfloat$(LIB) ++ $(DELETE) $(OBJS_ALL) $(LIBNAME)$(LIB) + diff --git a/pkg/urbit/compat/mingw/uv.patch b/pkg/urbit/compat/mingw/uv.patch new file mode 100644 index 0000000000..1338b78355 --- /dev/null +++ b/pkg/urbit/compat/mingw/uv.patch @@ -0,0 +1,30 @@ +diff --git a/src/win/pipe.c b/src/win/pipe.c +index 0f2bb869b..f81245ec6 100644 +--- a/src/win/pipe.c ++++ b/src/win/pipe.c +@@ -270,6 +270,12 @@ static int uv_set_pipe_handle(uv_loop_t* loop, + + if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) { + err = GetLastError(); ++ if ((err == ERROR_INVALID_FUNCTION || err == ERROR_INVALID_PARAMETER) && (duplex_flags & UV_HANDLE_WRITABLE)) { ++ /* ++ * it's not a pipe, but simple writes should be fine ++ * let's trust callers to know what they're doing ++ */ ++ } else + if (err == ERROR_ACCESS_DENIED) { + /* + * SetNamedPipeHandleState can fail if the handle doesn't have either +diff --git a/src/win/tty.c b/src/win/tty.c +index c359d5601..1b9d4f853 100644 +--- a/src/win/tty.c ++++ b/src/win/tty.c +@@ -367,7 +367,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { + flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + break; + case UV_TTY_MODE_RAW: +- flags = ENABLE_WINDOW_INPUT; ++ flags = ENABLE_WINDOW_INPUT | ENABLE_PROCESSED_INPUT; + break; + case UV_TTY_MODE_IO: + return UV_ENOTSUP; diff --git a/pkg/urbit/compat/poor-mans-nix-shell.sh b/pkg/urbit/compat/poor-mans-nix-shell.sh new file mode 100644 index 0000000000..45427e0285 --- /dev/null +++ b/pkg/urbit/compat/poor-mans-nix-shell.sh @@ -0,0 +1,148 @@ +declare -a cdirs +declare -a ldirs +declare -A hdeps +sources=(../../nix/sources.json ../../nix/sources-pmnsh.json) +patches=compat/$1 +deriver=urbit-$1-build +markfil=.$1~ +depdirs= +nixpath=${NIX_STORE-../build} + +# LDFLAGS doesn't like absolute paths +if [ "${nixpath:0:1}" == "/" ] +then + mkdir -p $nixpath + nixpath=$(realpath --relative-to=. $nixpath) +fi + +hex2nixbase32 () { + local digits='0123456789abcdfghijklmnpqrsvwxyz' + local bits=0 + local left=0 # number of bits left in $bits + local i=0 + while ((1)) + do + while ((left>=5)) + do + echo -n ${digits:$((bits&31)):1} + bits=$((bits>>5)) + left=$((left-5)) + done + if ((i == ${#1})) + then + break + fi + char=0x${1:i:2} + i=$((i+2)) + bits=$((bits|(char<<(left)))) + left=$((left+8)) + done + echo -n ${digits:$bits:1} +} + +buildnixdep () { + echo Building dependency $key... + local cache=https://app.cachix.org/api/v1/cache/${CACHIX_CACHE-} + local hash= + if [ -n "$url" ] + then + hash=${hdeps[$key]} + dir=$nixpath/$hash-$key + if [ -e $dir/$markfil ] + then + # dependency present, don't reupload + hash= + else + # dependency absent, check the binary cache if configured + if [ -n "${CACHIX_CACHE-}" ] + then + echo Checking binary cache for $hash-$key... + narinfo="$cache/${hash}.narinfo" + if curl -fLI "$narinfo" + then + url="$cache/$(curl -fL -H "Accept: application/json" "$narinfo"|jq -r '.url')" + echo Found $url + strip=0 + hash= + fi + fi + mkdir -p $dir + pushd $dir + curl -fL "$url"|(tar --strip $strip -xzf - || true) + popd + fi + else + # local dependency + dir=../$key + fi + + # patch and build the dependency if necessary + if [ ! -e $dir/$markfil ] + then + local patch=$patches/$key.patch + [ -e $patch ] && patch -d $dir -p 1 <$patch + pushd $dir + eval "$cmdprep" + eval make "$cmdmake" + touch $markfil + popd + fi + + # if configured, upload freshly built dependency to binary cache + if [ -n "$hash" -a -n "${CACHIX_AUTH_TOKEN-}" ] + then + ( + echo Uploading freshly built $hash-$key to binary cache... + tar -C $dir -czf $hash.tar . + local size=$(stat -c '%s' $hash.tar) + read filehash _ < <(sha256sum $hash.tar) + curl -fL -H "Content-Type: application/gzip" -H "Authorization: Bearer $CACHIX_AUTH_TOKEN" --data-binary @"$hash.tar" "$cache/nar" + curl -fL -H "Content-Type: application/json" -H "Authorization: Bearer $CACHIX_AUTH_TOKEN" --data-binary @- "$cache/${hash}.narinfo" < + +/* + This is set to the the write-end of a pipe when Urbit is started in + daemon mode. It's meant to be used as a signal to the parent process + that the child process has finished booting. +*/ +static c3_i _child_process_booted_signal_fd = -1; + +/* + This should be called whenever the ship has been booted enough to + handle commands from automation code. Specifically, once the Eyre's + `chis` interface is up and running. + + In daemon mode, this signals to the parent process that it can + exit. Otherwise, it does nothing. + + Once we've sent a signal with `write`, we close the file descriptor + and overwrite the global to make it impossible to accidentally do + this twice. +*/ +static void _on_boot_completed_cb() { + c3_c buf[2] = {0,0}; + + if ( -1 == _child_process_booted_signal_fd ) { + return; + } + + if ( 0 == write(_child_process_booted_signal_fd, buf, 1) ) { + c3_assert(!"_on_boot_completed_cb: Can't write to parent FD"); + } + + close(_child_process_booted_signal_fd); + _child_process_booted_signal_fd = -1; +} + +/* u3_daemon_init(): platform-specific daemon mode initialization. + + We use a pipe to communicate between the child and the parent. The + parent waits for the child to write something to the pipe and + then exits. If the pipe is closed with nothing written to it, get + the exit status from the child process and also exit with that status. + + We want the child to write to the pipe once it's booted, so we put + `_on_boot_completed_cb` into `u3_Host.bot_f`, which is NULL in + non-daemon mode. That gets called once the `chis` service is + available. + + In both processes, we are good fork() citizens, and close all unused + file descriptors. Closing `pipefd[1]` in the parent process is + especially important, since the pipe needs to be closed if the child + process dies. When the pipe is closed, the read fails, and that's + how we know that something went wrong. + + There are some edge cases around `WEXITSTATUS` that are not handled + here, but I don't think it matters. +*/ +void +u3_daemon_init() +{ + c3_i pipefd[2]; + + if ( 0 != pipe(pipefd) ) { + c3_assert(!"Failed to create pipe"); + } + + pid_t childpid = fork(); + + if ( 0 == childpid ) { + close(pipefd[0]); + _child_process_booted_signal_fd = pipefd[1]; + u3_Host.bot_f = _on_boot_completed_cb; + return; + } + + close(pipefd[1]); + close(0); + close(1); + close(2); + + c3_c buf[2] = {0,0}; + if ( 1 == read(pipefd[0], buf, 1) ) { + exit(0); + } + + c3_i status; + wait(&status); + exit(WEXITSTATUS(status)); +} diff --git a/pkg/urbit/compat/posix/ptty.c b/pkg/urbit/compat/posix/ptty.c new file mode 100644 index 0000000000..d7d2af91ca --- /dev/null +++ b/pkg/urbit/compat/posix/ptty.c @@ -0,0 +1,189 @@ +/* compat/posix/ptty.c +** +*/ +#include "all.h" +#include "vere/vere.h" +#include +#include + +/* u3_ptty: POSIX terminal extension to u3_utty. +*/ +typedef struct { + u3_utty tty_u; // common tty structure + c3_i cug_i; // blocking fcntl flags + c3_i nob_i; // nonblocking fcntl flags + struct termios bak_u; // cooked terminal state + struct termios raw_u; // raw terminal state +} u3_ptty; + +/* _term_tcsetattr(): tcsetattr w/retry on EINTR. +*/ +static c3_i +_term_tcsetattr(c3_i fil_i, c3_i act_i, const struct termios* tms_u) +{ + c3_i ret_i = 0; + c3_w len_w = 0; + + do { + // abort pathological retry loop + // + if ( 100 == ++len_w ) { + fprintf(stderr, "term: tcsetattr loop: %s\r\n", strerror(errno)); + return -1; + } + ret_i = tcsetattr(fil_i, act_i, tms_u); + } while ( (-1 == ret_i) && (EINTR == errno) ); + + return ret_i; +} + +/* _ttyf_start_raw_input(): sets the tty to raw input. +*/ +static c3_o +_ttyf_start_raw_input(u3_utty* uty_u) +{ + u3_ptty* pty_u = (u3_ptty*)uty_u; + if ( 0 != _term_tcsetattr(uty_u->fid_i, TCSADRAIN, &pty_u->raw_u) ) { + return c3n; + } + if ( -1 == fcntl(uty_u->fid_i, F_SETFL, pty_u->nob_i) ) { + c3_assert(!"init-fcntl"); + } + return c3y; +} + +/* _ttyf_start_raw_input(): ends raw input on the tty. +*/ +static c3_o +_ttyf_end_raw_input(u3_utty* uty_u) +{ + u3_ptty* pty_u = (u3_ptty*)uty_u; + if ( 0 != _term_tcsetattr(uty_u->fid_i, TCSADRAIN, &pty_u->bak_u) ) { + return c3n; + } + if ( -1 == fcntl(uty_u->fid_i, F_SETFL, pty_u->cug_i) ) { + c3_assert(!"exit-fcntl"); + } + return c3y; +} + +/* _ttyf_hija(): hijacks the tty for cooked output. +*/ +static c3_o +_ttyf_hija(u3_utty* uty_u) +{ + u3_ptty* pty_u = (u3_ptty*)uty_u; + if ( 0 != _term_tcsetattr(1, TCSADRAIN, &pty_u->bak_u) ) { + perror("hija-tcsetattr-1"); + c3_assert(!"hija-tcsetattr"); + } + if ( -1 == fcntl(1, F_SETFL, pty_u->cug_i) ) { + perror("hija-fcntl-1"); + c3_assert(!"hija-fcntl"); + } + if ( 0 != _term_tcsetattr(0, TCSADRAIN, &pty_u->bak_u) ) { + perror("hija-tcsetattr-0"); + c3_assert(!"hija-tcsetattr"); + } + if ( -1 == fcntl(0, F_SETFL, pty_u->cug_i) ) { + perror("hija-fcntl-0"); + c3_assert(!"hija-fcntl"); + } + return c3y; +} + +/* _ttyf_loja(): releases the tty from cooked output. +*/ +static c3_o +_ttyf_loja(u3_utty* uty_u) +{ + u3_ptty* pty_u = (u3_ptty*)uty_u; + if ( 0 != _term_tcsetattr(1, TCSADRAIN, &pty_u->raw_u) ) { + perror("loja-tcsetattr-1"); + c3_assert(!"loja-tcsetattr"); + } + if ( -1 == fcntl(1, F_SETFL, pty_u->nob_i) ) { + perror("hija-fcntl-1"); + c3_assert(!"loja-fcntl"); + } + if ( 0 != _term_tcsetattr(0, TCSADRAIN, &pty_u->raw_u) ) { + perror("loja-tcsetattr-0"); + c3_assert(!"loja-tcsetattr"); + } + if ( -1 == fcntl(0, F_SETFL, pty_u->nob_i) ) { + perror("hija-fcntl-0"); + c3_assert(!"loja-fcntl"); + } + return c3y; +} + +/* _ttyf_get_winsize(): gets the tty window size. +*/ +static c3_o +_ttyf_get_winsize(u3_utty* uty_u, c3_l* col_l, c3_l* row_l) +{ + struct winsize siz_u; + if ( 0 == ioctl(uty_u->fid_i, TIOCGWINSZ, &siz_u) ) + { + *col_l = siz_u.ws_col; + *row_l = siz_u.ws_row; + return c3y; + } else { + return c3n; + } +} + +/* u3_ptty_init(): initialize platform-specific tty. +*/ +u3_utty* +u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c) +{ + u3_ptty* pty_u = c3_calloc(sizeof(u3_ptty)); + u3_utty* uty_u = &pty_u->tty_u; + + if ( !isatty(0) || !isatty(1) ) { + *err_c = "not a tty"; + c3_free(pty_u); + return NULL; + } + + uv_pipe_init(lup_u, &uty_u->pin_u.pop_u, 0); + uv_pipe_init(lup_u, &uty_u->pop_u.pop_u, 0); + uv_pipe_open(&uty_u->pin_u.pop_u, 0); + uv_pipe_open(&uty_u->pop_u.pop_u, 1); + + // Load old terminal state to restore. + // + { + if ( 0 != tcgetattr(uty_u->fid_i, &pty_u->bak_u) ) { + c3_assert(!"init-tcgetattr"); + } + if ( -1 == fcntl(uty_u->fid_i, F_GETFL, &pty_u->cug_i) ) { + c3_assert(!"init-fcntl"); + } + pty_u->cug_i &= ~O_NONBLOCK; // could fix? + pty_u->nob_i = pty_u->cug_i | O_NONBLOCK; // O_NDELAY on older unix + } + + // Construct raw termios configuration. + // + { + pty_u->raw_u = pty_u->bak_u; + + pty_u->raw_u.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); + pty_u->raw_u.c_iflag &= ~(ICRNL | INPCK | ISTRIP); + pty_u->raw_u.c_cflag &= ~(CSIZE | PARENB); + pty_u->raw_u.c_cflag |= CS8; + pty_u->raw_u.c_oflag &= ~(OPOST); + pty_u->raw_u.c_cc[VMIN] = 0; + pty_u->raw_u.c_cc[VTIME] = 0; + } + + uty_u->fid_i = 1; + uty_u->sta_f = _ttyf_start_raw_input; + uty_u->sto_f = _ttyf_end_raw_input; + uty_u->hij_f = _ttyf_hija; + uty_u->loj_f = _ttyf_loja; + uty_u->wsz_f = _ttyf_get_winsize; + return uty_u; +} diff --git a/pkg/urbit/compat/posix/rsignal.h b/pkg/urbit/compat/posix/rsignal.h new file mode 100644 index 0000000000..276006a18b --- /dev/null +++ b/pkg/urbit/compat/posix/rsignal.h @@ -0,0 +1,11 @@ +#ifndef _RSIGNAL_H +#define _RSIGNAL_H + +#define rsignal_jmpbuf sigjmp_buf +#define rsignal_setjmp(buf) sigsetjmp((buf), 1) +#define rsignal_longjmp siglongjmp +#define rsignal_install_handler signal +#define rsignal_deinstall_handler(sig) signal((sig), SIG_IGN) +#define rsignal_setitimer setitimer + +#endif//_RSIGNAL_H diff --git a/pkg/urbit/configure b/pkg/urbit/configure index cfc42f83e3..949b2847bd 100755 --- a/pkg/urbit/configure +++ b/pkg/urbit/configure @@ -1,12 +1,12 @@ #!/usr/bin/env bash -set -e +set -euo pipefail URBIT_VERSION="$(cat ./version)" deps=" \ curl gmp sigsegv argon2 ed25519 ent h2o scrypt uv murmur3 secp256k1 \ - softfloat3 ssl crypto z lmdb ge-additions aes_siv pthread \ + softfloat3 aes_siv ssl crypto z lmdb ge-additions pthread \ " headers=" \ @@ -21,10 +21,28 @@ defmacro () { defmacro URBIT_VERSION "\"$URBIT_VERSION\"" -[ -n "$MEMORY_DEBUG" ] && defmacro U3_MEMORY_DEBUG 1 -[ -n "$MEMORY_LOG" ] && defmacro U3_MEMORY_LOG 1 -[ -n "$CPU_DEBUG" ] && defmacro U3_CPU_DEBUG 1 -[ -n "$EVENT_TIME_DEBUG" ] && defmacro U3_EVENT_TIME_DEBUG 1 +opt_debug= + +while test $# != 0 +do + case $1 in + --enable-debug) + opt_debug=1 + ;; + --disable-debug) + opt_debug= + ;; + *) + echo "unrecognized option: $1" + ;; + esac + shift +done + +[ -n "${MEMORY_DEBUG-}" ] && defmacro U3_MEMORY_DEBUG 1 +[ -n "${MEMORY_LOG-}" ] && defmacro U3_MEMORY_LOG 1 +[ -n "${CPU_DEBUG-}" ] && defmacro U3_CPU_DEBUG 1 +[ -n "${EVENT_TIME_DEBUG-}" ] && defmacro U3_EVENT_TIME_DEBUG 1 if [ -n "${HOST-}" ] then os=$(sed 's$^[^-]*-\([^-]*\)-.*$\1$' <<< "$HOST") @@ -58,14 +76,53 @@ esac # TODO Determine if the target cpu is little or big endian. case $(tr A-Z a-z <<< $os) in + *mingw*) + # ensure required mingw packages are installed + mpkgs=(cmake curl gcc jq make) + pacman -S --needed autoconf automake-wrapper libtool patch ${mpkgs[@]/#/mingw-w64-x86_64-} + + . compat/poor-mans-nix-shell.sh mingw + compat/create-include-files.sh 'stat -c %s' /etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt + + defmacro U3_OS_mingw 1 + + deps="${deps/sigsegv}" + compat="${compat-} mingw" + PKG_CONFIG=false + ;; + m1brew) + # ensure required packages are installed + brew install -q autoconf automake bash cmake coreutils gmp jq libsigsegv libtool libuv openssl pkgconfig + + if (( ${BASH_VERSION%%.*} < 5 )) + then + echo Running bash version $BASH_VERSION is too low, please restart bash to use freshly installed one + exit 1 + fi + + # for some reason pkg-config does not pick up openssl + export PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig:${PKG_CONFIG_PATH-}" + + . compat/poor-mans-nix-shell.sh m1brew + compat/create-include-files.sh 'stat -f %z' /etc/ssl/cert.pem + + defmacro U3_OS_osx 1 + + deps="${deps/ssl/openssl}" + deps="${deps/uv/libuv}" + compat="${compat-} posix m1brew" + ;; *linux*) defmacro U3_OS_linux 1 + defmacro U3_OS_PROF 1 ;; *darwin*) defmacro U3_OS_osx 1 + defmacro U3_OS_PROF 1 ;; *apple*) defmacro U3_OS_osx 1 + defmacro U3_OS_PROF 1 ;; *freebsd*) defmacro U3_OS_bsd 1 @@ -81,18 +138,27 @@ case $(tr A-Z a-z <<< $os) in esac for dep in ${osdeps-} $deps -do LDFLAGS="${LDFLAGS-} -l$dep" - ${PKG_CONFIG-pkg-config} --cflags --libs $dep 2>/dev/null || true +do + LDFLAGS="${LDFLAGS-} $(${PKG_CONFIG-pkg-config} --libs $dep 2>/dev/null || echo -l$dep)" + CFLAGS="${CFLAGS-} $(${PKG_CONFIG-pkg-config} --cflags $dep 2>/dev/null || true)" done for header in $headers do LDFLAGS="${LDFLAGS-} -I$header" done +compat="${compat-posix}" +for citem in $compat +do + CFLAGS="${CFLAGS-} -Icompat/$citem" +done + cat >config.mk <&2 diff --git a/pkg/urbit/daemon/main.c b/pkg/urbit/daemon/main.c index ab789a1aa3..7912560a86 100644 --- a/pkg/urbit/daemon/main.c +++ b/pkg/urbit/daemon/main.c @@ -1,16 +1,13 @@ /* vere/main.c ** */ -#include -#include -#include -#include -#include -#include +#define U3_GLOBAL +#define C3_GLOBAL +#include "all.h" +#include "vere/vere.h" +#if !defined(U3_OS_mingw) #include -#include -#include -#include +#endif #include #include #include @@ -18,13 +15,6 @@ #include #include #include -#include - -#define U3_GLOBAL -#define C3_GLOBAL -#include "all.h" -#include "vere/vere.h" - #include #include "ca-bundle.h" @@ -222,9 +212,9 @@ _main_getopt(c3_i argc, c3_c** argv) } } -#if defined(U3_OS_bsd) +#if !defined(U3_OS_PROF) if (u3_Host.ops_u.pro == c3y) { - fprintf(stderr, "profiling isn't yet supported on BSD\r\n"); + fprintf(stderr, "profiling isn't yet supported on your OS\r\n"); return c3n; } #endif @@ -307,7 +297,7 @@ _main_getopt(c3_i argc, c3_c** argv) } struct sockaddr_in t; - if ( u3_Host.ops_u.bin_c != 0 && inet_aton(u3_Host.ops_u.bin_c, &t.sin_addr) == 0 ) { + if ( u3_Host.ops_u.bin_c != 0 && inet_pton(AF_INET, u3_Host.ops_u.bin_c, &t.sin_addr) == 0 ) { fprintf(stderr, "-b invalid IP address\n"); return c3n; } @@ -373,26 +363,64 @@ _main_getopt(c3_i argc, c3_c** argv) return c3y; } -/* _setup_cert_store: writes our embedded certificate database to a temp file +/* _cert_store: decoded CA certificates + */ +static STACK_OF(X509_INFO)* _cert_store; + +/* _setup_cert_store(): decodes embedded CA certificates */ static void -_setup_cert_store(char* tmp_cert_file_name) +_setup_cert_store() { - errno = 0; - int fd = mkstemp(tmp_cert_file_name); - if (fd < 1) { - printf("boot: failed to write local ssl temporary certificate store: %s\n", - strerror(errno)); + BIO* cbio = BIO_new_mem_buf(include_ca_bundle_crt, include_ca_bundle_crt_len); + if ( !cbio || !(_cert_store = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL)) ) { + u3l_log("boot: failed to decode embedded CA certificates\r\n"); exit(1); } - if (-1 == write(fd, include_ca_bundle_crt, include_ca_bundle_crt_len)) { - printf("boot: failed to write local ssl temporary certificate store: %s\n", - strerror(errno)); - exit(1); + BIO_free(cbio); +} + +/* _setup_ssl_x509(): adds embedded CA certificates to a X509_STORE + */ +static void +_setup_ssl_x509(void* arg) +{ + X509_STORE* cts = arg; + int i; + for ( i = 0; i < sk_X509_INFO_num(_cert_store); i++ ) { + X509_INFO *itmp = sk_X509_INFO_value(_cert_store, i); + if(itmp->x509) { + X509_STORE_add_cert(cts, itmp->x509); + } + if(itmp->crl) { + X509_STORE_add_crl(cts, itmp->crl); + } } +} + +/* _curl_ssl_ctx_cb(): curl SSL context callback + */ +static CURLcode +_curl_ssl_ctx_cb(CURL* curl, SSL_CTX* sslctx, void* param) +{ + X509_STORE* cts = SSL_CTX_get_cert_store(sslctx); + if (!cts || !_cert_store) + return CURLE_ABORTED_BY_CALLBACK; + + _setup_ssl_x509(cts); + return CURLE_OK; +} - setenv("SSL_CERT_FILE", tmp_cert_file_name, 1); +/* _setup_ssl_curl(): adds embedded CA certificates to a curl context + */ +static void +_setup_ssl_curl(void* arg) +{ + CURL* curl = arg; + curl_easy_setopt(curl, CURLOPT_CAINFO, NULL); + curl_easy_setopt(curl, CURLOPT_CAPATH, NULL); + curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, _curl_ssl_ctx_cb); } @@ -486,9 +514,11 @@ report(void) { printf("urbit %s\n", URBIT_VERSION); printf("gmp: %s\n", gmp_version); +#if !defined(U3_OS_mingw) printf("sigsegv: %d.%d\n", (libsigsegv_version >> 8) & 0xff, libsigsegv_version & 0xff); +#endif printf("openssl: %s\n", SSLeay_version(SSLEAY_VERSION)); printf("libuv: %s\n", uv_version_string()); printf("libh2o: %d.%d.%d\n", @@ -517,96 +547,6 @@ _stop_exit(c3_i int_i) u3_king_bail(); } -/* - This is set to the the write-end of a pipe when Urbit is started in - daemon mode. It's meant to be used as a signal to the parent process - that the child process has finished booting. -*/ -static c3_i _child_process_booted_signal_fd = -1; - -/* - This should be called whenever the ship has been booted enough to - handle commands from automation code. Specifically, once the Eyre's - `chis` interface is up and running. - - In daemon mode, this signals to the parent process that it can - exit. Otherwise, it does nothing. - - Once we've sent a signal with `write`, we close the file descriptor - and overwrite the global to make it impossible to accidentally do - this twice. -*/ -static void _on_boot_completed_cb() { - c3_c buf[2] = {0,0}; - - if ( -1 == _child_process_booted_signal_fd ) { - return; - } - - if ( 0 == write(_child_process_booted_signal_fd, buf, 1) ) { - c3_assert(!"_on_boot_completed_cb: Can't write to parent FD"); - } - - close(_child_process_booted_signal_fd); - _child_process_booted_signal_fd = -1; -} - -/* - In daemon mode, run the urbit as a background process, but don't - exit from the parent process until the ship is finished booting. - - We use a pipe to communicate between the child and the parent. The - parent waits for the child to write something to the pipe and - then exits. If the pipe is closed with nothing written to it, get - the exit status from the child process and also exit with that status. - - We want the child to write to the pipe once it's booted, so we put - `_on_boot_completed_cb` into `u3_Host.bot_f`, which is NULL in - non-daemon mode. That gets called once the `chis` service is - available. - - In both processes, we are good fork() citizens, and close all unused - file descriptors. Closing `pipefd[1]` in the parent process is - especially important, since the pipe needs to be closed if the child - process dies. When the pipe is closed, the read fails, and that's - how we know that something went wrong. - - There are some edge cases around `WEXITSTATUS` that are not handled - here, but I don't think it matters. -*/ -static void -_fork_into_background_process() -{ - c3_i pipefd[2]; - - if ( 0 != pipe(pipefd) ) { - c3_assert(!"Failed to create pipe"); - } - - pid_t childpid = fork(); - - if ( 0 == childpid ) { - close(pipefd[0]); - _child_process_booted_signal_fd = pipefd[1]; - u3_Host.bot_f = _on_boot_completed_cb; - return; - } - - close(pipefd[1]); - close(0); - close(1); - close(2); - - c3_c buf[2] = {0,0}; - if ( 1 == read(pipefd[0], buf, 1) ) { - exit(0); - } - - c3_i status; - wait(&status); - exit(WEXITSTATUS(status)); -} - /* _stop_on_boot_completed_cb(): exit gracefully after boot is complete */ static void @@ -659,12 +599,24 @@ main(c3_i argc, } // Set `u3_Host.wrk_c` to the worker executable path. - c3_i worker_exe_len = 1 + strlen(argv[0]) + strlen("-worker"); + c3_i urbit_exe_len = strlen(argv[0]); + c3_i worker_exe_len = 1 + urbit_exe_len + strlen("-worker"); u3_Host.wrk_c = c3_malloc(worker_exe_len); + #if defined(U3_OS_mingw) + if ( urbit_exe_len >= 4 && !strcmp(argv[0] + urbit_exe_len - 4, ".exe")) { + snprintf(u3_Host.wrk_c, worker_exe_len, "%.*s-worker.exe", urbit_exe_len - 4, argv[0]); + } else { + snprintf(u3_Host.wrk_c, worker_exe_len, "%s-worker", argv[0]); + } + #else snprintf(u3_Host.wrk_c, worker_exe_len, "%s-worker", argv[0]); + #endif if ( c3y == u3_Host.ops_u.dem ) { - _fork_into_background_process(); + // In daemon mode, run the urbit as a background process, but don't + // exit from the parent process until the ship is finished booting. + // + u3_daemon_init(); } if ( c3y == u3_Host.ops_u.rep ) { @@ -688,6 +640,7 @@ main(c3_i argc, // // XX review, may be unnecessary due to similar in u3m_init() // +#if defined(U3_OS_PROF) if ( _(u3_Host.ops_u.pro) ) { sigset_t set; @@ -698,12 +651,15 @@ main(c3_i argc, exit(1); } } +#endif + #if !defined(U3_OS_mingw) // Handle SIGTSTP as if it was SIGTERM. // // Configured here using signal() so as to be immediately available. // signal(SIGTSTP, _stop_exit); + #endif printf("~\n"); // printf("welcome.\n"); @@ -735,9 +691,6 @@ main(c3_i argc, } // printf("vere: hostname is %s\n", u3_Host.ops_u.nam_c); - u3K.certs_c = strdup("/tmp/urbit-ca-cert-XXXXXX"); - _setup_cert_store(u3K.certs_c); - if ( c3y == u3_Host.ops_u.dem ) { printf("boot: running as daemon\n"); } @@ -804,6 +757,18 @@ main(c3_i argc, } } + #if defined(U3_OS_mingw) + // Initialize event used to transmit Ctrl-C to worker process + // + { + SECURITY_ATTRIBUTES sa = {sizeof(sa), NULL, TRUE}; + if ( NULL == (u3_Host.cev_u = CreateEvent(&sa, FALSE, FALSE, NULL)) ) { + u3l_log("boot: failed to create Ctrl-C event: %d\r\n", GetLastError()); + exit(1); + } + } + #endif + // Initialize OpenSSL for client and server // { @@ -818,6 +783,10 @@ main(c3_i argc, exit(1); } + _setup_cert_store(); + u3K.ssl_curl_f = _setup_ssl_curl; + u3K.ssl_x509_f = _setup_ssl_x509; + u3_king_commence(); // uninitialize curl diff --git a/pkg/urbit/include/c/portable.h b/pkg/urbit/include/c/portable.h index 62c410b851..4204769bf5 100644 --- a/pkg/urbit/include/c/portable.h +++ b/pkg/urbit/include/c/portable.h @@ -72,6 +72,25 @@ # include # include +# elif defined(U3_OS_mingw) +# define signal mingw_has_no_usable_signal +# define raise mingw_has_no_usable_raise +# define _POSIX +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include "mman.h" +# include "compat.h" + # else #error "port: headers" # endif @@ -97,14 +116,10 @@ # define U3_OS_LoomBase 0x36000000 # endif # define U3_OS_LoomBits 29 // ie, 2^29 words == 2GB -# elif defined(U3_OS_osx) -# ifdef __LP64__ -# define U3_OS_LoomBase 0x200000000 -# else -# define U3_OS_LoomBase 0x4000000 -# endif +# elif defined(U3_OS_osx) && defined(U3_CPU_aarch64) || defined(U3_OS_mingw) +# define U3_OS_LoomBase 0x28000000000 # define U3_OS_LoomBits 29 // ie, 2^29 words == 2GB -# elif defined(U3_OS_bsd) +# elif defined(U3_OS_osx) || defined(U3_OS_bsd) # ifdef __LP64__ # define U3_OS_LoomBase 0x200000000 # else @@ -153,7 +168,7 @@ /* Byte swapping. */ -# if defined(U3_OS_linux) || defined(U3_OS_bsd) +# if defined(U3_OS_linux) || defined(U3_OS_bsd) || defined(U3_OS_mingw) # define c3_bswap_16(x) bswap_16(x) # define c3_bswap_32(x) bswap_32(x) # define c3_bswap_64(x) bswap_64(x) @@ -167,7 +182,7 @@ /* Sync. */ -# if defined(U3_OS_linux) +# if defined(U3_OS_linux) || defined(U3_OS_mingw) # define c3_sync(fd) (fdatasync(fd)) # elif defined(U3_OS_osx) # define c3_sync(fd) (fcntl(fd, F_FULLFSYNC, 0)) @@ -182,7 +197,7 @@ # if defined(U3_OS_linux) # include # define c3_fpurge __fpurge -# elif defined(U3_OS_bsd) || defined(U3_OS_osx) +# elif defined(U3_OS_bsd) || defined(U3_OS_osx) || defined(U3_OS_mingw) # define c3_fpurge fpurge # else # error "port: fpurge" @@ -190,7 +205,7 @@ /* Stat. */ -# if defined(U3_OS_linux) +# if defined(U3_OS_linux) || defined(U3_OS_mingw) # define c3_stat_mtime(dp) (u3_time_t_in_ts((dp)->st_mtime)) # elif defined(U3_OS_osx) # define c3_stat_mtime(dp) (u3_time_in_ts(&((dp)->st_mtimespec))) @@ -200,6 +215,16 @@ # define lseek64 lseek # else # error "port: timeconvert" +# endif + + /* Null. + */ +# if defined(U3_OS_linux) || defined(U3_OS_bsd) || defined(U3_OS_osx) +# define c3_dev_null "/dev/null" +# elif defined(U3_OS_mingw) +# define c3_dev_null "nul" +# else +# error "port: /dev/null" # endif /* Static assertion. diff --git a/pkg/urbit/include/noun/allocate.h b/pkg/urbit/include/noun/allocate.h index 564b69dbab..b8f367d863 100644 --- a/pkg/urbit/include/noun/allocate.h +++ b/pkg/urbit/include/noun/allocate.h @@ -2,6 +2,9 @@ ** ** This file is in the public domain. */ + +#include + /** Constants. **/ /* u3a_bits: number of bits in word-addressed pointer. 29 == 2GB. diff --git a/pkg/urbit/include/vere/vere.h b/pkg/urbit/include/vere/vere.h index 3492ab5ca5..20f2b98778 100644 --- a/pkg/urbit/include/vere/vere.h +++ b/pkg/urbit/include/vere/vere.h @@ -222,22 +222,40 @@ }; #endif + /* u3_utty: unix tty. + */ + struct _u3_utty; + + /* u3_ustm: uv stream. + */ + typedef union _u3_ustm { + uv_pipe_t pop_u; + uv_tcp_t wax_u; + uv_tty_t tty_u; + } u3_ustm; + + /* u3_ttyf: simple unix tty function. + */ + typedef c3_o (*u3_ttyf)(struct _u3_utty* uty_u); + /* u3_utty: unix tty. */ typedef struct _u3_utty { - union { - uv_pipe_t pop_u; - uv_tcp_t wax_u; - }; + u3_ustm pin_u; // input stream + u3_ustm pop_u; // output stream struct _u3_utty* nex_u; // next in host list + u3_ttyf sta_f; // start tty + u3_ttyf sto_f; // clean up tty + u3_ttyf hij_f; // hijack tty for cooked print + u3_ttyf loj_f; // release tty from cooked print + c3_o (*wsz_f) + (struct _u3_utty* uty_u, + c3_l* col_l, + c3_l* row_l); // return tty window size c3_i fid_i; // file descriptor c3_w tid_l; // terminal identity number u3_utfo ufo_u; // terminfo strings - c3_i cug_i; // blocking fcntl flags - c3_i nob_i; // nonblocking fcntl flags u3_utat tat_u; // control state - struct termios bak_u; // cooked terminal state - struct termios raw_u; // raw terminal state struct _u3_auto* car_u; // driver hack } u3_utty; @@ -301,6 +319,9 @@ c3_d now_d; // event tick uv_loop_t* lup_u; // libuv event loop u3_usig* sig_u; // signal list + #if defined(U3_OS_mingw) + HANDLE cev_u; // Ctrl-C event handle + #endif u3_utty* uty_u; // linked terminal list u3_opts ops_u; // commandline options c3_i xit_i; // exit code for shutdown @@ -469,6 +490,7 @@ time_t wen_t; // process creation time u3_mojo inn_u; // client's stdin u3_moat out_u; // client's stdout + uv_pipe_t err_u; // client's stderr c3_w wag_w; // config flags c3_c* bin_c; // binary path c3_c* pax_c; // directory @@ -641,7 +663,8 @@ /* u3_king: all executing piers. */ typedef struct _u3_king { - c3_c* certs_c; // ssl certificate dump + void (*ssl_curl_f)(void*); // setup ssl CAs in CURL* + void (*ssl_x509_f)(void*); // setup ssl CAs in X509_STORE* u3_pier* pir_u; // pier list uv_timer_t tim_u; // gc timer } u3_king; @@ -716,7 +739,7 @@ */ u3_atom u3_time_in_ts(struct timespec* tim_ts); -#if defined(U3_OS_linux) +#if defined(U3_OS_linux) || defined(U3_OS_mingw) /* u3_time_t_in_ts(): urbit time from time_t. */ u3_atom @@ -1103,6 +1126,11 @@ void u3_term_log_exit(void); + /* u3_ptty_init(): initialize platform-specific tty. + */ + u3_utty* + u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c); + /** Ames, packet networking. **/ @@ -1371,6 +1399,15 @@ void u3_king_grab(void* ptr_v); + /* u3_daemon_init(): platform-specific daemon mode initialization. + */ + void + u3_daemon_init(); + + /* u3_write_fd(): retry interrupts, continue partial writes, assert errors. + */ + void + u3_write_fd(c3_i fid_i, const void* buf_v, size_t len_i); c3_w u3_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); diff --git a/pkg/urbit/jets/c/con.c b/pkg/urbit/jets/c/c0n.c similarity index 100% rename from pkg/urbit/jets/c/con.c rename to pkg/urbit/jets/c/c0n.c diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index df82bb9cfd..224eb86d9c 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -1,12 +1,11 @@ /* g/e.c ** */ +#include "all.h" #include #include #include -#include "all.h" - #ifdef U3_SNAPSHOT_VALIDATION /* Image check. */ @@ -815,8 +814,8 @@ u3e_save(void) _ce_image_sync(&u3P.nor_u); _ce_image_sync(&u3P.sou_u); - _ce_patch_delete(); _ce_patch_free(pat_u); + _ce_patch_delete(); } /* u3e_live(): start the checkpointing system. @@ -853,8 +852,8 @@ u3e_live(c3_o nuu_o, c3_c* dir_c) _ce_patch_apply(pat_u); _ce_image_sync(&u3P.nor_u); _ce_image_sync(&u3P.sou_u); - _ce_patch_delete(); _ce_patch_free(pat_u); + _ce_patch_delete(); } /* Write image files to memory; reinstate protection. diff --git a/pkg/urbit/noun/manage.c b/pkg/urbit/noun/manage.c index 4833228ff0..e1f9c52da7 100644 --- a/pkg/urbit/noun/manage.c +++ b/pkg/urbit/noun/manage.c @@ -1,17 +1,15 @@ /* n/m.c ** */ +#include "all.h" +#include "rsignal.h" +#include "vere/vere.h" #include #include #include #include -#include -#include #include -#include "all.h" -#include "vere/vere.h" - // XX stack-overflow recovery should be gated by -a // #undef NO_OVERFLOW @@ -75,7 +73,17 @@ u3_noun arg); -static sigjmp_buf u3_Signal; +// u3m_signal uses restricted functionality signals for compatibility reasons: +// some platforms may not provide true POSIX asynchronous signals and their +// compat layer will then implement this restricted functionality subset. +// u3m_signal never needs to interrupt I/O operations, its signal handlers +// do not manipulate signals, do not modify shared state, and always either +// return or longjmp. +// +static rsignal_jmpbuf u3_Signal; + +#if !defined(U3_OS_mingw) +#include #ifndef SIGSTKSZ # define SIGSTKSZ 16384 @@ -83,6 +91,7 @@ static sigjmp_buf u3_Signal; #ifndef NO_OVERFLOW static uint8_t Sigstk[SIGSTKSZ]; #endif +#endif #if 0 /* _cm_punt(): crudely print trace. @@ -129,17 +138,25 @@ static void _cm_overflow(void *arg1, void *arg2, void *arg3) static void _cm_signal_handle(c3_l sig_l) { +#ifndef U3_OS_mingw if ( c3__over == sig_l ) { +#ifndef NO_OVERFLOW sigsegv_leave_handler(_cm_overflow, NULL, NULL, NULL); - } - else { +#endif + } else +#endif + { u3m_signal(sig_l); } } #ifndef NO_OVERFLOW static void +#ifndef U3_OS_mingw _cm_signal_handle_over(int emergency, stackoverflow_context_t scp) +#else +_cm_signal_handle_over(int x) +#endif { _cm_signal_handle(c3__over); } @@ -330,10 +347,14 @@ _cm_signal_deep(c3_w mil_w) } #ifndef NO_OVERFLOW +#ifndef U3_OS_mingw stackoverflow_install_handler(_cm_signal_handle_over, Sigstk, SIGSTKSZ); +#else + rsignal_install_handler(SIGSTK, _cm_signal_handle_over); +#endif #endif - signal(SIGINT, _cm_signal_handle_intr); - signal(SIGTERM, _cm_signal_handle_term); + rsignal_install_handler(SIGINT, _cm_signal_handle_intr); + rsignal_install_handler(SIGTERM, _cm_signal_handle_term); // Provide a little emergency memory, for use in case things // go utterly haywire. @@ -349,11 +370,11 @@ _cm_signal_deep(c3_w mil_w) itm_u.it_value.tv_sec = (mil_w / 1000); itm_u.it_value.tv_usec = 1000 * (mil_w % 1000); - if ( setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { + if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { u3l_log("loom: set timer failed %s\r\n", strerror(errno)); } else { - signal(SIGVTALRM, _cm_signal_handle_alrm); + rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm); } } @@ -365,12 +386,16 @@ _cm_signal_deep(c3_w mil_w) static void _cm_signal_done() { - signal(SIGINT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - signal(SIGVTALRM, SIG_IGN); + rsignal_deinstall_handler(SIGINT); + rsignal_deinstall_handler(SIGTERM); + rsignal_deinstall_handler(SIGVTALRM); #ifndef NO_OVERFLOW +#ifndef U3_OS_mingw stackoverflow_deinstall_handler(); +#else + rsignal_deinstall_handler(SIGSTK); +#endif #endif { struct itimerval itm_u; @@ -378,7 +403,7 @@ _cm_signal_done() timerclear(&itm_u.it_interval); timerclear(&itm_u.it_value); - if ( setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { + if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { u3l_log("loom: clear timer failed %s\r\n", strerror(errno)); } } @@ -397,7 +422,7 @@ _cm_signal_done() void u3m_signal(u3_noun sig_l) { - siglongjmp(u3_Signal, sig_l); + rsignal_longjmp(u3_Signal, sig_l); } /* u3m_file(): load file, as atom, or bail. @@ -959,7 +984,7 @@ u3m_soft_top(c3_w mil_w, // timer ms */ _cm_signal_deep(mil_w); - if ( 0 != (sig_l = sigsetjmp(u3_Signal, 1)) ) { + if ( 0 != (sig_l = rsignal_setjmp(u3_Signal)) ) { // reinitialize trace state // u3t_init(); @@ -1559,6 +1584,10 @@ u3m_wall(u3_noun wol) static void _cm_limits(void) { +# ifdef U3_OS_mingw + // Windows doesn't have rlimits. Default maximum thread + // stack size is set in the executable file header. +# else struct rlimit rlm; // Moar stack. @@ -1606,6 +1635,7 @@ _cm_limits(void) } } # endif +# endif } /* _cm_signals(): set up interrupts, etc. @@ -1613,13 +1643,23 @@ _cm_limits(void) static void _cm_signals(void) { +# if defined(U3_OS_mingw) + // vere using libsigsegv on MingW is very slow, because libsigsegv + // works by installing a top-level SEH unhandled exception filter. + // The top-level filter runs only after Windows walks the whole stack, + // looking up registered exception filters for every stack frame, and + // finds no filter to handle the exception. + // Instead of libsigsegv, all vere functions register a SEH exception + // filter (see compat/mingw/seh_handler.c) that handles both memory + // access and stack overflow exceptions. It calls u3e_fault directly. +# else if ( 0 != sigsegv_install_handler(u3e_fault) ) { u3l_log("boot: sigsegv install failed\n"); exit(1); } - // signal(SIGINT, _loom_stop); - +# endif +# if defined(U3_OS_PROF) // Block SIGPROF, so that if/when we reactivate it on the // main thread for profiling, we won't get hits in parallel // on other threads. @@ -1634,6 +1674,7 @@ _cm_signals(void) exit(1); } } +# endif } /* u3m_init(): start the environment. @@ -1670,7 +1711,7 @@ u3m_init(void) u3l_log("boot: mapping %dMB failed\r\n", (len_w / (1024 * 1024))); u3l_log("see urbit.org/using/install/#about-swap-space" " for adding swap space\r\n"); - if ( -1 != (c3_ps)map_v ) { + if ( -1 != (c3_ps)dyn_v ) { u3l_log("if porting to a new platform, try U3_OS_LoomBase %p\r\n", dyn_v); } diff --git a/pkg/urbit/noun/serial.c b/pkg/urbit/noun/serial.c index 6480d2741c..ae0a78310c 100644 --- a/pkg/urbit/noun/serial.c +++ b/pkg/urbit/noun/serial.c @@ -2,11 +2,10 @@ ** */ -#include -#include - #include "all.h" #include "ur/ur.h" +#include +#include /* _cs_jam_buf: struct for tracking the fibonacci-allocated jam of a noun */ diff --git a/pkg/urbit/noun/trace.c b/pkg/urbit/noun/trace.c index f8fe81320c..1ee8168c70 100644 --- a/pkg/urbit/noun/trace.c +++ b/pkg/urbit/noun/trace.c @@ -519,7 +519,7 @@ u3t_boot(void) { if ( u3C.wag_w & u3o_debug_cpu ) { _ct_lop_o = c3n; -#if defined(U3_OS_osx) || defined(U3_OS_linux) +#if defined(U3_OS_PROF) // skip profiling if we don't yet have an arvo kernel // if ( 0 == u3A->roc ) { @@ -551,10 +551,6 @@ u3t_boot(void) itm_v.it_value = itm_v.it_interval; setitimer(ITIMER_PROF, &itm_v, 0); } -#elif defined(U3_OS_bsd) - // XX "Profiling isn't yet supported on BSD" -#else -# error "port: profiling" #endif } } @@ -565,7 +561,7 @@ void u3t_boff(void) { if ( u3C.wag_w & u3o_debug_cpu ) { -#if defined(U3_OS_osx) || defined(U3_OS_linux) +#if defined(U3_OS_PROF) // Mask SIGPROF signals in this thread (and this is the only // thread that unblocked them). { @@ -590,11 +586,6 @@ u3t_boff(void) sig_s.sa_handler = SIG_IGN; sigaction(SIGPROF, &sig_s, 0); } - -#elif defined(U3_OS_bsd) - // XX "Profiling isn't yet supported on BSD" -#else -# error "port: profiling" #endif } } diff --git a/pkg/urbit/noun/urth.c b/pkg/urbit/noun/urth.c index 27ac7364c6..f6df4910f6 100644 --- a/pkg/urbit/noun/urth.c +++ b/pkg/urbit/noun/urth.c @@ -1,14 +1,13 @@ /* noun/urth.c ** */ +#include "all.h" +#include "ur/ur.h" #include #include #include #include -#include "all.h" -#include "ur/ur.h" - /* _cu_atom_to_ref(): allocate indirect atom off-loom. */ static inline ur_nref diff --git a/pkg/urbit/noun/vortex.c b/pkg/urbit/noun/vortex.c index 4bd17746af..acf7eea9d2 100644 --- a/pkg/urbit/noun/vortex.c +++ b/pkg/urbit/noun/vortex.c @@ -1,8 +1,8 @@ /* g/v.c ** */ -#include #include "all.h" +#include #define _CVX_LOAD 4 #define _CVX_PEEK 22 diff --git a/pkg/urbit/vere/auto.c b/pkg/urbit/vere/auto.c index 4462b4de23..5a56d22bc4 100644 --- a/pkg/urbit/vere/auto.c +++ b/pkg/urbit/vere/auto.c @@ -1,21 +1,5 @@ /* vere/auto.c */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" diff --git a/pkg/urbit/vere/dawn.c b/pkg/urbit/vere/dawn.c index a2e09ab1cb..bc306a4611 100644 --- a/pkg/urbit/vere/dawn.c +++ b/pkg/urbit/vere/dawn.c @@ -2,11 +2,10 @@ ** ** ethereum-integrated pre-boot validation */ -#include -#include - #include "all.h" #include "vere/vere.h" +#include +#include /* _dawn_oct_to_buf(): +octs to uv_buf_t */ @@ -45,8 +44,10 @@ _dawn_buf_to_oct(uv_buf_t buf_u) /* _dawn_curl_alloc(): allocate a response buffer for curl */ static size_t -_dawn_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, uv_buf_t* buf_u) +_dawn_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, void* buf_v) { + uv_buf_t* buf_u = buf_v; + size_t siz_t = uni_t * mem_t; buf_u->base = c3_realloc(buf_u->base, 1 + siz_t + buf_u->len); @@ -80,7 +81,7 @@ _dawn_post_json(c3_c* url_c, uv_buf_t lod_u) // XX require TLS, pin default cert? // - curl_easy_setopt(curl, CURLOPT_CAINFO, u3K.certs_c); + u3K.ssl_curl_f(curl); curl_easy_setopt(curl, CURLOPT_URL, url_c); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _dawn_curl_alloc); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&buf_u); @@ -127,7 +128,7 @@ _dawn_get_jam(c3_c* url_c) // XX require TLS, pin default cert? // - curl_easy_setopt(curl, CURLOPT_CAINFO, u3K.certs_c); + u3K.ssl_curl_f(curl); curl_easy_setopt(curl, CURLOPT_URL, url_c); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _dawn_curl_alloc); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&buf_u); diff --git a/pkg/urbit/vere/db/lmdb.c b/pkg/urbit/vere/db/lmdb.c index e8f53d200a..a6acbba6d5 100644 --- a/pkg/urbit/vere/db/lmdb.c +++ b/pkg/urbit/vere/db/lmdb.c @@ -1,17 +1,18 @@ /* vere/db/lmdb.c */ - -#include -#include -#include - -#include - #include "c/portable.h" #include "c/types.h" #include "c/defs.h" +#include "vere/db/lmdb.h" +#include + +/* mdb_logerror(): writes an error message and lmdb error code to f. +*/ +void mdb_logerror(FILE* f, int err, const char* fmt, ...); -#include +/* mdb_get_filesize(): gets the size of a lmdb database file on disk. +*/ +intmax_t mdb_get_filesize(mdb_filehandle_t han_u); // lmdb api wrapper // @@ -42,31 +43,28 @@ u3_lmdb_init(const c3_c* pax_c, size_t siz_i) c3_w ret_w; if ( (ret_w = mdb_env_create(&env_u)) ) { - fprintf(stderr, "lmdb: init fail: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: init fail"); return 0; } // Our databases have two tables: META and EVENTS // if ( (ret_w = mdb_env_set_maxdbs(env_u, 2)) ) { - fprintf(stderr, "lmdb: failed to set number of databases: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: failed to set number of databases"); // XX dispose env_u // return 0; } if ( (ret_w = mdb_env_set_mapsize(env_u, siz_i)) ) { - fprintf(stderr, "lmdb: failed to set database size: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: failed to set database size"); // XX dispose env_u // return 0; } if ( (ret_w = mdb_env_open(env_u, pax_c, 0, 0664)) ) { - fprintf(stderr, "lmdb: failed to open event log: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: failed to open event log"); // XX dispose env_u // return 0; @@ -111,18 +109,17 @@ u3_lmdb_stat(MDB_env* env_u, FILE* fil_u) } { - c3_i fid_i; - struct stat sat_u; + mdb_filehandle_t han_u; + mdb_env_get_fd(env_u, &han_u); - mdb_env_get_fd(env_u, &fid_i); - fstat(fid_i, &sat_u); + intmax_t dis_i = mdb_get_filesize(han_u); - if ( siz_i != sat_u.st_size ) { + if ( siz_i != dis_i ) { fprintf(fil_u, "MISMATCH:\n"); } fprintf(fil_u, " file size (page): %zu\n", siz_i); - fprintf(fil_u, " file size (stat): %jd\n", (intmax_t)sat_u.st_size); + fprintf(fil_u, " file size (stat): %jd\n", dis_i); } } @@ -140,7 +137,7 @@ u3_lmdb_gulf(MDB_env* env_u, c3_d* low_d, c3_d* hig_d) // XX why no MDB_RDONLY? // if ( (ret_w = mdb_txn_begin(env_u, 0, 0, &txn_u)) ) { - fprintf(stderr, "lmdb: gulf: txn_begin fail: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: gulf: txn_begin fail"); return c3n; } @@ -150,7 +147,7 @@ u3_lmdb_gulf(MDB_env* env_u, c3_d* low_d, c3_d* hig_d) c3_w ops_w = MDB_CREATE | MDB_INTEGERKEY; if ( (ret_w = mdb_dbi_open(txn_u, "EVENTS", ops_w, &mdb_u)) ) { - fprintf(stderr, "lmdb: gulf: dbi_open fail: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: gulf: dbi_open fail"); // XX confirm // mdb_txn_abort(txn_u); @@ -167,8 +164,7 @@ u3_lmdb_gulf(MDB_env* env_u, c3_d* low_d, c3_d* hig_d) // creates a cursor to point to the last event // if ( (ret_w = mdb_cursor_open(txn_u, mdb_u, &cur_u)) ) { - fprintf(stderr, "lmdb: gulf: cursor_open fail: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: gulf: cursor_open fail"); // XX confirm // mdb_txn_abort(txn_u); @@ -187,8 +183,7 @@ u3_lmdb_gulf(MDB_env* env_u, c3_d* low_d, c3_d* hig_d) return c3y; } else if ( ret_w ) { - fprintf(stderr, "lmdb: gulf: head fail: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: gulf: head fail"); mdb_cursor_close(cur_u); mdb_txn_abort(txn_u); return c3n; @@ -211,7 +206,7 @@ u3_lmdb_gulf(MDB_env* env_u, c3_d* low_d, c3_d* hig_d) mdb_txn_abort(txn_u); if ( ret_w ) { - fprintf(stderr, "lmdb: gulf: last fail: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: gulf: last fail"); return c3n; } else { @@ -238,7 +233,7 @@ u3_lmdb_read(MDB_env* env_u, // create a read-only transaction. // if ( (ret_w = mdb_txn_begin(env_u, 0, MDB_RDONLY, &txn_u)) ) { - fprintf(stderr, "lmdb: read txn_begin fail: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: read txn_begin fail"); return c3n; } @@ -248,7 +243,7 @@ u3_lmdb_read(MDB_env* env_u, c3_w ops_w = MDB_CREATE | MDB_INTEGERKEY; if ( (ret_w = mdb_dbi_open(txn_u, "EVENTS", ops_w, &mdb_u)) ) { - fprintf(stderr, "lmdb: read: dbi_open fail: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: read: dbi_open fail"); // XX confirm // mdb_txn_abort(txn_u); @@ -267,8 +262,7 @@ u3_lmdb_read(MDB_env* env_u, // creates a cursor to iterate over keys starting at [eve_d] // if ( (ret_w = mdb_cursor_open(txn_u, mdb_u, &cur_u)) ) { - fprintf(stderr, "lmdb: read: cursor_open fail: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: read: cursor_open fail"); // XX confirm // mdb_txn_abort(txn_u); @@ -278,9 +272,7 @@ u3_lmdb_read(MDB_env* env_u, // set the cursor to the position of [eve_d] // if ( (ret_w = mdb_cursor_get(cur_u, &key_u, &val_u, MDB_SET_KEY)) ) { - fprintf(stderr, "lmdb: read: initial cursor_get failed at %" PRIu64 ": %s\r\n", - eve_d, - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: read: initial cursor_get failed at %" PRIu64, eve_d); mdb_cursor_close(cur_u); // XX confirm // @@ -325,8 +317,7 @@ u3_lmdb_read(MDB_env* env_u, if ( (ret_w = mdb_cursor_get(cur_u, &key_u, &val_u, MDB_NEXT)) && (MDB_NOTFOUND != ret_w) ) { - fprintf(stderr, "lmdb: read: error: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: read: error"); ret_o = c3n; break; } @@ -359,7 +350,7 @@ u3_lmdb_save(MDB_env* env_u, // create a write transaction // if ( (ret_w = mdb_txn_begin(env_u, 0, 0, &txn_u)) ) { - fprintf(stderr, "lmdb: write: txn_begin fail: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: write: txn_begin fail"); return c3n; } @@ -369,7 +360,7 @@ u3_lmdb_save(MDB_env* env_u, c3_w ops_w = MDB_CREATE | MDB_INTEGERKEY; if ( (ret_w = mdb_dbi_open(txn_u, "EVENTS", ops_w, &mdb_u)) ) { - fprintf(stderr, "lmdb: write: dbi_open fail: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: write: dbi_open fail"); mdb_txn_abort(txn_u); return c3n; } @@ -401,7 +392,7 @@ u3_lmdb_save(MDB_env* env_u, // commit transaction // if ( (ret_w = mdb_txn_commit(txn_u)) ) { - fprintf(stderr, "lmdb: write failed: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: write failed"); return c3n; } @@ -423,16 +414,14 @@ u3_lmdb_read_meta(MDB_env* env_u, // create a read transaction // if ( (ret_w = mdb_txn_begin(env_u, 0, MDB_RDONLY, &txn_u)) ) { - fprintf(stderr, "lmdb: meta read: txn_begin fail: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: meta read: txn_begin fail"); return read_f(ptr_v, 0, 0); } // open the database in the transaction // if ( (ret_w = mdb_dbi_open(txn_u, "META", 0, &mdb_u)) ) { - fprintf(stderr, "lmdb: meta read: dbi_open fail: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: meta read: dbi_open fail"); mdb_txn_abort(txn_u); return read_f(ptr_v, 0, 0); } @@ -443,7 +432,7 @@ u3_lmdb_read_meta(MDB_env* env_u, MDB_val val_u; if ( (ret_w = mdb_get(txn_u, mdb_u, &key_u, &val_u)) ) { - fprintf(stderr, "lmdb: read failed: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: read failed"); mdb_txn_abort(txn_u); return read_f(ptr_v, 0, 0); } @@ -472,16 +461,14 @@ u3_lmdb_save_meta(MDB_env* env_u, // create a write transaction // if ( (ret_w = mdb_txn_begin(env_u, 0, 0, &txn_u)) ) { - fprintf(stderr, "lmdb: meta write: txn_begin fail: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: meta write: txn_begin fail"); return c3n; } // opens the database in the transaction // if ( (ret_w = mdb_dbi_open(txn_u, "META", MDB_CREATE, &mdb_u)) ) { - fprintf(stderr, "lmdb: meta write: dbi_open fail: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: meta write: dbi_open fail"); mdb_txn_abort(txn_u); return c3n; } @@ -493,7 +480,7 @@ u3_lmdb_save_meta(MDB_env* env_u, MDB_val val_u = { .mv_size = val_i, .mv_data = val_p }; if ( (ret_w = mdb_put(txn_u, mdb_u, &key_u, &val_u, 0)) ) { - fprintf(stderr, "lmdb: write failed: %s\r\n", mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: write failed"); mdb_txn_abort(txn_u); return c3n; } @@ -502,10 +489,31 @@ u3_lmdb_save_meta(MDB_env* env_u, // commit txn // if ( (ret_w = mdb_txn_commit(txn_u)) ) { - fprintf(stderr, "lmdb: meta write: commit failed: %s\r\n", - mdb_strerror(ret_w)); + mdb_logerror(stderr, ret_w, "lmdb: meta write: commit failed"); return c3n; } return c3y; } + +#if !defined(U3_OS_mingw) +/* mdb_logerror(): writes an error message and lmdb error code to f. +*/ +void mdb_logerror(FILE* f, int err, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(f, fmt, ap); + va_end(ap); + fprintf(f, ": %s\r\n", mdb_strerror(err)); +} + +/* mdb_get_filesize(): gets the size of a lmdb database file on disk. +*/ +intmax_t mdb_get_filesize(mdb_filehandle_t han_u) +{ + struct stat sat_u; + fstat(han_u, &sat_u); + return (intmax_t)sat_u.st_size; +} +#endif diff --git a/pkg/urbit/vere/disk.c b/pkg/urbit/vere/disk.c index 691f2ae683..6f8240daae 100644 --- a/pkg/urbit/vere/disk.c +++ b/pkg/urbit/vere/disk.c @@ -1,21 +1,5 @@ /* vere/disk.c */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" #include diff --git a/pkg/urbit/vere/foil.c b/pkg/urbit/vere/foil.c index 9c78cd2969..1d844f5d41 100644 --- a/pkg/urbit/vere/foil.c +++ b/pkg/urbit/vere/foil.c @@ -4,22 +4,6 @@ */ #include "all.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "vere/vere.h" /* assumptions: diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 23ae77b2d3..1773e02ed1 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -1,15 +1,6 @@ /* vere/ames.c ** */ -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" #include "ur/serial.h" diff --git a/pkg/urbit/vere/io/behn.c b/pkg/urbit/vere/io/behn.c index a6a7b0736f..c9394564e1 100644 --- a/pkg/urbit/vere/io/behn.c +++ b/pkg/urbit/vere/io/behn.c @@ -1,13 +1,6 @@ /* vere/behn.c ** */ -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" diff --git a/pkg/urbit/vere/io/cttp.c b/pkg/urbit/vere/io/cttp.c index d4c28f6da7..1f19c3e414 100644 --- a/pkg/urbit/vere/io/cttp.c +++ b/pkg/urbit/vere/io/cttp.c @@ -1,18 +1,10 @@ /* vere/cttp.c ** */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" +#include +#include /* u3_csat: client connection state. */ @@ -985,8 +977,8 @@ _cttp_init_tls(void) // SSL_OP_NO_TLSv1 | // XX test SSL_OP_NO_COMPRESSION); + u3K.ssl_x509_f(SSL_CTX_get_cert_store(tls_u)); SSL_CTX_set_verify(tls_u, SSL_VERIFY_PEER, 0); - SSL_CTX_set_default_verify_paths(tls_u); SSL_CTX_set_session_cache_mode(tls_u, SSL_SESS_CACHE_OFF); SSL_CTX_set_cipher_list(tls_u, "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:" diff --git a/pkg/urbit/vere/io/fore.c b/pkg/urbit/vere/io/fore.c index 1834cc7e11..81476d92a1 100644 --- a/pkg/urbit/vere/io/fore.c +++ b/pkg/urbit/vere/io/fore.c @@ -1,13 +1,6 @@ /* vere/root.c ** */ -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" diff --git a/pkg/urbit/vere/io/hind.c b/pkg/urbit/vere/io/hind.c index b8b1577ee6..b0d207e838 100644 --- a/pkg/urbit/vere/io/hind.c +++ b/pkg/urbit/vere/io/hind.c @@ -1,13 +1,6 @@ /* vere/root.c ** */ -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" diff --git a/pkg/urbit/vere/io/http.c b/pkg/urbit/vere/io/http.c index 29c008df92..f0d2f0ea23 100644 --- a/pkg/urbit/vere/io/http.c +++ b/pkg/urbit/vere/io/http.c @@ -1,21 +1,12 @@ /* vere/http.c ** */ -#include -#include -#include -#include -#include -#include -#include -#include +#include "all.h" +#include "vere/vere.h" #include #include #include -#include "all.h" -#include "vere/vere.h" - typedef struct _u3_h2o_serv { h2o_globalconf_t fig_u; // h2o global config h2o_context_t ctx_u; // h2o ctx @@ -1468,7 +1459,7 @@ _http_serv_start(u3_http* htp_u) INADDR_ANY; if ( 0 != u3_Host.ops_u.bin_c && c3n == htp_u->lop ) { - inet_aton(u3_Host.ops_u.bin_c, &adr_u.sin_addr); + inet_pton(AF_INET, u3_Host.ops_u.bin_c, &adr_u.sin_addr); } uv_tcp_init(u3L, &htp_u->wax_u); @@ -1622,11 +1613,12 @@ _http_write_ports_file(u3_httd* htd_u, c3_c *pax_c) u3_http* htp_u = htd_u->htp_u; + c3_c temp[32]; while ( 0 != htp_u ) { if ( 0 < htp_u->por_s ) { - dprintf(por_i, "%u %s %s\n", htp_u->por_s, + u3_write_fd(por_i, temp, snprintf(temp, 32, "%u %s %s\n", htp_u->por_s, (c3y == htp_u->sec) ? "secure" : "insecure", - (c3y == htp_u->lop) ? "loopback" : "public"); + (c3y == htp_u->lop) ? "loopback" : "public")); } htp_u = htp_u->nex_u; diff --git a/pkg/urbit/vere/io/term.c b/pkg/urbit/vere/io/term.c index fe58abc32c..bfd6d2fc48 100644 --- a/pkg/urbit/vere/io/term.c +++ b/pkg/urbit/vere/io/term.c @@ -1,15 +1,6 @@ /* vere/term.c ** */ -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" @@ -25,12 +16,11 @@ static u3_utty* _term_main(); static void _term_read_cb(uv_stream_t* tcp_u, ssize_t siz_i, const uv_buf_t* buf_u); -static c3_i _term_tcsetattr(c3_i, c3_i, const struct termios*); -/* _write(): retry interrupts, continue partial writes, assert errors. +/* u3_write_fd(): retry interrupts, continue partial writes, assert errors. */ -static void -_write(c3_i fid_i, const void* buf_v, size_t len_i) +void +u3_write_fd(c3_i fid_i, const void* buf_v, size_t len_i) { ssize_t ret_i; @@ -54,7 +44,7 @@ _write(c3_i fid_i, const void* buf_v, size_t len_i) // assert on true errors // - // NB: can't call u3l_log here or we would re-enter _write() + // NB: can't call u3l_log here or we would re-enter u3_write_fd() // if ( ret_i < 0 ) { fprintf(stderr, "term: write failed %s\r\n", strerror(errno)); @@ -133,28 +123,24 @@ _term_close_cb(uv_handle_t* han_t) void u3_term_log_init(void) { - u3_utty* uty_u = c3_calloc(sizeof(u3_utty)); + u3_utty* uty_u; if ( c3y == u3_Host.ops_u.tem ) { + uty_u = c3_calloc(sizeof(u3_utty)); uty_u->fid_i = 1; - uv_pipe_init(u3L, &(uty_u->pop_u), 0); - uv_pipe_open(&(uty_u->pop_u), uty_u->fid_i); + uv_pipe_init(u3L, &(uty_u->pin_u.pop_u), 0); + uv_pipe_init(u3L, &(uty_u->pop_u.pop_u), 0); + uv_pipe_open(&(uty_u->pop_u.pop_u), uty_u->fid_i); } else { // Initialize event processing. Rawdog it. // - { - uty_u->fid_i = 0; // stdin, yes we write to it... - - if ( !isatty(uty_u->fid_i) ) { - fprintf(stderr, "vere: unable to initialize terminal (not a tty)\r\n" - " use -t to disable interactivity\r\n"); - u3_king_bail(); - } - - uv_pipe_init(u3L, &(uty_u->pop_u), 0); - uv_pipe_open(&(uty_u->pop_u), uty_u->fid_i); + const c3_c* err_c; + if ( NULL == (uty_u = u3_ptty_init(u3L, &err_c)) ) { + fprintf(stderr, "vere: unable to initialize terminal (%s)\r\n" + " use -t to disable interactivity\r\n", err_c); + u3_king_bail(); } // configure output escape sequences @@ -187,33 +173,6 @@ u3_term_log_init(void) // uty_u->ufo_u.inn.kcub1_u = TERM_LIT_BUF("\033[D"); // terminfo reports "\033OD" // } - // Load old terminal state to restore. - // - { - if ( 0 != tcgetattr(uty_u->fid_i, &uty_u->bak_u) ) { - c3_assert(!"init-tcgetattr"); - } - if ( -1 == fcntl(uty_u->fid_i, F_GETFL, &uty_u->cug_i) ) { - c3_assert(!"init-fcntl"); - } - uty_u->cug_i &= ~O_NONBLOCK; // could fix? - uty_u->nob_i = uty_u->cug_i | O_NONBLOCK; // O_NDELAY on older unix - } - - // Construct raw termios configuration. - // - { - uty_u->raw_u = uty_u->bak_u; - - uty_u->raw_u.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); - uty_u->raw_u.c_iflag &= ~(ICRNL | INPCK | ISTRIP); - uty_u->raw_u.c_cflag &= ~(CSIZE | PARENB); - uty_u->raw_u.c_cflag |= CS8; - uty_u->raw_u.c_oflag &= ~(OPOST); - uty_u->raw_u.c_cc[VMIN] = 0; - uty_u->raw_u.c_cc[VTIME] = 0; - } - // Initialize mirror and accumulator state. // { @@ -254,18 +213,24 @@ u3_term_log_init(void) u3_Host.uty_u = uty_u; } + // Disable I/O buffering on terminal streams. + // This is not necessary if output is a tty, + // but helps when output is redirected. + // + { + fflush(stdout); + fflush(stderr); + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + } + // if terminal/tty is enabled // if ( c3n == u3_Host.ops_u.tem ) { // Start raw input. // - { - if ( 0 != _term_tcsetattr(uty_u->fid_i, TCSADRAIN, &uty_u->raw_u) ) { - c3_assert(!"init-tcsetattr"); - } - if ( -1 == fcntl(uty_u->fid_i, F_SETFL, uty_u->nob_i) ) { - c3_assert(!"init-fcntl"); - } + if ( c3n == uty_u->sta_f(uty_u) ) { + c3_assert(!"init-tcsetattr"); } // initialize spinner timeout @@ -287,42 +252,19 @@ u3_term_log_exit(void) for ( uty_u = u3_Host.uty_u; uty_u; uty_u = uty_u->nex_u ) { if ( uty_u->fid_i == -1 ) { continue; } - if ( 0 != _term_tcsetattr(uty_u->fid_i, TCSADRAIN, &uty_u->bak_u) ) { + if ( c3n == uty_u->sto_f(uty_u) ) { c3_assert(!"exit-tcsetattr"); } - if ( -1 == fcntl(uty_u->fid_i, F_SETFL, uty_u->cug_i) ) { - c3_assert(!"exit-fcntl"); - } - _write(uty_u->fid_i, "\r\n", 2); + u3_write_fd(uty_u->fid_i, "\r\n", 2); } } if ( u3_Host.uty_u ) { + uv_close((uv_handle_t*)&u3_Host.uty_u->pin_u, 0); uv_close((uv_handle_t*)&u3_Host.uty_u->pop_u, 0); } } -/* _term_tcsetattr(): tcsetattr w/retry on EINTR. -*/ -static c3_i -_term_tcsetattr(c3_i fil_i, c3_i act_i, const struct termios* tms_u) -{ - c3_i ret_i = 0; - c3_w len_w = 0; - - do { - // abort pathological retry loop - // - if ( 100 == ++len_w ) { - fprintf(stderr, "term: tcsetattr loop: %s\r\n", strerror(errno)); - return -1; - } - ret_i = tcsetattr(fil_i, act_i, tms_u); - } while ( (-1 == ret_i) && (EINTR == errno) ); - - return ret_i; -} - /* _term_it_write_cb(): general write callback. */ static void @@ -780,7 +722,7 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) else if ( 8 == cay_y || 127 == cay_y ) { _term_io_belt(uty_u, u3nc(c3__bac, u3_nul)); } - else if ( 13 == cay_y ) { + else if ( 13 == cay_y || 10 == cay_y ) { _term_io_belt(uty_u, u3nc(c3__ret, u3_nul)); } #if 0 @@ -926,11 +868,7 @@ _term_spin_step(u3_utty* uty_u) // { uv_buf_t lef_u = uty_u->ufo_u.out.cub1_u; - c3_i fid_i; - - if ( uv_fileno((uv_handle_t*)&uty_u->pop_u, &fid_i) ) { - return; - } + c3_i fid_i = uty_u->fid_i; // One-time cursor backoff. // @@ -1071,14 +1009,9 @@ u3_term_get_blew(c3_l tid_l) u3_utty* uty_u = _term_ef_get(tid_l); c3_l col_l, row_l; - struct winsize siz_u; - if ( (c3n == u3_Host.ops_u.tem) && - uty_u && (0 == ioctl(uty_u->fid_i, TIOCGWINSZ, &siz_u)) ) + if ( (c3y == u3_Host.ops_u.tem) || !uty_u || + (c3y != uty_u->wsz_f(uty_u, &col_l, &row_l)) ) { - col_l = siz_u.ws_col; - row_l = siz_u.ws_row; - } - else { col_l = 80; row_l = 24; } @@ -1460,32 +1393,18 @@ u3_term_io_hija(void) } else { if ( c3n == u3_Host.ops_u.tem ) { - if ( 0 != _term_tcsetattr(1, TCSADRAIN, &uty_u->bak_u) ) { - perror("hija-tcsetattr-1"); - c3_assert(!"hija-tcsetattr"); - } - if ( -1 == fcntl(1, F_SETFL, uty_u->cug_i) ) { - perror("hija-fcntl-1"); - c3_assert(!"hija-fcntl"); - } - if ( 0 != _term_tcsetattr(0, TCSADRAIN, &uty_u->bak_u) ) { - perror("hija-tcsetattr-0"); + if ( c3y != uty_u->hij_f(uty_u) ) { c3_assert(!"hija-tcsetattr"); } - if ( -1 == fcntl(0, F_SETFL, uty_u->cug_i) ) { - perror("hija-fcntl-0"); - c3_assert(!"hija-fcntl"); - } - _write(uty_u->fid_i, "\r", 1); + u3_write_fd(uty_u->fid_i, "\r", 1); { uv_buf_t* buf_u = &uty_u->ufo_u.out.el_u; - _write(uty_u->fid_i, buf_u->base, buf_u->len); + u3_write_fd(uty_u->fid_i, buf_u->base, buf_u->len); } } - return stdout; } } - else return stdout; + return stdout; } /* u3_term_io_loja(): release console from fprintf. @@ -1505,24 +1424,10 @@ u3_term_io_loja(int x) else { if ( c3y == u3_Host.ops_u.tem ) { fflush(stdout); - } - else { - if ( 0 != _term_tcsetattr(1, TCSADRAIN, &uty_u->raw_u) ) { - perror("loja-tcsetattr-1"); + } else { + if ( c3y != uty_u->loj_f(uty_u) ) { c3_assert(!"loja-tcsetattr"); } - if ( -1 == fcntl(1, F_SETFL, uty_u->nob_i) ) { - perror("hija-fcntl-1"); - c3_assert(!"loja-fcntl"); - } - if ( 0 != _term_tcsetattr(0, TCSADRAIN, &uty_u->raw_u) ) { - perror("loja-tcsetattr-0"); - c3_assert(!"loja-tcsetattr"); - } - if ( -1 == fcntl(0, F_SETFL, uty_u->nob_i) ) { - perror("hija-fcntl-0"); - c3_assert(!"loja-fcntl"); - } _term_it_refresh_line(uty_u); } } @@ -1599,7 +1504,7 @@ _term_io_talk(u3_auto* car_u) if ( c3n == u3_Host.ops_u.tem ) { u3_utty* uty_u = _term_main(); - uv_read_start((uv_stream_t*)&(uty_u->pop_u), + uv_read_start((uv_stream_t*)&(uty_u->pin_u), _term_alloc, _term_read_cb); } @@ -1760,11 +1665,11 @@ _term_io_exit(u3_auto* car_u) { u3_utty* uty_u = _term_main(); - // NB, closed in u3_term_log_exit() - // - uv_read_stop((uv_stream_t*)&(uty_u->pop_u)); - if ( c3n == u3_Host.ops_u.tem ) { + // NB, closed in u3_term_log_exit() + // + uv_read_stop((uv_stream_t*)&(uty_u->pin_u)); + uv_timer_t* han_u = &(uty_u->tat_u.sun_u.tim_u); han_u->data = car_u; diff --git a/pkg/urbit/vere/io/unix.c b/pkg/urbit/vere/io/unix.c index 44c97069f6..4526298bcd 100644 --- a/pkg/urbit/vere/io/unix.c +++ b/pkg/urbit/vere/io/unix.c @@ -2,15 +2,7 @@ ** */ #include "all.h" -#include -#include -#include -#include -#include -#include -#include #include - #include "vere/vere.h" struct _u3_umon; diff --git a/pkg/urbit/vere/king.c b/pkg/urbit/vere/king.c index fd8ba8c693..e61f6ee33c 100644 --- a/pkg/urbit/vere/king.c +++ b/pkg/urbit/vere/king.c @@ -2,13 +2,11 @@ ** ** the main loop of the daemon process */ -#include -#include -#include - #include "all.h" #include "vere/vere.h" #include "ur/ur.h" +#include +#include #include "ivory.h" @@ -217,8 +215,10 @@ _king_pier(u3_noun pier) ** XX deduplicate with dawn.c */ static size_t -_king_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, uv_buf_t* buf_u) +_king_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, void* buf_v) { + uv_buf_t* buf_u = buf_v; + size_t siz_t = uni_t * mem_t; buf_u->base = c3_realloc(buf_u->base, 1 + siz_t + buf_u->len); @@ -246,7 +246,7 @@ _king_get_atom(c3_c* url_c) exit(1); } - curl_easy_setopt(curl, CURLOPT_CAINFO, u3K.certs_c); + u3K.ssl_curl_f(curl); curl_easy_setopt(curl, CURLOPT_URL, url_c); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _king_curl_alloc); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&buf_u); @@ -546,7 +546,7 @@ _king_sign_init(void) // handle SIGINFO (if available) // -#ifndef U3_OS_linux +#ifdef SIGINFO { u3_usig* sig_u; @@ -592,6 +592,10 @@ _king_sign_cb(uv_signal_t* sil_u, c3_i num_i) case SIGINT: { u3l_log("\r\ninterrupt\r\n"); u3_term_ef_ctlc(); + + #if defined(U3_OS_mingw) + PulseEvent(u3_Host.cev_u); + #endif break; } @@ -602,7 +606,7 @@ _king_sign_cb(uv_signal_t* sil_u, c3_i num_i) // fallthru if defined // -#ifndef U3_OS_linux +#ifdef SIGINFO case SIGINFO: #endif case SIGUSR1: { @@ -679,7 +683,6 @@ _king_loop_init() void _king_loop_exit() { - unlink(u3K.certs_c); } static void @@ -752,12 +755,14 @@ u3_king_commence() u3C.sign_move_f = _king_sign_move; // Ignore SIGPIPE signals. + #ifndef U3_OS_mingw { struct sigaction sig_s = {{0}}; sigemptyset(&(sig_s.sa_mask)); sig_s.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sig_s, 0); } + #endif // boot the ivory pill // @@ -765,6 +770,7 @@ u3_king_commence() // disable core dumps (due to lmdb size) // + #ifndef U3_OS_mingw { struct rlimit rlm; @@ -776,6 +782,7 @@ u3_king_commence() exit(1); } } + #endif // run the loop // diff --git a/pkg/urbit/vere/lord.c b/pkg/urbit/vere/lord.c index b910da1fd3..25ffe60962 100644 --- a/pkg/urbit/vere/lord.c +++ b/pkg/urbit/vere/lord.c @@ -1,21 +1,5 @@ /* vere/lord.c */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" #include "ur/hashcons.h" @@ -157,6 +141,8 @@ _lord_stop(u3_lord* god_u) u3_newt_moat_stop(&god_u->out_u, _lord_stop_cb); u3_newt_mojo_stop(&god_u->inn_u, _lord_bail_noop); + uv_read_stop((uv_stream_t*)&(god_u->err_u)); + uv_close((uv_handle_t*)&god_u->cub_u, 0); #if defined(LORD_TRACE_JAM) || defined(LORD_TRACE_CUE) @@ -1044,6 +1030,42 @@ u3_lord_halt(u3_lord* god_u) _lord_stop(god_u); } +/* _lord_serf_err_alloc(): libuv buffer allocator. +*/ +static void +_lord_serf_err_alloc(uv_handle_t* had_u, size_t len_i, uv_buf_t* buf) +{ + // error/info messages as a rule don't exceed one line + // + *buf = uv_buf_init(c3_malloc(80), 80); +} + +/* _lord_on_serf_err_cb(): subprocess stderr callback. +*/ +static void +_lord_on_serf_err_cb(uv_stream_t* pyp_u, + ssize_t siz_i, + const uv_buf_t* buf_u) +{ + if ( siz_i >= 0 ) { + // serf used to write to 2 directly + // this can't be any worse than that + // + u3_write_fd(2, buf_u->base, siz_i); + } else { + uv_read_stop(pyp_u); + + if ( siz_i != UV_EOF ) { + u3l_log("lord: serf stderr: %s\r\n", uv_strerror(siz_i)); + } + } + + if ( buf_u->base != NULL ) { + c3_free(buf_u->base); + } +} + + /* _lord_on_serf_exit(): handle subprocess exit. */ static void @@ -1123,6 +1145,7 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) c3_c key_c[256]; c3_c wag_c[11]; c3_c hap_c[11]; + c3_c cev_c[11]; c3_i err_i; sprintf(key_c, "%" PRIx64 ":%" PRIx64 ":%" PRIx64 ":%" PRIx64 "", @@ -1151,11 +1174,18 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) arg_c[6] = "0"; } + #if defined(U3_OS_mingw) + sprintf(cev_c, "%u", u3_Host.cev_u); + arg_c[7] = cev_c; + arg_c[8] = 0; + #else arg_c[7] = 0; + #endif uv_pipe_init(u3L, &god_u->inn_u.pyp_u, 0); uv_timer_init(u3L, &god_u->out_u.tim_u); uv_pipe_init(u3L, &god_u->out_u.pyp_u, 0); + uv_pipe_init(u3L, &god_u->err_u, 0); god_u->cod_u[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; god_u->cod_u[0].data.stream = (uv_stream_t *)&god_u->inn_u; @@ -1163,12 +1193,14 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) god_u->cod_u[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; god_u->cod_u[1].data.stream = (uv_stream_t *)&god_u->out_u; - god_u->cod_u[2].flags = UV_INHERIT_FD; - god_u->cod_u[2].data.fd = 2; + god_u->cod_u[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + god_u->cod_u[2].data.stream = (uv_stream_t *)&god_u->err_u; god_u->ops_u.stdio = god_u->cod_u; god_u->ops_u.stdio_count = 3; + // if any fds are inherited, libuv ignores UV_PROCESS_WINDOWS_HIDE* + god_u->ops_u.flags = UV_PROCESS_WINDOWS_HIDE; god_u->ops_u.exit_cb = _lord_on_serf_exit; god_u->ops_u.file = arg_c[0]; god_u->ops_u.args = arg_c; @@ -1178,6 +1210,8 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) return 0; } + + uv_read_start((uv_stream_t *)&god_u->err_u, _lord_serf_err_alloc, _lord_on_serf_err_cb); } #if defined(LORD_TRACE_JAM) || defined(LORD_TRACE_CUE) diff --git a/pkg/urbit/vere/newt.c b/pkg/urbit/vere/newt.c index d96c7197d2..6325f0ef90 100644 --- a/pkg/urbit/vere/newt.c +++ b/pkg/urbit/vere/newt.c @@ -9,22 +9,6 @@ ** the implementation is relatively inefficient and could ** lose a few copies, mallocs, etc. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" diff --git a/pkg/urbit/vere/pier.c b/pkg/urbit/vere/pier.c index 8735d79d21..d9f9dac1ca 100644 --- a/pkg/urbit/vere/pier.c +++ b/pkg/urbit/vere/pier.c @@ -1,26 +1,9 @@ /* vere/pier.c */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" - -#include +#include "vere/db/lmdb.h" +#include #define PIER_READ_BATCH 1000ULL #define PIER_PLAY_BATCH 500ULL @@ -1628,7 +1611,7 @@ u3_pier_stay(c3_w wag_w, u3_noun pax) if ( c3y == u3_Host.ops_u.veb ) { FILE* fil_u = u3_term_io_hija(); u3_lmdb_stat(pir_u->log_u->mdb_u, fil_u); - u3_term_io_loja(1 ); + u3_term_io_loja(1); } u3z(pax); diff --git a/pkg/urbit/vere/save.c b/pkg/urbit/vere/save.c index e2c042b243..b2fc5b3904 100644 --- a/pkg/urbit/vere/save.c +++ b/pkg/urbit/vere/save.c @@ -1,13 +1,6 @@ /* vere/save.c ** */ -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" @@ -20,6 +13,7 @@ _save_time_cb(uv_timer_t* tim_u) u3_pier_save(pir_u); } +#if 0 /* u3_save_ef_chld(): report save termination. */ void @@ -41,6 +35,7 @@ u3_save_ef_chld(u3_pier *pir_u) } sav_u->pid_w = 0; } +#endif /* u3_save_io_init(): initialize autosave. */ diff --git a/pkg/urbit/vere/time.c b/pkg/urbit/vere/time.c index e67046ba22..6e41c1e56a 100644 --- a/pkg/urbit/vere/time.c +++ b/pkg/urbit/vere/time.c @@ -1,12 +1,6 @@ /* vere/time.c ** */ -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" @@ -104,7 +98,7 @@ u3_time_in_ts(struct timespec* tim_ts) return u3_time_in_tv(&tim_tv); } -#if defined(U3_OS_linux) +#if defined(U3_OS_linux) || defined(U3_OS_mingw) /* u3_time_t_in_ts(): urbit time from time_t. */ u3_atom @@ -117,7 +111,7 @@ u3_time_t_in_ts(time_t tim) return u3_time_in_tv(&tim_tv); } -#endif // defined(U3_OS_linux) +#endif // defined(U3_OS_linux) || defined(U3_OS_mingw) /* u3_time_out_ts(): struct timespec from urbit time. */ diff --git a/pkg/urbit/vere/walk.c b/pkg/urbit/vere/walk.c index 1f7095a188..5c113cbac7 100644 --- a/pkg/urbit/vere/walk.c +++ b/pkg/urbit/vere/walk.c @@ -1,13 +1,6 @@ /* vere/walk.c ** */ -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" diff --git a/pkg/urbit/vere/ward.c b/pkg/urbit/vere/ward.c index f4db6badf7..f0c4260200 100644 --- a/pkg/urbit/vere/ward.c +++ b/pkg/urbit/vere/ward.c @@ -1,21 +1,5 @@ /* vere/ward.c */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include "vere/vere.h" diff --git a/pkg/urbit/worker/main.c b/pkg/urbit/worker/main.c index 46895f093b..b44add6170 100644 --- a/pkg/urbit/worker/main.c +++ b/pkg/urbit/worker/main.c @@ -2,23 +2,8 @@ ** ** the main loop of a serf process. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" +#include "rsignal.h" #include #include @@ -146,7 +131,7 @@ _cw_serf_stdio(c3_i* inn_i, c3_i* out_i) // we replace [FD 0] (stdin) with a fd pointing to /dev/null // we replace [FD 1] (stdout) with a dup of [FD 2] (stderr) // - c3_i nul_i = open("/dev/null", O_RDWR, 0); + c3_i nul_i = open(c3_dev_null, O_RDWR, 0); *inn_i = dup(0); *out_i = dup(1); @@ -155,6 +140,11 @@ _cw_serf_stdio(c3_i* inn_i, c3_i* out_i) dup2(2, 1); close(nul_i); + + // set stream I/O to unbuffered because it's now a pipe not a console + // + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); } /* _cw_serf_stdio(): cleanup on serf exit. @@ -166,6 +156,16 @@ _cw_serf_exit(void) u3t_trace_close(); } +#if defined(U3_OS_mingw) +/* _mingw_ctrlc_cb(): invoked when the lord signals the Ctrl-C event +*/ +static void +_mingw_ctrlc_cb(PVOID param, BOOLEAN timedOut) +{ + rsignal_raise(SIGINT); +} +#endif + /* _cw_serf_commence(); initialize and run serf */ static void @@ -174,7 +174,23 @@ _cw_serf_commence(c3_i argc, c3_c* argv[]) c3_i inn_i, out_i; _cw_serf_stdio(&inn_i, &out_i); + #if defined(U3_OS_mingw) + c3_assert( 8 == argc ); + + // Initialize serf's end of Ctrl-C handling + // + { + HANDLE h; + if ( 1 != sscanf(argv[7], "%u", &h) ) { + fprintf(stderr, "serf: Ctrl-C event: bad handle %s: %s\r\n", argv[7], strerror(errno)); + } else + if ( !RegisterWaitForSingleObject(&h, h, _mingw_ctrlc_cb, NULL, INFINITE, 0) ) { + fprintf(stderr, "serf: Ctrl-C event: RegisterWaitForSingleObject(%u) failed (%d)\r\n", h, GetLastError()); + } + } + #else c3_assert( 7 == argc ); + #endif uv_loop_t* lup_u = uv_default_loop(); c3_c* dir_c = argv[2]; @@ -211,12 +227,14 @@ _cw_serf_commence(c3_i argc, c3_c* argv[]) // Ignore SIGPIPE signals. // + #ifndef U3_OS_mingw { struct sigaction sig_s = {{0}}; sigemptyset(&(sig_s.sa_mask)); sig_s.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sig_s, 0); } + #endif // configure pipe to daemon process // @@ -444,7 +462,11 @@ _cw_usage(c3_i argc, c3_c* argv[]) " cue persistent state:\n" " %s queu \n\n" " run as a 'serf':\n" - " %s serf \n", + " %s serf " + #if defined(U3_OS_mingw) + " " + #endif + "\n", argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0]); } diff --git a/pkg/urbit/worker/serf.c b/pkg/urbit/worker/serf.c index 1173ae344f..8ed603b90f 100644 --- a/pkg/urbit/worker/serf.c +++ b/pkg/urbit/worker/serf.c @@ -1,21 +1,5 @@ /* worker/serf.c */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "all.h" #include #include