mirror of
https://github.com/urbit/shrub.git
synced 2024-12-01 06:35:32 +03:00
Separated new-vere executables into separate package for faster builds.
This commit is contained in:
parent
54fc5f6078
commit
3e518f4d99
@ -1,184 +0,0 @@
|
||||
{-
|
||||
TODO When is `u3_behn_io_init` called?
|
||||
-}
|
||||
|
||||
data Pier
|
||||
data Timer
|
||||
|
||||
data Wen = Wen Noun Noun Noun
|
||||
|
||||
data TimeVal = TimeVal
|
||||
{ tv_sec :: time_t -- seconds
|
||||
, tv_usec :: suseconds_t -- microseconds
|
||||
}
|
||||
|
||||
data Event
|
||||
= Wake
|
||||
| Born
|
||||
|
||||
data Wire
|
||||
= Blip -- Empty path
|
||||
| Behn
|
||||
| Sen Text -- "an instance string"
|
||||
|
||||
newtype Knot = Knot Text
|
||||
|
||||
newtype Wire = Wire [Knot]
|
||||
|
||||
data Duct = [Wire]
|
||||
|
||||
data Blip = Blip Behn (Maybe Void)
|
||||
|
||||
|
||||
{-
|
||||
alm -- is timer active?
|
||||
tim -- timer
|
||||
data -- associated pier
|
||||
-}
|
||||
data Behn = Behn
|
||||
{ _alm :: TVar Bool
|
||||
, _tim :: TVar Timer
|
||||
, _data :: TVar Pier
|
||||
}
|
||||
|
||||
makeLenses ''Behn
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
newTimer :: IO Timer
|
||||
newTimer = undefined
|
||||
|
||||
init :: Pier -> IO ()
|
||||
init p =
|
||||
timer <- newTimer
|
||||
atomically $ do
|
||||
writeTVar (p ^. teh.alm) False
|
||||
writeTVar (p ^. teh.tim) timer
|
||||
writeTVar (p ^. teh.data) p
|
||||
|
||||
exit :: Pier -> IO ()
|
||||
exit _ = pure ()
|
||||
|
||||
doze :: Pier -> Maybe Wen -> IO ()
|
||||
doze pir mWen = do
|
||||
(active, timer) <- do
|
||||
(,) <$> readTVarIO (pir ^. teh.alm)
|
||||
<*> readTVarIO (pir ^. teh.tim)
|
||||
|
||||
if active
|
||||
then stopTimer timer -- TODO Race condition
|
||||
else pure ()
|
||||
|
||||
case mWen of
|
||||
Nothing -> pure ()
|
||||
Just (Wen x y z) -> do
|
||||
timeVal <- getTimeOfDay
|
||||
let now = u3_time_in_tv timeVal
|
||||
let gap = u3_time_gap_ms(y, z)
|
||||
writeTVar (p ^. teh.alm) True
|
||||
startTimer timer gap $ do
|
||||
u3_pier *pir_u = tim_u->data;
|
||||
u3_behn* teh_u = pir_u->teh_u;
|
||||
writeTVar (p ^. teh.alm) False;
|
||||
pierWork pir [Blip Behn] Wake
|
||||
|
||||
bake :: Pier -> IO ()
|
||||
bake = do
|
||||
sen <- readTVarIO (u3A ^. sen)
|
||||
pierWork pir [Blip Behn (Sen sen)] Born
|
||||
|
||||
/* u3_behn_ef_bake(): notify %behn that we're live
|
||||
*/
|
||||
void
|
||||
u3_behn_ef_bake(u3_pier *pir_u)
|
||||
{
|
||||
u3_noun pax = u3nq(u3_blip, c3__behn, u3k(u3A->sen), u3_nul);
|
||||
|
||||
u3_pier_work(pir_u, pax, u3nc(c3__born, u3_nul));
|
||||
}
|
||||
|
||||
|
||||
{-
|
||||
u3_time_in_tv timeVal
|
||||
u3_time_gap_ms(y, z)
|
||||
u3nt(u3_blip, c3__behn, u3_nul),
|
||||
u3nc(c3__wake, u3_nul));
|
||||
-}
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
/* u3_behn(): initialize time timer.
|
||||
*/
|
||||
void
|
||||
u3_behn_io_init(u3_pier *pir_u)
|
||||
{
|
||||
u3_behn* teh_u = pir_u->teh_u;
|
||||
teh_u->alm = c3n;
|
||||
|
||||
uv_timer_init(u3L, &teh_u->tim_u);
|
||||
teh_u->tim_u.data = pir_u;
|
||||
}
|
||||
|
||||
/* u3_behn_io_exit(): terminate timer.
|
||||
*/
|
||||
void
|
||||
u3_behn_io_exit(u3_pier *pir_u)
|
||||
{
|
||||
}
|
||||
|
||||
/* _behn_time_cb(): timer callback.
|
||||
*/
|
||||
static void
|
||||
_behn_time_cb(uv_timer_t* tim_u)
|
||||
{
|
||||
u3_pier *pir_u = tim_u->data;
|
||||
u3_behn* teh_u = pir_u->teh_u;
|
||||
teh_u->alm = c3n;
|
||||
|
||||
{
|
||||
u3_pier_work
|
||||
(pir_u,
|
||||
u3nt(u3_blip, c3__behn, u3_nul),
|
||||
u3nc(c3__wake, u3_nul));
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_behn_ef_doze(): set or cancel timer
|
||||
*/
|
||||
void
|
||||
u3_behn_ef_doze(u3_pier *pir_u, u3_noun wen)
|
||||
{
|
||||
u3_behn* teh_u = pir_u->teh_u;
|
||||
|
||||
if ( c3y == teh_u->alm ) {
|
||||
uv_timer_stop(&teh_u->tim_u);
|
||||
teh_u->alm = c3n;
|
||||
}
|
||||
|
||||
if ( (u3_nul != wen) &&
|
||||
(c3y == u3du(wen)) &&
|
||||
(c3y == u3ud(u3t(wen))) )
|
||||
{
|
||||
struct timeval tim_tv;
|
||||
gettimeofday(&tim_tv, 0);
|
||||
|
||||
u3_noun now = u3_time_in_tv(&tim_tv);
|
||||
c3_d gap_d = u3_time_gap_ms(now, u3k(u3t(wen)));
|
||||
|
||||
teh_u->alm = c3y;
|
||||
uv_timer_start(&teh_u->tim_u, _behn_time_cb, gap_d, 0);
|
||||
}
|
||||
|
||||
u3z(wen);
|
||||
}
|
||||
|
||||
/* u3_behn_ef_bake(): notify %behn that we're live
|
||||
*/
|
||||
void
|
||||
u3_behn_ef_bake(u3_pier *pir_u)
|
||||
{
|
||||
u3_noun pax = u3nq(u3_blip, c3__behn, u3k(u3A->sen), u3_nul);
|
||||
|
||||
u3_pier_work(pir_u, pax, u3nc(c3__born, u3_nul));
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import ClassyPrelude hiding (atomically, newTVarIO)
|
||||
import Control.Lens
|
||||
import Control.Concurrent
|
||||
import Control.Concurrent.STM
|
||||
import Control.Concurrent.STM.TBMQueue
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
newtype Cpu st ev fx = Cpu { runCpu :: st -> ev -> (st, fx) }
|
||||
|
||||
data CpuApi ev st fx = CpuApi
|
||||
{ caHalt :: IO ()
|
||||
, caInput :: TBMQueue ev
|
||||
, caOutput :: TBMQueue (st, fx)
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
dummyCpu :: Cpu () () ()
|
||||
dummyCpu = Cpu $ (\() () -> ((), ()))
|
||||
|
||||
runCpuIO :: Cpu st ev fx
|
||||
-> TVar st
|
||||
-> TBMQueue ev
|
||||
-> TBMQueue (st, fx)
|
||||
-> IO ()
|
||||
runCpuIO cpu vSt inp out =
|
||||
forever $ atomically $ do
|
||||
ev <- readTBMQueue inp >>= maybe (error "No more input") pure
|
||||
st <- readTVar vSt
|
||||
runCpu cpu st ev & \(st', fx) -> do
|
||||
writeTVar vSt st'
|
||||
writeTBMQueue out (st', fx)
|
||||
|
||||
runCpuThread :: Cpu st ev fx
|
||||
-> st
|
||||
-> IO (CpuApi ev st fx)
|
||||
runCpuThread cpu init = do
|
||||
inp <- newTBMQueueIO 1
|
||||
out <- newTBMQueueIO 16
|
||||
vSt <- newTVarIO init
|
||||
tid <- forkIO (runCpuIO cpu vSt inp out)
|
||||
|
||||
let kill = do atomically (closeTBMQueue inp >> closeTBMQueue out)
|
||||
killThread tid
|
||||
|
||||
pure (CpuApi kill inp out)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
{-
|
||||
- When an event comes in:
|
||||
- process the event
|
||||
- persist the event
|
||||
- run the effects
|
||||
|
||||
- Take a snapshot at any time.
|
||||
-}
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
cpuProc <- runCpuThread dummyCpu ()
|
||||
caHalt cpuProc
|
@ -1,563 +0,0 @@
|
||||
/* vere/ames.c
|
||||
**
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <uv.h>
|
||||
#include <errno.h>
|
||||
#include <ncurses/curses.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses/term.h>
|
||||
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* _ames_alloc(): libuv buffer allocator.
|
||||
*/
|
||||
static void
|
||||
_ames_alloc(uv_handle_t* had_u,
|
||||
size_t len_i,
|
||||
uv_buf_t* buf
|
||||
)
|
||||
{
|
||||
// we allocate 2K, which gives us plenty of space
|
||||
// for a single ames packet (max size 1060 bytes)
|
||||
//
|
||||
void* ptr_v = c3_malloc(2048);
|
||||
*buf = uv_buf_init(ptr_v, 2048);
|
||||
}
|
||||
|
||||
/* _ames_free(): contrasting free.
|
||||
*/
|
||||
static void
|
||||
_ames_free(void* ptr_v)
|
||||
{
|
||||
// u3l_log("free %p\n", ptr_v);
|
||||
free(ptr_v);
|
||||
}
|
||||
|
||||
/* _ames_pact_free(): free packet struct.
|
||||
*/
|
||||
static void
|
||||
_ames_pact_free(u3_pact* pac_u)
|
||||
{
|
||||
free(pac_u->hun_y);
|
||||
free(pac_u->dns_c);
|
||||
free(pac_u);
|
||||
}
|
||||
|
||||
/* _ames_send_cb(): send callback.
|
||||
*/
|
||||
static void
|
||||
_ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i)
|
||||
{
|
||||
u3_pact* pac_u = (u3_pact*)req_u;
|
||||
|
||||
#if 0
|
||||
if ( 0 != sas_i ) {
|
||||
u3l_log("ames: send_cb: %s\n", uv_strerror(sas_i));
|
||||
}
|
||||
#endif
|
||||
|
||||
_ames_pact_free(pac_u);
|
||||
}
|
||||
|
||||
/* _ames_send(): send buffer to address on port.
|
||||
*/
|
||||
static void
|
||||
_ames_send(u3_pact* pac_u)
|
||||
{
|
||||
// XX revisit
|
||||
u3_pier* pir_u = u3_pier_stub();
|
||||
u3_ames* sam_u = pir_u->sam_u;
|
||||
|
||||
if ( !pac_u->hun_y ) {
|
||||
_ames_pact_free(pac_u);
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in add_u;
|
||||
|
||||
memset(&add_u, 0, sizeof(add_u));
|
||||
add_u.sin_family = AF_INET;
|
||||
add_u.sin_addr.s_addr = htonl(pac_u->pip_w);
|
||||
add_u.sin_port = htons(pac_u->por_s);
|
||||
|
||||
uv_buf_t buf_u = uv_buf_init((c3_c*)pac_u->hun_y, pac_u->len_w);
|
||||
|
||||
c3_i sas_i;
|
||||
|
||||
if ( 0 != (sas_i = uv_udp_send(&pac_u->snd_u,
|
||||
&sam_u->wax_u,
|
||||
&buf_u, 1,
|
||||
(const struct sockaddr*)&add_u,
|
||||
_ames_send_cb)) ) {
|
||||
u3l_log("ames: send: %s\n", uv_strerror(sas_i));
|
||||
}
|
||||
}
|
||||
|
||||
/* _ames_czar_port(): udp port for galaxy.
|
||||
*/
|
||||
static c3_s
|
||||
_ames_czar_port(c3_y imp_y)
|
||||
{
|
||||
if ( c3n == u3_Host.ops_u.net ) {
|
||||
return 31337 + imp_y;
|
||||
}
|
||||
else {
|
||||
return 13337 + imp_y;
|
||||
}
|
||||
}
|
||||
|
||||
/* _ames_czar_gone(): galaxy address resolution failed.
|
||||
*/
|
||||
static void
|
||||
_ames_czar_gone(u3_pact* pac_u, time_t now)
|
||||
{
|
||||
// XX revisit
|
||||
u3_pier* pir_u = u3_pier_stub();
|
||||
u3_ames* sam_u = pir_u->sam_u;
|
||||
|
||||
u3l_log("ames: czar at %s: not found (b)\n", pac_u->dns_c);
|
||||
if ( (0 == sam_u->imp_w[pac_u->imp_y]) ||
|
||||
(0xffffffff == sam_u->imp_w[pac_u->imp_y]) ) {
|
||||
sam_u->imp_w[pac_u->imp_y] = 0xffffffff;
|
||||
} /* else keep existing ip for 5 more minutes */
|
||||
sam_u->imp_t[pac_u->imp_y] = now;
|
||||
|
||||
_ames_pact_free(pac_u);
|
||||
}
|
||||
|
||||
/* _ames_czar_cb(): galaxy address resolution callback.
|
||||
*/
|
||||
static void
|
||||
_ames_czar_cb(uv_getaddrinfo_t* adr_u,
|
||||
c3_i sas_i,
|
||||
struct addrinfo* aif_u)
|
||||
{
|
||||
// XX revisit
|
||||
u3_pier* pir_u = u3_pier_stub();
|
||||
u3_ames* sam_u = pir_u->sam_u;
|
||||
|
||||
u3_pact* pac_u = (u3_pact*)adr_u->data;
|
||||
time_t now = time(0);
|
||||
|
||||
struct addrinfo* rai_u = aif_u;
|
||||
|
||||
while ( 1 ) {
|
||||
if ( !rai_u ) {
|
||||
_ames_czar_gone(pac_u, now);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( (AF_INET == rai_u->ai_family) ) {
|
||||
struct sockaddr_in* add_u = (struct sockaddr_in *)rai_u->ai_addr;
|
||||
c3_w old_w = sam_u->imp_w[pac_u->imp_y];
|
||||
|
||||
sam_u->imp_w[pac_u->imp_y] = ntohl(add_u->sin_addr.s_addr);
|
||||
sam_u->imp_t[pac_u->imp_y] = now;
|
||||
|
||||
#if 1
|
||||
if ( sam_u->imp_w[pac_u->imp_y] != old_w
|
||||
&& sam_u->imp_w[pac_u->imp_y] != 0xffffffff ) {
|
||||
u3_noun wad = u3i_words(1, &sam_u->imp_w[pac_u->imp_y]);
|
||||
u3_noun nam = u3dc("scot", c3__if, wad);
|
||||
c3_c* nam_c = u3r_string(nam);
|
||||
|
||||
u3l_log("ames: czar %s: ip %s\n", pac_u->dns_c, nam_c);
|
||||
|
||||
free(nam_c); u3z(nam);
|
||||
}
|
||||
#endif
|
||||
|
||||
_ames_send(pac_u);
|
||||
break;
|
||||
}
|
||||
|
||||
rai_u = rai_u->ai_next;
|
||||
}
|
||||
|
||||
free(adr_u);
|
||||
uv_freeaddrinfo(aif_u);
|
||||
}
|
||||
|
||||
|
||||
/* _ames_czar(): galaxy address resolution.
|
||||
*/
|
||||
static void
|
||||
_ames_czar(u3_pact* pac_u, c3_c* bos_c)
|
||||
{
|
||||
// XX revisit
|
||||
u3_pier* pir_u = u3_pier_stub();
|
||||
u3_ames* sam_u = pir_u->sam_u;
|
||||
|
||||
pac_u->por_s = _ames_czar_port(pac_u->imp_y);
|
||||
|
||||
if ( c3n == u3_Host.ops_u.net ) {
|
||||
pac_u->pip_w = 0x7f000001;
|
||||
_ames_send(pac_u);
|
||||
return;
|
||||
}
|
||||
|
||||
// if we don't have a galaxy domain, no-op
|
||||
//
|
||||
if ( 0 == bos_c ) {
|
||||
u3_noun nam = u3dc("scot", 'p', pac_u->imp_y);
|
||||
c3_c* nam_c = u3r_string(nam);
|
||||
u3l_log("ames: no galaxy domain for %s, no-op\r\n", nam_c);
|
||||
|
||||
free(nam_c);
|
||||
u3z(nam);
|
||||
return;
|
||||
}
|
||||
|
||||
time_t now = time(0);
|
||||
|
||||
// backoff
|
||||
if ( (0xffffffff == sam_u->imp_w[pac_u->imp_y]) &&
|
||||
(now - sam_u->imp_t[pac_u->imp_y]) < 300 ) {
|
||||
_ames_pact_free(pac_u);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (0 == sam_u->imp_w[pac_u->imp_y]) ||
|
||||
(now - sam_u->imp_t[pac_u->imp_y]) > 300 ) { /* 5 minute TTL */
|
||||
u3_noun nam = u3dc("scot", 'p', pac_u->imp_y);
|
||||
c3_c* nam_c = u3r_string(nam);
|
||||
// XX remove extra byte for '~'
|
||||
pac_u->dns_c = c3_malloc(1 + strlen(bos_c) + 1 + strlen(nam_c));
|
||||
|
||||
snprintf(pac_u->dns_c, 256, "%s.%s", nam_c + 1, bos_c);
|
||||
// u3l_log("czar %s, dns %s\n", nam_c, pac_u->dns_c);
|
||||
|
||||
free(nam_c);
|
||||
u3z(nam);
|
||||
|
||||
{
|
||||
uv_getaddrinfo_t* adr_u = c3_malloc(sizeof(*adr_u));
|
||||
adr_u->data = pac_u;
|
||||
|
||||
c3_i sas_i;
|
||||
|
||||
if ( 0 != (sas_i = uv_getaddrinfo(u3L, adr_u,
|
||||
_ames_czar_cb,
|
||||
pac_u->dns_c, 0, 0)) ) {
|
||||
u3l_log("ames: %s\n", uv_strerror(sas_i));
|
||||
_ames_czar_gone(pac_u, now);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
pac_u->pip_w = sam_u->imp_w[pac_u->imp_y];
|
||||
_ames_send(pac_u);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* _ames_lane_ipv4(): IPv4 address/ from lane.
|
||||
*/
|
||||
u3_noun
|
||||
_ames_lane_ip(u3_noun lan, c3_s* por_s, c3_w* pip_w)
|
||||
{
|
||||
switch ( u3h(lan) ) {
|
||||
case c3__if: {
|
||||
*por_s= (c3_s) u3h(u3t(u3t(lan)));
|
||||
*pip_w = u3r_word(0, u3t(u3t(u3t(lan))));
|
||||
|
||||
return c3y;
|
||||
} break;
|
||||
case c3__is: {
|
||||
u3_noun pq_lan = u3h(u3t(u3t(lan)));
|
||||
|
||||
if ( u3_nul == pq_lan ) return c3n;
|
||||
else return _ames_lane_ip(u3t(pq_lan), por_s, pip_w);
|
||||
} break;
|
||||
case c3__ix: {
|
||||
*por_s = (c3_s) u3h(u3t(u3t(lan)));
|
||||
*pip_w = u3r_word(0, u3t(u3t(u3t(lan))));
|
||||
|
||||
return c3y;
|
||||
} break;
|
||||
}
|
||||
return c3n;
|
||||
}
|
||||
|
||||
/* u3_ames_ef_bake(): notify %ames that we're live.
|
||||
*/
|
||||
void
|
||||
u3_ames_ef_bake(u3_pier* pir_u)
|
||||
{
|
||||
u3_noun pax = u3nq(u3_blip, c3__newt, u3k(u3A->sen), u3_nul);
|
||||
|
||||
u3_pier_plan(pax, u3nc(c3__barn, u3_nul));
|
||||
}
|
||||
|
||||
/* u3_ames_ef_send(): send packet to network (v4).
|
||||
*/
|
||||
void
|
||||
u3_ames_ef_send(u3_pier* pir_u, u3_noun lan, u3_noun pac)
|
||||
{
|
||||
u3_ames* sam_u = pir_u->sam_u;
|
||||
|
||||
if ( u3_Host.ops_u.fuz_w && ((rand() % 100) < u3_Host.ops_u.fuz_w) ) {
|
||||
u3z(lan); u3z(pac);
|
||||
return;
|
||||
}
|
||||
|
||||
u3_pact* pac_u = c3_calloc(sizeof(*pac_u));
|
||||
|
||||
if ( c3y == _ames_lane_ip(lan, &pac_u->por_s, &pac_u->pip_w) ) {
|
||||
pac_u->len_w = u3r_met(3, pac);
|
||||
pac_u->hun_y = c3_malloc(pac_u->len_w);
|
||||
|
||||
u3r_bytes(0, pac_u->len_w, pac_u->hun_y, pac);
|
||||
|
||||
if ( 0 == pac_u->pip_w ) {
|
||||
pac_u->pip_w = 0x7f000001;
|
||||
pac_u->por_s = pir_u->por_s;
|
||||
}
|
||||
|
||||
if ( (0 == (pac_u->pip_w >> 16)) && (1 == (pac_u->pip_w >> 8)) ) {
|
||||
pac_u->imp_y = (pac_u->pip_w & 0xff);
|
||||
|
||||
_ames_czar(pac_u, sam_u->dns_c);
|
||||
}
|
||||
else if ( (c3y == u3_Host.ops_u.net) || (0x7f000001 == pac_u->pip_w) ) {
|
||||
_ames_send(pac_u);
|
||||
}
|
||||
else {
|
||||
// networking disabled
|
||||
_ames_pact_free(pac_u);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_ames_pact_free(pac_u);
|
||||
}
|
||||
|
||||
u3z(lan); u3z(pac);
|
||||
}
|
||||
|
||||
/* _ames_recv_cb(): receive callback.
|
||||
*/
|
||||
static void
|
||||
_ames_recv_cb(uv_udp_t* wax_u,
|
||||
ssize_t nrd_i,
|
||||
const uv_buf_t * buf_u,
|
||||
const struct sockaddr* adr_u,
|
||||
unsigned flg_i)
|
||||
{
|
||||
// u3l_log("ames: rx %p\r\n", buf_u.base);
|
||||
|
||||
if ( 0 == nrd_i ) {
|
||||
_ames_free(buf_u->base);
|
||||
}
|
||||
else {
|
||||
{
|
||||
u3_noun msg = u3i_bytes((c3_w)nrd_i, (c3_y*)buf_u->base);
|
||||
|
||||
// u3l_log("ames: plan\r\n");
|
||||
#if 0
|
||||
u3z(msg);
|
||||
#else
|
||||
struct sockaddr_in* add_u = (struct sockaddr_in *)adr_u;
|
||||
c3_s por_s = ntohs(add_u->sin_port);
|
||||
c3_w pip_w = ntohl(add_u->sin_addr.s_addr);
|
||||
|
||||
u3_pier_plan
|
||||
(u3nt(u3_blip, c3__ames, u3_nul),
|
||||
u3nt(c3__hear,
|
||||
u3nq(c3__if, u3k(u3A->now), por_s, u3i_words(1, &pip_w)),
|
||||
msg));
|
||||
#endif
|
||||
}
|
||||
_ames_free(buf_u->base);
|
||||
}
|
||||
}
|
||||
|
||||
/* _ames_io_start(): initialize ames I/O.
|
||||
*/
|
||||
static void
|
||||
_ames_io_start(u3_pier* pir_u)
|
||||
{
|
||||
u3_ames* sam_u = pir_u->sam_u;
|
||||
c3_s por_s = pir_u->por_s;
|
||||
u3_noun who = u3i_chubs(2, pir_u->who_d);
|
||||
u3_noun rac = u3do("clan:title", u3k(who));
|
||||
|
||||
if ( c3__czar == rac ) {
|
||||
u3_noun imp = u3dc("scot", 'p', u3k(who));
|
||||
c3_c* imp_c = u3r_string(imp);
|
||||
c3_y num_y = (c3_y)pir_u->who_d[0];
|
||||
|
||||
por_s = _ames_czar_port(num_y);
|
||||
|
||||
if ( c3y == u3_Host.ops_u.net ) {
|
||||
u3l_log("ames: czar: %s on %d\n", imp_c, por_s);
|
||||
}
|
||||
else {
|
||||
u3l_log("ames: czar: %s on %d (localhost only)\n", imp_c, por_s);
|
||||
}
|
||||
|
||||
u3z(imp);
|
||||
free(imp_c);
|
||||
}
|
||||
|
||||
int ret;
|
||||
if ( 0 != (ret = uv_udp_init(u3L, &sam_u->wax_u)) ) {
|
||||
u3l_log("ames: init: %s\n", uv_strerror(ret));
|
||||
c3_assert(0);
|
||||
}
|
||||
|
||||
// Bind and stuff.
|
||||
{
|
||||
struct sockaddr_in add_u;
|
||||
c3_i add_i = sizeof(add_u);
|
||||
|
||||
memset(&add_u, 0, sizeof(add_u));
|
||||
add_u.sin_family = AF_INET;
|
||||
add_u.sin_addr.s_addr = _(u3_Host.ops_u.net) ?
|
||||
htonl(INADDR_ANY) :
|
||||
htonl(INADDR_LOOPBACK);
|
||||
add_u.sin_port = htons(por_s);
|
||||
|
||||
int ret;
|
||||
if ( (ret = uv_udp_bind(&sam_u->wax_u,
|
||||
(const struct sockaddr*) & add_u, 0)) != 0 ) {
|
||||
u3l_log("ames: bind: %s\n",
|
||||
uv_strerror(ret));
|
||||
if (UV_EADDRINUSE == ret){
|
||||
u3l_log(" ...perhaps you've got two copies of vere running?\n");
|
||||
}
|
||||
u3_pier_exit(pir_u);
|
||||
}
|
||||
|
||||
uv_udp_getsockname(&sam_u->wax_u, (struct sockaddr *)&add_u, &add_i);
|
||||
c3_assert(add_u.sin_port);
|
||||
|
||||
sam_u->por_s = ntohs(add_u.sin_port);
|
||||
}
|
||||
|
||||
// u3l_log("ames: on localhost, UDP %d.\n", sam_u->por_s);
|
||||
uv_udp_recv_start(&sam_u->wax_u, _ames_alloc, _ames_recv_cb);
|
||||
|
||||
sam_u->liv = c3y;
|
||||
u3z(rac);
|
||||
u3z(who);
|
||||
}
|
||||
|
||||
/* _cttp_mcut_char(): measure/cut character.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_char(c3_c* buf_c, c3_w len_w, c3_c chr_c)
|
||||
{
|
||||
if ( buf_c ) {
|
||||
buf_c[len_w] = chr_c;
|
||||
}
|
||||
return len_w + 1;
|
||||
}
|
||||
|
||||
/* _cttp_mcut_cord(): measure/cut cord.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_cord(c3_c* buf_c, c3_w len_w, u3_noun san)
|
||||
{
|
||||
c3_w ten_w = u3r_met(3, san);
|
||||
|
||||
if ( buf_c ) {
|
||||
u3r_bytes(0, ten_w, (c3_y *)(buf_c + len_w), san);
|
||||
}
|
||||
u3z(san);
|
||||
return (len_w + ten_w);
|
||||
}
|
||||
|
||||
/* _cttp_mcut_path(): measure/cut cord list.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_path(c3_c* buf_c, c3_w len_w, c3_c sep_c, u3_noun pax)
|
||||
{
|
||||
u3_noun axp = pax;
|
||||
|
||||
while ( u3_nul != axp ) {
|
||||
u3_noun h_axp = u3h(axp);
|
||||
|
||||
len_w = _cttp_mcut_cord(buf_c, len_w, u3k(h_axp));
|
||||
axp = u3t(axp);
|
||||
|
||||
if ( u3_nul != axp ) {
|
||||
len_w = _cttp_mcut_char(buf_c, len_w, sep_c);
|
||||
}
|
||||
}
|
||||
u3z(pax);
|
||||
return len_w;
|
||||
}
|
||||
|
||||
/* _cttp_mcut_host(): measure/cut host.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_host(c3_c* buf_c, c3_w len_w, u3_noun hot)
|
||||
{
|
||||
len_w = _cttp_mcut_path(buf_c, len_w, '.', u3kb_flop(u3k(hot)));
|
||||
u3z(hot);
|
||||
return len_w;
|
||||
}
|
||||
|
||||
/* u3_ames_ef_turf(): initialize ames I/O on domain(s).
|
||||
*/
|
||||
void
|
||||
u3_ames_ef_turf(u3_pier* pir_u, u3_noun tuf)
|
||||
{
|
||||
u3_ames* sam_u = pir_u->sam_u;
|
||||
|
||||
if ( u3_nul != tuf ) {
|
||||
// XX save all for fallback, not just first
|
||||
u3_noun hot = u3k(u3h(tuf));
|
||||
c3_w len_w = _cttp_mcut_host(0, 0, u3k(hot));
|
||||
|
||||
sam_u->dns_c = c3_malloc(1 + len_w);
|
||||
_cttp_mcut_host(sam_u->dns_c, 0, hot);
|
||||
sam_u->dns_c[len_w] = 0;
|
||||
|
||||
u3z(tuf);
|
||||
}
|
||||
else if ( (c3n == pir_u->fak_o) && (0 == sam_u->dns_c) ) {
|
||||
u3l_log("ames: turf: no domains\n");
|
||||
}
|
||||
|
||||
if ( c3n == sam_u->liv ) {
|
||||
_ames_io_start(pir_u);
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_ames_io_init(): initialize ames I/O.
|
||||
*/
|
||||
void
|
||||
u3_ames_io_init(u3_pier* pir_u)
|
||||
{
|
||||
u3_ames* sam_u = pir_u->sam_u;
|
||||
sam_u->liv = c3n;
|
||||
}
|
||||
|
||||
/* u3_ames_io_talk(): start receiving ames traffic.
|
||||
*/
|
||||
void
|
||||
u3_ames_io_talk(u3_pier* pir_u)
|
||||
{
|
||||
}
|
||||
|
||||
/* u3_ames_io_exit(): terminate ames I/O.
|
||||
*/
|
||||
void
|
||||
u3_ames_io_exit(u3_pier* pir_u)
|
||||
{
|
||||
u3_ames* sam_u = pir_u->sam_u;
|
||||
|
||||
if ( c3y == sam_u->liv ) {
|
||||
// XX remove had_u/wax_u union, cast and close wax_u
|
||||
uv_close(&sam_u->had_u, 0);
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/* vere/behn.c
|
||||
**
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <uv.h>
|
||||
#include <ncurses/curses.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses/term.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* u3_behn(): initialize time timer.
|
||||
*/
|
||||
void
|
||||
u3_behn_io_init(u3_pier *pir_u)
|
||||
{
|
||||
u3_behn* teh_u = pir_u->teh_u;
|
||||
teh_u->alm = c3n;
|
||||
|
||||
uv_timer_init(u3L, &teh_u->tim_u);
|
||||
teh_u->tim_u.data = pir_u;
|
||||
}
|
||||
|
||||
/* u3_behn_io_exit(): terminate timer.
|
||||
*/
|
||||
void
|
||||
u3_behn_io_exit(u3_pier *pir_u)
|
||||
{
|
||||
}
|
||||
|
||||
/* _behn_time_cb(): timer callback.
|
||||
*/
|
||||
static void
|
||||
_behn_time_cb(uv_timer_t* tim_u)
|
||||
{
|
||||
u3_pier *pir_u = tim_u->data;
|
||||
u3_behn* teh_u = pir_u->teh_u;
|
||||
teh_u->alm = c3n;
|
||||
|
||||
{
|
||||
u3_pier_work
|
||||
(pir_u,
|
||||
u3nt(u3_blip, c3__behn, u3_nul),
|
||||
u3nc(c3__wake, u3_nul));
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_behn_ef_doze(): set or cancel timer
|
||||
*/
|
||||
void
|
||||
u3_behn_ef_doze(u3_pier *pir_u, u3_noun wen)
|
||||
{
|
||||
u3_behn* teh_u = pir_u->teh_u;
|
||||
|
||||
if ( c3y == teh_u->alm ) {
|
||||
uv_timer_stop(&teh_u->tim_u);
|
||||
teh_u->alm = c3n;
|
||||
}
|
||||
|
||||
if ( (u3_nul != wen) &&
|
||||
(c3y == u3du(wen)) &&
|
||||
(c3y == u3ud(u3t(wen))) )
|
||||
{
|
||||
struct timeval tim_tv;
|
||||
gettimeofday(&tim_tv, 0);
|
||||
|
||||
u3_noun now = u3_time_in_tv(&tim_tv);
|
||||
c3_d gap_d = u3_time_gap_ms(now, u3k(u3t(wen)));
|
||||
|
||||
teh_u->alm = c3y;
|
||||
uv_timer_start(&teh_u->tim_u, _behn_time_cb, gap_d, 0);
|
||||
}
|
||||
|
||||
u3z(wen);
|
||||
}
|
||||
|
||||
/* u3_behn_ef_bake(): notify %behn that we're live
|
||||
*/
|
||||
void
|
||||
u3_behn_ef_bake(u3_pier *pir_u)
|
||||
{
|
||||
u3_noun pax = u3nq(u3_blip, c3__behn, u3k(u3A->sen), u3_nul);
|
||||
|
||||
u3_pier_work(pir_u, pax, u3nc(c3__born, u3_nul));
|
||||
}
|
@ -1,989 +0,0 @@
|
||||
/* vere/cttp.c
|
||||
**
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <uv.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <h2o.h>
|
||||
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
|
||||
// XX deduplicate with _http_vec_to_atom
|
||||
/* _cttp_vec_to_atom(): convert h2o_iovec_t to atom (cord)
|
||||
*/
|
||||
static u3_noun
|
||||
_cttp_vec_to_atom(h2o_iovec_t vec_u)
|
||||
{
|
||||
return u3i_bytes(vec_u.len, (const c3_y*)vec_u.base);
|
||||
}
|
||||
|
||||
/* _cttp_bods_free(): free body structure.
|
||||
*/
|
||||
static void
|
||||
_cttp_bods_free(u3_hbod* bod_u)
|
||||
{
|
||||
while ( bod_u ) {
|
||||
u3_hbod* nex_u = bod_u->nex_u;
|
||||
|
||||
free(bod_u);
|
||||
bod_u = nex_u;
|
||||
}
|
||||
}
|
||||
|
||||
/* _cttp_bod_new(): create a data buffer
|
||||
*/
|
||||
static u3_hbod*
|
||||
_cttp_bod_new(c3_w len_w, c3_c* hun_c)
|
||||
{
|
||||
u3_hbod* bod_u = c3_malloc(1 + len_w + sizeof(*bod_u));
|
||||
bod_u->hun_y[len_w] = 0;
|
||||
bod_u->len_w = len_w;
|
||||
memcpy(bod_u->hun_y, (const c3_y*)hun_c, len_w);
|
||||
|
||||
bod_u->nex_u = 0;
|
||||
return bod_u;
|
||||
}
|
||||
|
||||
/* _cttp_bod_from_hed(): create a data buffer from a header
|
||||
*/
|
||||
static u3_hbod*
|
||||
_cttp_bod_from_hed(u3_hhed* hed_u)
|
||||
{
|
||||
c3_w len_w = hed_u->nam_w + 2 + hed_u->val_w + 2;
|
||||
u3_hbod* bod_u = c3_malloc(1 + len_w + sizeof(*bod_u));
|
||||
bod_u->hun_y[len_w] = 0;
|
||||
|
||||
memcpy(bod_u->hun_y, hed_u->nam_c, hed_u->nam_w);
|
||||
memcpy(bod_u->hun_y + hed_u->nam_w, ": ", 2);
|
||||
memcpy(bod_u->hun_y + hed_u->nam_w + 2, hed_u->val_c, hed_u->val_w);
|
||||
memcpy(bod_u->hun_y + hed_u->nam_w + 2 + hed_u->val_w, "\r\n", 2);
|
||||
|
||||
bod_u->len_w = len_w;
|
||||
bod_u->nex_u = 0;
|
||||
|
||||
return bod_u;
|
||||
}
|
||||
|
||||
/* _cttp_bods_to_octs: translate body buffer into octet-stream noun.
|
||||
*/
|
||||
static u3_noun
|
||||
_cttp_bods_to_octs(u3_hbod* bod_u)
|
||||
{
|
||||
c3_w len_w;
|
||||
c3_y* buf_y;
|
||||
u3_noun cos;
|
||||
|
||||
{
|
||||
u3_hbod* bid_u = bod_u;
|
||||
|
||||
len_w = 0;
|
||||
while ( bid_u ) {
|
||||
len_w += bid_u->len_w;
|
||||
bid_u = bid_u->nex_u;
|
||||
}
|
||||
}
|
||||
buf_y = c3_malloc(1 + len_w);
|
||||
buf_y[len_w] = 0;
|
||||
|
||||
{
|
||||
c3_y* ptr_y = buf_y;
|
||||
|
||||
while ( bod_u ) {
|
||||
memcpy(ptr_y, bod_u->hun_y, bod_u->len_w);
|
||||
ptr_y += bod_u->len_w;
|
||||
bod_u = bod_u->nex_u;
|
||||
}
|
||||
}
|
||||
cos = u3i_bytes(len_w, buf_y);
|
||||
free(buf_y);
|
||||
return u3nc(len_w, cos);
|
||||
}
|
||||
|
||||
/* _cttp_bod_from_octs(): translate octet-stream noun into body.
|
||||
*/
|
||||
static u3_hbod*
|
||||
_cttp_bod_from_octs(u3_noun oct)
|
||||
{
|
||||
c3_w len_w;
|
||||
|
||||
if ( !_(u3a_is_cat(u3h(oct))) ) { // 2GB max
|
||||
u3m_bail(c3__fail); return 0;
|
||||
}
|
||||
len_w = u3h(oct);
|
||||
|
||||
{
|
||||
u3_hbod* bod_u = c3_malloc(1 + len_w + sizeof(*bod_u));
|
||||
bod_u->hun_y[len_w] = 0;
|
||||
bod_u->len_w = len_w;
|
||||
u3r_bytes(0, len_w, bod_u->hun_y, u3t(oct));
|
||||
|
||||
bod_u->nex_u = 0;
|
||||
|
||||
u3z(oct);
|
||||
return bod_u;
|
||||
}
|
||||
}
|
||||
|
||||
/* _cttp_bods_to_vec(): translate body buffers to array of h2o_iovec_t
|
||||
*/
|
||||
static h2o_iovec_t*
|
||||
_cttp_bods_to_vec(u3_hbod* bod_u, c3_w* tot_w)
|
||||
{
|
||||
h2o_iovec_t* vec_u;
|
||||
c3_w len_w;
|
||||
|
||||
{
|
||||
u3_hbod* bid_u = bod_u;
|
||||
len_w = 0;
|
||||
|
||||
while( bid_u ) {
|
||||
len_w++;
|
||||
bid_u = bid_u->nex_u;
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 == len_w ) {
|
||||
*tot_w = len_w;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec_u = c3_malloc(sizeof(h2o_iovec_t) * len_w);
|
||||
len_w = 0;
|
||||
|
||||
while( bod_u ) {
|
||||
vec_u[len_w] = h2o_iovec_init(bod_u->hun_y, bod_u->len_w);
|
||||
len_w++;
|
||||
bod_u = bod_u->nex_u;
|
||||
}
|
||||
|
||||
*tot_w = len_w;
|
||||
|
||||
return vec_u;
|
||||
}
|
||||
|
||||
// XX deduplicate with _http_heds_free
|
||||
/* _cttp_heds_free(): free header linked list
|
||||
*/
|
||||
static void
|
||||
_cttp_heds_free(u3_hhed* hed_u)
|
||||
{
|
||||
while ( hed_u ) {
|
||||
u3_hhed* nex_u = hed_u->nex_u;
|
||||
|
||||
free(hed_u->nam_c);
|
||||
free(hed_u->val_c);
|
||||
free(hed_u);
|
||||
hed_u = nex_u;
|
||||
}
|
||||
}
|
||||
|
||||
// XX deduplicate with _http_hed_new
|
||||
/* _cttp_hed_new(): create u3_hhed from nam/val cords
|
||||
*/
|
||||
static u3_hhed*
|
||||
_cttp_hed_new(u3_atom nam, u3_atom val)
|
||||
{
|
||||
c3_w nam_w = u3r_met(3, nam);
|
||||
c3_w val_w = u3r_met(3, val);
|
||||
u3_hhed* hed_u = c3_malloc(sizeof(*hed_u));
|
||||
|
||||
hed_u->nam_c = c3_malloc(1 + nam_w);
|
||||
hed_u->val_c = c3_malloc(1 + val_w);
|
||||
hed_u->nam_c[nam_w] = 0;
|
||||
hed_u->val_c[val_w] = 0;
|
||||
hed_u->nex_u = 0;
|
||||
hed_u->nam_w = nam_w;
|
||||
hed_u->val_w = val_w;
|
||||
|
||||
u3r_bytes(0, nam_w, (c3_y*)hed_u->nam_c, nam);
|
||||
u3r_bytes(0, val_w, (c3_y*)hed_u->val_c, val);
|
||||
|
||||
return hed_u;
|
||||
}
|
||||
|
||||
// XX vv similar to _http_heds_from_noun
|
||||
/* _cttp_heds_math(): create headers from +math
|
||||
*/
|
||||
static u3_hhed*
|
||||
_cttp_heds_math(u3_noun mah)
|
||||
{
|
||||
u3_noun hed = u3kdi_tap(mah);
|
||||
u3_noun deh = hed;
|
||||
|
||||
u3_hhed* hed_u = 0;
|
||||
|
||||
while ( u3_nul != hed ) {
|
||||
u3_noun nam = u3h(u3h(hed));
|
||||
u3_noun lit = u3t(u3h(hed));
|
||||
|
||||
while ( u3_nul != lit ) {
|
||||
u3_hhed* nex_u = _cttp_hed_new(nam, u3h(lit));
|
||||
nex_u->nex_u = hed_u;
|
||||
|
||||
hed_u = nex_u;
|
||||
lit = u3t(lit);
|
||||
}
|
||||
|
||||
hed = u3t(hed);
|
||||
}
|
||||
|
||||
u3z(deh);
|
||||
return hed_u;
|
||||
}
|
||||
|
||||
// XX deduplicate with _http_heds_to_noun
|
||||
/* _cttp_heds_to_noun(): convert h2o_header_t to (list (pair @t @t))
|
||||
*/
|
||||
static u3_noun
|
||||
_cttp_heds_to_noun(h2o_header_t* hed_u, c3_d hed_d)
|
||||
{
|
||||
u3_noun hed = u3_nul;
|
||||
c3_d dex_d = hed_d;
|
||||
|
||||
h2o_header_t deh_u;
|
||||
|
||||
while ( 0 < dex_d ) {
|
||||
deh_u = hed_u[--dex_d];
|
||||
hed = u3nc(u3nc(_cttp_vec_to_atom(*deh_u.name),
|
||||
_cttp_vec_to_atom(deh_u.value)), hed);
|
||||
}
|
||||
|
||||
return hed;
|
||||
}
|
||||
|
||||
/* _cttp_cres_free(): free a u3_cres.
|
||||
*/
|
||||
static void
|
||||
_cttp_cres_free(u3_cres* res_u)
|
||||
{
|
||||
_cttp_bods_free(res_u->bod_u);
|
||||
free(res_u);
|
||||
}
|
||||
|
||||
/* _cttp_cres_new(): create a response
|
||||
*/
|
||||
static void
|
||||
_cttp_cres_new(u3_creq* ceq_u, c3_w sas_w)
|
||||
{
|
||||
ceq_u->res_u = c3_calloc(sizeof(*ceq_u->res_u));
|
||||
ceq_u->res_u->sas_w = sas_w;
|
||||
}
|
||||
|
||||
/* _cttp_cres_fire_body(): attach response body buffer
|
||||
*/
|
||||
static void
|
||||
_cttp_cres_fire_body(u3_cres* res_u, u3_hbod* bod_u)
|
||||
{
|
||||
c3_assert(!bod_u->nex_u);
|
||||
|
||||
if ( !(res_u->bod_u) ) {
|
||||
res_u->bod_u = res_u->dob_u = bod_u;
|
||||
}
|
||||
else {
|
||||
res_u->dob_u->nex_u = bod_u;
|
||||
res_u->dob_u = bod_u;
|
||||
}
|
||||
}
|
||||
|
||||
/* _cttp_mcut_char(): measure/cut character.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_char(c3_c* buf_c, c3_w len_w, c3_c chr_c)
|
||||
{
|
||||
if ( buf_c ) {
|
||||
buf_c[len_w] = chr_c;
|
||||
}
|
||||
return len_w + 1;
|
||||
}
|
||||
|
||||
/* _cttp_mcut_cord(): measure/cut cord.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_cord(c3_c* buf_c, c3_w len_w, u3_noun san)
|
||||
{
|
||||
c3_w ten_w = u3r_met(3, san);
|
||||
|
||||
if ( buf_c ) {
|
||||
u3r_bytes(0, ten_w, (c3_y *)(buf_c + len_w), san);
|
||||
}
|
||||
u3z(san);
|
||||
return (len_w + ten_w);
|
||||
}
|
||||
|
||||
/* _cttp_mcut_path(): measure/cut cord list.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_path(c3_c* buf_c, c3_w len_w, c3_c sep_c, u3_noun pax)
|
||||
{
|
||||
u3_noun axp = pax;
|
||||
|
||||
while ( u3_nul != axp ) {
|
||||
u3_noun h_axp = u3h(axp);
|
||||
|
||||
len_w = _cttp_mcut_cord(buf_c, len_w, u3k(h_axp));
|
||||
axp = u3t(axp);
|
||||
|
||||
if ( u3_nul != axp ) {
|
||||
len_w = _cttp_mcut_char(buf_c, len_w, sep_c);
|
||||
}
|
||||
}
|
||||
u3z(pax);
|
||||
return len_w;
|
||||
}
|
||||
|
||||
/* _cttp_mcut_host(): measure/cut host.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_host(c3_c* buf_c, c3_w len_w, u3_noun hot)
|
||||
{
|
||||
len_w = _cttp_mcut_path(buf_c, len_w, '.', u3kb_flop(u3k(hot)));
|
||||
u3z(hot);
|
||||
return len_w;
|
||||
}
|
||||
|
||||
/* _cttp_mcut_pork(): measure/cut path/extension.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_pork(c3_c* buf_c, c3_w len_w, u3_noun pok)
|
||||
{
|
||||
u3_noun h_pok = u3h(pok);
|
||||
u3_noun t_pok = u3t(pok);
|
||||
|
||||
len_w = _cttp_mcut_path(buf_c, len_w, '/', u3k(t_pok));
|
||||
if ( u3_nul != h_pok ) {
|
||||
len_w = _cttp_mcut_char(buf_c, len_w, '.');
|
||||
len_w = _cttp_mcut_cord(buf_c, len_w, u3k(u3t(h_pok)));
|
||||
}
|
||||
u3z(pok);
|
||||
return len_w;
|
||||
}
|
||||
|
||||
/* _cttp_mcut_quay(): measure/cut query.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_quay(c3_c* buf_c, c3_w len_w, u3_noun quy)
|
||||
{
|
||||
if ( u3_nul == quy ) {
|
||||
return len_w;
|
||||
}
|
||||
else {
|
||||
u3_noun i_quy = u3h(quy);
|
||||
u3_noun pi_quy = u3h(i_quy);
|
||||
u3_noun qi_quy = u3t(i_quy);
|
||||
u3_noun t_quy = u3t(quy);
|
||||
|
||||
len_w = _cttp_mcut_char(buf_c, len_w, '&');
|
||||
len_w = _cttp_mcut_cord(buf_c, len_w, u3k(pi_quy));
|
||||
len_w = _cttp_mcut_char(buf_c, len_w, '=');
|
||||
len_w = _cttp_mcut_cord(buf_c, len_w, u3k(qi_quy));
|
||||
|
||||
len_w = _cttp_mcut_quay(buf_c, len_w, u3k(t_quy));
|
||||
}
|
||||
u3z(quy);
|
||||
return len_w;
|
||||
}
|
||||
|
||||
/* _cttp_mcut_url(): measure/cut purl, producing relative URL.
|
||||
*/
|
||||
static c3_w
|
||||
_cttp_mcut_url(c3_c* buf_c, c3_w len_w, u3_noun pul)
|
||||
{
|
||||
u3_noun q_pul = u3h(u3t(pul));
|
||||
u3_noun r_pul = u3t(u3t(pul));
|
||||
|
||||
len_w = _cttp_mcut_char(buf_c, len_w, '/');
|
||||
len_w = _cttp_mcut_pork(buf_c, len_w, u3k(q_pul));
|
||||
|
||||
if ( u3_nul != r_pul ) {
|
||||
len_w = _cttp_mcut_char(buf_c, len_w, '?');
|
||||
len_w = _cttp_mcut_quay(buf_c, len_w, u3k(r_pul));
|
||||
}
|
||||
u3z(pul);
|
||||
return len_w;
|
||||
}
|
||||
|
||||
/* _cttp_creq_port(): stringify port
|
||||
*/
|
||||
static c3_c*
|
||||
_cttp_creq_port(c3_s por_s)
|
||||
{
|
||||
c3_c* por_c = c3_malloc(8);
|
||||
snprintf(por_c, 7, "%d", 0xffff & por_s);
|
||||
return por_c;
|
||||
}
|
||||
|
||||
/* _cttp_creq_url(): construct url from noun.
|
||||
*/
|
||||
static c3_c*
|
||||
_cttp_creq_url(u3_noun pul)
|
||||
{
|
||||
c3_w len_w = _cttp_mcut_url(0, 0, u3k(pul));
|
||||
c3_c* url_c = c3_malloc(1 + len_w);
|
||||
|
||||
_cttp_mcut_url(url_c, 0, pul);
|
||||
url_c[len_w] = 0;
|
||||
|
||||
return url_c;
|
||||
}
|
||||
|
||||
/* _cttp_creq_host(): construct host from noun.
|
||||
*/
|
||||
static c3_c*
|
||||
_cttp_creq_host(u3_noun hot)
|
||||
{
|
||||
c3_w len_w = _cttp_mcut_host(0, 0, u3k(hot));
|
||||
c3_c* hot_c = c3_malloc(1 + len_w);
|
||||
|
||||
_cttp_mcut_host(hot_c, 0, hot);
|
||||
hot_c[len_w] = 0;
|
||||
|
||||
return hot_c;
|
||||
}
|
||||
|
||||
/* _cttp_creq_ip(): stringify ip
|
||||
*/
|
||||
static c3_c*
|
||||
_cttp_creq_ip(c3_w ipf_w)
|
||||
{
|
||||
c3_c* ipf_c = c3_malloc(17);
|
||||
snprintf(ipf_c, 16, "%d.%d.%d.%d", (ipf_w >> 24),
|
||||
((ipf_w >> 16) & 255),
|
||||
((ipf_w >> 8) & 255),
|
||||
(ipf_w & 255));
|
||||
return ipf_c;
|
||||
}
|
||||
|
||||
/* _cttp_creq_find(): find a request by number in the client
|
||||
*/
|
||||
static u3_creq*
|
||||
_cttp_creq_find(c3_l num_l)
|
||||
{
|
||||
u3_creq* ceq_u = u3_Host.ctp_u.ceq_u;
|
||||
|
||||
// XX glories of linear search
|
||||
//
|
||||
while ( ceq_u ) {
|
||||
if ( num_l == ceq_u->num_l ) {
|
||||
return ceq_u;
|
||||
}
|
||||
ceq_u = ceq_u->nex_u;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* _cttp_creq_link(): link request to client
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_link(u3_creq* ceq_u)
|
||||
{
|
||||
ceq_u->nex_u = u3_Host.ctp_u.ceq_u;
|
||||
|
||||
if ( 0 != ceq_u->nex_u ) {
|
||||
ceq_u->nex_u->pre_u = ceq_u;
|
||||
}
|
||||
u3_Host.ctp_u.ceq_u = ceq_u;
|
||||
}
|
||||
|
||||
/* _cttp_creq_unlink(): unlink request from client
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_unlink(u3_creq* ceq_u)
|
||||
{
|
||||
if ( ceq_u->pre_u ) {
|
||||
ceq_u->pre_u->nex_u = ceq_u->nex_u;
|
||||
|
||||
if ( 0 != ceq_u->nex_u ) {
|
||||
ceq_u->nex_u->pre_u = ceq_u->pre_u;
|
||||
}
|
||||
}
|
||||
else {
|
||||
u3_Host.ctp_u.ceq_u = ceq_u->nex_u;
|
||||
|
||||
if ( 0 != ceq_u->nex_u ) {
|
||||
ceq_u->nex_u->pre_u = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* _cttp_creq_free(): free a u3_creq.
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_free(u3_creq* ceq_u)
|
||||
{
|
||||
_cttp_creq_unlink(ceq_u);
|
||||
|
||||
_cttp_heds_free(ceq_u->hed_u);
|
||||
// Note: ceq_u->bod_u is covered here
|
||||
_cttp_bods_free(ceq_u->rub_u);
|
||||
|
||||
if ( ceq_u->res_u ) {
|
||||
_cttp_cres_free(ceq_u->res_u);
|
||||
}
|
||||
|
||||
free(ceq_u->hot_c);
|
||||
free(ceq_u->por_c);
|
||||
free(ceq_u->url_c);
|
||||
free(ceq_u->vec_u);
|
||||
free(ceq_u);
|
||||
}
|
||||
|
||||
/* _cttp_creq_new(): create a request from a +hiss noun
|
||||
*/
|
||||
static u3_creq*
|
||||
_cttp_creq_new(c3_l num_l, u3_noun hes)
|
||||
{
|
||||
u3_creq* ceq_u = c3_calloc(sizeof(*ceq_u));
|
||||
|
||||
u3_noun pul = u3h(hes); // +purl
|
||||
u3_noun hat = u3h(pul); // +hart
|
||||
u3_noun sec = u3h(hat);
|
||||
u3_noun por = u3h(u3t(hat));
|
||||
u3_noun hot = u3t(u3t(hat)); // +host
|
||||
u3_noun moh = u3t(hes); // +moth
|
||||
u3_noun met = u3h(moh); // +meth
|
||||
u3_noun mah = u3h(u3t(moh)); // +math
|
||||
u3_noun bod = u3t(u3t(moh));
|
||||
|
||||
ceq_u->sat_e = u3_csat_init;
|
||||
ceq_u->num_l = num_l;
|
||||
ceq_u->sec = sec;
|
||||
|
||||
if ( c3y == u3h(hot) ) {
|
||||
ceq_u->hot_c = _cttp_creq_host(u3k(u3t(hot)));
|
||||
} else {
|
||||
ceq_u->ipf_w = u3r_word(0, u3t(hot));
|
||||
ceq_u->ipf_c = _cttp_creq_ip(ceq_u->ipf_w);
|
||||
}
|
||||
|
||||
if ( u3_nul != por ) {
|
||||
ceq_u->por_s = u3t(por);
|
||||
ceq_u->por_c = _cttp_creq_port(ceq_u->por_s);
|
||||
}
|
||||
|
||||
ceq_u->met_m = met;
|
||||
ceq_u->url_c = _cttp_creq_url(u3k(pul));
|
||||
ceq_u->hed_u = _cttp_heds_math(u3k(mah));
|
||||
|
||||
if ( u3_nul != bod ) {
|
||||
ceq_u->bod_u = _cttp_bod_from_octs(u3k(u3t(bod)));
|
||||
}
|
||||
|
||||
_cttp_creq_link(ceq_u);
|
||||
|
||||
u3z(hes);
|
||||
return ceq_u;
|
||||
}
|
||||
|
||||
/* _cttp_creq_fire_body(): attach body to request buffers.
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_fire_body(u3_creq* ceq_u, u3_hbod *rub_u)
|
||||
{
|
||||
c3_assert(!rub_u->nex_u);
|
||||
|
||||
if ( !(ceq_u->rub_u) ) {
|
||||
ceq_u->rub_u = ceq_u->bur_u = rub_u;
|
||||
}
|
||||
else {
|
||||
ceq_u->bur_u->nex_u = rub_u;
|
||||
ceq_u->bur_u = rub_u;
|
||||
}
|
||||
}
|
||||
|
||||
/* _cttp_creq_fire_str(): attach string to request buffers.
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_fire_str(u3_creq* ceq_u, c3_c* str_c)
|
||||
{
|
||||
_cttp_creq_fire_body(ceq_u, _cttp_bod_new(strlen(str_c), str_c));
|
||||
}
|
||||
|
||||
/* _cttp_creq_fire_heds(): attach output headers.
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_fire_heds(u3_creq* ceq_u, u3_hhed* hed_u)
|
||||
{
|
||||
while ( hed_u ) {
|
||||
_cttp_creq_fire_body(ceq_u, _cttp_bod_from_hed(hed_u));
|
||||
hed_u = hed_u->nex_u;
|
||||
}
|
||||
}
|
||||
|
||||
/* _cttp_creq_fire(): load request data for into buffers.
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_fire(u3_creq* ceq_u)
|
||||
{
|
||||
switch ( ceq_u->met_m ) {
|
||||
default: c3_assert(0);
|
||||
case c3__get: _cttp_creq_fire_str(ceq_u, "GET "); break;
|
||||
case c3__put: _cttp_creq_fire_str(ceq_u, "PUT "); break;
|
||||
case c3__post: _cttp_creq_fire_str(ceq_u, "POST "); break;
|
||||
case c3__head: _cttp_creq_fire_str(ceq_u, "HEAD "); break;
|
||||
case c3__conn: _cttp_creq_fire_str(ceq_u, "CONNECT "); break;
|
||||
case c3__delt: _cttp_creq_fire_str(ceq_u, "DELETE "); break;
|
||||
case c3__opts: _cttp_creq_fire_str(ceq_u, "OPTIONS "); break;
|
||||
case c3__trac: _cttp_creq_fire_str(ceq_u, "TRACE "); break;
|
||||
}
|
||||
_cttp_creq_fire_str(ceq_u, ceq_u->url_c);
|
||||
_cttp_creq_fire_str(ceq_u, " HTTP/1.1\r\n");
|
||||
|
||||
{
|
||||
c3_c* hot_c = ceq_u->hot_c ? ceq_u->hot_c : ceq_u->ipf_c;
|
||||
c3_c* hos_c;
|
||||
c3_w len_w;
|
||||
|
||||
if ( ceq_u->por_c ) {
|
||||
len_w = 6 + strlen(hot_c) + 1 + strlen(ceq_u->por_c) + 3;
|
||||
hos_c = c3_malloc(len_w);
|
||||
len_w = snprintf(hos_c, len_w, "Host: %s:%s\r\n", hot_c, ceq_u->por_c);
|
||||
}
|
||||
else {
|
||||
len_w = 6 + strlen(hot_c) + 3;
|
||||
hos_c = c3_malloc(len_w);
|
||||
len_w = snprintf(hos_c, len_w, "Host: %s\r\n", hot_c);
|
||||
}
|
||||
|
||||
_cttp_creq_fire_body(ceq_u, _cttp_bod_new(len_w, hos_c));
|
||||
free(hos_c);
|
||||
}
|
||||
|
||||
_cttp_creq_fire_heds(ceq_u, ceq_u->hed_u);
|
||||
|
||||
if ( !ceq_u->bod_u ) {
|
||||
_cttp_creq_fire_body(ceq_u, _cttp_bod_new(2, "\r\n"));
|
||||
}
|
||||
else {
|
||||
c3_c len_c[41];
|
||||
c3_w len_w = snprintf(len_c, 40, "Content-Length: %u\r\n\r\n",
|
||||
ceq_u->bod_u->len_w);
|
||||
|
||||
_cttp_creq_fire_body(ceq_u, _cttp_bod_new(len_w, len_c));
|
||||
_cttp_creq_fire_body(ceq_u, ceq_u->bod_u);
|
||||
}
|
||||
}
|
||||
|
||||
/* _cttp_creq_quit(): cancel a u3_creq
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_quit(u3_creq* ceq_u)
|
||||
{
|
||||
if ( u3_csat_addr == ceq_u->sat_e ) {
|
||||
ceq_u->sat_e = u3_csat_quit;
|
||||
return; // wait to be called again on address resolution
|
||||
}
|
||||
|
||||
if ( ceq_u->cli_u ) {
|
||||
h2o_http1client_cancel(ceq_u->cli_u);
|
||||
}
|
||||
|
||||
_cttp_creq_free(ceq_u);
|
||||
}
|
||||
|
||||
/* _cttp_httr(): dispatch http response to %eyre
|
||||
*/
|
||||
static void
|
||||
_cttp_httr(c3_l num_l, c3_w sas_w, u3_noun mes, u3_noun uct)
|
||||
{
|
||||
u3_noun htr = u3nt(sas_w, mes, uct);
|
||||
u3_noun pox = u3nt(u3_blip, c3__http, u3_nul);
|
||||
|
||||
u3_pier_plan(pox, u3nt(c3__they, num_l, htr));
|
||||
}
|
||||
|
||||
/* _cttp_creq_quit(): dispatch error response
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_fail(u3_creq* ceq_u, const c3_c* err_c)
|
||||
{
|
||||
// XX anything other than a 504?
|
||||
c3_w cod_w = 504;
|
||||
|
||||
u3l_log("http: fail (%d, %d): %s\r\n", ceq_u->num_l, cod_w, err_c);
|
||||
|
||||
// XX include err_c as response body?
|
||||
_cttp_httr(ceq_u->num_l, cod_w, u3_nul, u3_nul);
|
||||
_cttp_creq_free(ceq_u);
|
||||
}
|
||||
|
||||
/* _cttp_creq_quit(): dispatch response
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_respond(u3_creq* ceq_u)
|
||||
{
|
||||
u3_cres* res_u = ceq_u->res_u;
|
||||
|
||||
_cttp_httr(ceq_u->num_l, res_u->sas_w, res_u->hed,
|
||||
( !res_u->bod_u ) ? u3_nul :
|
||||
u3nc(u3_nul, _cttp_bods_to_octs(res_u->bod_u)));
|
||||
|
||||
_cttp_creq_free(ceq_u);
|
||||
}
|
||||
|
||||
// XX research: may be called with closed client?
|
||||
/* _cttp_creq_on_body(): cb invoked by h2o upon receiving a response body
|
||||
*/
|
||||
static c3_i
|
||||
_cttp_creq_on_body(h2o_http1client_t* cli_u, const c3_c* err_c)
|
||||
{
|
||||
u3_creq* ceq_u = (u3_creq *)cli_u->data;
|
||||
|
||||
if ( 0 != err_c && h2o_http1client_error_is_eos != err_c ) {
|
||||
_cttp_creq_fail(ceq_u, err_c);
|
||||
return -1;
|
||||
}
|
||||
|
||||
h2o_buffer_t* buf_u = cli_u->sock->input;
|
||||
|
||||
if ( buf_u->size ) {
|
||||
_cttp_cres_fire_body(ceq_u->res_u,
|
||||
_cttp_bod_new(buf_u->size, buf_u->bytes));
|
||||
h2o_buffer_consume(&cli_u->sock->input, buf_u->size);
|
||||
}
|
||||
|
||||
if ( h2o_http1client_error_is_eos == err_c ) {
|
||||
_cttp_creq_respond(ceq_u);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* _cttp_creq_on_head(): cb invoked by h2o upon receiving response headers
|
||||
*/
|
||||
static h2o_http1client_body_cb
|
||||
_cttp_creq_on_head(h2o_http1client_t* cli_u, const c3_c* err_c, c3_i ver_i,
|
||||
c3_i sas_i, h2o_iovec_t sas_u, h2o_header_t* hed_u,
|
||||
size_t hed_t, c3_i len_i)
|
||||
{
|
||||
u3_creq* ceq_u = (u3_creq *)cli_u->data;
|
||||
|
||||
if ( 0 != err_c && h2o_http1client_error_is_eos != err_c ) {
|
||||
_cttp_creq_fail(ceq_u, err_c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cttp_cres_new(ceq_u, (c3_w)sas_i);
|
||||
ceq_u->res_u->hed = _cttp_heds_to_noun(hed_u, hed_t);
|
||||
|
||||
if ( h2o_http1client_error_is_eos == err_c ) {
|
||||
_cttp_creq_respond(ceq_u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _cttp_creq_on_body;
|
||||
}
|
||||
|
||||
/* _cttp_creq_on_connect(): cb invoked by h2o upon successful connection
|
||||
*/
|
||||
static h2o_http1client_head_cb
|
||||
_cttp_creq_on_connect(h2o_http1client_t* cli_u, const c3_c* err_c,
|
||||
h2o_iovec_t** vec_p, size_t* vec_t, c3_i* hed_i)
|
||||
{
|
||||
u3_creq* ceq_u = (u3_creq *)cli_u->data;
|
||||
|
||||
if ( 0 != err_c ) {
|
||||
_cttp_creq_fail(ceq_u, err_c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
c3_w len_w;
|
||||
ceq_u->vec_u = _cttp_bods_to_vec(ceq_u->rub_u, &len_w);
|
||||
*vec_t = len_w;
|
||||
*vec_p = ceq_u->vec_u;
|
||||
*hed_i = c3__head == ceq_u->met_m;
|
||||
}
|
||||
|
||||
return _cttp_creq_on_head;
|
||||
}
|
||||
|
||||
/* _cttp_creq_connect(): establish connection
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_connect(u3_creq* ceq_u)
|
||||
{
|
||||
c3_assert(u3_csat_ripe == ceq_u->sat_e);
|
||||
c3_assert(ceq_u->ipf_c);
|
||||
|
||||
h2o_iovec_t ipf_u = h2o_iovec_init(ceq_u->ipf_c, strlen(ceq_u->ipf_c));
|
||||
c3_s por_s = ceq_u->por_s ? ceq_u->por_s :
|
||||
( c3y == ceq_u->sec ) ? 443 : 80;
|
||||
|
||||
// connect by IP
|
||||
h2o_http1client_connect(&ceq_u->cli_u, ceq_u, u3_Host.ctp_u.ctx_u, ipf_u,
|
||||
por_s, c3y == ceq_u->sec, _cttp_creq_on_connect);
|
||||
|
||||
// set hostname for TLS handshake
|
||||
if ( ceq_u->hot_c && c3y == ceq_u->sec ) {
|
||||
c3_w len_w = 1 + strlen(ceq_u->hot_c);
|
||||
c3_c* hot_c = c3_malloc(len_w);
|
||||
strncpy(hot_c, ceq_u->hot_c, len_w);
|
||||
|
||||
free(ceq_u->cli_u->ssl.server_name);
|
||||
ceq_u->cli_u->ssl.server_name = hot_c;
|
||||
}
|
||||
|
||||
_cttp_creq_fire(ceq_u);
|
||||
}
|
||||
|
||||
/* _cttp_creq_resolve_cb(): cb upon IP address resolution
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_resolve_cb(uv_getaddrinfo_t* adr_u,
|
||||
c3_i sas_i,
|
||||
struct addrinfo* aif_u)
|
||||
{
|
||||
u3_creq* ceq_u = adr_u->data;
|
||||
|
||||
if ( u3_csat_quit == ceq_u->sat_e ) {
|
||||
_cttp_creq_quit(ceq_u);;
|
||||
}
|
||||
else if ( 0 != sas_i ) {
|
||||
_cttp_creq_fail(ceq_u, uv_strerror(sas_i));
|
||||
}
|
||||
else {
|
||||
// XX traverse struct a la _ames_czar_cb
|
||||
ceq_u->ipf_w = ntohl(((struct sockaddr_in *)aif_u->ai_addr)->sin_addr.s_addr);
|
||||
ceq_u->ipf_c = _cttp_creq_ip(ceq_u->ipf_w);
|
||||
|
||||
ceq_u->sat_e = u3_csat_ripe;
|
||||
_cttp_creq_connect(ceq_u);
|
||||
}
|
||||
|
||||
free(adr_u);
|
||||
uv_freeaddrinfo(aif_u);
|
||||
}
|
||||
|
||||
/* _cttp_creq_resolve(): resolve hostname to IP address
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_resolve(u3_creq* ceq_u)
|
||||
{
|
||||
c3_assert(u3_csat_addr == ceq_u->sat_e);
|
||||
c3_assert(ceq_u->hot_c);
|
||||
|
||||
uv_getaddrinfo_t* adr_u = c3_malloc(sizeof(*adr_u));
|
||||
adr_u->data = ceq_u;
|
||||
|
||||
struct addrinfo hin_u;
|
||||
memset(&hin_u, 0, sizeof(struct addrinfo));
|
||||
|
||||
hin_u.ai_family = PF_INET;
|
||||
hin_u.ai_socktype = SOCK_STREAM;
|
||||
hin_u.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
// XX is this necessary?
|
||||
c3_c* por_c = ceq_u->por_c ? ceq_u->por_c :
|
||||
( c3y == ceq_u->sec ) ? "443" : "80";
|
||||
|
||||
c3_i sas_i;
|
||||
|
||||
if ( 0 != (sas_i = uv_getaddrinfo(u3L, adr_u, _cttp_creq_resolve_cb,
|
||||
ceq_u->hot_c, por_c, &hin_u)) ) {
|
||||
_cttp_creq_fail(ceq_u, uv_strerror(sas_i));
|
||||
}
|
||||
}
|
||||
|
||||
/* _cttp_creq_start(): start a request
|
||||
*/
|
||||
static void
|
||||
_cttp_creq_start(u3_creq* ceq_u)
|
||||
{
|
||||
if ( ceq_u->ipf_c ) {
|
||||
ceq_u->sat_e = u3_csat_ripe;
|
||||
_cttp_creq_connect(ceq_u);
|
||||
} else {
|
||||
ceq_u->sat_e = u3_csat_addr;
|
||||
_cttp_creq_resolve(ceq_u);
|
||||
}
|
||||
}
|
||||
|
||||
/* _cttp_init_tls: initialize OpenSSL context
|
||||
*/
|
||||
static SSL_CTX*
|
||||
_cttp_init_tls()
|
||||
{
|
||||
// XX require 1.1.0 and use TLS_client_method()
|
||||
SSL_CTX* tls_u = SSL_CTX_new(SSLv23_client_method());
|
||||
// XX use SSL_CTX_set_max_proto_version() and SSL_CTX_set_min_proto_version()
|
||||
SSL_CTX_set_options(tls_u, SSL_OP_NO_SSLv2 |
|
||||
SSL_OP_NO_SSLv3 |
|
||||
// SSL_OP_NO_TLSv1 | // XX test
|
||||
SSL_OP_NO_COMPRESSION);
|
||||
|
||||
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:"
|
||||
"ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:"
|
||||
"RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS");
|
||||
|
||||
return tls_u;
|
||||
}
|
||||
|
||||
/* _cttp_init_h2o: initialize h2o client ctx and timeout
|
||||
*/
|
||||
static h2o_http1client_ctx_t*
|
||||
_cttp_init_h2o()
|
||||
{
|
||||
h2o_timeout_t* tim_u = c3_malloc(sizeof(*tim_u));
|
||||
|
||||
h2o_timeout_init(u3L, tim_u, 300 * 1000);
|
||||
|
||||
h2o_http1client_ctx_t* ctx_u = c3_calloc(sizeof(*ctx_u));
|
||||
ctx_u->loop = u3L;
|
||||
ctx_u->io_timeout = tim_u;
|
||||
|
||||
return ctx_u;
|
||||
};
|
||||
|
||||
/* u3_cttp_ef_thus(): send %thus effect (outgoing request) to cttp.
|
||||
*/
|
||||
void
|
||||
u3_cttp_ef_thus(c3_l num_l,
|
||||
u3_noun cuq)
|
||||
{
|
||||
u3_creq* ceq_u;
|
||||
|
||||
if ( u3_nul == cuq ) {
|
||||
ceq_u =_cttp_creq_find(num_l);
|
||||
|
||||
if ( ceq_u ) {
|
||||
_cttp_creq_quit(ceq_u);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ceq_u = _cttp_creq_new(num_l, u3k(u3t(cuq)));
|
||||
_cttp_creq_start(ceq_u);
|
||||
}
|
||||
u3z(cuq);
|
||||
}
|
||||
|
||||
/* u3_cttp_io_init(): initialize http client I/O.
|
||||
*/
|
||||
void
|
||||
u3_cttp_io_init()
|
||||
{
|
||||
u3_Host.ctp_u.tls_u = _cttp_init_tls();
|
||||
u3_Host.ctp_u.ctx_u = _cttp_init_h2o();
|
||||
u3_Host.ctp_u.ctx_u->ssl_ctx = u3_Host.ctp_u.tls_u;
|
||||
u3_Host.ctp_u.ceq_u = 0;
|
||||
}
|
||||
|
||||
/* u3_cttp_io_exit(): shut down cttp.
|
||||
*/
|
||||
void
|
||||
u3_cttp_io_exit(void)
|
||||
{
|
||||
SSL_CTX_free(u3_Host.ctp_u.tls_u);
|
||||
free(u3_Host.ctp_u.ctx_u->io_timeout);
|
||||
free(u3_Host.ctp_u.ctx_u);
|
||||
}
|
@ -1,735 +0,0 @@
|
||||
/* vere/main.c
|
||||
**
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <limits.h>
|
||||
#include <uv.h>
|
||||
#include <sigsegv.h>
|
||||
#include <stdlib.h>
|
||||
#include <ncurses/curses.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses/term.h>
|
||||
#include <dirent.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <h2o.h>
|
||||
#include <curl/curl.h>
|
||||
#include <argon2.h>
|
||||
|
||||
#define U3_GLOBAL
|
||||
#define C3_GLOBAL
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* Require unsigned char
|
||||
*/
|
||||
STATIC_ASSERT(( 0 == CHAR_MIN && UCHAR_MAX == CHAR_MAX ),
|
||||
"unsigned char required");
|
||||
|
||||
/* _main_readw(): parse a word from a string.
|
||||
*/
|
||||
static u3_noun
|
||||
_main_readw(const c3_c* str_c, c3_w max_w, c3_w* out_w)
|
||||
{
|
||||
c3_c* end_c;
|
||||
c3_w par_w = strtoul(str_c, &end_c, 0);
|
||||
|
||||
if ( *str_c != '\0' && *end_c == '\0' && par_w < max_w ) {
|
||||
*out_w = par_w;
|
||||
return c3y;
|
||||
}
|
||||
else return c3n;
|
||||
}
|
||||
|
||||
/* _main_presig(): prefix optional sig.
|
||||
*/
|
||||
c3_c*
|
||||
_main_presig(c3_c* txt_c)
|
||||
{
|
||||
c3_c* new_c = malloc(2 + strlen(txt_c));
|
||||
|
||||
if ( '~' == *txt_c ) {
|
||||
strcpy(new_c, txt_c);
|
||||
} else {
|
||||
new_c[0] = '~';
|
||||
strcpy(new_c + 1, txt_c);
|
||||
}
|
||||
return new_c;
|
||||
}
|
||||
|
||||
/* _main_getopt(): extract option map from command line.
|
||||
*/
|
||||
static u3_noun
|
||||
_main_getopt(c3_i argc, c3_c** argv)
|
||||
{
|
||||
c3_i ch_i;
|
||||
c3_w arg_w;
|
||||
|
||||
u3_Host.ops_u.abo = c3n;
|
||||
u3_Host.ops_u.bat = c3n;
|
||||
u3_Host.ops_u.can = c3n;
|
||||
u3_Host.ops_u.dem = c3n;
|
||||
u3_Host.ops_u.dry = c3n;
|
||||
u3_Host.ops_u.etn = c3n;
|
||||
u3_Host.ops_u.gab = c3n;
|
||||
u3_Host.ops_u.git = c3n;
|
||||
|
||||
// always disable hashboard
|
||||
// XX temporary, remove once hashes are added
|
||||
//
|
||||
u3_Host.ops_u.has = c3y;
|
||||
|
||||
u3_Host.ops_u.net = c3y;
|
||||
u3_Host.ops_u.nuu = c3n;
|
||||
u3_Host.ops_u.pro = c3n;
|
||||
u3_Host.ops_u.qui = c3n;
|
||||
u3_Host.ops_u.rep = c3n;
|
||||
u3_Host.ops_u.tex = c3n;
|
||||
u3_Host.ops_u.tra = c3n;
|
||||
u3_Host.ops_u.veb = c3n;
|
||||
u3_Host.ops_u.kno_w = DefaultKernel;
|
||||
|
||||
while ( -1 != (ch_i=getopt(argc, argv,
|
||||
"G:J:B:K:A:H:w:u:e:E:f:F:k:m:p:LjabcCdgqstvxPDRS")) )
|
||||
{
|
||||
switch ( ch_i ) {
|
||||
case 'J': {
|
||||
u3_Host.ops_u.lit_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'B': {
|
||||
u3_Host.ops_u.pil_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'G': {
|
||||
u3_Host.ops_u.gen_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'A': {
|
||||
u3_Host.ops_u.arv_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'H': {
|
||||
u3_Host.ops_u.dns_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'e': {
|
||||
u3_Host.ops_u.eth_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'E': {
|
||||
u3_Host.ops_u.ets_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'F': {
|
||||
u3_Host.ops_u.fak_c = _main_presig(optarg);
|
||||
u3_Host.ops_u.net = c3n;
|
||||
break;
|
||||
}
|
||||
case 'w': {
|
||||
u3_Host.ops_u.who_c = _main_presig(optarg);
|
||||
u3_Host.ops_u.nuu = c3y;
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
u3_Host.ops_u.url_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
u3_Host.ops_u.tex = c3y;
|
||||
break;
|
||||
}
|
||||
case 'f': {
|
||||
if ( c3n == _main_readw(optarg, 100, &u3_Host.ops_u.fuz_w) ) {
|
||||
return c3n;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'K': {
|
||||
if ( c3n == _main_readw(optarg, 256, &u3_Host.ops_u.kno_w) ) {
|
||||
return c3n;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'k': {
|
||||
u3_Host.ops_u.key_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
u3_Host.ops_u.sap_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
if ( c3n == _main_readw(optarg, 65536, &arg_w) ) {
|
||||
return c3n;
|
||||
} else u3_Host.ops_u.por_s = arg_w;
|
||||
break;
|
||||
}
|
||||
case 'R': {
|
||||
u3_Host.ops_u.rep = c3y;
|
||||
return c3y;
|
||||
}
|
||||
case 'L': { u3_Host.ops_u.net = c3n; break; }
|
||||
case 'j': { u3_Host.ops_u.tra = c3y; break; }
|
||||
case 'a': { u3_Host.ops_u.abo = c3y; break; }
|
||||
case 'b': { u3_Host.ops_u.bat = c3y; break; }
|
||||
case 'c': { u3_Host.ops_u.nuu = c3y; break; }
|
||||
case 'C': { u3_Host.ops_u.can = c3y; break; }
|
||||
case 'd': { u3_Host.ops_u.dem = c3y; break; }
|
||||
case 'g': { u3_Host.ops_u.gab = c3y; break; }
|
||||
case 'P': { u3_Host.ops_u.pro = c3y; break; }
|
||||
case 'D': { u3_Host.ops_u.dry = c3y; break; }
|
||||
case 'q': { u3_Host.ops_u.qui = c3y; break; }
|
||||
case 'v': { u3_Host.ops_u.veb = c3y; break; }
|
||||
case 's': { u3_Host.ops_u.git = c3y; break; }
|
||||
case 'S': { u3_Host.ops_u.has = c3y; break; }
|
||||
case 't': { u3_Host.ops_u.etn = c3y; break; }
|
||||
case '?': default: {
|
||||
return c3n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(U3_OS_bsd)
|
||||
if (u3_Host.ops_u.pro == c3y) {
|
||||
fprintf(stderr, "profiling isn't yet supported on BSD\r\n");
|
||||
return c3n;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( 0 != u3_Host.ops_u.fak_c ) {
|
||||
if ( 28 < strlen(u3_Host.ops_u.fak_c) ) {
|
||||
fprintf(stderr, "fake comets are disallowed\r\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
u3_Host.ops_u.who_c = strdup(u3_Host.ops_u.fak_c);
|
||||
u3_Host.ops_u.has = c3y; /* no battery hashing on fake ships. */
|
||||
u3_Host.ops_u.net = c3n; /* no networking on fake ships. */
|
||||
u3_Host.ops_u.nuu = c3y;
|
||||
}
|
||||
|
||||
if ( argc != (optind + 1) && u3_Host.ops_u.who_c != 0 ) {
|
||||
u3_Host.dir_c = strdup(1 + u3_Host.ops_u.who_c);
|
||||
}
|
||||
|
||||
if ( argc != (optind + 1) ) {
|
||||
return u3_Host.dir_c ? c3y : c3n;
|
||||
} else {
|
||||
{
|
||||
c3_c* ash_c;
|
||||
|
||||
if ( (ash_c = strrchr(argv[optind], '/')) && (ash_c[1] == 0) ) {
|
||||
*ash_c = 0;
|
||||
}
|
||||
}
|
||||
|
||||
u3_Host.dir_c = strdup(argv[optind]);
|
||||
}
|
||||
|
||||
if ( c3y == u3_Host.ops_u.bat ) {
|
||||
u3_Host.ops_u.dem = c3y;
|
||||
u3_Host.ops_u.nuu = c3y;
|
||||
}
|
||||
|
||||
// make -c optional, catch invalid boot of existing pier
|
||||
//
|
||||
{
|
||||
struct stat s;
|
||||
if ( 0 != stat(u3_Host.dir_c, &s) ) {
|
||||
if ( c3n == u3_Host.ops_u.nuu ) {
|
||||
u3_Host.ops_u.nuu = c3y;
|
||||
}
|
||||
}
|
||||
else if ( c3y == u3_Host.ops_u.nuu ) {
|
||||
fprintf(stderr, "tried to create, but %s already exists\n", u3_Host.dir_c);
|
||||
fprintf(stderr, "normal usage: %s %s\n", argv[0], u3_Host.dir_c);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
c3_t imp_t = ((0 != u3_Host.ops_u.who_c) &&
|
||||
(4 == strlen(u3_Host.ops_u.who_c)));
|
||||
|
||||
if ( u3_Host.ops_u.gen_c != 0 && u3_Host.ops_u.nuu == c3n ) {
|
||||
fprintf(stderr, "-G only makes sense when bootstrapping a new instance\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.who_c != 0) {
|
||||
fprintf(stderr, "-w only makes sense when creating a new ship\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.pil_c != 0) {
|
||||
fprintf(stderr, "-B only makes sense when creating a new ship\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.dns_c != 0) {
|
||||
fprintf(stderr, "-H only makes sense when bootstrapping a new instance\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.pil_c != 0) {
|
||||
fprintf(stderr, "-B only makes sense when bootstrapping a new instance\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.key_c != 0) {
|
||||
fprintf(stderr, "-k only makes sense when bootstrapping a new instance\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.url_c != 0 ) {
|
||||
fprintf(stderr, "-u only makes sense when bootstrapping a new instance\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.sap_c != 0 ) {
|
||||
fprintf(stderr, "-m only makes sense when bootstrapping a new instance\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.fak_c != 0 && u3_Host.ops_u.sap_c != 0 ) {
|
||||
fprintf(stderr, "-m and -F cannot be used together\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.ets_c != 0 && u3_Host.ops_u.sap_c != 0 ) {
|
||||
fprintf(stderr, "-m and -E cannot be used together\n");
|
||||
return c3n;
|
||||
}
|
||||
if ( u3_Host.ops_u.can == c3y && u3_Host.ops_u.sap_c != 0 ) {
|
||||
fprintf(stderr, "-m and -C cannot be used together\n");
|
||||
return c3n;
|
||||
}
|
||||
if ( u3_Host.ops_u.can == c3y && u3_Host.ops_u.ets_c != 0 ) {
|
||||
fprintf(stderr, "-C and -E cannot be used together\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.eth_c == 0 && imp_t ) {
|
||||
u3_Host.ops_u.eth_c = "http://eth-mainnet.urbit.org:8545";
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.sap_c == 0 && u3_Host.ops_u.can == c3n ) {
|
||||
|
||||
u3_Host.ops_u.sap_c =
|
||||
"https://bootstrap.urbit.org/urbit-" URBIT_VERSION ".snap";
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.url_c != 0 && u3_Host.ops_u.pil_c != 0 ) {
|
||||
fprintf(stderr, "-B and -u cannot be used together\n");
|
||||
return c3n;
|
||||
}
|
||||
else if ( u3_Host.ops_u.nuu == c3y
|
||||
&& u3_Host.ops_u.url_c == 0
|
||||
&& u3_Host.ops_u.git == c3n ) {
|
||||
u3_Host.ops_u.url_c =
|
||||
"https://bootstrap.urbit.org/urbit-" URBIT_VERSION ".pill";
|
||||
}
|
||||
else if ( u3_Host.ops_u.nuu == c3y
|
||||
&& u3_Host.ops_u.url_c == 0
|
||||
&& u3_Host.ops_u.arv_c == 0 ) {
|
||||
|
||||
fprintf(stderr, "-s only makes sense with -A\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.pil_c != 0 ) {
|
||||
struct stat s;
|
||||
if ( stat(u3_Host.ops_u.pil_c, &s) != 0 ) {
|
||||
fprintf(stderr, "pill %s not found\n", u3_Host.ops_u.pil_c);
|
||||
return c3n;
|
||||
}
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.key_c != 0 ) {
|
||||
struct stat s;
|
||||
if ( stat(u3_Host.ops_u.key_c, &s) != 0 ) {
|
||||
fprintf(stderr, "keyfile %s not found\n", u3_Host.ops_u.key_c);
|
||||
return c3n;
|
||||
}
|
||||
}
|
||||
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* u3_ve_usage(): print usage and exit.
|
||||
*/
|
||||
static void
|
||||
u3_ve_usage(c3_i argc, c3_c** argv)
|
||||
{
|
||||
c3_c *use_c[] = {
|
||||
"Urbit: a personal server operating function\n",
|
||||
"https://urbit.org\n",
|
||||
"Version " URBIT_VERSION "\n",
|
||||
"\n",
|
||||
"Usage: %s [options...] ship_name\n",
|
||||
"where ship_name is a @p phonetic representation of an urbit address\n",
|
||||
"without the leading '~', and options is some subset of the following:\n",
|
||||
"\n",
|
||||
// XX find a way to re-enable
|
||||
// "-A dir Use dir for initial galaxy sync\n",
|
||||
"-B pill Bootstrap from this pill\n",
|
||||
"-b Batch create\n",
|
||||
"-c pier Create a new urbit in pier/\n",
|
||||
"-D Recompute from events\n",
|
||||
"-d Daemon mode\n",
|
||||
"-e url Ethereum gateway\n",
|
||||
"-F ship Fake keys; also disables networking\n",
|
||||
"-f Fuzz testing\n",
|
||||
"-g Set GC flag\n",
|
||||
"-j file Create json trace file\n",
|
||||
"-K stage Start at Hoon kernel version stage\n",
|
||||
"-k keys Private key file\n",
|
||||
"-L local networking only\n",
|
||||
"-P Profiling\n",
|
||||
"-p ames_port Set the ames port to bind to\n",
|
||||
"-q Quiet\n",
|
||||
"-R Report urbit build info\n",
|
||||
"-S Disable battery hashing\n",
|
||||
// XX find a way to re-enable
|
||||
// "-s Pill URL from arvo git hash\n",
|
||||
"-u url URL from which to download pill\n",
|
||||
"-v Verbose\n",
|
||||
"-w name Boot as ~name\n",
|
||||
"-x Exit immediately\n",
|
||||
"\n",
|
||||
"Development Usage:\n",
|
||||
" To create a development ship, use a fakezod:\n",
|
||||
" %s -F zod -A /path/to/arvo/folder -B /path/to/pill -c zod\n",
|
||||
"\n",
|
||||
" For more information about developing on urbit, see:\n",
|
||||
" https://github.com/urbit/urbit/blob/master/CONTRIBUTING.md\n",
|
||||
"\n",
|
||||
"Simple Usage: \n",
|
||||
" %s -c <my-comet> to create a comet (anonymous urbit)\n",
|
||||
" %s -w <my-planet> -k <my-key-file> if you own a planet\n",
|
||||
" %s <myplanet or mycomet> to restart an existing urbit\n",
|
||||
0
|
||||
};
|
||||
|
||||
c3_i i;
|
||||
for ( i=0; use_c[i]; i++ ) {
|
||||
fprintf(stderr, use_c[i], argv[0]);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* u3_ve_panic(): panic and exit.
|
||||
*/
|
||||
static void
|
||||
u3_ve_panic(c3_i argc, c3_c** argv)
|
||||
{
|
||||
fprintf(stderr, "%s: gross system failure\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* u3_ve_sysopt(): apply option map to system state.
|
||||
*/
|
||||
static void
|
||||
u3_ve_sysopt()
|
||||
{
|
||||
u3_Local = strdup(u3_Host.dir_c);
|
||||
}
|
||||
|
||||
static void
|
||||
report(void)
|
||||
{
|
||||
printf("urbit %s\n", URBIT_VERSION);
|
||||
printf("---------\nLibraries\n---------\n");
|
||||
printf("gmp: %s\n", gmp_version);
|
||||
printf("sigsegv: %d.%d\n",
|
||||
(libsigsegv_version >> 8) & 0xff,
|
||||
libsigsegv_version & 0xff);
|
||||
printf("openssl: %s\n", SSLeay_version(SSLEAY_VERSION));
|
||||
printf("curses: %s\n", curses_version());
|
||||
printf("libuv: %s\n", uv_version_string());
|
||||
printf("libh2o: %d.%d.%d\n",
|
||||
H2O_LIBRARY_VERSION_MAJOR,
|
||||
H2O_LIBRARY_VERSION_MINOR,
|
||||
H2O_LIBRARY_VERSION_PATCH);
|
||||
printf("lmdb: %d.%d.%d\n",
|
||||
MDB_VERSION_MAJOR,
|
||||
MDB_VERSION_MINOR,
|
||||
MDB_VERSION_PATCH);
|
||||
printf("curl: %d.%d.%d\n",
|
||||
LIBCURL_VERSION_MAJOR,
|
||||
LIBCURL_VERSION_MINOR,
|
||||
LIBCURL_VERSION_PATCH);
|
||||
printf("argon2: 0x%x\n", ARGON2_VERSION_NUMBER);
|
||||
}
|
||||
|
||||
static void
|
||||
_stop_exit(c3_i int_i)
|
||||
{
|
||||
// explicit fprintf to avoid allocation in u3l_log
|
||||
//
|
||||
fprintf(stderr, "\r\n[received keyboard stop signal, exiting]\r\n");
|
||||
u3_daemon_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));
|
||||
}
|
||||
|
||||
c3_i
|
||||
main(c3_i argc,
|
||||
c3_c** argv)
|
||||
{
|
||||
// Parse options.
|
||||
//
|
||||
if ( c3n == _main_getopt(argc, argv) ) {
|
||||
u3_ve_usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set `u3_Host.wrk_c` to the worker executable path.
|
||||
c3_i worker_exe_len = 1 + strlen(argv[0]) + strlen("-worker");
|
||||
u3_Host.wrk_c = c3_malloc(worker_exe_len);
|
||||
snprintf(u3_Host.wrk_c, worker_exe_len, "%s-worker", argv[0]);
|
||||
|
||||
// Set TERMINFO_DIRS environment variable
|
||||
c3_i terminfo_len = 1 + strlen(argv[0]) + strlen("-terminfo");
|
||||
c3_c terminfo_dir[terminfo_len];
|
||||
snprintf(terminfo_dir, terminfo_len, "%s-terminfo", argv[0]);
|
||||
setenv("TERMINFO_DIRS", terminfo_dir, 1);
|
||||
|
||||
if ( c3y == u3_Host.ops_u.dem ) {
|
||||
_fork_into_background_process();
|
||||
}
|
||||
|
||||
if ( c3y == u3_Host.ops_u.rep ) {
|
||||
report();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if ( 0 == getuid() ) {
|
||||
chroot(u3_Host.dir_c);
|
||||
u3_Host.dir_c = "/";
|
||||
}
|
||||
#endif
|
||||
u3_ve_sysopt();
|
||||
|
||||
// Block profiling signal, which should be delivered to exactly one thread.
|
||||
//
|
||||
// XX review, may be unnecessary due to similar in u3m_init()
|
||||
//
|
||||
if ( _(u3_Host.ops_u.pro) ) {
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGPROF);
|
||||
if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) {
|
||||
u3l_log("boot: thread mask SIGPROF: %s\r\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle SIGTSTP as if it was SIGTERM.
|
||||
//
|
||||
// Configured here using signal() so as to be immediately available.
|
||||
//
|
||||
signal(SIGTSTP, _stop_exit);
|
||||
|
||||
printf("~\n");
|
||||
// printf("welcome.\n");
|
||||
printf("urbit %s\n", URBIT_VERSION);
|
||||
|
||||
// prints the absolute path of the pier
|
||||
//
|
||||
c3_c* abs_c = realpath(u3_Host.dir_c, 0);
|
||||
|
||||
// if the ship is being booted, we use realpath(). Otherwise, we use getcwd()
|
||||
// with a memory-allocation loop
|
||||
//
|
||||
if (abs_c == NULL) {
|
||||
c3_i mprint_i = 1000;
|
||||
abs_c = c3_malloc(mprint_i);
|
||||
|
||||
// allocates more memory as needed if the path is too large
|
||||
//
|
||||
while ( abs_c != getcwd(abs_c, mprint_i) ) {
|
||||
free(abs_c);
|
||||
mprint_i *= 2;
|
||||
abs_c = c3_malloc(mprint_i);
|
||||
}
|
||||
printf("boot: home is %s/%s\n", abs_c, u3_Host.dir_c);
|
||||
free(abs_c);
|
||||
} else {
|
||||
printf("boot: home is %s\n", abs_c);
|
||||
free(abs_c);
|
||||
}
|
||||
// printf("vere: hostname is %s\n", u3_Host.ops_u.nam_c);
|
||||
|
||||
if ( c3y == u3_Host.ops_u.dem && c3n == u3_Host.ops_u.bat ) {
|
||||
printf("boot: running as daemon\n");
|
||||
}
|
||||
|
||||
// Seed prng. Don't panic -- just for fuzz testing.
|
||||
//
|
||||
srand(getpid());
|
||||
|
||||
// Instantiate process globals.
|
||||
{
|
||||
/* Boot the image and checkpoint. Set flags.
|
||||
*/
|
||||
{
|
||||
/* Set pier directory.
|
||||
*/
|
||||
u3C.dir_c = u3_Host.dir_c;
|
||||
|
||||
/* Logging that doesn't interfere with console output.
|
||||
*/
|
||||
u3C.stderr_log_f = u3_term_io_log;
|
||||
|
||||
/* Set GC flag.
|
||||
*/
|
||||
if ( _(u3_Host.ops_u.gab) ) {
|
||||
u3C.wag_w |= u3o_debug_ram;
|
||||
}
|
||||
|
||||
/* Set profile flag.
|
||||
*/
|
||||
if ( _(u3_Host.ops_u.pro) ) {
|
||||
u3C.wag_w |= u3o_debug_cpu;
|
||||
}
|
||||
|
||||
/* Set verbose flag.
|
||||
*/
|
||||
if ( _(u3_Host.ops_u.veb) ) {
|
||||
u3C.wag_w |= u3o_verbose;
|
||||
}
|
||||
|
||||
/* Set quiet flag.
|
||||
*/
|
||||
if ( _(u3_Host.ops_u.qui) ) {
|
||||
u3C.wag_w |= u3o_quiet;
|
||||
}
|
||||
|
||||
/* Set dry-run flag.
|
||||
*/
|
||||
if ( _(u3_Host.ops_u.dry) ) {
|
||||
u3C.wag_w |= u3o_dryrun;
|
||||
}
|
||||
|
||||
/* Set hashboard flag
|
||||
*/
|
||||
if ( _(u3_Host.ops_u.has) ) {
|
||||
u3C.wag_w |= u3o_hashless;
|
||||
}
|
||||
|
||||
/* Set tracing flag
|
||||
*/
|
||||
if ( _(u3_Host.ops_u.tra) ) {
|
||||
u3C.wag_w |= u3o_trace;
|
||||
u3_Host.tra_u.nid_w = 0;
|
||||
u3_Host.tra_u.fil_u = NULL;
|
||||
u3_Host.tra_u.con_w = 0;
|
||||
u3_Host.tra_u.fun_w = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize OpenSSL for client and server
|
||||
*/
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
|
||||
u3_daemon_commence();
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,525 +0,0 @@
|
||||
/* vere/dawn.c
|
||||
**
|
||||
** ethereum-integrated pre-boot validation
|
||||
*/
|
||||
#include <curl/curl.h>
|
||||
#include <uv.h>
|
||||
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* _dawn_oct_to_buf(): +octs to uv_buf_t
|
||||
*/
|
||||
static uv_buf_t
|
||||
_dawn_oct_to_buf(u3_noun oct)
|
||||
{
|
||||
if ( c3n == u3a_is_cat(u3h(oct)) ) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
c3_w len_w = u3h(oct);
|
||||
c3_y* buf_y = c3_malloc(1 + len_w);
|
||||
buf_y[len_w] = 0;
|
||||
|
||||
u3r_bytes(0, len_w, buf_y, u3t(oct));
|
||||
|
||||
u3z(oct);
|
||||
return uv_buf_init((void*)buf_y, len_w);
|
||||
}
|
||||
|
||||
/* _dawn_buf_to_oct(): uv_buf_t to +octs
|
||||
*/
|
||||
static u3_noun
|
||||
_dawn_buf_to_oct(uv_buf_t buf_u)
|
||||
{
|
||||
u3_noun len = u3i_words(1, (c3_w*)&buf_u.len);
|
||||
|
||||
if ( c3n == u3a_is_cat(len) ) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return u3nc(len, u3i_bytes(buf_u.len, (const c3_y*)buf_u.base));
|
||||
}
|
||||
|
||||
|
||||
/* _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)
|
||||
{
|
||||
size_t siz_t = uni_t * mem_t;
|
||||
buf_u->base = c3_realloc(buf_u->base, 1 + siz_t + buf_u->len);
|
||||
|
||||
memcpy(buf_u->base + buf_u->len, dat_v, siz_t);
|
||||
buf_u->len += siz_t;
|
||||
buf_u->base[buf_u->len] = 0;
|
||||
|
||||
return siz_t;
|
||||
}
|
||||
|
||||
/* _dawn_post_json(): POST JSON to url_c
|
||||
*/
|
||||
static uv_buf_t
|
||||
_dawn_post_json(c3_c* url_c, uv_buf_t lod_u)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode result;
|
||||
long cod_l;
|
||||
struct curl_slist* hed_u = 0;
|
||||
|
||||
uv_buf_t buf_u = uv_buf_init(c3_malloc(1), 0);
|
||||
|
||||
if ( !(curl = curl_easy_init()) ) {
|
||||
u3l_log("failed to initialize libcurl\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hed_u = curl_slist_append(hed_u, "Accept: application/json");
|
||||
hed_u = curl_slist_append(hed_u, "Content-Type: application/json");
|
||||
hed_u = curl_slist_append(hed_u, "charsets: utf-8");
|
||||
|
||||
// XX require TLS, pin default cert?
|
||||
|
||||
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);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hed_u);
|
||||
|
||||
// note: must be terminated!
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, lod_u.base);
|
||||
|
||||
result = curl_easy_perform(curl);
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &cod_l);
|
||||
|
||||
// XX retry?
|
||||
if ( CURLE_OK != result ) {
|
||||
u3l_log("failed to fetch %s: %s\n",
|
||||
url_c, curl_easy_strerror(result));
|
||||
exit(1);
|
||||
}
|
||||
if ( 300 <= cod_l ) {
|
||||
u3l_log("error fetching %s: HTTP %ld\n", url_c, cod_l);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
curl_slist_free_all(hed_u);
|
||||
|
||||
return buf_u;
|
||||
}
|
||||
|
||||
/* _dawn_get_jam(): GET a jammed noun from url_c
|
||||
*/
|
||||
static u3_noun
|
||||
_dawn_get_jam(c3_c* url_c)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode result;
|
||||
long cod_l;
|
||||
|
||||
uv_buf_t buf_u = uv_buf_init(c3_malloc(1), 0);
|
||||
|
||||
if ( !(curl = curl_easy_init()) ) {
|
||||
u3l_log("failed to initialize libcurl\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// XX require TLS, pin default cert?
|
||||
|
||||
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);
|
||||
|
||||
result = curl_easy_perform(curl);
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &cod_l);
|
||||
|
||||
// XX retry?
|
||||
if ( CURLE_OK != result ) {
|
||||
u3l_log("failed to fetch %s: %s\n",
|
||||
url_c, curl_easy_strerror(result));
|
||||
exit(1);
|
||||
}
|
||||
if ( 300 <= cod_l ) {
|
||||
u3l_log("error fetching %s: HTTP %ld\n", url_c, cod_l);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
// throw away the length from the octs
|
||||
//
|
||||
u3_noun octs = _dawn_buf_to_oct(buf_u);
|
||||
u3_noun jammed = u3k(u3t(octs));
|
||||
u3z(octs);
|
||||
|
||||
return u3ke_cue(jammed);
|
||||
}
|
||||
|
||||
/* _dawn_eth_rpc(): ethereum JSON RPC with request/response as +octs
|
||||
*/
|
||||
static u3_noun
|
||||
_dawn_eth_rpc(c3_c* url_c, u3_noun oct)
|
||||
{
|
||||
return _dawn_buf_to_oct(_dawn_post_json(url_c, _dawn_oct_to_buf(oct)));
|
||||
}
|
||||
|
||||
/* _dawn_fail(): pre-boot validation failed
|
||||
*/
|
||||
static void
|
||||
_dawn_fail(u3_noun who, u3_noun rac, u3_noun sas)
|
||||
{
|
||||
u3_noun how = u3dc("scot", 'p', u3k(who));
|
||||
c3_c* how_c = u3r_string(u3k(how));
|
||||
|
||||
c3_c* rac_c;
|
||||
|
||||
switch (rac) {
|
||||
default: c3_assert(0);
|
||||
case c3__czar: {
|
||||
rac_c = "galaxy";
|
||||
break;
|
||||
}
|
||||
case c3__king: {
|
||||
rac_c = "star";
|
||||
break;
|
||||
}
|
||||
case c3__duke: {
|
||||
rac_c = "planet";
|
||||
break;
|
||||
}
|
||||
case c3__earl: {
|
||||
rac_c = "moon";
|
||||
break;
|
||||
}
|
||||
case c3__pawn: {
|
||||
rac_c = "comet";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u3l_log("boot: invalid keys for %s '%s'\r\n", rac_c, how_c);
|
||||
|
||||
// XX deconstruct sas, print helpful error messages
|
||||
u3m_p("pre-boot error", u3t(sas));
|
||||
|
||||
u3z(how);
|
||||
free(how_c);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* _dawn_need_unit(): produce a value or print error and exit
|
||||
*/
|
||||
static u3_noun
|
||||
_dawn_need_unit(u3_noun nit, c3_c* msg_c)
|
||||
{
|
||||
if ( u3_nul == nit ) {
|
||||
u3l_log("%s\r\n", msg_c);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
u3_noun pro = u3k(u3t(nit));
|
||||
u3z(nit);
|
||||
return pro;
|
||||
}
|
||||
}
|
||||
|
||||
/* _dawn_purl(): ethereum gateway url as (unit purl)
|
||||
*/
|
||||
static u3_noun
|
||||
_dawn_purl(u3_noun rac)
|
||||
{
|
||||
u3_noun url;
|
||||
|
||||
if ( 0 == u3_Host.ops_u.eth_c ) {
|
||||
if ( c3__czar == rac ) {
|
||||
u3l_log("boot: galaxy requires ethereum gateway via -e\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
url = u3_nul;
|
||||
}
|
||||
else {
|
||||
// XX call de-purl directly
|
||||
//
|
||||
u3_noun par = u3v_wish("auru:de-purl:html");
|
||||
u3_noun lur = u3i_string(u3_Host.ops_u.eth_c);
|
||||
u3_noun rul = u3dc("rush", u3k(lur), u3k(par));
|
||||
|
||||
if ( u3_nul == rul ) {
|
||||
if ( c3__czar == rac ) {
|
||||
u3l_log("boot: galaxy requires ethereum gateway via -e\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
url = u3_nul;
|
||||
}
|
||||
else {
|
||||
// XX revise for de-purl
|
||||
// auru:de-purl:html parses to (pair user purl)
|
||||
// we need (unit purl)
|
||||
//
|
||||
url = u3nc(u3_nul, u3k(u3t(u3t(rul))));
|
||||
}
|
||||
|
||||
u3z(par); u3z(lur); u3z(rul);
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/* _dawn_turf(): override contract domains with -H
|
||||
*/
|
||||
static u3_noun
|
||||
_dawn_turf(c3_c* dns_c)
|
||||
{
|
||||
u3_noun tuf;
|
||||
|
||||
u3_noun par = u3v_wish("thos:de-purl:html");
|
||||
u3_noun dns = u3i_string(dns_c);
|
||||
u3_noun rul = u3dc("rush", u3k(dns), u3k(par));
|
||||
|
||||
if ( (u3_nul == rul) || (c3n == u3h(u3t(rul))) ) {
|
||||
u3l_log("boot: invalid domain specified with -H %s\r\n", dns_c);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
u3l_log("boot: overriding network domains with %s\r\n", dns_c);
|
||||
u3_noun dom = u3t(u3t(rul));
|
||||
tuf = u3nc(u3k(dom), u3_nul);
|
||||
}
|
||||
|
||||
u3z(par); u3z(dns); u3z(rul);
|
||||
|
||||
return tuf;
|
||||
}
|
||||
|
||||
/* u3_dawn_vent(): validated boot event
|
||||
*/
|
||||
u3_noun
|
||||
u3_dawn_vent(u3_noun seed)
|
||||
{
|
||||
u3_noun url, bok, pon, zar, tuf, sap;
|
||||
|
||||
u3_noun ship = u3h(seed);
|
||||
u3_noun rank = u3do("clan:title", u3k(ship));
|
||||
|
||||
// load snapshot from file
|
||||
//
|
||||
if ( 0 != u3_Host.ops_u.ets_c ) {
|
||||
u3l_log("boot: loading azimuth snapshot\r\n");
|
||||
u3_noun raw_snap = u3ke_cue(u3m_file(u3_Host.ops_u.ets_c));
|
||||
sap = u3nc(u3_nul, raw_snap);
|
||||
}
|
||||
// load snapshot from HTTP URL
|
||||
//
|
||||
else if ( 0 != u3_Host.ops_u.sap_c ) {
|
||||
u3l_log("boot: downloading azimuth snapshot from %s\r\n",
|
||||
u3_Host.ops_u.sap_c);
|
||||
u3_noun raw_snap = _dawn_get_jam(u3_Host.ops_u.sap_c);
|
||||
sap = u3nc(u3_nul, raw_snap);
|
||||
}
|
||||
// no snapshot
|
||||
//
|
||||
else {
|
||||
u3l_log("boot: no azimuth snapshot specified\n");
|
||||
sap = u3_nul;
|
||||
}
|
||||
|
||||
url = _dawn_purl(rank);
|
||||
|
||||
// XX require https?
|
||||
//
|
||||
c3_c* url_c = ( 0 != u3_Host.ops_u.eth_c ) ?
|
||||
u3_Host.ops_u.eth_c :
|
||||
"https://mainnet.infura.io/v3/196a7f37c7d54211b4a07904ec73ad87";
|
||||
|
||||
// pin block number
|
||||
//
|
||||
if ( c3y == u3_Host.ops_u.etn ) {
|
||||
u3l_log("boot: extracting block from snapshot\r\n");
|
||||
|
||||
bok = _dawn_need_unit(u3do("bloq:snap:dawn", u3k(u3t(sap))),
|
||||
"boot: failed to extract "
|
||||
"block from snapshot");
|
||||
}
|
||||
else {
|
||||
u3l_log("boot: retrieving latest block\r\n");
|
||||
|
||||
u3_noun oct = u3v_wish("bloq:give:dawn");
|
||||
u3_noun kob = _dawn_eth_rpc(url_c, u3k(oct));
|
||||
|
||||
bok = _dawn_need_unit(u3do("bloq:take:dawn", u3k(kob)),
|
||||
"boot: block retrieval failed");
|
||||
u3z(oct); u3z(kob);
|
||||
}
|
||||
|
||||
{
|
||||
// +point:azimuth: on-chain state
|
||||
//
|
||||
u3_noun pot;
|
||||
|
||||
if ( c3y == u3_Host.ops_u.etn ) {
|
||||
u3l_log("boot: extracting public keys from snapshot\r\n");
|
||||
|
||||
pot = _dawn_need_unit(u3dc("point:snap:dawn", u3k(ship), u3k(u3t(sap))),
|
||||
"boot: failed to extract "
|
||||
"public keys from snapshot");
|
||||
}
|
||||
else if ( c3__pawn == rank ) {
|
||||
// irrelevant, just bunt +point
|
||||
//
|
||||
pot = u3v_wish("*point:azimuth");
|
||||
}
|
||||
else {
|
||||
u3_noun who;
|
||||
|
||||
if ( c3__earl == rank ) {
|
||||
who = u3do("^sein:title", u3k(ship));
|
||||
|
||||
{
|
||||
u3_noun seg = u3dc("scot", 'p', u3k(who));
|
||||
c3_c* seg_c = u3r_string(seg);
|
||||
|
||||
u3l_log("boot: retrieving %s's public keys (for %s)\r\n",
|
||||
seg_c, u3_Host.ops_u.who_c);
|
||||
free(seg_c);
|
||||
u3z(seg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
who = u3k(ship);
|
||||
u3l_log("boot: retrieving %s's public keys\r\n",
|
||||
u3_Host.ops_u.who_c);
|
||||
}
|
||||
|
||||
{
|
||||
u3_noun oct = u3dc("point:give:dawn", u3k(bok), u3k(who));
|
||||
u3_noun luh = _dawn_eth_rpc(url_c, u3k(oct));
|
||||
|
||||
pot = _dawn_need_unit(u3dc("point:take:dawn", u3k(ship), u3k(luh)),
|
||||
"boot: failed to retrieve public keys");
|
||||
u3z(oct); u3z(luh);
|
||||
}
|
||||
|
||||
u3z(who);
|
||||
}
|
||||
|
||||
// +live:dawn: network state
|
||||
// XX actually make request
|
||||
//
|
||||
u3_noun liv = u3_nul;
|
||||
// u3_noun liv = _dawn_get_json(parent, /some/url)
|
||||
|
||||
u3l_log("boot: verifying keys\r\n");
|
||||
|
||||
// (each sponsor=ship error=@tas)
|
||||
//
|
||||
u3_noun sas = u3dt("veri:dawn", u3k(seed), u3k(pot), u3k(liv));
|
||||
|
||||
if ( c3n == u3h(sas) ) {
|
||||
// bails, won't return
|
||||
_dawn_fail(ship, rank, sas);
|
||||
return u3_none;
|
||||
}
|
||||
|
||||
// ship: sponsor
|
||||
// produced by +veri:dawn to avoid coupling to +point structure
|
||||
// XX reconsider
|
||||
//
|
||||
pon = u3k(u3t(sas));
|
||||
|
||||
u3z(pot); u3z(liv); u3z(sas);
|
||||
}
|
||||
|
||||
// (map ship [=life =pass]): galaxy table
|
||||
//
|
||||
if ( c3y == u3_Host.ops_u.etn ) {
|
||||
u3l_log("boot: extracting galaxy table from snapshot\r\n");
|
||||
|
||||
zar = _dawn_need_unit(u3do("czar:snap:dawn", u3k(u3t(sap))),
|
||||
"boot: failed to extract "
|
||||
"galaxy table from snapshot");
|
||||
}
|
||||
else {
|
||||
u3l_log("boot: retrieving galaxy table\r\n");
|
||||
|
||||
u3_noun oct = u3do("czar:give:dawn", u3k(bok));
|
||||
u3_noun raz = _dawn_eth_rpc(url_c, u3k(oct));
|
||||
|
||||
zar = _dawn_need_unit(u3do("czar:take:dawn", u3k(raz)),
|
||||
"boot: failed to retrieve galaxy table");
|
||||
u3z(oct); u3z(raz);
|
||||
}
|
||||
|
||||
// (list turf): ames domains
|
||||
//
|
||||
if ( 0 != u3_Host.ops_u.dns_c ) {
|
||||
tuf = _dawn_turf(u3_Host.ops_u.dns_c);
|
||||
}
|
||||
else if ( c3y == u3_Host.ops_u.etn ) {
|
||||
u3l_log("boot: extracting network domains from snapshot\r\n");
|
||||
|
||||
tuf = _dawn_need_unit(u3do("turf:snap:dawn", u3k(u3t(sap))),
|
||||
"boot: failed to extract "
|
||||
"network domains from snapshot");
|
||||
}
|
||||
else {
|
||||
u3l_log("boot: retrieving network domains\r\n");
|
||||
|
||||
u3_noun oct = u3do("turf:give:dawn", u3k(bok));
|
||||
u3_noun fut = _dawn_eth_rpc(url_c, u3k(oct));
|
||||
|
||||
tuf = _dawn_need_unit(u3do("turf:take:dawn", u3k(fut)),
|
||||
"boot: failed to retrieve network domains");
|
||||
u3z(oct); u3z(fut);
|
||||
}
|
||||
|
||||
u3z(rank);
|
||||
|
||||
// [%dawn seed sponsor galaxies domains block eth-url snap]
|
||||
//
|
||||
return u3nc(c3__dawn, u3nq(seed, pon, zar, u3nq(tuf, bok, url, sap)));
|
||||
}
|
||||
|
||||
/* _dawn_come(): mine a comet under a list of stars
|
||||
*/
|
||||
static u3_noun
|
||||
_dawn_come(u3_noun stars)
|
||||
{
|
||||
u3_noun seed;
|
||||
{
|
||||
c3_w eny_w[16];
|
||||
u3_noun eny;
|
||||
|
||||
c3_rand(eny_w);
|
||||
eny = u3i_words(16, eny_w);
|
||||
|
||||
u3l_log("boot: mining a comet. May take up to an hour.\r\n");
|
||||
u3l_log("If you want to boot faster, get an Azimuth point.\r\n");
|
||||
|
||||
seed = u3dc("come:dawn", u3k(stars), u3k(eny));
|
||||
u3z(eny);
|
||||
}
|
||||
|
||||
{
|
||||
u3_noun who = u3dc("scot", 'p', u3k(u3h(seed)));
|
||||
c3_c* who_c = u3r_string(who);
|
||||
|
||||
u3l_log("boot: found comet %s\r\n", who_c);
|
||||
free(who_c);
|
||||
u3z(who);
|
||||
}
|
||||
|
||||
u3z(stars);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
/* u3_dawn_come(): mine a comet under a list of stars we download
|
||||
*/
|
||||
u3_noun
|
||||
u3_dawn_come()
|
||||
{
|
||||
return _dawn_come(
|
||||
_dawn_get_jam("https://bootstrap.urbit.org/comet-stars.jam"));
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
/* vere/foil.c
|
||||
**
|
||||
** This file is in the public domain.
|
||||
*/
|
||||
|
||||
#include "all.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <setjmp.h>
|
||||
#include <gmp.h>
|
||||
#include <dirent.h>
|
||||
#include <stdint.h>
|
||||
#include <uv.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses/term.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <ftw.h>
|
||||
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* assumptions:
|
||||
** all measurements are in chubs (double-words, c3_d, uint64_t).
|
||||
** little-endian addressing is ASSUMED.
|
||||
**
|
||||
** framing:
|
||||
** the last two chubs of a frame:
|
||||
**
|
||||
** {
|
||||
** 64-bit frame length
|
||||
** {
|
||||
** (high 32 bits) mug of frame
|
||||
** (low 32 bits) mug of current address
|
||||
** }
|
||||
** }
|
||||
**
|
||||
** we can scan for one of these frames with very low probability
|
||||
** of a false positive. we always write to and read from the end
|
||||
** of a file. a frame position points to its end.
|
||||
**
|
||||
** protocol:
|
||||
** once the callback is called, all results are fully fsynced.
|
||||
** all callbacks are optional and can be passed 0.
|
||||
*/
|
||||
|
||||
/* _foil_fail(): fail with error.
|
||||
*/
|
||||
static void
|
||||
_foil_fail(const c3_c* why_c, c3_i err_i)
|
||||
{
|
||||
if ( err_i ) {
|
||||
u3l_log("%s: error: %s\r\n", why_c, uv_strerror(err_i));
|
||||
c3_assert(0);
|
||||
} else {
|
||||
u3l_log("%s: file error\r\n", why_c);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* _foil_close(): close file, blockingly.
|
||||
*/
|
||||
static void
|
||||
_foil_close(uv_file fil_f)
|
||||
{
|
||||
c3_i err_i;
|
||||
uv_fs_t ruq_u;
|
||||
|
||||
if ( 0 != (err_i = uv_fs_close(u3L, &ruq_u, fil_f, 0)) ) {
|
||||
_foil_fail("uv_fs_close", err_i);
|
||||
}
|
||||
}
|
||||
|
||||
/* _foil_path(): allocate path.
|
||||
*/
|
||||
static c3_c*
|
||||
_foil_path(u3_dire* dir_u,
|
||||
const c3_c* nam_c)
|
||||
{
|
||||
c3_w len_w = strlen(dir_u->pax_c);
|
||||
c3_c* pax_c;
|
||||
|
||||
pax_c = c3_malloc(1 + len_w + 1 + strlen(nam_c));
|
||||
strcpy(pax_c, dir_u->pax_c);
|
||||
pax_c[len_w] = '/';
|
||||
strcpy(pax_c + len_w + 1, nam_c);
|
||||
|
||||
return pax_c;
|
||||
}
|
||||
|
||||
/* u3_foil_folder(): load directory, blockingly. null if nonexistent.
|
||||
*/
|
||||
u3_dire*
|
||||
u3_foil_folder(const c3_c* pax_c)
|
||||
{
|
||||
u3_dire* dir_u;
|
||||
uv_fs_t ruq_u;
|
||||
uv_dirent_t den_u;
|
||||
c3_i err_i;
|
||||
|
||||
/* open directory, synchronously
|
||||
*/
|
||||
{
|
||||
err_i = uv_fs_scandir(u3L, &ruq_u, pax_c, 0, 0);
|
||||
|
||||
if ( err_i < 0 ) {
|
||||
if ( UV_ENOENT != err_i ) {
|
||||
_foil_fail(pax_c, err_i);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if ( 0 != (err_i = uv_fs_mkdir(u3L, &ruq_u, pax_c, 0700, 0)) ) {
|
||||
_foil_fail(pax_c, err_i);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
uv_fs_req_cleanup(&ruq_u);
|
||||
return u3_foil_folder(pax_c);
|
||||
}
|
||||
}
|
||||
}
|
||||
dir_u = c3_malloc(sizeof *dir_u);
|
||||
dir_u->all_u = 0;
|
||||
dir_u->pax_c = c3_malloc(1 + strlen(pax_c));
|
||||
strcpy(dir_u->pax_c, pax_c);
|
||||
}
|
||||
|
||||
/* create entries for all files
|
||||
*/
|
||||
while ( UV_EOF != uv_fs_scandir_next(&ruq_u, &den_u) ) {
|
||||
if ( UV_DIRENT_FILE == den_u.type ) {
|
||||
u3_dent* det_u = c3_malloc(sizeof(*det_u));
|
||||
|
||||
det_u->nam_c = c3_malloc(1 + strlen(den_u.name));
|
||||
strcpy(det_u->nam_c, den_u.name);
|
||||
|
||||
det_u->nex_u = dir_u->all_u;
|
||||
dir_u->all_u = det_u;
|
||||
}
|
||||
}
|
||||
|
||||
/* clean up request
|
||||
*/
|
||||
{
|
||||
uv_fs_req_cleanup(&ruq_u);
|
||||
}
|
||||
|
||||
/* open directory file for reading, to fsync
|
||||
*/
|
||||
{
|
||||
if ( 0 > (err_i = uv_fs_open(u3L,
|
||||
&ruq_u,
|
||||
pax_c,
|
||||
O_RDONLY,
|
||||
0600,
|
||||
0)) )
|
||||
{
|
||||
_foil_fail("open directory", err_i);
|
||||
return 0;
|
||||
}
|
||||
dir_u->fil_u = ruq_u.result;
|
||||
|
||||
uv_fs_req_cleanup(&ruq_u);
|
||||
}
|
||||
return dir_u;
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
#include "all.h"
|
||||
|
||||
/* _setup(): prepare for tests.
|
||||
*/
|
||||
static void
|
||||
_setup(void)
|
||||
{
|
||||
u3m_init();
|
||||
u3m_pave(c3y, c3n);
|
||||
}
|
||||
|
||||
/* _test_mug(): spot check u3r_mug hashes.
|
||||
*/
|
||||
static void
|
||||
_test_mug(void)
|
||||
{
|
||||
if ( 0x4d441035 != u3r_mug_string("Hello, world!") ) {
|
||||
fprintf(stderr, "fail (a)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( 0x4d441035 != u3r_mug(u3i_string("Hello, world!")) ) {
|
||||
fprintf(stderr, "fail (b)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( 0x79ff04e8 != u3r_mug_bytes(0, 0) ) {
|
||||
fprintf(stderr, "fail (c)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( 0x64dfda5c != u3r_mug(u3i_string("xxxxxxxxxxxxxxxxxxxxxxxxxxxx")) ) {
|
||||
fprintf(stderr, "fail (d)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( 0x389ca03a != u3r_mug_cell(0, 0) ) {
|
||||
fprintf(stderr, "fail (e)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( 0x389ca03a != u3r_mug_cell(1, 1) ) {
|
||||
fprintf(stderr, "fail (f)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( 0x5258a6c0 != u3r_mug_cell(0, u3qc_bex(32)) ) {
|
||||
fprintf(stderr, "fail (g)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( 0x2ad39968 != u3r_mug_cell(u3qa_dec(u3qc_bex(128)), 1) ) {
|
||||
fprintf(stderr, "fail (h)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
{
|
||||
// stick some zero bytes in a string
|
||||
//
|
||||
u3_noun str = u3kc_lsh(3, 1,
|
||||
u3kc_mix(u3qc_bex(212),
|
||||
u3i_string("abcdefjhijklmnopqrstuvwxyz")));
|
||||
|
||||
c3_w byt_w = u3r_met(3, str);
|
||||
c3_w wor_w = u3r_met(5, str);
|
||||
c3_y* str_y = c3_malloc(byt_w);
|
||||
c3_w* str_w = c3_malloc(4 * wor_w);
|
||||
c3_d str_d = 0;
|
||||
|
||||
u3r_bytes(0, byt_w, str_y, str);
|
||||
u3r_words(0, wor_w, str_w, str);
|
||||
|
||||
str_d |= str_w[0];
|
||||
str_d |= ((c3_d)str_w[1] << 32ULL);
|
||||
|
||||
if ( 0x34d08717 != u3r_mug(str) ) {
|
||||
fprintf(stderr, "fail (i) (1) \r\n");
|
||||
exit(1);
|
||||
}
|
||||
if ( 0x34d08717 != u3r_mug_bytes(str_y, byt_w) ) {
|
||||
fprintf(stderr, "fail (i) (2)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
if ( 0x34d08717 != u3r_mug_words(str_w, wor_w) ) {
|
||||
fprintf(stderr, "fail (i) (3)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
if ( u3r_mug_words(str_w, 2) != u3r_mug_chub(str_d) ) {
|
||||
fprintf(stderr, "fail (i) (4)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* main(): run all test cases.
|
||||
*/
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
_setup();
|
||||
|
||||
_test_mug();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
#include "all.h"
|
||||
|
||||
static void _setup(void);
|
||||
static void _test_cache_replace_value(void);
|
||||
static void _test_cache_trimming(void);
|
||||
static void _test_no_cache(void);
|
||||
static void _test_skip_slot(void);
|
||||
|
||||
// defined in noun/hashtable.c
|
||||
c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w);
|
||||
|
||||
|
||||
/* main(): run all test cases.
|
||||
*/
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
_setup();
|
||||
|
||||
_test_no_cache();
|
||||
_test_skip_slot();
|
||||
_test_cache_trimming();
|
||||
_test_cache_replace_value();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* _setup(): prepare for tests.
|
||||
*/
|
||||
static void
|
||||
_setup(void)
|
||||
{
|
||||
u3m_init();
|
||||
u3m_pave(c3y, c3n);
|
||||
}
|
||||
|
||||
/* _test_no_cache(): test a hashtable without caching.
|
||||
*/
|
||||
static void
|
||||
_test_no_cache(void)
|
||||
{
|
||||
c3_w i_w;
|
||||
c3_w max_w = 1000;
|
||||
|
||||
u3p(u3h_root) har_p = u3h_new();
|
||||
|
||||
for ( i_w = 0; i_w < max_w; i_w++ ) {
|
||||
u3h_put(har_p, i_w, i_w + max_w);
|
||||
}
|
||||
|
||||
for ( i_w = 0; i_w < max_w; i_w++ ) {
|
||||
c3_assert(i_w + max_w == u3h_get(har_p, i_w));
|
||||
}
|
||||
printf("test_no_cache: ok\n");
|
||||
}
|
||||
|
||||
/* _test_skip_slot():
|
||||
*/
|
||||
static void
|
||||
_test_skip_slot(void)
|
||||
{
|
||||
// root table
|
||||
{
|
||||
c3_w mug_w = 0x17 << 25;
|
||||
c3_w res_w = _ch_skip_slot(mug_w, 25);
|
||||
c3_assert((0x18 << 25) == res_w);
|
||||
}
|
||||
|
||||
{
|
||||
c3_w mug_w = 63 << 25; // 6 bits, all ones
|
||||
c3_w res_w = _ch_skip_slot(mug_w, 25);
|
||||
c3_assert(0 == res_w);
|
||||
}
|
||||
|
||||
// child nodes
|
||||
{
|
||||
c3_w mug_w = 17 << 20;
|
||||
c3_w res_w = _ch_skip_slot(mug_w, 20);
|
||||
c3_assert((18 << 20) == res_w);
|
||||
}
|
||||
|
||||
{
|
||||
c3_w mug_w = 31 << 20; // 5 bits, all ones
|
||||
c3_w res_w = _ch_skip_slot(mug_w, 20);
|
||||
c3_assert((1 << 25) == res_w);
|
||||
}
|
||||
|
||||
fprintf(stderr, "test_skip_slot: ok\n");
|
||||
}
|
||||
|
||||
/* _test_cache_trimming(): ensure a caching hashtable removes stale items.
|
||||
*/
|
||||
static void
|
||||
_test_cache_trimming(void)
|
||||
{
|
||||
c3_w max_w = 620;
|
||||
c3_w i_w;
|
||||
|
||||
//u3p(u3h_root) har_p = u3h_new_cache(max_w / 2);
|
||||
u3p(u3h_root) har_p = u3h_new_cache(max_w / 10 );
|
||||
u3h_root* har_u = u3to(u3h_root, har_p);
|
||||
|
||||
for ( i_w = 0; i_w < max_w; i_w++ ) {
|
||||
u3h_put(har_p, i_w, i_w + max_w);
|
||||
}
|
||||
|
||||
if ( ( max_w + max_w - 1) != u3h_get(har_p, max_w - 1) ) {
|
||||
fprintf(stderr, "fail\r\n");
|
||||
exit(1);
|
||||
}
|
||||
if ( ( max_w / 10 ) != har_u->use_w ) {
|
||||
fprintf(stderr, "fail\r\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "test_cache_trimming: ok\n");
|
||||
}
|
||||
|
||||
static void
|
||||
_test_cache_replace_value(void)
|
||||
{
|
||||
c3_w max_w = 100;
|
||||
c3_w i_w;
|
||||
|
||||
u3p(u3h_root) har_p = u3h_new_cache(max_w);
|
||||
u3h_root* har_u = u3to(u3h_root, har_p);
|
||||
|
||||
for ( i_w = 0; i_w < max_w; i_w++ ) {
|
||||
u3h_put(har_p, i_w, i_w + max_w);
|
||||
}
|
||||
|
||||
for ( i_w = 0; i_w < max_w; i_w++ ) {
|
||||
u3h_put(har_p, i_w, i_w + max_w + 1);
|
||||
}
|
||||
|
||||
if ( (2 * max_w) != u3h_get(har_p, max_w - 1) ) {
|
||||
fprintf(stderr, "fail\r\n");
|
||||
exit(1);
|
||||
}
|
||||
if ( max_w != har_u->use_w ) {
|
||||
fprintf(stderr, "fail\r\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "test_cache_replace_value: ok\r\n");
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,670 +0,0 @@
|
||||
/* vere/lmdb.c
|
||||
*/
|
||||
|
||||
#include "all.h"
|
||||
|
||||
#include <uv.h>
|
||||
#include <lmdb.h>
|
||||
|
||||
#include "vere/vere.h"
|
||||
|
||||
// Event log persistence for Urbit
|
||||
//
|
||||
// Persistence works by having an lmdb environment opened on the main
|
||||
// thread. This environment is used to create read-only transactions
|
||||
// synchronously when needed.
|
||||
//
|
||||
// But the majority of lmdb writes operate asynchronously in the uv worker
|
||||
// pool. Since individual transactions are bound to threads, we perform all
|
||||
// blocking writing on worker threads.
|
||||
//
|
||||
// We perform the very first metadata writes on the main thread because we
|
||||
// can't do anything until they persist.
|
||||
|
||||
/* u3_lmdb_init(): Opens up a log environment
|
||||
**
|
||||
** Precondition: log_path points to an already created directory
|
||||
*/
|
||||
MDB_env* u3_lmdb_init(const char* log_path)
|
||||
{
|
||||
MDB_env* env = 0;
|
||||
c3_w ret_w = mdb_env_create(&env);
|
||||
if (ret_w != 0) {
|
||||
u3l_log("lmdb: init fail: %s\n", mdb_strerror(ret_w));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Our databases have up to three tables: META, EVENTS, and GRAINS.
|
||||
ret_w = mdb_env_set_maxdbs(env, 3);
|
||||
if (ret_w != 0) {
|
||||
u3l_log("lmdb: failed to set number of databases: %s\n", mdb_strerror(ret_w));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: Start with forty gigabytes for the maximum event log size. We'll
|
||||
// need to do something more sophisticated for real in the long term, though.
|
||||
//
|
||||
const size_t forty_gigabytes = 42949672960;
|
||||
ret_w = mdb_env_set_mapsize(env, forty_gigabytes);
|
||||
if (ret_w != 0) {
|
||||
u3l_log("lmdb: failed to set database size: %s\n", mdb_strerror(ret_w));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret_w = mdb_env_open(env, log_path, 0, 0664);
|
||||
if (ret_w != 0) {
|
||||
u3l_log("lmdb: failed to open event log: %s\n", mdb_strerror(ret_w));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
/* u3_lmdb_shutdown(): Shuts down lmdb
|
||||
*/
|
||||
void u3_lmdb_shutdown(MDB_env* env)
|
||||
{
|
||||
mdb_env_close(env);
|
||||
}
|
||||
|
||||
/* _perform_put_on_database_raw(): Writes a key/value pair to a specific
|
||||
** database as part of a transaction.
|
||||
**
|
||||
** The raw version doesn't take ownership of either key/value and performs no
|
||||
** nock calculations, so it is safe to call from any thread.
|
||||
*/
|
||||
static
|
||||
c3_o _perform_put_on_database_raw(MDB_txn* transaction_u,
|
||||
MDB_dbi database_u,
|
||||
c3_w flags,
|
||||
void* key,
|
||||
size_t key_len,
|
||||
void* value,
|
||||
size_t value_len) {
|
||||
MDB_val key_val, value_val;
|
||||
|
||||
key_val.mv_size = key_len;
|
||||
key_val.mv_data = key;
|
||||
|
||||
value_val.mv_size = value_len;
|
||||
value_val.mv_data = value;
|
||||
|
||||
c3_w ret_w = mdb_put(transaction_u, database_u, &key_val, &value_val, flags);
|
||||
if (ret_w != 0) {
|
||||
u3l_log("lmdb: write failed: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _perform_get_on_database_raw(): Reads a key/value pair to a specific
|
||||
** database as part of a transaction.
|
||||
*/
|
||||
static
|
||||
c3_o _perform_get_on_database_raw(MDB_txn* transaction_u,
|
||||
MDB_dbi database_u,
|
||||
void* key,
|
||||
size_t key_len,
|
||||
MDB_val* value) {
|
||||
MDB_val key_val;
|
||||
key_val.mv_size = key_len;
|
||||
key_val.mv_data = key;
|
||||
|
||||
c3_w ret_w = mdb_get(transaction_u, database_u, &key_val, value);
|
||||
if (ret_w != 0) {
|
||||
u3l_log("lmdb: read failed: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _perform_put_on_database_noun(): Writes a noun to the database.
|
||||
**
|
||||
** This requires access to the loom so it must only be run from the libuv
|
||||
** thread.
|
||||
*/
|
||||
static
|
||||
c3_o _perform_put_on_database_noun(MDB_txn* transaction_u,
|
||||
MDB_dbi database_u,
|
||||
c3_c* key,
|
||||
u3_noun noun) {
|
||||
// jam noun into an atom representation
|
||||
u3_atom mat = u3ke_jam(noun);
|
||||
|
||||
// copy the jammed noun into a byte buffer we can hand to lmdb
|
||||
c3_w len_w = u3r_met(3, mat);
|
||||
c3_y* bytes_y = (c3_y*) malloc(len_w);
|
||||
u3r_bytes(0, len_w, bytes_y, mat);
|
||||
|
||||
c3_o ret = _perform_put_on_database_raw(
|
||||
transaction_u,
|
||||
database_u,
|
||||
0,
|
||||
key, strlen(key),
|
||||
bytes_y, len_w);
|
||||
|
||||
free(bytes_y);
|
||||
u3z(mat);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* _perform_get_on_database_noun(): Reads a noun from the database.
|
||||
**
|
||||
** This requires access to the loom so it must only be run from the libuv
|
||||
** thread.
|
||||
*/
|
||||
static
|
||||
c3_o _perform_get_on_database_noun(MDB_txn* transaction_u,
|
||||
MDB_dbi database_u,
|
||||
c3_c* key,
|
||||
u3_noun* noun) {
|
||||
MDB_val value_val;
|
||||
c3_o ret = _perform_get_on_database_raw(transaction_u,
|
||||
database_u,
|
||||
key, strlen(key),
|
||||
&value_val);
|
||||
if (ret == c3n) {
|
||||
return c3y;
|
||||
}
|
||||
|
||||
// Take the bytes and cue them.
|
||||
u3_atom raw_atom = u3i_bytes(value_val.mv_size, value_val.mv_data);
|
||||
*noun = u3qe_cue(raw_atom);
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* u3_lmdb_write_request: Events to be written together
|
||||
*/
|
||||
struct u3_lmdb_write_request {
|
||||
// The event number of the first event.
|
||||
c3_d first_event;
|
||||
|
||||
// The number of events in this write request. Nonzero.
|
||||
c3_d event_count;
|
||||
|
||||
// An array of serialized event datas. The array size is |event_count|. We
|
||||
// perform the event serialization on the main thread so we can read the loom
|
||||
// and write into a malloced structure for the worker thread.
|
||||
void** malloced_event_data;
|
||||
|
||||
// An array of sizes of serialized event datas. We keep track of this for the
|
||||
// database write.
|
||||
size_t* malloced_event_data_size;
|
||||
};
|
||||
|
||||
/* u3_lmdb_build_write_request(): Allocates and builds a write request
|
||||
*/
|
||||
struct u3_lmdb_write_request*
|
||||
u3_lmdb_build_write_request(u3_writ* event_u, c3_d count)
|
||||
{
|
||||
struct u3_lmdb_write_request* request =
|
||||
c3_malloc(sizeof(struct u3_lmdb_write_request));
|
||||
request->first_event = event_u->evt_d;
|
||||
request->event_count = count;
|
||||
request->malloced_event_data = c3_malloc(sizeof(void*) * count);
|
||||
request->malloced_event_data_size = c3_malloc(sizeof(size_t) * count);
|
||||
|
||||
for (c3_d i = 0; i < count; ++i) {
|
||||
// Sanity check that the events in u3_writ are in order.
|
||||
c3_assert(event_u->evt_d == (request->first_event + i));
|
||||
|
||||
// Serialize the jammed event log entry into a malloced buffer we can send
|
||||
// to the other thread.
|
||||
c3_w siz_w = u3r_met(3, event_u->mat);
|
||||
c3_y* data_u = c3_calloc(siz_w);
|
||||
u3r_bytes(0, siz_w, data_u, event_u->mat);
|
||||
|
||||
request->malloced_event_data[i] = data_u;
|
||||
request->malloced_event_data_size[i] = siz_w;
|
||||
|
||||
event_u = event_u->nex_u;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/* u3_lmdb_free_write_request(): Frees a write request
|
||||
*/
|
||||
void u3_lmdb_free_write_request(struct u3_lmdb_write_request* request) {
|
||||
for (c3_d i = 0; i < request->event_count; ++i)
|
||||
free(request->malloced_event_data[i]);
|
||||
|
||||
free(request->malloced_event_data);
|
||||
free(request->malloced_event_data_size);
|
||||
free(request);
|
||||
}
|
||||
|
||||
/* _write_request_data: callback struct for u3_lmdb_write_event()
|
||||
*/
|
||||
struct _write_request_data {
|
||||
// The database environment to write to. This object is thread-safe, though
|
||||
// the transactions and handles opened from it are explicitly not.
|
||||
MDB_env* environment;
|
||||
|
||||
// The pier that we're writing for.
|
||||
u3_pier* pir_u;
|
||||
|
||||
// The encapsulated request. This may contain multiple event writes.
|
||||
struct u3_lmdb_write_request* request;
|
||||
|
||||
// Whether the write completed successfully.
|
||||
c3_o success;
|
||||
|
||||
// Called on main loop thread on completion.
|
||||
void (*on_complete)(c3_o, u3_pier*, c3_d, c3_d);
|
||||
};
|
||||
|
||||
/* _u3_lmdb_write_event_cb(): Implementation of u3_lmdb_write_event()
|
||||
**
|
||||
** This is always run on a libuv background worker thread; actual nouns cannot
|
||||
** be touched here.
|
||||
*/
|
||||
static void _u3_lmdb_write_event_cb(uv_work_t* req) {
|
||||
struct _write_request_data* data = req->data;
|
||||
|
||||
// Creates the write transaction.
|
||||
MDB_txn* transaction_u;
|
||||
c3_w ret_w = mdb_txn_begin(data->environment,
|
||||
(MDB_txn *) NULL,
|
||||
0, /* flags */
|
||||
&transaction_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: txn_begin fail: %s\n", mdb_strerror(ret_w));
|
||||
return;
|
||||
}
|
||||
|
||||
// Opens the database as part of the transaction.
|
||||
c3_w flags_w = MDB_CREATE | MDB_INTEGERKEY;
|
||||
MDB_dbi database_u;
|
||||
ret_w = mdb_dbi_open(transaction_u,
|
||||
"EVENTS",
|
||||
flags_w,
|
||||
&database_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: dbi_open fail: %s\n", mdb_strerror(ret_w));
|
||||
return;
|
||||
}
|
||||
|
||||
struct u3_lmdb_write_request* request = data->request;
|
||||
for (c3_d i = 0; i < request->event_count; ++i) {
|
||||
c3_d event_number = request->first_event + i;
|
||||
|
||||
c3_o success = _perform_put_on_database_raw(
|
||||
transaction_u,
|
||||
database_u,
|
||||
MDB_NOOVERWRITE,
|
||||
&event_number,
|
||||
sizeof(c3_d),
|
||||
request->malloced_event_data[i],
|
||||
request->malloced_event_data_size[i]);
|
||||
|
||||
if (success == c3n) {
|
||||
u3l_log("lmdb: failed to write event %" PRIu64 "\n", event_number);
|
||||
mdb_txn_abort(transaction_u);
|
||||
data->success = c3n;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ret_w = mdb_txn_commit(transaction_u);
|
||||
if (0 != ret_w) {
|
||||
if ( request->event_count == 1 ) {
|
||||
u3l_log("lmdb: failed to commit event %" PRIu64 ": %s\n",
|
||||
request->first_event,
|
||||
mdb_strerror(ret_w));
|
||||
} else {
|
||||
c3_d through = request->first_event + request->event_count - 1ULL;
|
||||
u3l_log("lmdb: failed to commit events %" PRIu64 " through %" PRIu64
|
||||
": %s\n",
|
||||
request->first_event,
|
||||
through,
|
||||
mdb_strerror(ret_w));
|
||||
}
|
||||
data->success = c3n;
|
||||
return;
|
||||
}
|
||||
|
||||
data->success = c3y;
|
||||
}
|
||||
|
||||
/* _u3_lmdb_write_event_after_cb(): Implementation of u3_lmdb_write_event()
|
||||
**
|
||||
** This is always run on the main loop thread after the worker thread event
|
||||
** completes.
|
||||
*/
|
||||
static void _u3_lmdb_write_event_after_cb(uv_work_t* req, int status) {
|
||||
struct _write_request_data* data = req->data;
|
||||
|
||||
data->on_complete(data->success,
|
||||
data->pir_u,
|
||||
data->request->first_event,
|
||||
data->request->event_count);
|
||||
|
||||
u3_lmdb_free_write_request(data->request);
|
||||
free(data);
|
||||
free(req);
|
||||
}
|
||||
|
||||
/* u3_lmdb_write_event(): Asynchronously writes events to the database.
|
||||
**
|
||||
** This writes all the passed in events along with log metadata updates to the
|
||||
** database as a single transaction on a worker thread. Once the transaction
|
||||
** is completed, it calls the passed in callback on the main loop thread.
|
||||
*/
|
||||
void u3_lmdb_write_event(MDB_env* environment,
|
||||
u3_pier* pir_u,
|
||||
struct u3_lmdb_write_request* request_u,
|
||||
void (*on_complete)(c3_o, u3_pier*, c3_d, c3_d))
|
||||
{
|
||||
// Structure to pass to the worker thread.
|
||||
struct _write_request_data* data = c3_malloc(sizeof(struct _write_request_data));
|
||||
data->environment = environment;
|
||||
data->pir_u = pir_u;
|
||||
data->request = request_u;
|
||||
data->on_complete = on_complete;
|
||||
data->success = c3n;
|
||||
|
||||
// Queue asynchronous work to happen on the other thread.
|
||||
uv_work_t* req = c3_malloc(sizeof(uv_work_t));
|
||||
req->data = data;
|
||||
|
||||
uv_queue_work(uv_default_loop(),
|
||||
req,
|
||||
_u3_lmdb_write_event_cb,
|
||||
_u3_lmdb_write_event_after_cb);
|
||||
}
|
||||
|
||||
/* u3_lmdb_read_events(): Synchronously reads events from the database.
|
||||
**
|
||||
** Reads back up to |len_d| events starting with |first_event_d|. For
|
||||
** each event, the event will be passed to |on_event_read| and further
|
||||
** reading will be aborted if the callback returns c3n.
|
||||
**
|
||||
** Returns c3y on complete success; c3n on any error.
|
||||
*/
|
||||
c3_o u3_lmdb_read_events(u3_pier* pir_u,
|
||||
c3_d first_event_d,
|
||||
c3_d len_d,
|
||||
c3_o(*on_event_read)(u3_pier* pir_u, c3_d id,
|
||||
u3_noun mat))
|
||||
{
|
||||
// Creates the read transaction.
|
||||
MDB_txn* transaction_u;
|
||||
c3_w ret_w = mdb_txn_begin(pir_u->log_u->db_u,
|
||||
//environment,
|
||||
(MDB_txn *) NULL,
|
||||
MDB_RDONLY, /* flags */
|
||||
&transaction_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: txn_begin fail: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Opens the database as part of the transaction.
|
||||
c3_w flags_w = MDB_CREATE | MDB_INTEGERKEY;
|
||||
MDB_dbi database_u;
|
||||
ret_w = mdb_dbi_open(transaction_u,
|
||||
"EVENTS",
|
||||
flags_w,
|
||||
&database_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: dbi_open fail: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Creates a cursor to iterate over keys starting at first_event_d.
|
||||
MDB_cursor* cursor_u;
|
||||
ret_w = mdb_cursor_open(transaction_u, database_u, &cursor_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: cursor_open fail: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Sets the cursor to the position of first_event_d.
|
||||
MDB_val key;
|
||||
MDB_val val;
|
||||
key.mv_size = sizeof(c3_d);
|
||||
key.mv_data = &first_event_d;
|
||||
|
||||
ret_w = mdb_cursor_get(cursor_u, &key, &val, MDB_SET_KEY);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: could not find initial event %" PRIu64 ": %s\r\n",
|
||||
first_event_d, mdb_strerror(ret_w));
|
||||
mdb_cursor_close(cursor_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Load up to len_d events, iterating forward across the cursor.
|
||||
for (c3_d loaded = 0; (ret_w != MDB_NOTFOUND) && (loaded < len_d); ++loaded) {
|
||||
// As a sanity check, we make sure that there aren't any discontinuities in
|
||||
// the sequence of loaded events.
|
||||
c3_d current_id = first_event_d + loaded;
|
||||
if (key.mv_size != sizeof(c3_d)) {
|
||||
u3l_log("lmdb: invalid cursor key\r\n");
|
||||
return c3n;
|
||||
}
|
||||
if (*(c3_d*)key.mv_data != current_id) {
|
||||
u3l_log("lmdb: missing event in database. Expected %" PRIu64 ", received %"
|
||||
PRIu64 "\r\n",
|
||||
current_id,
|
||||
*(c3_d*)key.mv_data);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Now build the atom version and then the cued version from the raw data
|
||||
u3_noun mat = u3i_bytes(val.mv_size, val.mv_data);
|
||||
|
||||
if (on_event_read(pir_u, current_id, mat) == c3n) {
|
||||
u3z(mat);
|
||||
u3l_log("lmdb: aborting replay due to error.\r\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
u3z(mat);
|
||||
|
||||
ret_w = mdb_cursor_get(cursor_u, &key, &val, MDB_NEXT);
|
||||
if (ret_w != 0 && ret_w != MDB_NOTFOUND) {
|
||||
u3l_log("lmdb: error while loading events: %s\r\n",
|
||||
mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
}
|
||||
|
||||
mdb_cursor_close(cursor_u);
|
||||
|
||||
// Read-only transactions are aborted since we don't need to record the fact
|
||||
// that we performed a read.
|
||||
mdb_txn_abort(transaction_u);
|
||||
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* u3_lmdb_get_latest_event_number(): Gets last event id persisted
|
||||
**
|
||||
** Reads the last key in order from the EVENTS table as the latest event
|
||||
** number. On table empty, returns c3y but doesn't modify event_number.
|
||||
*/
|
||||
c3_o u3_lmdb_get_latest_event_number(MDB_env* environment, c3_d* event_number)
|
||||
{
|
||||
// Creates the read transaction.
|
||||
MDB_txn* transaction_u;
|
||||
c3_w ret_w = mdb_txn_begin(environment,
|
||||
(MDB_txn *) NULL,
|
||||
0, /* flags */
|
||||
&transaction_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: txn_begin fail: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Opens the database as part of the transaction.
|
||||
c3_w flags_w = MDB_CREATE | MDB_INTEGERKEY;
|
||||
MDB_dbi database_u;
|
||||
ret_w = mdb_dbi_open(transaction_u,
|
||||
"EVENTS",
|
||||
flags_w,
|
||||
&database_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: dbi_open fail: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Creates a cursor to point to the last event
|
||||
MDB_cursor* cursor_u;
|
||||
ret_w = mdb_cursor_open(transaction_u, database_u, &cursor_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: cursor_open fail: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Set the cursor at the end of the line.
|
||||
MDB_val key;
|
||||
MDB_val val;
|
||||
ret_w = mdb_cursor_get(cursor_u, &key, &val, MDB_LAST);
|
||||
if (MDB_NOTFOUND == ret_w) {
|
||||
// Clean up, but don't error out.
|
||||
mdb_cursor_close(cursor_u);
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3y;
|
||||
}
|
||||
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: could not find last event: %s\r\n", mdb_strerror(ret_w));
|
||||
mdb_cursor_close(cursor_u);
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
*event_number = *(c3_d*)key.mv_data;
|
||||
|
||||
mdb_cursor_close(cursor_u);
|
||||
|
||||
// Read-only transactions are aborted since we don't need to record the fact
|
||||
// that we performed a read.
|
||||
mdb_txn_abort(transaction_u);
|
||||
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* u3_lmdb_write_identity(): Writes the event log identity information
|
||||
**
|
||||
** We have a secondary database (table) in this environment named META where we
|
||||
** read/write identity information from/to.
|
||||
*/
|
||||
c3_o u3_lmdb_write_identity(MDB_env* environment,
|
||||
u3_noun who,
|
||||
u3_noun is_fake,
|
||||
u3_noun life)
|
||||
{
|
||||
// Creates the write transaction.
|
||||
MDB_txn* transaction_u;
|
||||
c3_w ret_w = mdb_txn_begin(environment,
|
||||
(MDB_txn *) NULL,
|
||||
0, /* flags */
|
||||
&transaction_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: txn_begin fail: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Opens the database as part of the transaction.
|
||||
c3_w flags_w = MDB_CREATE;
|
||||
MDB_dbi database_u;
|
||||
ret_w = mdb_dbi_open(transaction_u,
|
||||
"META",
|
||||
flags_w,
|
||||
&database_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: dbi_open fail: %s\n", mdb_strerror(ret_w));
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
c3_o ret;
|
||||
ret = _perform_put_on_database_noun(transaction_u, database_u, "who", who);
|
||||
if (ret == c3n) {
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
ret = _perform_put_on_database_noun(transaction_u, database_u, "is-fake",
|
||||
is_fake);
|
||||
if (ret == c3n) {
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
ret = _perform_put_on_database_noun(transaction_u, database_u, "life", life);
|
||||
if (ret == c3n) {
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
ret_w = mdb_txn_commit(transaction_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: failed to commit transaction: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
return c3y;
|
||||
}
|
||||
|
||||
|
||||
/* u3_lmdb_read_identity(): Reads the event log identity information.
|
||||
*/
|
||||
c3_o u3_lmdb_read_identity(MDB_env* environment,
|
||||
u3_noun* who,
|
||||
u3_noun* is_fake,
|
||||
u3_noun* life) {
|
||||
// Creates the write transaction.
|
||||
MDB_txn* transaction_u;
|
||||
c3_w ret_w = mdb_txn_begin(environment,
|
||||
(MDB_txn *) NULL,
|
||||
MDB_RDONLY, /* flags */
|
||||
&transaction_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: txn_begin fail: %s\n", mdb_strerror(ret_w));
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Opens the database as part of the transaction.
|
||||
MDB_dbi database_u;
|
||||
ret_w = mdb_dbi_open(transaction_u,
|
||||
"META",
|
||||
0,
|
||||
&database_u);
|
||||
if (0 != ret_w) {
|
||||
u3l_log("lmdb: dbi_open fail: %s\n", mdb_strerror(ret_w));
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
c3_o ret;
|
||||
ret = _perform_get_on_database_noun(transaction_u, database_u, "who", who);
|
||||
if (ret == c3n) {
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
ret = _perform_get_on_database_noun(transaction_u, database_u, "is-fake",
|
||||
is_fake);
|
||||
if (ret == c3n) {
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
ret = _perform_get_on_database_noun(transaction_u, database_u, "life", life);
|
||||
if (ret == c3n) {
|
||||
mdb_txn_abort(transaction_u);
|
||||
return c3n;
|
||||
}
|
||||
|
||||
// Read-only transactions are aborted since we don't need to record the fact
|
||||
// that we performed a read.
|
||||
mdb_txn_abort(transaction_u);
|
||||
|
||||
return c3y;
|
||||
}
|
@ -1,359 +0,0 @@
|
||||
/* vere/newt.c
|
||||
**
|
||||
** implements noun blob messages with trivial framing.
|
||||
**
|
||||
** a message is a 64-bit little-endian byte count, followed
|
||||
** by the indicated number of bytes. the bytes are the
|
||||
** the ++cue of of a noun.
|
||||
**
|
||||
** the implementation is relatively inefficient and could
|
||||
** lose a few copies, mallocs, etc.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <setjmp.h>
|
||||
#include <gmp.h>
|
||||
#include <sigsegv.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <uv.h>
|
||||
#include <errno.h>
|
||||
#include <ncurses/curses.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses/term.h>
|
||||
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
#undef NEWT_VERBOSE
|
||||
|
||||
/* _newt_consume(): advance buffer processing.
|
||||
*/
|
||||
static void
|
||||
_newt_consume(u3_moat* mot_u)
|
||||
{
|
||||
/* process stray bytes, trying to create a new message
|
||||
** or add a block to an existing one.
|
||||
*/
|
||||
while ( 1 ) {
|
||||
if ( mot_u->rag_y ) {
|
||||
/* if there is a live message, add a block to the queue.
|
||||
*/
|
||||
if ( mot_u->mes_u ) {
|
||||
u3_meat* met_u;
|
||||
|
||||
/* create block
|
||||
*/
|
||||
met_u = c3_malloc(mot_u->len_d + (c3_d) sizeof(u3_meat));
|
||||
met_u->nex_u = 0;
|
||||
met_u->len_d = mot_u->len_d;
|
||||
memcpy(met_u->hun_y, mot_u->rag_y, mot_u->len_d);
|
||||
|
||||
#ifdef NEWT_VERBOSE
|
||||
u3l_log("newt: %d: create: msg %p, new block %p, len %"
|
||||
PRIu64 ", has %" PRIu64 ", needs %" PRIu64 "\r\n",
|
||||
getpid(),
|
||||
mot_u->mes_u,
|
||||
met_u,
|
||||
met_u->len_d,
|
||||
mot_u->mes_u->has_d,
|
||||
mot_u->mes_u->len_d);
|
||||
#endif
|
||||
/* enqueue block
|
||||
*/
|
||||
if ( !mot_u->mes_u->meq_u ) {
|
||||
mot_u->mes_u->meq_u = mot_u->mes_u->qem_u = met_u;
|
||||
}
|
||||
else {
|
||||
mot_u->mes_u->qem_u->nex_u = met_u;
|
||||
mot_u->mes_u->qem_u = met_u;
|
||||
}
|
||||
mot_u->mes_u->has_d += met_u->len_d;
|
||||
|
||||
/* free consumed stray bytes
|
||||
*/
|
||||
c3_free(mot_u->rag_y);
|
||||
mot_u->len_d = 0;
|
||||
mot_u->rag_y = 0;
|
||||
}
|
||||
else {
|
||||
/* no message, but enough stray bytes to fill in
|
||||
** a length; collect them and create a message.
|
||||
*/
|
||||
if ( mot_u->len_d >= 8ULL ) {
|
||||
c3_d nel_d = 0;
|
||||
|
||||
nel_d |= ((c3_d) mot_u->rag_y[0]) << 0ULL;
|
||||
nel_d |= ((c3_d) mot_u->rag_y[1]) << 8ULL;
|
||||
nel_d |= ((c3_d) mot_u->rag_y[2]) << 16ULL;
|
||||
nel_d |= ((c3_d) mot_u->rag_y[3]) << 24ULL;
|
||||
nel_d |= ((c3_d) mot_u->rag_y[4]) << 32ULL;
|
||||
nel_d |= ((c3_d) mot_u->rag_y[5]) << 40ULL;
|
||||
nel_d |= ((c3_d) mot_u->rag_y[6]) << 48ULL;
|
||||
nel_d |= ((c3_d) mot_u->rag_y[7]) << 56ULL;
|
||||
|
||||
#ifdef NEWT_VERBOSE
|
||||
u3l_log("newt: %d: parsed length %" PRIu64 "\r\n",
|
||||
getpid(),
|
||||
nel_d);
|
||||
#endif
|
||||
mot_u->len_d -= 8ULL;
|
||||
|
||||
mot_u->mes_u = c3_malloc(sizeof(u3_mess));
|
||||
mot_u->mes_u->len_d = nel_d;
|
||||
mot_u->mes_u->has_d = 0;
|
||||
mot_u->mes_u->meq_u = mot_u->mes_u->qem_u = 0;
|
||||
|
||||
if ( !mot_u->len_d ) {
|
||||
c3_free(mot_u->rag_y);
|
||||
mot_u->rag_y = 0;
|
||||
}
|
||||
else {
|
||||
/* remove consumed length from stray bytes
|
||||
*/
|
||||
c3_y* buf_y = c3_malloc(mot_u->len_d);
|
||||
|
||||
memcpy(buf_y, mot_u->rag_y + 8, mot_u->len_d);
|
||||
|
||||
c3_free(mot_u->rag_y);
|
||||
mot_u->rag_y = buf_y;
|
||||
|
||||
/* remaining bytes will be installed as message meat
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check for message completions
|
||||
*/
|
||||
if ( mot_u->mes_u && (mot_u->mes_u->has_d >= mot_u->mes_u->len_d) ) {
|
||||
c3_d len_d = mot_u->mes_u->len_d;
|
||||
c3_y* buf_y = c3_malloc(len_d);
|
||||
c3_d pat_d = 0;
|
||||
u3_meat* met_u;
|
||||
|
||||
/* we should have just cleared this
|
||||
*/
|
||||
c3_assert(!mot_u->rag_y);
|
||||
c3_assert(!mot_u->len_d);
|
||||
|
||||
/* collect queue blocks, cleaning them up; return any spare meat
|
||||
** to the rag.
|
||||
*/
|
||||
{
|
||||
met_u = mot_u->mes_u->meq_u;
|
||||
while ( met_u && (pat_d < len_d) ) {
|
||||
u3_meat* nex_u = met_u->nex_u;
|
||||
c3_d end_d = (pat_d + met_u->len_d);
|
||||
c3_d eat_d;
|
||||
c3_d rem_d;
|
||||
|
||||
eat_d = c3_min(len_d, end_d) - pat_d;
|
||||
memcpy(buf_y + pat_d, met_u->hun_y, eat_d);
|
||||
pat_d += eat_d;
|
||||
|
||||
rem_d = (met_u->len_d - eat_d);
|
||||
if ( rem_d ) {
|
||||
mot_u->rag_y = c3_malloc(rem_d);
|
||||
memcpy(mot_u->rag_y, met_u->hun_y + eat_d, rem_d);
|
||||
mot_u->len_d = rem_d;
|
||||
|
||||
/* one: unless we got a bad length, this has to be the last
|
||||
** block in the message.
|
||||
**
|
||||
** two: bad data on a newt channel can cause us to assert.
|
||||
** that's actually the right thing for a private channel.
|
||||
*/
|
||||
c3_assert(0 == nex_u);
|
||||
}
|
||||
c3_free(met_u);
|
||||
met_u = nex_u;
|
||||
}
|
||||
c3_assert(pat_d == len_d);
|
||||
|
||||
/* clear the message
|
||||
*/
|
||||
c3_free(mot_u->mes_u);
|
||||
mot_u->mes_u = 0;
|
||||
}
|
||||
|
||||
/* build and send the object
|
||||
*/
|
||||
{
|
||||
u3_noun mat = u3i_bytes((c3_w) len_d, buf_y);
|
||||
|
||||
mot_u->pok_f(mot_u->vod_p, mat);
|
||||
}
|
||||
|
||||
/* continue; spare meat may need processing
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* nothing happening, await next event
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* _raft_alloc(): libuv-style allocator for raft.
|
||||
*/
|
||||
static void
|
||||
_newt_alloc(uv_handle_t* had_u,
|
||||
size_t len_i,
|
||||
uv_buf_t* buf_u)
|
||||
{
|
||||
void* ptr_v = c3_malloc(len_i);
|
||||
|
||||
*buf_u = uv_buf_init(ptr_v, len_i);
|
||||
}
|
||||
|
||||
/* _newt_read_cb(): stream input callback.
|
||||
*/
|
||||
void
|
||||
_newt_read_cb(uv_stream_t* str_u,
|
||||
ssize_t len_i,
|
||||
const uv_buf_t* buf_u)
|
||||
{
|
||||
c3_d len_d = (c3_d) len_i;
|
||||
u3_moat* mot_u = (void *)str_u;
|
||||
|
||||
if ( UV_EOF == len_i ) {
|
||||
// u3l_log("newt: %d: stream closed\r\n", getpid());
|
||||
uv_read_stop(str_u);
|
||||
mot_u->bal_f(mot_u->vod_p, "stream closed");
|
||||
}
|
||||
else {
|
||||
#ifdef NEWT_VERBOSE
|
||||
u3l_log("newt: %d: read %ld\r\n", getpid(), len_i);
|
||||
#endif
|
||||
|
||||
#ifdef NEWT_VERBOSE
|
||||
u3l_log("newt: %d: <bytes>", getpid());
|
||||
for ( int i = 0; i < len_i; i++) {
|
||||
if (0 == (i % 16)) u3l_log("\r\n");
|
||||
u3l_log(" %02x", (unsigned) buf_u->base[i]);
|
||||
}
|
||||
u3l_log("\r\nnewt: %d: </bytes>\r\n", getpid());
|
||||
#endif
|
||||
|
||||
// grow read buffer by `len_d` bytes
|
||||
//
|
||||
if ( mot_u->rag_y ) {
|
||||
mot_u->rag_y = c3_realloc(mot_u->rag_y, mot_u->len_d + len_d);
|
||||
memcpy(mot_u->rag_y + mot_u->len_d, buf_u->base, len_d);
|
||||
c3_free(buf_u->base);
|
||||
}
|
||||
else {
|
||||
mot_u->rag_y = (c3_y *)buf_u->base;
|
||||
mot_u->len_d = len_d;
|
||||
}
|
||||
_newt_consume(mot_u);
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_newt_read(): start stream reading.
|
||||
*/
|
||||
void
|
||||
u3_newt_read(u3_moat* mot_u)
|
||||
{
|
||||
c3_i err_i;
|
||||
|
||||
mot_u->mes_u = 0;
|
||||
mot_u->len_d = 0;
|
||||
mot_u->rag_y = 0;
|
||||
|
||||
err_i = uv_read_start((uv_stream_t*) &mot_u->pyp_u,
|
||||
_newt_alloc,
|
||||
_newt_read_cb);
|
||||
|
||||
if ( err_i != 0 ) {
|
||||
mot_u->bal_f(mot_u, uv_strerror(err_i));
|
||||
}
|
||||
}
|
||||
|
||||
/* write request for newt
|
||||
*/
|
||||
struct _u3_write_t {
|
||||
uv_write_t wri_u;
|
||||
u3_mojo* moj_u;
|
||||
void* vod_p;
|
||||
c3_y* buf_y;
|
||||
};
|
||||
|
||||
/* _newt_write_cb(): generic write callback.
|
||||
*/
|
||||
static void
|
||||
_newt_write_cb(uv_write_t* wri_u, c3_i sas_i)
|
||||
{
|
||||
struct _u3_write_t* req_u = (struct _u3_write_t*)wri_u;
|
||||
void* vod_p = req_u->vod_p;
|
||||
u3_mojo* moj_u = req_u->moj_u;
|
||||
|
||||
free(req_u->buf_y);
|
||||
free(req_u);
|
||||
|
||||
if ( 0 != sas_i ) {
|
||||
u3l_log("newt: bad write %d\r\n", sas_i);
|
||||
moj_u->bal_f(vod_p, uv_strerror(sas_i));
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_newt_write(): write atom to stream; free atom.
|
||||
*/
|
||||
void
|
||||
u3_newt_write(u3_mojo* moj_u,
|
||||
u3_atom mat,
|
||||
void* vod_p)
|
||||
{
|
||||
c3_w len_w = u3r_met(3, mat);
|
||||
c3_y* buf_y = c3_malloc(len_w + 8);
|
||||
struct _u3_write_t* req_u = c3_malloc(sizeof(*req_u));
|
||||
uv_buf_t buf_u;
|
||||
c3_i err_i;
|
||||
|
||||
/* write header; c3_d is futureproofing
|
||||
*/
|
||||
buf_y[0] = ((len_w >> 0) & 0xff);
|
||||
buf_y[1] = ((len_w >> 8) & 0xff);
|
||||
buf_y[2] = ((len_w >> 16) & 0xff);
|
||||
buf_y[3] = ((len_w >> 24) & 0xff);
|
||||
buf_y[4] = buf_y[5] = buf_y[6] = buf_y[7] = 0;
|
||||
u3r_bytes(0, len_w, buf_y + 8, mat);
|
||||
u3z(mat);
|
||||
|
||||
req_u->moj_u = moj_u;
|
||||
req_u->buf_y = buf_y;
|
||||
buf_u.base = (c3_c*) buf_y;
|
||||
buf_u.len = len_w + 8;
|
||||
|
||||
#ifdef NEWT_VERBOSE
|
||||
u3l_log("newt: %d: write %d\n", getpid(), len_w + 8);
|
||||
#endif
|
||||
|
||||
#ifdef NEWT_VERBOSE
|
||||
u3l_log("newt: %d: <bytes>", getpid());
|
||||
for ( int i = 0; i < len_w+8; i++) {
|
||||
if (0 == (i % 16)) u3l_log("\r\n");
|
||||
u3l_log(" %02x", (unsigned) buf_u.base[i]);
|
||||
}
|
||||
u3l_log("\r\nnewt: %d: </bytes>\r\n", getpid());
|
||||
#endif
|
||||
|
||||
if ( 0 != (err_i = uv_write((uv_write_t*)req_u,
|
||||
(uv_stream_t*)&moj_u->pyp_u,
|
||||
&buf_u,
|
||||
1,
|
||||
_newt_write_cb)) )
|
||||
{
|
||||
moj_u->bal_f(moj_u, uv_strerror(err_i));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,482 +0,0 @@
|
||||
/* vere/reck.c
|
||||
**
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <uv.h>
|
||||
#include <ncurses/curses.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses/term.h>
|
||||
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* _reck_mole(): parse simple atomic mole.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_mole(u3_noun fot,
|
||||
u3_noun san,
|
||||
c3_d* ato_d)
|
||||
{
|
||||
u3_noun uco = u3dc("slaw", fot, san);
|
||||
u3_noun p_uco, q_uco;
|
||||
|
||||
if ( (c3n == u3r_cell(uco, &p_uco, &q_uco)) ||
|
||||
(u3_nul != p_uco) )
|
||||
{
|
||||
u3l_log("strange mole %s\n", u3r_string(san));
|
||||
|
||||
u3z(fot); u3z(uco); return c3n;
|
||||
}
|
||||
else {
|
||||
*ato_d = u3r_chub(0, q_uco);
|
||||
|
||||
u3z(fot); u3z(uco); return c3y;
|
||||
}
|
||||
}
|
||||
|
||||
/* _reck_lily(): parse little atom.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_lily(u3_noun fot, u3_noun txt, c3_l* tid_l)
|
||||
{
|
||||
c3_d ato_d;
|
||||
|
||||
if ( c3n == _reck_mole(fot, txt, &ato_d) ) {
|
||||
return c3n;
|
||||
} else {
|
||||
if ( ato_d >= 0x80000000ULL ) {
|
||||
return c3n;
|
||||
} else {
|
||||
*tid_l = (c3_l) ato_d;
|
||||
|
||||
return c3y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* _reck_orchid(): parses only a number as text
|
||||
*
|
||||
* Parses a text string which contains a decimal number. In practice, this
|
||||
* number is always '1'.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_orchid(u3_noun fot, u3_noun txt, c3_l* tid_l)
|
||||
{
|
||||
c3_c* str = u3r_string(txt);
|
||||
c3_d ato_d = strtol(str, NULL, 10);
|
||||
free(str);
|
||||
|
||||
if ( ato_d >= 0x80000000ULL ) {
|
||||
return c3n;
|
||||
} else {
|
||||
*tid_l = (c3_l) ato_d;
|
||||
|
||||
return c3y;
|
||||
}
|
||||
}
|
||||
|
||||
/* _reck_kick_term(): apply terminal outputs.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_kick_term(u3_pier* pir_u, u3_noun pox, c3_l tid_l, u3_noun fav)
|
||||
{
|
||||
u3_noun p_fav;
|
||||
|
||||
if ( c3n == u3du(fav) ) {
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
else switch ( u3h(fav) ) {
|
||||
default: u3z(pox); u3z(fav); return c3n;
|
||||
case c3__bbye:
|
||||
{
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
|
||||
case c3__blit: p_fav = u3t(fav);
|
||||
{
|
||||
u3_term_ef_blit(tid_l, u3k(p_fav));
|
||||
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
|
||||
// this can return through dill due to our fscked up boot sequence
|
||||
//
|
||||
case c3__send: {
|
||||
u3_noun lan = u3k(u3h(u3t(fav)));
|
||||
u3_noun pac = u3k(u3t(u3t(fav)));
|
||||
|
||||
u3l_log("kick: strange send\r\n");
|
||||
u3_ames_ef_send(pir_u, lan, pac);
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
|
||||
case c3__logo:
|
||||
{
|
||||
u3_pier_exit(pir_u);
|
||||
u3_Host.xit_i = u3t(fav);
|
||||
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
|
||||
case c3__init: p_fav = u3t(fav);
|
||||
{
|
||||
// daemon ignores %init
|
||||
// u3A->own = u3nc(u3k(p_fav), u3A->own);
|
||||
// u3l_log("kick: init: %d\n", p_fav);
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
|
||||
case c3__mass: p_fav = u3t(fav);
|
||||
{
|
||||
u3z(pox); u3z(fav);
|
||||
|
||||
// gc the daemon area
|
||||
//
|
||||
uv_timer_start(&u3K.tim_u, (uv_timer_cb)u3_daemon_grab, 0, 0);
|
||||
return c3y;
|
||||
} break;
|
||||
}
|
||||
c3_assert(!"not reached"); return 0;
|
||||
}
|
||||
|
||||
/* _reck_kick_http(): apply http effects.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_kick_http(u3_pier* pir_u,
|
||||
u3_noun pox,
|
||||
c3_l sev_l,
|
||||
c3_l coq_l,
|
||||
c3_l seq_l,
|
||||
u3_noun fav)
|
||||
{
|
||||
u3_noun p_fav, q_fav;
|
||||
|
||||
if ( c3n == u3du(fav) ) {
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
else switch ( u3h(fav) ) {
|
||||
default: u3z(pox); u3z(fav); return c3n;
|
||||
|
||||
case c3__form: p_fav = u3t(fav);
|
||||
{
|
||||
u3_http_ef_form(u3k(p_fav));
|
||||
|
||||
// The control server has now started.
|
||||
//
|
||||
// If we're in daemon mode, we need to inform the parent process
|
||||
// that we've finished booting.
|
||||
if (u3_Host.bot_f) {
|
||||
u3_Host.bot_f();
|
||||
}
|
||||
|
||||
u3z(pox); u3z(fav);
|
||||
return c3y;
|
||||
}
|
||||
|
||||
case c3__that: p_fav = u3t(fav);
|
||||
{
|
||||
u3_http_ef_that(u3k(p_fav));
|
||||
|
||||
u3z(pox); u3z(fav);
|
||||
return c3y;
|
||||
}
|
||||
|
||||
case c3__thus: p_fav = u3h(u3t(fav)); q_fav = u3t(u3t(fav));
|
||||
{
|
||||
u3_cttp_ef_thus(u3r_word(0, p_fav), u3k(q_fav));
|
||||
|
||||
u3z(pox); u3z(fav);
|
||||
return c3y;
|
||||
}
|
||||
case c3__thou: p_fav = u3t(fav);
|
||||
{
|
||||
u3_http_ef_thou(sev_l, coq_l, seq_l, u3k(p_fav));
|
||||
|
||||
u3z(pox); u3z(fav);
|
||||
return c3y;
|
||||
} break;
|
||||
}
|
||||
c3_assert(!"not reached"); return c3n;
|
||||
}
|
||||
|
||||
/* _reck_kick_behn(): apply packet network outputs.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_kick_behn(u3_pier* pir_u, u3_noun pox, u3_noun fav)
|
||||
{
|
||||
switch ( u3h(fav) ) {
|
||||
default: break;
|
||||
|
||||
case c3__doze: {
|
||||
u3_behn_ef_doze(pir_u, u3k(u3t(fav)));
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
}
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
|
||||
/* _reck_kick_sync(): apply sync outputs.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_kick_sync(u3_pier* pir_u, u3_noun pox, u3_noun fav)
|
||||
{
|
||||
switch ( u3h(fav) ) {
|
||||
default: break;
|
||||
case c3__dirk: {
|
||||
u3_unix_ef_dirk(pir_u, u3k(u3t(fav)));
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
}
|
||||
case c3__ergo: {
|
||||
u3_noun mon = u3k(u3h(u3t(fav)));
|
||||
u3_noun can = u3k(u3t(u3t(fav)));
|
||||
|
||||
u3_unix_ef_ergo(pir_u, mon, can);
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
case c3__ogre: {
|
||||
u3_unix_ef_ogre(pir_u, u3k(u3t(fav)));
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
}
|
||||
case c3__hill: {
|
||||
u3_unix_ef_hill(pir_u, u3k(u3t(fav)));
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
}
|
||||
}
|
||||
|
||||
// XX obviously not right!
|
||||
// ? looks fine to me
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
|
||||
/* _reck_kick_newt(): apply packet network outputs.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_kick_newt(u3_pier* pir_u, u3_noun pox, u3_noun fav)
|
||||
{
|
||||
switch ( u3h(fav) ) {
|
||||
default: break;
|
||||
case c3__send: {
|
||||
u3_noun lan = u3k(u3h(u3t(fav)));
|
||||
u3_noun pac = u3k(u3t(u3t(fav)));
|
||||
|
||||
u3_ames_ef_send(pir_u, lan, pac);
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
|
||||
case c3__turf: {
|
||||
u3_ames_ef_turf(pir_u, u3k(u3t(fav)));
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
|
||||
}
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
|
||||
/* _reck_kick_ames(): apply packet network outputs.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_kick_ames(u3_pier* pir_u, u3_noun pox, u3_noun fav)
|
||||
{
|
||||
u3_noun p_fav;
|
||||
|
||||
switch ( u3h(fav) ) {
|
||||
default: break;
|
||||
case c3__init: p_fav = u3t(fav);
|
||||
{
|
||||
// daemon ignores %init
|
||||
// u3A->own = u3nc(u3k(p_fav), u3A->own);
|
||||
// u3l_log("kick: init: %d\n", p_fav);
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
}
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
|
||||
/* _reck_kick_spec(): apply an effect, by path.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_kick_spec(u3_pier* pir_u, u3_noun pox, u3_noun fav)
|
||||
{
|
||||
u3_noun i_pox, t_pox;
|
||||
|
||||
if ( (c3n == u3r_cell(pox, &i_pox, &t_pox)) ||
|
||||
((i_pox != u3_blip) &&
|
||||
(i_pox != c3__gold) &&
|
||||
(i_pox != c3__iron) &&
|
||||
(i_pox != c3__lead)) )
|
||||
{
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
} else {
|
||||
u3_noun it_pox, tt_pox;
|
||||
|
||||
if ( (c3n == u3r_cell(t_pox, &it_pox, &tt_pox)) ) {
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
else switch ( it_pox ) {
|
||||
default: u3z(pox); u3z(fav); return c3n;
|
||||
|
||||
case c3__http: {
|
||||
u3_noun pud = tt_pox;
|
||||
u3_noun p_pud, t_pud, tt_pud, q_pud, r_pud, s_pud;
|
||||
c3_l sev_l, coq_l, seq_l;
|
||||
|
||||
if ( (c3n == u3r_cell(pud, &p_pud, &t_pud)) ||
|
||||
(c3n == _reck_lily(c3__uv, u3k(p_pud), &sev_l)) )
|
||||
{
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
|
||||
if ( u3_nul == t_pud ) {
|
||||
coq_l = seq_l = 0;
|
||||
}
|
||||
else {
|
||||
if ( (c3n == u3r_cell(t_pud, &q_pud, &tt_pud)) ||
|
||||
(c3n == _reck_lily(c3__ud, u3k(q_pud), &coq_l)) )
|
||||
{
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
|
||||
if ( u3_nul == tt_pud ) {
|
||||
seq_l = 0;
|
||||
} else {
|
||||
if ( (c3n == u3r_cell(tt_pud, &r_pud, &s_pud)) ||
|
||||
(u3_nul != s_pud) ||
|
||||
(c3n == _reck_lily(c3__ud, u3k(r_pud), &seq_l)) )
|
||||
{
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _reck_kick_http(pir_u, pox, sev_l, coq_l, seq_l, fav);
|
||||
} break;
|
||||
|
||||
case c3__behn: {
|
||||
return _reck_kick_behn(pir_u, pox, fav);
|
||||
} break;
|
||||
|
||||
case c3__clay:
|
||||
case c3__boat:
|
||||
case c3__sync: {
|
||||
return _reck_kick_sync(pir_u, pox, fav);
|
||||
} break;
|
||||
|
||||
case c3__newt: {
|
||||
return _reck_kick_newt(pir_u, pox, fav);
|
||||
} break;
|
||||
|
||||
case c3__ames: {
|
||||
if ( (u3_nul != tt_pox) ) {
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
else {
|
||||
return _reck_kick_ames(pir_u, pox, fav);
|
||||
}
|
||||
} break;
|
||||
|
||||
case c3__init: {
|
||||
// daemon ignores %init
|
||||
// p_fav = u3t(fav);
|
||||
// u3A->own = u3nc(u3k(p_fav), u3A->own);
|
||||
// u3l_log("kick: init: %d\n", p_fav);
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
|
||||
case c3__term: {
|
||||
u3_noun pud = tt_pox;
|
||||
u3_noun p_pud, q_pud;
|
||||
c3_l tid_l;
|
||||
|
||||
if ( (c3n == u3r_cell(pud, &p_pud, &q_pud)) ||
|
||||
(u3_nul != q_pud) ||
|
||||
(c3n == _reck_orchid(c3__ud, u3k(p_pud), &tid_l)) )
|
||||
{
|
||||
u3l_log("term: bad tire\n");
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
} else {
|
||||
return _reck_kick_term(pir_u, pox, tid_l, fav);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
c3_assert(!"not reached");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
/* _reck_kick_norm(): non path-specific effect handling.
|
||||
*/
|
||||
static u3_noun
|
||||
_reck_kick_norm(u3_pier* pir_u, u3_noun pox, u3_noun fav)
|
||||
{
|
||||
if ( c3n == u3du(fav) ) {
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
else switch ( u3h(fav) ) {
|
||||
default: u3z(pox); u3z(fav); return c3n;
|
||||
|
||||
case c3__vega:
|
||||
{
|
||||
u3l_log("<<<reset>>>\n");
|
||||
u3z(pox); u3z(fav);
|
||||
|
||||
// reclaim memory from persistent caches
|
||||
//
|
||||
u3m_reclaim();
|
||||
|
||||
return c3y;
|
||||
}
|
||||
case c3__exit:
|
||||
{
|
||||
u3l_log("<<<goodbye>>>\n");
|
||||
u3_pier_exit(pir_u);
|
||||
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
} break;
|
||||
}
|
||||
c3_assert(!"not reached"); return c3n;
|
||||
u3z(pox); u3z(fav); return c3n;
|
||||
}
|
||||
|
||||
/* u3_reck_kick(): handle effect.
|
||||
*/
|
||||
void
|
||||
u3_reck_kick(u3_pier* pir_u, u3_noun ovo)
|
||||
{
|
||||
if ( (c3n == _reck_kick_spec(pir_u, u3k(u3h(ovo)), u3k(u3t(ovo)))) &&
|
||||
(c3n == _reck_kick_norm(pir_u, u3k(u3h(ovo)), u3k(u3t(ovo)))) )
|
||||
{
|
||||
#if 0
|
||||
if ( (c3__warn != u3h(u3t(ovo))) &&
|
||||
(c3__text != u3h(u3t(ovo))) &&
|
||||
(c3__note != u3h(u3t(ovo))) )
|
||||
#endif
|
||||
#if 1
|
||||
if ( (c3__crud == u3h(u3t(ovo))) )
|
||||
#if 0
|
||||
(c3__talk == u3h(u3t(ovo))) ||
|
||||
(c3__helo == u3h(u3t(ovo))) ||
|
||||
(c3__init == u3h(u3t(ovo))) )
|
||||
#endif
|
||||
{
|
||||
u3_pier_work(pir_u,
|
||||
u3nt(u3_blip, c3__term, u3_nul),
|
||||
u3nc(c3__flog, u3k(u3t(ovo))));
|
||||
}
|
||||
else {
|
||||
u3_noun tox = u3do("spat", u3k(u3h(ovo)));
|
||||
u3l_log("kick: lost %%%s on %s\n",
|
||||
u3r_string(u3h(u3t(ovo))),
|
||||
u3r_string(tox));
|
||||
u3z(tox);
|
||||
#if 0
|
||||
if ( c3__hear == u3h(u3t(ovo)) ) {
|
||||
c3_assert(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
u3z(ovo);
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/* vere/save.c
|
||||
**
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <termios.h>
|
||||
#include <uv.h>
|
||||
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* _save_time_cb(): timer callback.
|
||||
*/
|
||||
static void
|
||||
_save_time_cb(uv_timer_t* tim_u)
|
||||
{
|
||||
u3_pier *pir_u = tim_u->data;
|
||||
u3_pier_snap(pir_u);
|
||||
}
|
||||
|
||||
/* u3_save_ef_chld(): report save termination.
|
||||
*/
|
||||
void
|
||||
u3_save_ef_chld(u3_pier *pir_u)
|
||||
{
|
||||
u3_save* sav_u = pir_u->sav_u;
|
||||
c3_i loc_i;
|
||||
c3_w pid_w;
|
||||
|
||||
/* modified for cases with no pid_w
|
||||
*/
|
||||
u3l_log("checkpoint: complete %d\n", sav_u->pid_w);
|
||||
pid_w = wait(&loc_i);
|
||||
if (0 != sav_u->pid_w) {
|
||||
c3_assert(pid_w == sav_u->pid_w);
|
||||
}
|
||||
else {
|
||||
c3_assert(pid_w > 0);
|
||||
}
|
||||
sav_u->pid_w = 0;
|
||||
}
|
||||
|
||||
/* u3_save_io_init(): initialize autosave.
|
||||
*/
|
||||
void
|
||||
u3_save_io_init(u3_pier *pir_u)
|
||||
{
|
||||
u3_save* sav_u = pir_u->sav_u;
|
||||
|
||||
sav_u->req_d = 0;
|
||||
sav_u->dun_d = 0;
|
||||
sav_u->pid_w = 0;
|
||||
|
||||
sav_u->tim_u.data = pir_u;
|
||||
uv_timer_init(u3L, &sav_u->tim_u);
|
||||
uv_timer_start(&sav_u->tim_u, _save_time_cb, 120000, 120000);
|
||||
}
|
||||
|
||||
/* u3_save_io_exit(): terminate save I/O.
|
||||
*/
|
||||
void
|
||||
u3_save_io_exit(u3_pier *pir_u)
|
||||
{
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,179 +0,0 @@
|
||||
/* vere/time.c
|
||||
**
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <uv.h>
|
||||
#include <ncurses/curses.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses/term.h>
|
||||
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* u3_time_sec_in(): urbit seconds from unix time.
|
||||
**
|
||||
** Adjust for future leap secs!
|
||||
*/
|
||||
c3_d
|
||||
u3_time_sec_in(c3_w unx_w)
|
||||
{
|
||||
return 0x8000000cce9e0d80ULL + (c3_d)unx_w;
|
||||
}
|
||||
|
||||
/* u3_time_sec_out(): unix time from urbit seconds.
|
||||
**
|
||||
** Adjust for future leap secs!
|
||||
*/
|
||||
c3_w
|
||||
u3_time_sec_out(c3_d urs_d)
|
||||
{
|
||||
c3_d adj_d = (urs_d - 0x8000000cce9e0d80ULL);
|
||||
|
||||
if ( adj_d > 0xffffffffULL ) {
|
||||
fprintf(stderr, "Agh! It's 2106! And no one's fixed this shite!\n");
|
||||
exit(1);
|
||||
}
|
||||
return (c3_w)adj_d;
|
||||
}
|
||||
|
||||
/* u3_time_fsc_in(): urbit fracto-seconds from unix microseconds.
|
||||
*/
|
||||
c3_d
|
||||
u3_time_fsc_in(c3_w usc_w)
|
||||
{
|
||||
c3_d usc_d = usc_w;
|
||||
|
||||
return ((usc_d * 65536ULL) / 1000000ULL) << 48ULL;
|
||||
}
|
||||
|
||||
/* u3_time_fsc_out: unix microseconds from urbit fracto-seconds.
|
||||
*/
|
||||
c3_w
|
||||
u3_time_fsc_out(c3_d ufc_d)
|
||||
{
|
||||
return (c3_w) (((ufc_d >> 48ULL) * 1000000ULL) / 65536ULL);
|
||||
}
|
||||
|
||||
/* u3_time_msc_out: unix microseconds from urbit fracto-seconds.
|
||||
*/
|
||||
c3_w
|
||||
u3_time_msc_out(c3_d ufc_d)
|
||||
{
|
||||
return (c3_w) (((ufc_d >> 48ULL) * 1000ULL) / 65536ULL);
|
||||
}
|
||||
|
||||
/* u3_time_in_tv(): urbit time from struct timeval.
|
||||
*/
|
||||
u3_atom
|
||||
u3_time_in_tv(struct timeval* tim_tv)
|
||||
{
|
||||
c3_w unx_w = tim_tv->tv_sec;
|
||||
c3_w usc_w = tim_tv->tv_usec;
|
||||
c3_d cub_d[2];
|
||||
|
||||
cub_d[0] = u3_time_fsc_in(usc_w);
|
||||
cub_d[1] = u3_time_sec_in(unx_w);
|
||||
|
||||
return u3i_chubs(2, cub_d);
|
||||
}
|
||||
|
||||
/* u3_time_out_tv(): struct timeval from urbit time.
|
||||
*/
|
||||
void
|
||||
u3_time_out_tv(struct timeval* tim_tv, u3_noun now)
|
||||
{
|
||||
c3_d ufc_d = u3r_chub(0, now);
|
||||
c3_d urs_d = u3r_chub(1, now);
|
||||
|
||||
tim_tv->tv_sec = u3_time_sec_out(urs_d);
|
||||
tim_tv->tv_usec = u3_time_fsc_out(ufc_d);
|
||||
|
||||
u3z(now);
|
||||
}
|
||||
|
||||
/* u3_time_in_ts(): urbit time from struct timespec.
|
||||
*/
|
||||
u3_atom
|
||||
u3_time_in_ts(struct timespec* tim_ts)
|
||||
{
|
||||
struct timeval tim_tv;
|
||||
|
||||
tim_tv.tv_sec = tim_ts->tv_sec;
|
||||
tim_tv.tv_usec = (tim_ts->tv_nsec / 1000);
|
||||
|
||||
return u3_time_in_tv(&tim_tv);
|
||||
}
|
||||
|
||||
#if defined(U3_OS_linux)
|
||||
/* u3_time_t_in_ts(): urbit time from time_t.
|
||||
*/
|
||||
u3_atom
|
||||
u3_time_t_in_ts(time_t tim)
|
||||
{
|
||||
struct timeval tim_tv;
|
||||
|
||||
tim_tv.tv_sec = tim;
|
||||
tim_tv.tv_usec = 0;
|
||||
|
||||
return u3_time_in_tv(&tim_tv);
|
||||
}
|
||||
#endif // defined(U3_OS_linux)
|
||||
|
||||
/* u3_time_out_ts(): struct timespec from urbit time.
|
||||
*/
|
||||
void
|
||||
u3_time_out_ts(struct timespec* tim_ts, u3_noun now)
|
||||
{
|
||||
struct timeval tim_tv;
|
||||
|
||||
u3_time_out_tv(&tim_tv, now);
|
||||
|
||||
tim_ts->tv_sec = tim_tv.tv_sec;
|
||||
tim_ts->tv_nsec = (tim_tv.tv_usec * 1000);
|
||||
}
|
||||
|
||||
/* u3_time_gap_ms(): (wen - now) in ms.
|
||||
*/
|
||||
c3_d
|
||||
u3_time_gap_ms(u3_noun now, u3_noun wen)
|
||||
{
|
||||
if ( c3n == u3ka_gth(u3k(wen), u3k(now)) ) {
|
||||
u3z(wen); u3z(now);
|
||||
return 0ULL;
|
||||
}
|
||||
else {
|
||||
u3_noun dif = u3ka_sub(wen, now);
|
||||
c3_d fsc_d = u3r_chub(0, dif);
|
||||
c3_d sec_d = u3r_chub(1, dif);
|
||||
|
||||
u3z(dif);
|
||||
return (sec_d * 1000ULL) + u3_time_msc_out(fsc_d);
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_time_gap_double(): (wen - now) in libev resolution.
|
||||
*/
|
||||
double
|
||||
u3_time_gap_double(u3_noun now, u3_noun wen)
|
||||
{
|
||||
mpz_t now_mp, wen_mp, dif_mp;
|
||||
double sec_g = (((double)(1ULL << 32ULL)) * ((double)(1ULL << 32ULL)));
|
||||
double gap_g, dif_g;
|
||||
|
||||
u3r_mp(now_mp, now);
|
||||
u3r_mp(wen_mp, wen);
|
||||
mpz_init(dif_mp);
|
||||
mpz_sub(dif_mp, wen_mp, now_mp);
|
||||
|
||||
u3z(now);
|
||||
u3z(wen);
|
||||
|
||||
dif_g = mpz_get_d(dif_mp) / sec_g;
|
||||
gap_g = (dif_g > 0.0) ? dif_g : 0.0;
|
||||
mpz_clear(dif_mp); mpz_clear(wen_mp); mpz_clear(now_mp);
|
||||
|
||||
return gap_g;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,334 +0,0 @@
|
||||
/* vere/walk.c
|
||||
**
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <uv.h>
|
||||
#include <ncurses/curses.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses/term.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* |%
|
||||
** ++ arch :: fs node
|
||||
** $% [& p=@uvI q=*] :: file, hash/data
|
||||
** [| p=(map ,@ta arch)] :: directory
|
||||
** == ::
|
||||
** --
|
||||
*/
|
||||
|
||||
#if 0
|
||||
static u3_noun
|
||||
_walk_ok(u3_noun nod)
|
||||
{
|
||||
u3_noun don = u3n_mung(u3k(u2A->toy.arch), u3k(nod));
|
||||
|
||||
if ( c3n == u3_sing(nod, don) ) {
|
||||
c3_assert(0);
|
||||
}
|
||||
u3z(don);
|
||||
return nod;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* u3_walk_safe(): load file or 0.
|
||||
*/
|
||||
u3_noun
|
||||
u3_walk_safe(c3_c* pas_c)
|
||||
{
|
||||
struct stat buf_b;
|
||||
c3_i fid_i = open(pas_c, O_RDONLY, 0644);
|
||||
c3_w fln_w, red_w;
|
||||
c3_y* pad_y;
|
||||
|
||||
if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) {
|
||||
// u3l_log("%s: %s\n", pas_c, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
fln_w = buf_b.st_size;
|
||||
pad_y = c3_malloc(buf_b.st_size);
|
||||
|
||||
red_w = read(fid_i, pad_y, fln_w);
|
||||
close(fid_i);
|
||||
|
||||
if ( fln_w != red_w ) {
|
||||
free(pad_y);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y);
|
||||
free(pad_y);
|
||||
|
||||
return pad;
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_walk_load(): load file or bail.
|
||||
*/
|
||||
u3_noun
|
||||
u3_walk_load(c3_c* pas_c)
|
||||
{
|
||||
struct stat buf_b;
|
||||
c3_i fid_i = open(pas_c, O_RDONLY, 0644);
|
||||
c3_w fln_w, red_w;
|
||||
c3_y* pad_y;
|
||||
|
||||
if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) {
|
||||
u3l_log("%s: %s\n", pas_c, strerror(errno));
|
||||
return u3m_bail(c3__fail);
|
||||
}
|
||||
fln_w = buf_b.st_size;
|
||||
pad_y = c3_malloc(buf_b.st_size);
|
||||
|
||||
red_w = read(fid_i, pad_y, fln_w);
|
||||
close(fid_i);
|
||||
|
||||
if ( fln_w != red_w ) {
|
||||
free(pad_y);
|
||||
return u3m_bail(c3__fail);
|
||||
}
|
||||
else {
|
||||
u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y);
|
||||
free(pad_y);
|
||||
|
||||
return pad;
|
||||
}
|
||||
}
|
||||
|
||||
/* _walk_mkdirp(): recursively make directories in pax at bas_c (RETAIN)
|
||||
*/
|
||||
static void
|
||||
_walk_mkdirp(c3_c* bas_c, u3_noun pax)
|
||||
{
|
||||
c3_c* pax_c;
|
||||
c3_y* waq_y;
|
||||
c3_w pax_w, fas_w, len_w;
|
||||
|
||||
if ( u3_nul == pax ) {
|
||||
return;
|
||||
}
|
||||
|
||||
pax_w = u3r_met(3, u3h(pax));
|
||||
fas_w = strlen(bas_c);
|
||||
len_w = 1 + fas_w + pax_w;
|
||||
|
||||
pax_c = c3_malloc(1 + len_w);
|
||||
strncpy(pax_c, bas_c, len_w);
|
||||
pax_c[fas_w] = '/';
|
||||
waq_y = (void*)(1 + pax_c + fas_w);
|
||||
u3r_bytes(0, pax_w, waq_y, u3h(pax));
|
||||
pax_c[len_w] = '\0';
|
||||
|
||||
if ( 0 != mkdir(pax_c, 0755) && EEXIST != errno ) {
|
||||
u3l_log("error mkdiring %s: %s\n", pax_c, strerror(errno));
|
||||
u3m_bail(c3__fail);
|
||||
}
|
||||
|
||||
_walk_mkdirp(pax_c, u3t(pax));
|
||||
free(pax_c);
|
||||
}
|
||||
|
||||
/* u3_walk_save(): save file or bail.
|
||||
*/
|
||||
void
|
||||
u3_walk_save(c3_c* pas_c, u3_noun tim, u3_atom pad, c3_c* bas_c, u3_noun pax)
|
||||
{
|
||||
c3_i fid_i = open(pas_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
c3_w fln_w, rit_w;
|
||||
c3_y* pad_y;
|
||||
|
||||
if ( fid_i < 0 ) {
|
||||
if ( ENOENT == errno && u3_nul != pax ) {
|
||||
_walk_mkdirp(bas_c, pax);
|
||||
return u3_walk_save(pas_c, tim, pad, 0, u3_nul);
|
||||
}
|
||||
|
||||
u3l_log("%s: %s\n", pas_c, strerror(errno));
|
||||
u3m_bail(c3__fail);
|
||||
}
|
||||
|
||||
fln_w = u3r_met(3, pad);
|
||||
pad_y = c3_malloc(fln_w);
|
||||
u3r_bytes(0, fln_w, pad_y, pad);
|
||||
u3z(pad);
|
||||
u3z(pax);
|
||||
|
||||
rit_w = write(fid_i, pad_y, fln_w);
|
||||
close(fid_i);
|
||||
free(pad_y);
|
||||
|
||||
if ( rit_w != fln_w ) {
|
||||
u3l_log("%s: %s\n", pas_c, strerror(errno));
|
||||
u3m_bail(c3__fail);
|
||||
}
|
||||
|
||||
if ( 0 != tim ) {
|
||||
struct timeval tim_tv[2];
|
||||
|
||||
u3_time_out_tv(&tim_tv[0], u3k(tim));
|
||||
u3_time_out_tv(&tim_tv[1], tim);
|
||||
|
||||
utimes(pas_c, tim_tv);
|
||||
}
|
||||
}
|
||||
|
||||
/* _walk_in(): inner loop of _walk(), producing map.
|
||||
*/
|
||||
static u3_noun
|
||||
_walk_in(const c3_c* dir_c, c3_w len_w)
|
||||
{
|
||||
DIR* dir_d = opendir(dir_c);
|
||||
u3_noun map = u3_nul;
|
||||
|
||||
if ( !dir_d ) {
|
||||
return u3_nul;
|
||||
}
|
||||
else while ( 1 ) {
|
||||
struct dirent ent_n;
|
||||
struct dirent* out_n;
|
||||
|
||||
if ( u3_readdir_r(dir_d, &ent_n, &out_n) != 0 ) {
|
||||
u3l_log("%s: %s\n", dir_c, strerror(errno));
|
||||
break;
|
||||
}
|
||||
else if ( !out_n ) {
|
||||
break;
|
||||
}
|
||||
else if ( !strcmp(out_n->d_name, ".") ||
|
||||
!strcmp(out_n->d_name, "..") ||
|
||||
('~' == out_n->d_name[0]) ||
|
||||
('.' == out_n->d_name[0]) ) // XX restricts some spans
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
c3_c* fil_c = out_n->d_name;
|
||||
c3_w lef_w = len_w + 1 + strlen(fil_c);
|
||||
c3_c* pat_c = c3_malloc(lef_w + 1);
|
||||
struct stat buf_b;
|
||||
|
||||
strncpy(pat_c, dir_c, lef_w);
|
||||
pat_c[len_w] = '/';
|
||||
strncpy(pat_c + len_w + 1, fil_c, lef_w);
|
||||
pat_c[lef_w] = '\0';
|
||||
|
||||
if ( 0 != stat(pat_c, &buf_b) ) {
|
||||
free(pat_c);
|
||||
} else {
|
||||
u3_noun tim = c3_stat_mtime(&buf_b);
|
||||
|
||||
if ( !S_ISDIR(buf_b.st_mode) ) {
|
||||
c3_c* dot_c = strrchr(fil_c, '.');
|
||||
c3_c* nam_c = strdup(fil_c);
|
||||
c3_c* ext_c = strdup(dot_c + 1);
|
||||
|
||||
nam_c[dot_c - fil_c] = 0;
|
||||
{
|
||||
u3_noun nam = u3i_string(nam_c);
|
||||
u3_noun ext = u3i_string(ext_c);
|
||||
u3_noun get = u3kdb_get(u3k(map), u3k(nam));
|
||||
u3_noun dat = u3_walk_load(pat_c);
|
||||
u3_noun hax;
|
||||
|
||||
if ( !strcmp("noun", ext_c) ) {
|
||||
dat = u3ke_cue(dat);
|
||||
}
|
||||
hax = u3do("sham", u3k(dat));
|
||||
if ( u3_none == get ) { get = u3_nul; }
|
||||
|
||||
get = u3kdb_put(get, ext, u3nt(c3y, hax, dat));
|
||||
map = u3kdb_put(map, nam, u3nc(c3n, get));
|
||||
}
|
||||
free(nam_c);
|
||||
free(ext_c);
|
||||
}
|
||||
else {
|
||||
u3_noun dir = _walk_in(pat_c, lef_w);
|
||||
|
||||
if ( u3_nul != dir ) {
|
||||
map = u3kdb_put
|
||||
(map, u3i_string(fil_c), u3nc(c3n, dir));
|
||||
}
|
||||
else u3z(tim);
|
||||
}
|
||||
free(pat_c);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir_d);
|
||||
return map;
|
||||
}
|
||||
|
||||
/* u3_walk(): traverse `dir_c` to produce an arch, updating `old`.
|
||||
*/
|
||||
u3_noun
|
||||
u3_walk(const c3_c* dir_c, u3_noun old)
|
||||
{
|
||||
// XX - obviously, cheaper to update old data.
|
||||
u3z(old);
|
||||
{
|
||||
struct stat buf_b;
|
||||
|
||||
if ( 0 != stat(dir_c, &buf_b) ) {
|
||||
u3l_log("can't stat %s\n", dir_c);
|
||||
// return u3m_bail(c3__fail);
|
||||
c3_assert(0);
|
||||
}
|
||||
else {
|
||||
return u3nc(c3n,
|
||||
_walk_in(dir_c, strlen(dir_c)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_path(): C unix path in computer for file or directory.
|
||||
*/
|
||||
c3_c*
|
||||
u3_path(c3_o fyl, u3_noun pax)
|
||||
{
|
||||
c3_w len_w;
|
||||
c3_c *pas_c;
|
||||
|
||||
// measure
|
||||
//
|
||||
len_w = strlen(u3_Local);
|
||||
{
|
||||
u3_noun wiz = pax;
|
||||
|
||||
while ( u3_nul != wiz ) {
|
||||
len_w += (1 + u3r_met(3, u3h(wiz)));
|
||||
wiz = u3t(wiz);
|
||||
}
|
||||
}
|
||||
|
||||
// cut
|
||||
//
|
||||
pas_c = c3_malloc(len_w + 1);
|
||||
strncpy(pas_c, u3_Local, len_w);
|
||||
pas_c[len_w] = '\0';
|
||||
{
|
||||
u3_noun wiz = pax;
|
||||
c3_c* waq_c = (pas_c + strlen(pas_c));
|
||||
|
||||
while ( u3_nul != wiz ) {
|
||||
c3_w tis_w = u3r_met(3, u3h(wiz));
|
||||
|
||||
if ( (c3y == fyl) && (u3_nul == u3t(wiz)) ) {
|
||||
*waq_c++ = '.';
|
||||
} else *waq_c++ = '/';
|
||||
|
||||
u3r_bytes(0, tis_w, (c3_y*)waq_c, u3h(wiz));
|
||||
waq_c += tis_w;
|
||||
|
||||
wiz = u3t(wiz);
|
||||
}
|
||||
*waq_c = 0;
|
||||
}
|
||||
u3z(pax);
|
||||
return pas_c;
|
||||
}
|
@ -1,947 +0,0 @@
|
||||
/* worker/main.c
|
||||
**
|
||||
** the main loop of a worker process.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <setjmp.h>
|
||||
#include <gmp.h>
|
||||
#include <sigsegv.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <uv.h>
|
||||
#include <errno.h>
|
||||
#include <ncurses/curses.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses/term.h>
|
||||
|
||||
#include "all.h"
|
||||
#include <vere/vere.h>
|
||||
|
||||
typedef struct _u3_worker {
|
||||
c3_w len_w; // boot sequence length
|
||||
u3_noun roe; // lifecycle formulas
|
||||
c3_d sen_d; // last event requested
|
||||
c3_d dun_d; // last event processed
|
||||
c3_l mug_l; // hash of state
|
||||
c3_d key_d[4]; // disk key
|
||||
u3_moat inn_u; // message input
|
||||
u3_mojo out_u; // message output
|
||||
c3_c* dir_c; // execution directory (pier)
|
||||
} u3_worker;
|
||||
static u3_worker u3V;
|
||||
|
||||
/*
|
||||
:: worker to daemon protocol
|
||||
::
|
||||
|%
|
||||
:: +plea: from worker to daemon
|
||||
::
|
||||
+$ plea
|
||||
$% :: status on startup
|
||||
::
|
||||
$: %play
|
||||
$= p
|
||||
:: ~ if no snapshot
|
||||
::
|
||||
%- unit
|
||||
:: p: event number expected
|
||||
:: q: mug of kernel
|
||||
:: r: identity, fake flag
|
||||
::
|
||||
[p=@ q=@ r=[our=@p fak=?]]
|
||||
==
|
||||
:: event executed unchanged (in response to %work)
|
||||
::
|
||||
$: %done
|
||||
:: p: event number
|
||||
:: q: mug of kernel
|
||||
:: r: effects
|
||||
::
|
||||
[p=@ q=@ r=(list ovum)]
|
||||
==
|
||||
:: replace event and retry (in response to %work)
|
||||
::
|
||||
$: %work
|
||||
:: p: event number
|
||||
:: q: mug of kernel
|
||||
:: r: replacement event (at date)
|
||||
::
|
||||
[p=@ q=@ r=(pair date ovum)]
|
||||
==
|
||||
:: sends a line to stderr while computing event
|
||||
::
|
||||
$: %stdr
|
||||
:: p: event number
|
||||
:: q: output cord
|
||||
::
|
||||
[p=@ q=cord]
|
||||
==
|
||||
:: send slog hint while computing event
|
||||
::
|
||||
$: %slog
|
||||
:: p: event number
|
||||
:: q: priority
|
||||
:: r: output tank
|
||||
::
|
||||
[p=@ q=@ r=tank]
|
||||
== ==
|
||||
:: +writ: from daemon to worker
|
||||
::
|
||||
+$ writ
|
||||
$% :: prepare to boot
|
||||
::
|
||||
:: p: identity
|
||||
:: q: fake?
|
||||
:: r: number of boot formulas
|
||||
::
|
||||
[%boot p=@p q=? r=@]
|
||||
:: exit immediately
|
||||
::
|
||||
:: p: exit code
|
||||
::
|
||||
[%exit p=@]
|
||||
:: save snapshot to disk
|
||||
::
|
||||
:: p: event number
|
||||
::
|
||||
[%save p=@]
|
||||
:: execute event
|
||||
::
|
||||
$: %work
|
||||
:: p: event number
|
||||
:: q: a jammed noun [mug [date ovum]]
|
||||
::
|
||||
[p=@ q=@]
|
||||
== ==
|
||||
--
|
||||
*/
|
||||
|
||||
/* _worker_space(): print n spaces.
|
||||
*/
|
||||
void _worker_space(FILE* fil_u, c3_w n)
|
||||
{
|
||||
for (; n > 0; n--)
|
||||
(fprintf(fil_u," "));
|
||||
}
|
||||
|
||||
/* _worker_print_memory(): print memory amount.
|
||||
**
|
||||
** Helper for _worker_prof(), just an un-captioned u3a_print_memory().
|
||||
*/
|
||||
void
|
||||
_worker_print_memory(FILE* fil_u, c3_w wor_w)
|
||||
{
|
||||
c3_w byt_w = (wor_w * 4);
|
||||
c3_w gib_w = (byt_w / 1000000000);
|
||||
c3_w mib_w = (byt_w % 1000000000) / 1000000;
|
||||
c3_w kib_w = (byt_w % 1000000) / 1000;
|
||||
c3_w bib_w = (byt_w % 1000);
|
||||
|
||||
if ( gib_w ) {
|
||||
(fprintf(fil_u, "GB/%d.%03d.%03d.%03d\r\n",
|
||||
gib_w, mib_w, kib_w, bib_w));
|
||||
}
|
||||
else if ( mib_w ) {
|
||||
(fprintf(fil_u, "MB/%d.%03d.%03d\r\n", mib_w, kib_w, bib_w));
|
||||
}
|
||||
else if ( kib_w ) {
|
||||
(fprintf(fil_u, "KB/%d.%03d\r\n", kib_w, bib_w));
|
||||
}
|
||||
else {
|
||||
(fprintf(fil_u, "B/%d\r\n", bib_w));
|
||||
}
|
||||
}
|
||||
|
||||
/* _worker_prof(): print memory profile. RETAIN.
|
||||
*/
|
||||
c3_w
|
||||
_worker_prof(FILE* fil_u, c3_w den, u3_noun mas)
|
||||
{
|
||||
c3_w tot_w = 0;
|
||||
u3_noun h_mas, t_mas;
|
||||
|
||||
if ( c3n == u3r_cell(mas, &h_mas, &t_mas) ) {
|
||||
_worker_space(fil_u, den);
|
||||
fprintf(fil_u, "mistyped mass\r\n");
|
||||
return tot_w;
|
||||
}
|
||||
else if ( _(u3du(h_mas)) ) {
|
||||
_worker_space(fil_u, den);
|
||||
fprintf(fil_u, "mistyped mass head\r\n");
|
||||
{
|
||||
c3_c* lab_c = u3m_pretty(h_mas);
|
||||
fprintf(fil_u, "h_mas: %s", lab_c);
|
||||
free(lab_c);
|
||||
}
|
||||
return tot_w;
|
||||
}
|
||||
else {
|
||||
_worker_space(fil_u, den);
|
||||
|
||||
{
|
||||
c3_c* lab_c = u3m_pretty(h_mas);
|
||||
fprintf(fil_u, "%s: ", lab_c);
|
||||
free(lab_c);
|
||||
}
|
||||
|
||||
u3_noun it_mas, tt_mas;
|
||||
|
||||
if ( c3n == u3r_cell(t_mas, &it_mas, &tt_mas) ) {
|
||||
fprintf(fil_u, "mistyped mass tail\r\n");
|
||||
return tot_w;
|
||||
}
|
||||
else if ( c3y == it_mas ) {
|
||||
tot_w += u3a_mark_noun(tt_mas);
|
||||
_worker_print_memory(fil_u, tot_w);
|
||||
|
||||
#if 1
|
||||
/* The basic issue here is that tt_mas is included in .sac
|
||||
* (the whole profile), so they can't both be roots in the
|
||||
* normal sense. When we mark .sac later on, we want tt_mas
|
||||
* to appear unmarked, but its children should be already
|
||||
* marked.
|
||||
*/
|
||||
if ( _(u3a_is_dog(tt_mas)) ) {
|
||||
u3a_box* box_u = u3a_botox(u3a_to_ptr(tt_mas));
|
||||
#ifdef U3_MEMORY_DEBUG
|
||||
if ( 1 == box_u->eus_w ) {
|
||||
box_u->eus_w = 0xffffffff;
|
||||
}
|
||||
else {
|
||||
box_u->eus_w -= 1;
|
||||
}
|
||||
#else
|
||||
if ( -1 == (c3_w)box_u->use_w ) {
|
||||
box_u->use_w = 0x80000000;
|
||||
}
|
||||
else {
|
||||
box_u->use_w += 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return tot_w;
|
||||
}
|
||||
else if ( c3n == it_mas ) {
|
||||
fprintf(fil_u, "\r\n");
|
||||
|
||||
while ( _(u3du(tt_mas)) ) {
|
||||
tot_w += _worker_prof(fil_u, den+2, u3h(tt_mas));
|
||||
tt_mas = u3t(tt_mas);
|
||||
}
|
||||
|
||||
_worker_space(fil_u, den);
|
||||
fprintf(fil_u, "--");
|
||||
_worker_print_memory(fil_u, tot_w);
|
||||
|
||||
return tot_w;
|
||||
|
||||
}
|
||||
else {
|
||||
_worker_space(fil_u, den);
|
||||
fprintf(fil_u, "mistyped (strange) mass tail\r\n");
|
||||
return tot_w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* _worker_grab(): garbage collect, checking for profiling. RETAIN.
|
||||
*/
|
||||
static void
|
||||
_worker_grab(u3_noun sac, u3_noun ovo, u3_noun vir)
|
||||
{
|
||||
if ( u3_nul == sac) {
|
||||
if ( u3C.wag_w & (u3o_debug_ram | u3o_check_corrupt) ) {
|
||||
u3m_grab(sac, ovo, vir, u3_none);
|
||||
}
|
||||
}
|
||||
else {
|
||||
c3_w usr_w = 0, man_w = 0, sac_w = 0, ova_w = 0, roe_w = 0, vir_w = 0;
|
||||
|
||||
FILE* fil_u;
|
||||
|
||||
#ifdef U3_MEMORY_LOG
|
||||
{
|
||||
u3_noun wen = u3dc("scot", c3__da, u3k(u3A->now));
|
||||
c3_c* wen_c = u3r_string(wen);
|
||||
|
||||
c3_c nam_c[2048];
|
||||
snprintf(nam_c, 2048, "%s/.urb/put/mass", u3P.dir_c);
|
||||
|
||||
struct stat st;
|
||||
if ( -1 == stat(nam_c, &st) ) {
|
||||
mkdir(nam_c, 0700);
|
||||
}
|
||||
|
||||
c3_c man_c[2048];
|
||||
snprintf(man_c, 2048, "%s/%s.txt", nam_c, wen_c);
|
||||
|
||||
fil_u = fopen(man_c, "w");
|
||||
fprintf(fil_u, "%s\r\n", wen_c);
|
||||
|
||||
free(wen_c);
|
||||
u3z(wen);
|
||||
}
|
||||
#else
|
||||
{
|
||||
fil_u = stderr;
|
||||
}
|
||||
#endif
|
||||
|
||||
c3_assert( u3R == &(u3H->rod_u) );
|
||||
|
||||
fprintf(fil_u, "\r\n");
|
||||
usr_w = _worker_prof(fil_u, 0, sac);
|
||||
u3a_print_memory(fil_u, "total userspace", usr_w);
|
||||
|
||||
man_w = u3m_mark(fil_u);
|
||||
|
||||
sac_w = u3a_mark_noun(sac);
|
||||
u3a_print_memory(fil_u, "space profile", sac_w);
|
||||
|
||||
ova_w = u3a_mark_noun(ovo);
|
||||
u3a_print_memory(fil_u, "event", ova_w);
|
||||
|
||||
roe_w = u3a_mark_noun(u3V.roe);
|
||||
u3a_print_memory(fil_u, "lifecycle events", roe_w);
|
||||
|
||||
vir_w = u3a_mark_noun(vir);
|
||||
u3a_print_memory(fil_u, "effects", vir_w);
|
||||
|
||||
u3a_print_memory(fil_u, "total marked", usr_w + man_w + sac_w + ova_w + vir_w);
|
||||
|
||||
u3a_print_memory(fil_u, "sweep", u3a_sweep());
|
||||
|
||||
#ifdef U3_MEMORY_LOG
|
||||
{
|
||||
fclose(fil_u);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* _worker_fail(): failure stub.
|
||||
*/
|
||||
static void
|
||||
_worker_fail(void* vod_p, const c3_c* wut_c)
|
||||
{
|
||||
u3l_log("work: fail: %s\r\n", wut_c);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* _worker_send(): send result back to daemon.
|
||||
*/
|
||||
static void
|
||||
_worker_send(u3_noun job)
|
||||
{
|
||||
u3_newt_write(&u3V.out_u, u3ke_jam(job), 0);
|
||||
}
|
||||
|
||||
/* _worker_send_replace(): send replacement job back to daemon.
|
||||
*/
|
||||
static void
|
||||
_worker_send_replace(c3_d evt_d, u3_noun job)
|
||||
{
|
||||
u3l_log("worker_send_replace %" PRIu64 " %s\r\n",
|
||||
evt_d,
|
||||
u3r_string(u3h(u3t(u3t(job)))));
|
||||
|
||||
_worker_send(u3nt(c3__work,
|
||||
u3i_chubs(1, &evt_d),
|
||||
u3ke_jam(u3nc(u3V.mug_l, job))));
|
||||
}
|
||||
|
||||
/* _worker_send_complete(): report completion.
|
||||
*/
|
||||
static void
|
||||
_worker_send_complete(u3_noun vir)
|
||||
{
|
||||
_worker_send(u3nq(c3__done,
|
||||
u3i_chubs(1, &u3V.dun_d),
|
||||
u3V.mug_l,
|
||||
vir));
|
||||
}
|
||||
|
||||
/* _worker_send_stdr(): send stderr output
|
||||
*/
|
||||
static void
|
||||
_worker_send_stdr(c3_c* str_c)
|
||||
{
|
||||
_worker_send(u3nt(c3__stdr, u3i_chubs(1, &u3V.sen_d), u3i_string(str_c)));
|
||||
}
|
||||
|
||||
/* _worker_send_slog(): send hint output (hod is [priority tank]).
|
||||
*/
|
||||
static void
|
||||
_worker_send_slog(u3_noun hod)
|
||||
{
|
||||
_worker_send(u3nt(c3__slog, u3i_chubs(1, &u3V.sen_d), hod));
|
||||
}
|
||||
|
||||
/* _worker_lame(): event failed, replace with error event.
|
||||
*/
|
||||
static void
|
||||
_worker_lame(c3_d evt_d, u3_noun now, u3_noun ovo, u3_noun why, u3_noun tan)
|
||||
{
|
||||
u3_noun rep;
|
||||
u3_noun wir, tag, cad;
|
||||
|
||||
u3x_trel(ovo, &wir, &tag, &cad);
|
||||
|
||||
// a deterministic error (%exit) in a network packet (%hear)
|
||||
// generates a negative-acknowlegement attempt (%hole).
|
||||
//
|
||||
// A comment from the old implementation:
|
||||
// There should be a separate path for crypto failures,
|
||||
// to prevent timing attacks, but isn't right now. To deal
|
||||
// with a crypto failure, just drop the packet.
|
||||
//
|
||||
if ( (c3__hear == tag) && (c3__exit == why) ) {
|
||||
rep = u3nt(u3k(wir), c3__hole, u3k(cad));
|
||||
}
|
||||
// failed event notifications (%crud) are replaced with
|
||||
// an even more generic notifications, on a generic arvo wire.
|
||||
// N.B this must not be allowed to fail!
|
||||
//
|
||||
// [%warn original-event-tag=@tas combined-trace=(list tank)]
|
||||
//
|
||||
else if ( c3__crud == tag ) {
|
||||
u3_noun lef = u3nc(c3__leaf, u3i_tape("crude crashed!"));
|
||||
u3_noun nat = u3kb_weld(u3k(u3t(cad)), u3nc(lef, u3k(tan)));
|
||||
rep = u3nc(u3nt(u3_blip, c3__arvo, u3_nul),
|
||||
u3nt(c3__warn, u3k(u3h(cad)), nat));
|
||||
}
|
||||
// failed failure failing fails
|
||||
//
|
||||
else if ( c3__warn == tag ) {
|
||||
_worker_fail(0, "%warn replacement event failed");
|
||||
c3_assert(0);
|
||||
}
|
||||
// failure notifications are sent on the same wire
|
||||
//
|
||||
// [%crud event-tag=@tas event-trace=(list tank)]
|
||||
//
|
||||
else {
|
||||
// prepend failure mote to tank
|
||||
//
|
||||
u3_noun lef = u3nc(c3__leaf, u3kb_weld(u3i_tape("bail: "),
|
||||
u3qc_rip(3, why)));
|
||||
u3_noun nat = u3kb_weld(u3k(tan), u3nc(lef, u3_nul));
|
||||
rep = u3nc(u3k(wir), u3nt(c3__crud, u3k(tag), nat));
|
||||
}
|
||||
|
||||
_worker_send_replace(evt_d, u3nc(now, rep));
|
||||
|
||||
u3z(ovo); u3z(why); u3z(tan);
|
||||
}
|
||||
|
||||
/* _worker_sure(): event succeeded, report completion.
|
||||
*/
|
||||
static void
|
||||
_worker_sure(u3_noun ovo, u3_noun vir, u3_noun cor)
|
||||
{
|
||||
u3z(u3A->roc);
|
||||
u3A->roc = cor;
|
||||
u3A->ent_d = u3V.dun_d;
|
||||
u3V.mug_l = u3r_mug(u3A->roc);
|
||||
|
||||
u3_noun sac = u3_nul;
|
||||
|
||||
// intercept |mass, observe |reset
|
||||
//
|
||||
{
|
||||
u3_noun riv = vir;
|
||||
c3_w i_w = 0;
|
||||
|
||||
while ( u3_nul != riv ) {
|
||||
u3_noun fec = u3t(u3h(riv));
|
||||
|
||||
// assumes a max of one %mass effect per event
|
||||
//
|
||||
if ( c3__mass == u3h(fec) ) {
|
||||
// save a copy of the %mass data
|
||||
//
|
||||
sac = u3k(u3t(fec));
|
||||
// replace the %mass data with ~
|
||||
//
|
||||
// For efficient transmission to daemon.
|
||||
//
|
||||
riv = u3kb_weld(u3qb_scag(i_w, vir),
|
||||
u3nc(u3nt(u3k(u3h(u3h(riv))), c3__mass, u3_nul),
|
||||
u3qb_slag(1 + i_w, vir)));
|
||||
u3z(vir);
|
||||
vir = riv;
|
||||
break;
|
||||
}
|
||||
|
||||
// reclaim memory from persistent caches on |reset
|
||||
//
|
||||
if ( c3__vega == u3h(fec) ) {
|
||||
u3m_reclaim();
|
||||
}
|
||||
|
||||
riv = u3t(riv);
|
||||
i_w++;
|
||||
}
|
||||
}
|
||||
|
||||
// XX this runs on replay too
|
||||
//
|
||||
_worker_grab(sac, ovo, vir);
|
||||
_worker_send_complete(vir);
|
||||
|
||||
u3z(sac); u3z(ovo);
|
||||
}
|
||||
|
||||
/* _worker_work_live(): apply event.
|
||||
*/
|
||||
static void
|
||||
_worker_work_live(c3_d evt_d, u3_noun job)
|
||||
{
|
||||
u3_noun now, ovo, gon;
|
||||
u3_noun last_date;
|
||||
|
||||
c3_assert(evt_d == u3V.dun_d + 1ULL);
|
||||
u3V.sen_d = evt_d;
|
||||
|
||||
u3x_cell(job, &now, &ovo);
|
||||
|
||||
last_date = u3A->now;
|
||||
u3A->now = u3k(now);
|
||||
|
||||
#ifdef U3_EVENT_TIME_DEBUG
|
||||
{
|
||||
struct timeval b4, f2, d0;
|
||||
gettimeofday(&b4, 0);
|
||||
|
||||
if ( c3__belt != u3h(u3t(ovo)) ) {
|
||||
c3_c* txt_c = u3r_string(u3h(u3t(ovo)));
|
||||
|
||||
u3l_log("work: %s (%" PRIu64 ") live\r\n", txt_c, evt_d);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
gon = u3m_soft(0, u3v_poke, u3k(ovo));
|
||||
|
||||
#ifdef U3_EVENT_TIME_DEBUG
|
||||
{
|
||||
c3_c* txt_c = u3r_string(u3h(u3t(ovo)));
|
||||
c3_w ms_w;
|
||||
c3_w clr_w;
|
||||
|
||||
gettimeofday(&f2, 0);
|
||||
timersub(&f2, &b4, &d0);
|
||||
ms_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000);
|
||||
clr_w = ms_w > 1000 ? 1 : ms_w < 100 ? 2 : 3; // red, green, yellow
|
||||
if (c3__belt != u3h(u3t(ovo)) || clr_w != 2) {
|
||||
u3l_log("\x1b[3%dm%%%s (%" PRIu64 ") %4d.%02dms\x1b[0m\n",
|
||||
clr_w, txt_c, evt_d, ms_w,
|
||||
(int) (d0.tv_usec % 1000) / 10);
|
||||
}
|
||||
free(txt_c);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( u3_blip != u3h(gon) ) {
|
||||
// event rejected
|
||||
//
|
||||
u3V.sen_d = u3V.dun_d;
|
||||
// restore previous time
|
||||
//
|
||||
u3_noun nex = u3A->now;
|
||||
u3A->now = last_date;
|
||||
|
||||
u3_noun why, tan;
|
||||
u3x_cell(gon, &why, &tan);
|
||||
|
||||
u3k(ovo); u3k(why); u3k(tan);
|
||||
u3z(gon); u3z(job);
|
||||
|
||||
_worker_lame(evt_d, nex, ovo, why, tan);
|
||||
}
|
||||
else {
|
||||
// event accepted
|
||||
//
|
||||
u3V.dun_d = u3V.sen_d;
|
||||
u3z(last_date);
|
||||
|
||||
// vir/(list ovum) list of effects
|
||||
// cor/arvo arvo core
|
||||
//
|
||||
u3_noun vir, cor;
|
||||
u3x_trel(gon, 0, &vir, &cor);
|
||||
|
||||
u3k(ovo); u3k(vir); u3k(cor);
|
||||
u3z(gon); u3z(job);
|
||||
|
||||
_worker_sure(ovo, vir, cor);
|
||||
|
||||
// reclaim memory from persistent caches periodically
|
||||
//
|
||||
// XX this is a hack to work around the fact that
|
||||
// the bytecode caches grow rapidly and are not
|
||||
// able to be simply capped (due to internal posts).
|
||||
//
|
||||
if ( 0 == (evt_d % 1000ULL) ) {
|
||||
u3m_reclaim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* _worker_work_boot(): apply initial-stage event.
|
||||
*/
|
||||
static void
|
||||
_worker_work_boot(c3_d evt_d, u3_noun job)
|
||||
{
|
||||
// here we asset on u3V.sen_d, because u3V.dun_d isn't set until
|
||||
// after u3V.sen_d == u3V.len_w (ie, after the lifecycle evaluation)
|
||||
//
|
||||
c3_assert(evt_d == u3V.sen_d + 1ULL);
|
||||
u3V.sen_d = evt_d;
|
||||
|
||||
u3V.roe = u3nc(job, u3V.roe);
|
||||
|
||||
u3l_log("work: (%" PRIu64 ")| boot\r\n", evt_d);
|
||||
|
||||
if ( u3V.len_w == evt_d ) {
|
||||
u3_noun eve = u3kb_flop(u3V.roe);
|
||||
u3V.roe = u3_nul;
|
||||
|
||||
u3l_log("work: (%" PRIu64 ")| pill: %x\r\n", evt_d, u3r_mug(eve));
|
||||
|
||||
if ( c3n == u3v_boot(eve) ) {
|
||||
u3l_log("work: boot failed: invalid sequence (from pill)\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
u3V.dun_d = evt_d;
|
||||
u3V.mug_l = u3r_mug(u3A->roc);
|
||||
u3A->ent_d = u3V.dun_d;
|
||||
|
||||
u3l_log("work: (%" PRIu64 ")| core: %x\r\n", evt_d, u3V.mug_l);
|
||||
}
|
||||
else {
|
||||
// prior to the evaluation of the entire lifecycle sequence,
|
||||
// we simply use the mug of the formula as the kernel mug
|
||||
//
|
||||
u3V.mug_l = u3r_mug(job);
|
||||
}
|
||||
|
||||
_worker_send(u3nq(c3__done,
|
||||
u3i_chubs(1, &evt_d),
|
||||
u3V.mug_l,
|
||||
u3_nul));
|
||||
}
|
||||
|
||||
/* _worker_poke_work(): apply event.
|
||||
*/
|
||||
static void
|
||||
_worker_poke_work(c3_d evt_d, // event number
|
||||
c3_l mug_l, // mug of state
|
||||
u3_noun job) // full event
|
||||
{
|
||||
if ( u3C.wag_w & u3o_trace ) {
|
||||
if ( u3_Host.tra_u.con_w == 0 && u3_Host.tra_u.fun_w == 0 ) {
|
||||
u3t_trace_open(u3V.dir_c);
|
||||
}
|
||||
else if ( u3_Host.tra_u.con_w >= 100000 ) {
|
||||
u3t_trace_close();
|
||||
u3t_trace_open(u3V.dir_c);
|
||||
}
|
||||
}
|
||||
|
||||
// Require mugs to match
|
||||
//
|
||||
// We use mugs to enforce that %work is always performed against
|
||||
// the exact kernel we expect it to be. If it isn't, we have either
|
||||
// event-log corruption or non-determism on replay, or programmer error
|
||||
// in normal operation. In either case, we immediately exit.
|
||||
//
|
||||
if ( u3V.mug_l != mug_l ) {
|
||||
u3l_log("work: invalid %%work for event %" PRIu64 ".\r\n", evt_d);
|
||||
u3l_log("work: computed mug is %x but event %" PRIu64 " expected %x.\r\n",
|
||||
u3V.mug_l,
|
||||
evt_d,
|
||||
mug_l);
|
||||
_worker_fail(0, "bad jar");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( evt_d <= u3V.len_w ) {
|
||||
c3_c lab_c[8];
|
||||
snprintf(lab_c, 8, "boot: %" PRIu64 "", evt_d);
|
||||
|
||||
u3t_event_trace(lab_c, 'B');
|
||||
_worker_work_boot(evt_d, job);
|
||||
u3t_event_trace(lab_c, 'E');
|
||||
}
|
||||
else {
|
||||
u3_noun wir = u3h(u3t(job));
|
||||
u3_noun cad = u3h(u3t(u3t(job)));
|
||||
|
||||
c3_c lab_c[2048];
|
||||
snprintf(lab_c, 2048, "event %" PRIu64 ": [%s %s]", evt_d,
|
||||
u3m_pretty_path(wir), u3m_pretty(cad));
|
||||
|
||||
u3t_event_trace(lab_c, 'B');
|
||||
_worker_work_live(evt_d, job);
|
||||
u3t_event_trace(lab_c, 'E');
|
||||
}
|
||||
}
|
||||
|
||||
/* _worker_poke_exit(): exit on command.
|
||||
*/
|
||||
static void
|
||||
_worker_poke_exit(c3_w cod_w) // exit code
|
||||
{
|
||||
if ( u3C.wag_w & u3o_debug_cpu ) {
|
||||
u3t_damp();
|
||||
}
|
||||
|
||||
exit(cod_w);
|
||||
}
|
||||
|
||||
/* _worker_poke_boot(): prepare to boot.
|
||||
*/
|
||||
static void
|
||||
_worker_poke_boot(u3_noun who, u3_noun fak, c3_w len_w)
|
||||
{
|
||||
c3_assert( u3_none == u3A->our );
|
||||
c3_assert( 0 != len_w );
|
||||
|
||||
u3A->our = who;
|
||||
u3A->fak = fak;
|
||||
u3V.len_w = len_w;
|
||||
}
|
||||
|
||||
/* _worker_poke():
|
||||
*/
|
||||
void
|
||||
_worker_poke(void* vod_p, u3_noun mat)
|
||||
{
|
||||
u3_noun jar = u3ke_cue(mat);
|
||||
|
||||
if ( c3y != u3du(jar) ) {
|
||||
goto error;
|
||||
}
|
||||
else {
|
||||
switch ( u3h(jar) ) {
|
||||
default: {
|
||||
goto error;
|
||||
}
|
||||
|
||||
case c3__boot: {
|
||||
u3_noun who, fak, len;
|
||||
c3_w len_w;
|
||||
|
||||
if ( (c3n == u3r_qual(jar, 0, &who, &fak, &len)) ||
|
||||
(c3n == u3ud(who)) ||
|
||||
(1 < u3r_met(7, who)) ||
|
||||
(c3n == u3ud(fak)) ||
|
||||
(1 < u3r_met(0, fak)) ||
|
||||
(c3n == u3ud(len)) ||
|
||||
(1 < u3r_met(3, len)) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
len_w = u3r_word(0, len);
|
||||
u3k(who);
|
||||
u3k(fak);
|
||||
u3z(jar);
|
||||
|
||||
return _worker_poke_boot(who, fak, len_w);
|
||||
}
|
||||
|
||||
case c3__work: {
|
||||
u3_noun evt, jammed_entry, mug, job;
|
||||
c3_d evt_d;
|
||||
c3_l mug_l;
|
||||
|
||||
if ( (c3n == u3r_trel(jar, 0, &evt, &jammed_entry)) ||
|
||||
(c3n == u3ud(evt)) ||
|
||||
(1 != u3r_met(6, evt)) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
u3_noun entry = u3qe_cue(jammed_entry);
|
||||
if ( (c3y != u3du(entry)) ||
|
||||
(c3n == u3r_cell(entry, &mug, &job)) ||
|
||||
(c3n == u3ud(mug)) ||
|
||||
(1 < u3r_met(5, mug)) ) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
evt_d = u3r_chub(0, evt);
|
||||
mug_l = u3r_word(0, mug);
|
||||
u3k(job);
|
||||
u3z(entry);
|
||||
u3z(jar);
|
||||
|
||||
return _worker_poke_work(evt_d, mug_l, job);
|
||||
}
|
||||
|
||||
case c3__exit: {
|
||||
u3_noun cod;
|
||||
c3_w cod_w;
|
||||
|
||||
if ( (c3n == u3r_cell(jar, 0, &cod)) ||
|
||||
(c3n == u3ud(cod)) ||
|
||||
(1 < u3r_met(3, cod)) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
cod_w = u3r_word(0, cod);
|
||||
u3z(jar);
|
||||
|
||||
return _worker_poke_exit(cod_w);
|
||||
}
|
||||
|
||||
case c3__save: {
|
||||
u3_noun evt;
|
||||
c3_d evt_d;
|
||||
|
||||
if ( (c3n == u3r_cell(jar, 0, &evt)) ||
|
||||
(c3n == u3ud(evt)) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
evt_d = u3r_chub(0, evt);
|
||||
u3z(jar);
|
||||
|
||||
c3_assert( evt_d == u3V.dun_d );
|
||||
|
||||
return u3e_save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error: {
|
||||
u3z(jar);
|
||||
_worker_fail(0, "bad jar");
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_worker_boot(): send startup message to manager.
|
||||
*/
|
||||
void
|
||||
u3_worker_boot(void)
|
||||
{
|
||||
c3_d nex_d = 1ULL;
|
||||
u3_noun dat = u3_nul;
|
||||
|
||||
if ( u3_none != u3A->our ) {
|
||||
u3V.mug_l = u3r_mug(u3A->roc);
|
||||
nex_d = u3V.dun_d + 1ULL;
|
||||
dat = u3nc(u3_nul, u3nt(u3i_chubs(1, &nex_d),
|
||||
u3V.mug_l,
|
||||
u3nc(u3k(u3A->our), u3k(u3A->fak))));
|
||||
|
||||
// disable hashboard for fake ships
|
||||
//
|
||||
if ( c3y == u3A->fak ) {
|
||||
u3C.wag_w |= u3o_hashless;
|
||||
}
|
||||
|
||||
// no boot sequence expected
|
||||
//
|
||||
u3V.len_w = 0;
|
||||
}
|
||||
|
||||
u3l_log("work: play %" PRIu64 "\r\n", nex_d);
|
||||
|
||||
_worker_send(u3nc(c3__play, dat));
|
||||
}
|
||||
|
||||
/* main(): main() when run as urbit-worker
|
||||
*/
|
||||
c3_i
|
||||
main(c3_i argc, c3_c* argv[])
|
||||
{
|
||||
uv_loop_t* lup_u = uv_default_loop();
|
||||
c3_c* dir_c = argv[1];
|
||||
c3_c* key_c = argv[2];
|
||||
c3_c* wag_c = argv[3];
|
||||
|
||||
c3_assert(4 == argc);
|
||||
|
||||
memset(&u3V, 0, sizeof(u3V));
|
||||
memset(&u3_Host.tra_u, 0, sizeof(u3_Host.tra_u));
|
||||
|
||||
/* load passkey
|
||||
*/
|
||||
{
|
||||
sscanf(key_c, "%" PRIx64 ":%" PRIx64 ":%" PRIx64 ":%" PRIx64 "",
|
||||
&u3V.key_d[0],
|
||||
&u3V.key_d[1],
|
||||
&u3V.key_d[2],
|
||||
&u3V.key_d[3]);
|
||||
}
|
||||
|
||||
/* load runtime config
|
||||
*/
|
||||
{
|
||||
sscanf(wag_c, "%" SCNu32, &u3C.wag_w);
|
||||
}
|
||||
|
||||
/* load pier directory
|
||||
*/
|
||||
{
|
||||
u3V.dir_c = strdup(dir_c);
|
||||
}
|
||||
|
||||
/* boot image
|
||||
*/
|
||||
{
|
||||
u3V.sen_d = u3V.dun_d = u3m_boot(dir_c);
|
||||
u3C.stderr_log_f = _worker_send_stdr;
|
||||
u3C.slog_f = _worker_send_slog;
|
||||
}
|
||||
|
||||
/* configure pipe to daemon process
|
||||
*/
|
||||
{
|
||||
c3_i err_i;
|
||||
|
||||
err_i = uv_pipe_init(lup_u, &u3V.inn_u.pyp_u, 0);
|
||||
c3_assert(!err_i);
|
||||
uv_pipe_open(&u3V.inn_u.pyp_u, 0);
|
||||
|
||||
err_i = uv_pipe_init(lup_u, &u3V.out_u.pyp_u, 0);
|
||||
c3_assert(!err_i);
|
||||
uv_pipe_open(&u3V.out_u.pyp_u, 1);
|
||||
}
|
||||
|
||||
/* set up writing
|
||||
*/
|
||||
u3V.out_u.bal_f = _worker_fail;
|
||||
|
||||
/* start reading
|
||||
*/
|
||||
u3V.inn_u.vod_p = &u3V;
|
||||
u3V.inn_u.pok_f = _worker_poke;
|
||||
u3V.inn_u.bal_f = _worker_fail;
|
||||
|
||||
u3_newt_read(&u3V.inn_u);
|
||||
|
||||
/* send start request
|
||||
*/
|
||||
u3_worker_boot();
|
||||
|
||||
/* enter loop
|
||||
*/
|
||||
uv_run(lup_u, UV_RUN_DEFAULT);
|
||||
return 0;
|
||||
}
|
90
pkg/hs-urbit/package.yaml
Normal file
90
pkg/hs-urbit/package.yaml
Normal file
@ -0,0 +1,90 @@
|
||||
name: urbit
|
||||
version: 0.1.0
|
||||
license: AGPL-3.0-only
|
||||
|
||||
library:
|
||||
source-dirs: lib
|
||||
ghc-options:
|
||||
- -fwarn-incomplete-patterns
|
||||
- -O2
|
||||
|
||||
dependencies:
|
||||
- async
|
||||
- base
|
||||
- bytestring
|
||||
- case-insensitive
|
||||
- classy-prelude
|
||||
- containers
|
||||
- data-fix
|
||||
- extra
|
||||
- flat
|
||||
- ghc-prim
|
||||
- hashtables
|
||||
- http-client
|
||||
- http-types
|
||||
- integer-gmp
|
||||
- largeword
|
||||
- lens
|
||||
- lmdb
|
||||
- megaparsec
|
||||
- mtl
|
||||
- multimap
|
||||
- para
|
||||
- pretty-show
|
||||
- primitive
|
||||
- process
|
||||
- QuickCheck
|
||||
- sdl2
|
||||
- sdl2-image
|
||||
- semigroups
|
||||
- smallcheck
|
||||
- stm
|
||||
- stm-chans
|
||||
- tasty
|
||||
- tasty-quickcheck
|
||||
- tasty-th
|
||||
- text
|
||||
- these
|
||||
- time
|
||||
- transformers
|
||||
- unordered-containers
|
||||
- vector
|
||||
- wai
|
||||
- warp
|
||||
- warp-tls
|
||||
|
||||
default-extensions:
|
||||
- ApplicativeDo
|
||||
- BangPatterns
|
||||
- BlockArguments
|
||||
- DeriveAnyClass
|
||||
- DeriveDataTypeable
|
||||
- DeriveFoldable
|
||||
- DeriveGeneric
|
||||
- DeriveTraversable
|
||||
- DerivingStrategies
|
||||
- EmptyDataDecls
|
||||
- FlexibleContexts
|
||||
- FlexibleInstances
|
||||
- FunctionalDependencies
|
||||
- GADTs
|
||||
- GeneralizedNewtypeDeriving
|
||||
- LambdaCase
|
||||
- MultiParamTypeClasses
|
||||
- NamedFieldPuns
|
||||
- NoImplicitPrelude
|
||||
- NumericUnderscores
|
||||
- OverloadedStrings
|
||||
- PartialTypeSignatures
|
||||
- QuasiQuotes
|
||||
- Rank2Types
|
||||
- RankNTypes
|
||||
- RecordWildCards
|
||||
- StandaloneDeriving
|
||||
- ScopedTypeVariables
|
||||
- TemplateHaskell
|
||||
- TupleSections
|
||||
- TypeApplications
|
||||
- TypeFamilies
|
||||
- UnicodeSyntax
|
||||
- ViewPatterns
|
2
pkg/hs-vere/.gitignore
vendored
Normal file
2
pkg/hs-vere/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.stack-work
|
||||
*.cabal
|
@ -2,17 +2,11 @@ name: vere
|
||||
version: 0.1.0
|
||||
license: AGPL-3.0-only
|
||||
|
||||
library:
|
||||
source-dirs: lib
|
||||
ghc-options:
|
||||
- -fwarn-incomplete-patterns
|
||||
- -O2
|
||||
|
||||
executables:
|
||||
test:
|
||||
main: Main.hs
|
||||
source-dirs: app/test
|
||||
dependencies: ["vere"]
|
||||
dependencies: ["urbit"]
|
||||
ghc-options:
|
||||
- -threaded
|
||||
- -rtsopts
|
||||
@ -23,7 +17,7 @@ executables:
|
||||
uterm:
|
||||
main: Main.hs
|
||||
source-dirs: app/uterm
|
||||
dependencies: ["vere"]
|
||||
dependencies: ["urbit"]
|
||||
ghc-options:
|
||||
- -threaded
|
||||
- -rtsopts
|
||||
@ -34,7 +28,7 @@ executables:
|
||||
vere:
|
||||
main: Main.hs
|
||||
source-dirs: app/vere
|
||||
dependencies: ["vere"]
|
||||
dependencies: ["urbit"]
|
||||
ghc-options:
|
||||
- -threaded
|
||||
- -rtsopts
|
||||
@ -44,6 +38,7 @@ executables:
|
||||
|
||||
dependencies:
|
||||
- async
|
||||
- urbit
|
||||
- base
|
||||
- bytestring
|
||||
- case-insensitive
|
16
stack.yaml
16
stack.yaml
@ -1,17 +1,15 @@
|
||||
resolver: lts-13.10
|
||||
|
||||
packages:
|
||||
- pkg/hair
|
||||
- pkg/hoon
|
||||
|
||||
ghc-options:
|
||||
vere: "-fobject-code"
|
||||
- pkg/hs-urbit
|
||||
- pkg/hs-vere
|
||||
- pkg/hs-hoon
|
||||
|
||||
extra-deps:
|
||||
- para-1.1@sha256:a90eebb063ad70271e6e2a7f00a93e8e8f8b77273f100f39852fbf8301926f81
|
||||
- flat-0.3.4@sha256:002a0e0ae656ea8cc02a772d0bcb6ea7dbd7f2e79070959cc748ad1e7138eb38
|
||||
|
||||
build:
|
||||
library-profiling: true
|
||||
executable-profiling: true
|
||||
executable-stripping: false
|
||||
# build:
|
||||
# library-profiling: true
|
||||
# executable-profiling: true
|
||||
# executable-stripping: false
|
||||
|
Loading…
Reference in New Issue
Block a user