Ossasepia

September 27, 2018

Tester for UDP Communications

Filed under: Coding, UDP — Diana Coman @ 8:33 p.m.

This code builds on Stanislav Datskovskiy's minimal UDP lib to provide a convenient way of gathering data to evaluate UDP communications between any desired two nodes. The initial specification was to provide a reliable way to "send a soup of all packets lengths from 1 to 65536 bytes each hour back and forth" but this was refined further down the line1 to reduce the maximum length of the payload to 2048 and to include a Mersenne-Twister (MT) pseudorandom number generator (prng) for scrambling the various message sizes. To accomplish that, there are two main parts that I'm adding to the original UDP library:

  1. The MT lib that is simply an Ada implementation of the MT prng algorithm.
  2. The UDP_Tester package that uses a slightly adapted UDP lib and the MT lib above to provide a UDP sender and a corresponding UDP receiver that implement the testing specification and log the relevant data.

MT lib
The MT lib is a standalone Ada library implementing the well-known Mersenne Twister algorithm for pseudorandom number generation2. I am not aware of any other Ada implementation of MT and since I really don't want to add C code to my plate unless I absolutely have to, I simply ported to Ada the reference C implementation provided by the original authors of MT. As such, there isn't much to discuss about the implementation itself - I'll point however the changes I made with respect to the original implementation, namely:

  • In my Ada version of MT, there is no default seeding of the MT generator. The C version allows the caller to ask the generator for numbers without having seeded it - in this case, the C implementation seeds itself with a magic default value that is hardcoded at the checking spot and then just proceeds as if nothing was wrong. I find this approach abhorent because it effectively hides an error (calling the generator without seeding it first) rather than complaining about it and forcing its correction. Consequently, my MT lib will simply abort if the generator is asked for numbers without having been seeded first.3
  • Because Ada is most pointedly not a sort of C, there was no need for the various types of hacks added to the C version to ensure that it still worked correctly on 64-bit machines and not only on the 32-bit machines for which the code was initially written. In Ada it's enough to specify one's types correctly to be exactly and guaranteed 32-bits and then proceed to work with them as such, regardless of whether the processor running the code has 32-bit or 64-bit or x-bit registers.
  • My MT lib provides just one type of pseudorandom numbers, namely unsigned integers on 32 bits. The original C implementation had several wrappers around this main function to map the 32 bits pseudorandom numbers to the interval (0,1) for instance and similar. All the mappings were trivial and they can be easily done by any caller that requires them - precisely in the way they require them. At this stage at least I don't quite see the need for those as part of MT lib and so I left them out - there is only the core offering of 32 pseudorandom bits as it were and the caller can then use or interpret them as they see fit.
  • To check that my implementation results in precisely the same sequence of numbers as the original C MT, I added an automated test (still in Ada) that uses the reference seed and checks the output of MT lib (number by number) against the reference output from the original C MT, reporting any mismatches.

The code of MT lib is self-contained with declarations in mt.ads:

 -- Ada implementation of the Mersenne Twister Pseudo-Random number generator
 -- S.MG, 2018

with Interfaces; use Interfaces;

package MT is
  -- Interfaces.Unsigned_32 in GNAT is mod 2**32 and has bitwise shifts defined
  subtype U32 is Interfaces.Unsigned_32;

  -- period parameters
  N          : constant := 624;
  M          : constant := 397;
  MATRIX_MASK: constant U32 := 16#9908_b0df#;
  UPPER_MASK : constant U32 := 16#8000_0000#;
  LOWER_MASK : constant U32 := 16#7fff_ffff#;

  -- array type for storing the state vector of the generator
  type State_Type is Array( 0 .. N-1 ) of U32;

  -- array type for initialization by array - change key len here if needed
  KEY_LEN    : constant := 4;
  type Init_Array_Type is Array( 0 .. KEY_LEN - 1 ) of U32;

  -- exception raised by a call to generator before initializing it
  No_Init_Exception : exception;

  -- initialize the generator with a seed (number)
  procedure Init_Genrand(Seed : in U32);

  -- initialize the generator with array of 8-octets elements
  procedure Init_Genrand(Seed : in Init_Array_Type);

  -- generate the next pseudo-random 32 bits number in the sequence
  function Gen_U32 return U32;

  -- for testing
  function Get_State return State_Type;

  -- internals of the generator, NOT for direct access
private
  -- actual state of the generator
  State      : State_Type;

  -- flag for generator routine
  Mti_Flag : U32 := N + 1;  -- default value -> state(N) is not initialised

end MT;

And implementation in mt.adb:

 -- Ada implementation of the Mersenne Twister Pseudo-Random number generator
 -- S.MG, 2018

package body MT is

  procedure Init_Genrand(Seed : in U32) is
  begin
    State(0) := Seed;
    for I in State'First + 1 .. State'Last loop
      State(I) := U32(1812433253) *
                  ( State(I - 1) xor
                    ( Shift_Right(State(I - 1), 30) )
                  ) + U32(I) ;
    end loop;
    Mti_Flag := N;
  end Init_Genrand;

  procedure Init_Genrand(Seed : in Init_Array_Type) is
    Default_Seed: constant U32 := U32(19650218); -- magic value!
    I, J, K : Integer;
  begin
    Init_Genrand(Default_Seed);
    I := 1;
    J := 0;
    if N > Seed'Length then
      K := N;
    else
      K := Seed'Length;
    end if;

    while K > 0 loop
      State(I) := (State(I) xor
                  ( (State(I-1) xor
                     Shift_Right(State(I-1), 30)
                    ) * U32(1664525)
                  )) + Seed(J) + U32(J);
      I := I + 1;
      J := J + 1;
      if I >= N then
        State(0) := State(N-1);
        I := 1;
      end if;
      if J >= Seed'Length then
        J := 0;
      end if;
      K := K - 1;
    end loop;

    K := N -1;
    while K > 0 loop
      State(I) := (State(I) xor
                  ( (State(I-1) xor
                     Shift_Right(State(I-1), 30)
                    ) * U32(1566083941)
                  )) - U32(I);
      I := I + 1;
      if I >= N then
        State(0) := State(N-1);
        I := 1;
      end if;
      K := K - 1;
    end loop;
    State(0) := 16#8000_0000#; -- MSB is 1 to ensure non-zero initial state
  end Init_Genrand;

  function Gen_U32 return U32 is
    Y     : U32;
    MASK1 : constant U32 := U32(1);
    Mag01 : Array ( 0 .. 1 ) of U32;
  begin
    -- Mag01[x] is x * Matrix_A of the algorithm for x 0 or 1
    Mag01(0) := U32(0);
    Mag01(1) := MATRIX_MASK;

    -- if no numbers available, generate another set of N words
    if Mti_Flag >= N then

      -- check it's not a non-initialised generator
      if Mti_Flag = (N + 1) then
         -- Generator was NOT initialised!
         -- Original C code initialises with default seed 5489
         -- This code will simply raise exception and abort
         raise No_Init_Exception;
      end if;

      for K in 0 .. N - M - 1 loop
        Y := ( State(K)   and UPPER_MASK ) or
             ( State(K+1) and LOWER_MASK );
        State(K) := State(K+M) xor
                      Shift_Right(Y, 1) xor
                        Mag01(Integer(Y and MASK1));
      end loop;
      for K in N-M .. N - 2 loop
        Y := ( State(K)   and UPPER_MASK  ) or
             ( State(K+1) and LOWER_MASK);
        State(K) := State(K + M - N) xor
                      Shift_Right(Y, 1) xor
                        Mag01(Integer(Y and MASK1));
      end loop;
      Y := (State(N-1) and UPPER_MASK ) or
             (State(0) and LOWER_MASK );
      State(N - 1) := State(M-1) xor
                        Shift_Right(Y, 1) xor
                          Mag01(Integer(Y and MASK1));
      Mti_Flag := 0;
    end if;

    -- retrieve next available number
    Y        := State(Integer(Mti_Flag));
    Mti_Flag := Mti_Flag + 1;

    -- tempering
    Y := Y xor Shift_Right(Y, 11);
    Y := Y xor (Shift_Left(Y, 7) and 16#9d2c_5680#);
    Y := Y xor (Shift_Left(Y, 15) and 16#efc6_0000#);
    Y := Y xor Shift_Right(Y, 18);

    -- return tempered number
    return Y;
  end Gen_U32;

  function Get_State return State_Type is
  begin
    return State;
  end Get_State;

end MT;

The test for the above MT lib is in its own testmt/test_mt.adb, including the reference output (that really is the largest part of the whole file):

  --S.MG, 2018

with Ada.Text_IO; use Ada.Text_IO;
with Interfaces; use Interfaces;
with MT;

procedure Tests_MT is
  Seeds : MT.Init_Array_Type;
  X     : MT.U32;
  No    : constant Integer := 1000;
  Result: Array(0..No-1) of MT.U32 := (
    1067595299,  955945823,  477289528, 4107218783, 4228976476,
    3344332714, 3355579695,  227628506,  810200273, 2591290167,
    2560260675, 3242736208,  646746669, 1479517882, 4245472273,
    1143372638, 3863670494, 3221021970, 1773610557, 1138697238,
    1421897700, 1269916527, 2859934041, 1764463362, 3874892047,
    3965319921,   72549643, 2383988930, 2600218693, 3237492380,
    2792901476,  725331109,  605841842,  271258942,  715137098,
    3297999536, 1322965544, 4229579109, 1395091102, 3735697720,
    2101727825, 3730287744, 2950434330, 1661921839, 2895579582,
    2370511479, 1004092106, 2247096681, 2111242379, 3237345263,
    4082424759,  219785033, 2454039889, 3709582971,  835606218,
    2411949883, 2735205030,  756421180, 2175209704, 1873865952,
    2762534237, 4161807854, 3351099340,  181129879, 3269891896,
     776029799, 2218161979, 3001745796, 1866825872, 2133627728,
      34862734, 1191934573, 3102311354, 2916517763, 1012402762,
    2184831317, 4257399449, 2899497138, 3818095062, 3030756734,
    1282161629,  420003642, 2326421477, 2741455717, 1278020671,
    3744179621,  271777016, 2626330018, 2560563991, 3055977700,
    4233527566, 1228397661, 3595579322, 1077915006, 2395931898,
    1851927286, 3013683506, 1999971931, 3006888962, 1049781534,
    1488758959, 3491776230,  104418065, 2448267297, 3075614115,
    3872332600,  891912190, 3936547759, 2269180963, 2633455084,
    1047636807, 2604612377, 2709305729, 1952216715,  207593580,
    2849898034,  670771757, 2210471108,  467711165,  263046873,
    3569667915, 1042291111, 3863517079, 1464270005, 2758321352,
    3790799816, 2301278724, 3106281430,    7974801, 2792461636,
     555991332,  621766759, 1322453093,  853629228,  686962251,
    1455120532,  957753161, 1802033300, 1021534190, 3486047311,
    1902128914, 3701138056, 4176424663, 1795608698,  560858864,
    3737752754, 3141170998, 1553553385, 3367807274,  711546358,
    2475125503,  262969859,  251416325, 2980076994, 1806565895,
     969527843, 3529327173, 2736343040, 2987196734, 1649016367,
    2206175811, 3048174801, 3662503553, 3138851612, 2660143804,
    1663017612, 1816683231,  411916003, 3887461314, 2347044079,
    1015311755, 1203592432, 2170947766, 2569420716,  813872093,
    1105387678, 1431142475,  220570551, 4243632715, 4179591855,
    2607469131, 3090613241,  282341803, 1734241730, 1391822177,
    1001254810,  827927915, 1886687171, 3935097347, 2631788714,
    3905163266,  110554195, 2447955646, 3717202975, 3304793075,
    3739614479, 3059127468,  953919171, 2590123714, 1132511021,
    3795593679, 2788030429,  982155079, 3472349556,  859942552,
    2681007391, 2299624053,  647443547,  233600422,  608168955,
    3689327453, 1849778220, 1608438222, 3968158357, 2692977776,
    2851872572,  246750393, 3582818628, 3329652309, 4036366910,
    1012970930,  950780808, 3959768744, 2538550045,  191422718,
    2658142375, 3276369011, 2927737484, 1234200027, 1920815603,
    3536074689, 1535612501, 2184142071, 3276955054,  428488088,
    2378411984, 4059769550, 3913744741, 2732139246,   64369859,
    3755670074,  842839565, 2819894466, 2414718973, 1010060670,
    1839715346, 2410311136,  152774329, 3485009480, 4102101512,
    2852724304,  879944024, 1785007662, 2748284463, 1354768064,
    3267784736, 2269127717, 3001240761, 3179796763,  895723219,
     865924942, 4291570937,   89355264, 1471026971, 4114180745,
    3201939751, 2867476999, 2460866060, 3603874571, 2238880432,
    3308416168, 2072246611, 2755653839, 3773737248, 1709066580,
    4282731467, 2746170170, 2832568330,  433439009, 3175778732,
      26248366, 2551382801,  183214346, 3893339516, 1928168445,
    1337157619, 3429096554, 3275170900, 1782047316, 4264403756,
    1876594403, 4289659572, 3223834894, 1728705513, 4068244734,
    2867840287, 1147798696,  302879820, 1730407747, 1923824407,
    1180597908, 1569786639,  198796327,  560793173, 2107345620,
    2705990316, 3448772106, 3678374155,  758635715,  884524671,
     486356516, 1774865603, 3881226226, 2635213607, 1181121587,
    1508809820, 3178988241, 1594193633, 1235154121,  326117244,
    2304031425,  937054774, 2687415945, 3192389340, 2003740439,
    1823766188, 2759543402,   10067710, 1533252662, 4132494984,
      82378136,  420615890, 3467563163,  541562091, 3535949864,
    2277319197, 3330822853, 3215654174, 4113831979, 4204996991,
    2162248333, 3255093522, 2219088909, 2978279037,  255818579,
    2859348628, 3097280311, 2569721123, 1861951120, 2907080079,
    2719467166,  998319094, 2521935127, 2404125338,  259456032,
    2086860995, 1839848496, 1893547357, 2527997525, 1489393124,
    2860855349,   76448234, 2264934035,  744914583, 2586791259,
    1385380501,   66529922, 1819103258, 1899300332, 2098173828,
    1793831094,  276463159,  360132945, 4178212058,  595015228,
     177071838, 2800080290, 1573557746, 1548998935,  378454223,
    1460534296, 1116274283, 3112385063, 3709761796,  827999348,
    3580042847, 1913901014,  614021289, 4278528023, 1905177404,
      45407939, 3298183234, 1184848810, 3644926330, 3923635459,
    1627046213, 3677876759,  969772772, 1160524753, 1522441192,
     452369933, 1527502551,  832490847, 1003299676, 1071381111,
    2891255476,  973747308, 4086897108, 1847554542, 3895651598,
    2227820339, 1621250941, 2881344691, 3583565821, 3510404498,
     849362119,  862871471,  797858058, 2867774932, 2821282612,
    3272403146, 3997979905,  209178708, 1805135652,    6783381,
    2823361423,  792580494, 4263749770,  776439581, 3798193823,
    2853444094, 2729507474, 1071873341, 1329010206, 1289336450,
    3327680758, 2011491779,   80157208,  922428856, 1158943220,
    1667230961, 2461022820, 2608845159,  387516115, 3345351910,
    1495629111, 4098154157, 3156649613, 3525698599, 4134908037,
     446713264, 2137537399, 3617403512,  813966752, 1157943946,
    3734692965, 1680301658, 3180398473, 3509854711, 2228114612,
    1008102291,  486805123,  863791847, 3189125290, 1050308116,
    3777341526, 4291726501,  844061465, 1347461791, 2826481581,
     745465012, 2055805750, 4260209475, 2386693097, 2980646741,
     447229436, 2077782664, 1232942813, 4023002732, 1399011509,
    3140569849, 2579909222, 3794857471,  900758066, 2887199683,
    1720257997, 3367494931, 2668921229,  955539029, 3818726432,
    1105704962, 3889207255, 2277369307, 2746484505, 1761846513,
    2413916784, 2685127085, 4240257943, 1166726899, 4215215715,
    3082092067, 3960461946, 1663304043, 2087473241, 4162589986,
    2507310778, 1579665506,  767234210,  970676017,  492207530,
    1441679602, 1314785090, 3262202570, 3417091742, 1561989210,
    3011406780, 1146609202, 3262321040, 1374872171, 1634688712,
    1280458888, 2230023982,  419323804, 3262899800,   39783310,
    1641619040, 1700368658, 2207946628, 2571300939, 2424079766,
     780290914, 2715195096, 3390957695,  163151474, 2309534542,
    1860018424,  555755123,  280320104, 1604831083, 2713022383,
    1728987441, 3639955502,  623065489, 3828630947, 4275479050,
    3516347383, 2343951195, 2430677756,  635534992, 3868699749,
     808442435, 3070644069, 4282166003, 2093181383, 2023555632,
    1568662086, 3422372620, 4134522350, 3016979543, 3259320234,
    2888030729, 3185253876, 4258779643, 1267304371, 1022517473,
     815943045,  929020012, 2995251018, 3371283296, 3608029049,
    2018485115,  122123397, 2810669150, 1411365618, 1238391329,
    1186786476, 3155969091, 2242941310, 1765554882,  279121160,
    4279838515, 1641578514, 3796324015,   13351065,  103516986,
    1609694427,  551411743, 2493771609, 1316337047, 3932650856,
    4189700203,  463397996, 2937735066, 1855616529, 2626847990,
      55091862, 3823351211,  753448970, 4045045500, 1274127772,
    1124182256,   92039808, 2126345552,  425973257,  386287896,
    2589870191, 1987762798, 4084826973, 2172456685, 3366583455,
    3602966653, 2378803535, 2901764433, 3716929006, 3710159000,
    2653449155, 3469742630, 3096444476, 3932564653, 2595257433,
     318974657, 3146202484,  853571438,  144400272, 3768408841,
     782634401, 2161109003,  570039522, 1886241521,   14249488,
    2230804228, 1604941699, 3928713335, 3921942509, 2155806892,
     134366254,  430507376, 1924011722,  276713377,  196481886,
    3614810992, 1610021185, 1785757066,  851346168, 3761148643,
    2918835642, 3364422385, 3012284466, 3735958851, 2643153892,
    3778608231, 1164289832,  205853021, 2876112231, 3503398282,
    3078397001, 3472037921, 1748894853, 2740861475,  316056182,
    1660426908,  168885906,  956005527, 3984354789,  566521563,
    1001109523, 1216710575, 2952284757, 3834433081, 3842608301,
    2467352408, 3974441264, 3256601745, 1409353924, 1329904859,
    2307560293, 3125217879, 3622920184, 3832785684, 3882365951,
    2308537115, 2659155028, 1450441945, 3532257603, 3186324194,
    1225603425, 1124246549,  175808705, 3009142319, 2796710159,
    3651990107,  160762750, 1902254979, 1698648476, 1134980669,
     497144426, 3302689335, 4057485630, 3603530763, 4087252587,
     427812652,  286876201,  823134128, 1627554964, 3745564327,
    2589226092, 4202024494,   62878473, 3275585894, 3987124064,
    2791777159, 1916869511, 2585861905, 1375038919, 1403421920,
      60249114, 3811870450, 3021498009, 2612993202,  528933105,
    2757361321, 3341402964, 2621861700,  273128190, 4015252178,
    3094781002, 1621621288, 2337611177, 1796718448, 1258965619,
    4241913140, 2138560392, 3022190223, 4174180924,  450094611,
    3274724580,  617150026, 2704660665, 1469700689, 1341616587,
     356715071, 1188789960, 2278869135, 1766569160, 2795896635,
      57824704, 2893496380, 1235723989, 1630694347, 3927960522,
     428891364, 1814070806, 2287999787, 4125941184, 3968103889,
    3548724050, 1025597707, 1404281500, 2002212197,   92429143,
    2313943944, 2403086080, 3006180634, 3561981764, 1671860914,
    1768520622, 1803542985,  844848113, 3006139921, 1410888995,
    1157749833, 2125704913, 1789979528, 1799263423,  741157179,
    2405862309,  767040434, 2655241390, 3663420179, 2172009096,
    2511931187, 1680542666,  231857466, 1154981000,  157168255,
    1454112128, 3505872099, 1929775046, 2309422350, 2143329496,
    2960716902,  407610648, 2938108129, 2581749599,  538837155,
    2342628867,  430543915,  740188568, 1937713272, 3315215132,
    2085587024, 4030765687,  766054429, 3517641839,  689721775,
    1294158986, 1753287754, 4202601348, 1974852792,   33459103,
    3568087535, 3144677435, 1686130825, 4134943013, 3005738435,
    3599293386,  426570142,  754104406, 3660892564, 1964545167,
     829466833,  821587464, 1746693036, 1006492428, 1595312919,
    1256599985, 1024482560, 1897312280, 2902903201,  691790057,
    1037515867, 3176831208, 1968401055, 2173506824, 1089055278,
    1748401123, 2941380082,  968412354, 1818753861, 2973200866,
    3875951774, 1119354008, 3988604139, 1647155589, 2232450826,
    3486058011, 3655784043, 3759258462,  847163678, 1082052057,
     989516446, 2871541755, 3196311070, 3929963078,  658187585,
    3664944641, 2175149170, 2203709147, 2756014689, 2456473919,
    3890267390, 1293787864, 2830347984, 3059280931, 4158802520,
    1561677400, 2586570938,  783570352, 1355506163,   31495586,
    3789437343, 3340549429, 2092501630,  896419368,  671715824,
    3530450081, 3603554138, 1055991716, 3442308219, 1499434728,
    3130288473, 3639507000,   17769680, 2259741420,  487032199,
    4227143402, 3693771256, 1880482820, 3924810796,  381462353,
    4017855991, 2452034943, 2736680833, 2209866385, 2128986379,
     437874044,  595759426,  641721026, 1636065708, 3899136933,
     629879088, 3591174506,  351984326, 2638783544, 2348444281,
    2341604660, 2123933692,  143443325, 1525942256,  364660499,
     599149312,  939093251, 1523003209,  106601097,  376589484,
    1346282236, 1297387043,  764598052, 3741218111,  933457002,
    1886424424, 3219631016,  525405256, 3014235619,  323149677,
    2038881721, 4100129043, 2851715101, 2984028078, 1888574695,
    2014194741, 3515193880, 4180573530, 3461824363, 2641995497,
    3179230245, 2902294983, 2217320456, 4040852155, 1784656905,
    3311906931,   87498458, 2752971818, 2635474297, 2831215366,
    3682231106, 2920043893, 3772929704, 2816374944,  309949752,
    2383758854,  154870719,  385111597, 1191604312, 1840700563,
     872191186, 2925548701, 1310412747, 2102066999, 1504727249,
    3574298750, 1191230036, 3330575266, 3180292097, 3539347721,
     681369118, 3305125752, 3648233597,  950049240, 4173257693,
    1760124957,  512151405,  681175196,  580563018, 1169662867,
    4015033554, 2687781101,  699691603, 2673494188, 1137221356,
     123599888,  472658308, 1053598179, 1012713758, 3481064843,
    3759461013, 3981457956, 3830587662, 1877191791, 3650996736,
     988064871, 3515461600, 4089077232, 2225147448, 1249609188,
    2643151863, 3896204135, 2416995901, 1397735321, 3460025646);

begin
  Seeds(0) := MT.U32(16#123#);
  Seeds(1) := MT.U32(16#234#);
  Seeds(2) := MT.U32(16#345#);
  Seeds(3) := MT.U32(16#456#);
  MT.Init_Genrand(Seeds);

  Put_Line("Generating numbers...");
  for I in 0 .. No-1 loop
    X := MT.Gen_U32;
    Put(".");
    if X /= Result(I) then
      Put_Line("");
      Put_Line("ERROR at position " & Integer'Image(I) &
               "; expected " & MT.U32'Image(Result(I)) &
               " but result is " & MT.U32'Image(X));
    end if;
  end loop;
  Put_Line("");
end Tests_MT;

UDP_Tester
The UDP_Tester has two main components: the sender and the receiver. For convenience, there are simple wrappers for those components - udp_sender.adb and udp_receiver.adb respectively - so that a build of UDP_Tester will directly provide two executables - sender and receiver. The IP and port numbers are knobs that can be easily changed from those wrappers directly since they are passed as parameters to the UDP_tester methods themselves.
udp_sender.adb:

  -- S.MG, 2018

with UDP_Tester;

procedure UDP_Sender is
  -- Sender and Receiver addresses + ports
  Receiver_IP   : constant String   := "161.0.121.202"; -- smg.test machine
  Receiver_Port : constant          := 7000;

  Sender_Port   : constant          := 5000;

begin

  UDP_Tester.Sender( Receiver_IP, Receiver_Port, Sender_Port) ;

end UDP_Sender;

udp_receiver.adb:

  -- S.MG, 2018

with UDP_Tester;

procedure UDP_Receiver is
  -- Port to listen on
  Receiver_Port : constant          := 7000;
begin

  UDP_Tester.Receiver( Receiver_Port );

end UDP_Receiver;

The UDP_Tester.Receiver method simply runs an endless loop in which it listens for UDP packages on a given port number and logs basic information about each pacakge it receives. The UDP_Tester.Sender method assembles and sends in a pseudorandom order all packages with length between 6 (size of own header) and maximum length. Note that the sender will send each size of package *only once* and it will simply finish once it sent one package of each size. Consequently, for data collection purposes, the sender will have to be started repeatedly from outside - most conveniently through a cron task4. Because the workings of both sender and receiver are quite basic, I won't cover them here in more detail - the code and comments should make it clear enough and if that's not the case, you can always ask your questions here in the comments. However, it's worth noting instead a few important points about the tester as a whole and the changes it imposes on the UDP lib:

  • To enable sending of packets with various sizes, the UDP lib had to be made generic. In Ada, this means that a calling packet can then instantiate the UDP type with its desired parameters (in this case the size of the UDP package). Specifically, from the UDP_Tester.Sender code, this reads:
          declare
            K : constant Positive := Packet_Size;
            -- sender will have *current* size of UDP packet
            package UDP_Sdr is new UDP( Payload_Size => K );
    

    Essentially the sender runs a loop and at each iteration it selects one of the remaining packet sizes, it instantiates UDP_Sdr as a parametrized UDP package and only then proceeds to use it to send the actual data.

    Note that this change is *not* required in production - it's simply needed for testing purposes. It's for this reason that it's part of the .vpatch for UDP_Tester rather than a .vpatch in itself on the UDP lib directly.

  • The sender will wait 1 second between any 2 packages it sends. This is mainly because a first version without this delay proved to result in significant packet loss that was clearly due to the burst mode (i.e. more than 2000 packages sent in 1 second) rather than anything else. Since the point of the test was to gather some data on UDP communication in relaxed rather than stress conditions, the delay of 1 second was introduced. However, should you wish to stress-test for any reason, you can easily remove this delay - simply comment out the "delay 1.0" line in the sender and that's all.
  • The UDP_Tester currently logs some information on both sides. Both sender and receiver will first check for a fixed-name file and if it doesn't exist they will create it, writing the header to it as well. After that, all new data will simply be appended to the file. The sender logs the size, local time, destination IP, destination port and seed used for the MT prng - this seed is the local time (unix style) when the sender is started. The receiver logs the size (both as received and as claimed in the packet's own header), the time (local time when sent and local time when received), the source IP, the source port and the number of octets that are different from expected. In addition, the receiver will further log in a separate file the actual octets that are found to contain errors, if any (together with information to easily link them back to the exact package they were part of).
  • There is no attempt to match directlty the times at the sender and at the receiver - any difference between the two local times should be noted when the tests are run and then provided together with the data so that the analysis can be done in a meaningful way. Specifically, the local times used by sender and receiver are simply retrieved with Ada.Calendar.Clock and then converted to unix style by subtracting from them the "epoch" (0 on 1/1/1970).
  • The use of generic packages and of Ada.Calendar in UDP_Tester imposed a relaxation of restrictions upstream i.e. in the UDP and MT libs. Since the relaxation of those restrictions is again (just like the generics change) required for testing *only*, they are simply commented out as part of the changes included in the UDP_Tester .vpatch.

To obtain a working UDP_Tester, simply download the relevant set of .vpatch and .sig files and press with your favourite V5. The patches are available as usual on my Reference Shelf and linked from here as well, for your convenience:

At the moment I am running the above tester in both directions between a node in the UK and one in Uruguay so hopefully I'll soon have some data to look at!


  1. Follow the discussion in the logs as there is no better way to get the details than to actually read through the log. 

  2. M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-dimensionally equidistributed uniform pseudorandom number generator", ACM Transactions on Modelling and Computer Simulation Vol. 8, No. 1, January, pp.3-30, 1998. 

  3. If one really wants a default value, this could be perhaps added as a constant in the package and then used as such by the caller but I must say that I don't quite see the point of this. 

  4. It is of course possible to change the code so that the sender also runs in a loop and simply wakes up at given intervals and resends packages but I don't quite see any real benefit to doing it this way - on the contrary, I see benefit to *not* doing it this way, since cron tasks are quite perfect for this and even more robust (no idle time and guaranteed recovery even in more extreme cases such as computer reset). 

  5. NB: Using Keccak hashes, as per current republican standard for V-trees. 

September 23, 2018

Dressing Directions of Sorts

Filed under: Lyf, Young, old and oldest — Diana Coman @ 7:40 p.m.

Dressing up and dressing down used to be all nice and fine when such directions were at least clear and firm. But what does one do when up or down are much the same since all the world around is - apparently - flatly equal at all its points anyway? Well, as per adapted nursery rhyme, when they were up they dressed up and they were down they dressed down and when they were neither up nor down, they were... salad dressing.

Salads and directions aside, sartorial choices at 6 years of age can be interesting to watch - perhaps even more so, at a later time when they have been forgotten. And they can certainly swing from velvet and hat and shiny bow tie one day to apron and chef hat the next1:

victor_pizzaiolo
velvet_and_hat2


  1. Since it took me about 20 years to even start taking pictures, I can hope I'll also start using a decent camera sometime within the next 40 years or so. 

September 14, 2018

SMG.Comms Implementation - Chapter 1

Filed under: Coding, SMG_Comms — Diana Coman @ 11:02 a.m.

~ This is a work in progress towards an Ada implementation of the communication protocol discussed on Trilema four months ago. ~

As far as I know, there isn't any more recent discussion of the above specification, nor any other attempt at all at any sort of implementation. Consequently, this is the first ever attempt - a prototype at this stage rather than a reference implementation. Moreover, it's also a sort of double first, since it clearly requires a deeper knowledge of Ada than I ever needed before. My approach to this pile of unknown here is to simply start working on it and expose the path travelled from this very first attempt to the final product, mistakes and detours and pitfalls to come included. You are welcome to follow along, to help if you can, to question if you don't understand, to extract perhaps in doing so some benefit for yourself.

The first decision I had to make before I could even really attempt any sort of prototype implementation at all concerned the library to use for the actual network communication. Since GNAT is the de-facto republican Ada compiler1, the logical decision is to simply use GNAT's own library, GNAT.Sockets and avoid otherwise as much as possible introducing additional, external dependencies - I really can't see any reason to add even more code even indirectly. So then GNAT.Sockets it is and hooray for that - except that there doesn't seem to be much documentation about it other than the comments in g-socket.ads and g-socket.adb! Still, the .ads file has a rather detailed introduction of the package with some commented examples in there so definitely worth reading as a starting point especially since... there isn't any other starting point really.

The g-socket files reveal essentially that any data to be sent or received through GNAT.Sockets will have to be stored at one point or another in an entity of Ada.Streams.Stream_Element_Array type. The examples in the file (and most everything else I could find on the topic) really focus almost exclusively2 on TCP connections - I suspect one "should prefer" TCP over UDP simply like that and we are even past the point of discussing therefore UDP in any scant docs or something. Nevertheless, I don't prefer it: Eulora's protocol is rather specifically designed to be stateless and to keep communications as simple and clear as possible - for as long as UDP is enough for the job, I'd rather use it!

Rummaging a bit in the g-sockets files reveals happily that UDP with GNAT.Sockets is in fact quite straightforward: one simply needs to specify "Socket_Datagram" as mode for the socket when calling Create_Socket and then use directly the Send_Socket( socket, data, last, to_address) and Receive_Socket(socket, data, last, from_address) methods. As one would expect, there is no reliable connection established, no "stream" of send and receive but only sockets that allow independent "send" and "receive" calls - each of those could in principle use a different address even. A quick example - keep reading for a a full, working example - of a server and client working with a UDP socket looks like this:

 -- on server:
     -- create UDP socket
    Create_Socket( Sock, Family_Inet, Socket_Datagram );

    -- set options on UDP socket
    Set_Socket_Option( Sock, Socket_Level, (Reuse_Address, True));

    -- set address and bind
    Address.Addr := Any_Inet_Addr;
    Address.Port := Port_No; -- the port number that server is listening on
    Bind_Socket( Sock, Address );
    Receive_Socket( Sock, Data, Last, From );

 -- on client:
    Address.Port := Port_No; -- server's port number
    Address.Addr := Inet_Addr("127.0.0.1"); -- this should be server's address here!
    Create_Socket(Sock, Family_Inet, Socket_Datagram);

    Send_Socket(Sock, Data, Last, Address);

With the very basics of the sockets part at least in place, the next part to decide on is how to send and receive over those sockets the actual data types defined by the protocol. After reading quite a bit on the Systems Programming (an annex of the Ada standard and therefore compiler-dependent) part of Ada (that is relevant for data representation) and on streams and on representation clauses and pragmas supported by GNAT and records and discriminants for records and everything else from the Ada reference book3 that I thought could help with this, I got to the conclusion that I'll keep it simple and clear especially for now, while I'm just starting to figure it all out! So I'll simply use GNAT's fixed width types defined in the Interfaces package and I'll copy otherwise the raw octets from and to those types using Ada.Unchecked_Conversion that works as far as I understand it precisely as a raw copy from memory. Once the data is simply obtained as a vector of raw octets, I can implement two simple functions to copy them into the Stream_Element_Array structure that can be sent directly through the UDP socket. Moreover, at this stage - and at this stage *only* - I'll worry about potentially different endianness of the local machine and the network: if local environment is little endian, the methods converting to and from network format will simply read the octets in reverse order. The relevant basic types and conversion methods are defined in the smg_comms_types.ads file:

 -- S.MG, 2018
 -- prototype implementation of S.MG communication protocol

with Ada.Streams; use Ada.Streams;
with Interfaces; use Interfaces; -- Integer_n and Unsigned_n
with Ada.Unchecked_Conversion; -- converting int/uint to array of octets

package SMG_comms_types is
  -- basic types with guaranteed lengths
  type Octet_Array is array(Natural range <>) of Unsigned_8;

  subtype Octets_1 is Octet_Array( 1 .. 1 );
  subtype Octets_2 is Octet_Array( 1 .. 2 );
  subtype Octets_4 is Octet_Array( 1 .. 4 );
  subtype Octets_8 is Octet_Array( 1 .. 8 );

  subtype Message is Octet_Array( 1 .. 512 );
  subtype RSAMessage is Octet_Array( 1 .. 245 );

  -- blind, unchecked casts ( memcpy style )
  function Cast is new Ada.Unchecked_Conversion( Integer_8, Octets_1 );
  function Cast is new Ada.Unchecked_Conversion( Octets_1, Integer_8 );
  function Cast is new Ada.Unchecked_Conversion( Integer_16, Octets_2 );
  function Cast is new Ada.Unchecked_Conversion( Octets_2, Integer_16 );

  function Cast is new Ada.Unchecked_Conversion( Integer_32, Octets_4 );
  function Cast is new Ada.Unchecked_Conversion( Octets_4, Integer_32 );

  function Cast is new Ada.Unchecked_Conversion( Integer_64, Octets_8 );
  function Cast is new Ada.Unchecked_Conversion( Octets_8, Integer_64 );

  -- to and from streams for network communications - general
  procedure ToNetworkFormat(
      Item   : in Octet_Array;
      Buffer : out Stream_Element_Array);

  procedure FromNetworkFormat(
      Buffer : in Stream_Element_Array;
      Item   : out Octet_Array);

  -- specific, convenience methods for the basic types
    -- Integer_8
  procedure ToNetworkFormat(
      Item   : in Integer_8;
      Buffer : out Stream_Element_Array);

  procedure FromNetworkFormat(
      Buffer : in Stream_Element_Array;
      Item   : out Integer_8);

end SMG_comms_types;

As you can easily notice, the above does not yet cover fully even the 3.0 "Basic types" part of the protocol specification. It's all right for now though - there is quite enough there for the first basic tests and once those are fine, I'll add gradually the rest of types too. There is little point in spending the time now to implement them all before I even got the chance to change my mind regarding *how* to implement them! So if you have a better implementation solution than the above, speak up in the comments section below and save me some time and a lot of headache! Note however that simplicity, clarity and hard guarantees are rather important here.

One small point on which I'm already rather undecided is whether to continue implementing the convenience methods for different types so that one can simply call ToNetworkFormat and FromNetworkFormat for anything or to leave only the generic methods at least for basic types. At the moment I incline towards providing all those methods (i.e. adding to the single pairof methods for the Integer_8 type defined above) because more complex types will likely need such methods anyway and moreover, this approach helps to keep all those casts (unchecked_conversion) in one place rather than scattered all through the rest of the code. However, it does add to the LOC count of this package. Anyway, moving further for now, the corresponding .adb file with the implementation of smg_comms_types:

  -- S.MG, 2018
  -- prototype implementation of S.MG communication protocol

with SMG_comms_types; use SMG_comms_types;
with System; use System; -- endianness
with Ada.Exceptions;
with Ada.Streams; use Ada.Streams;

package body SMG_comms_types is

  -- to and from network format (i.e. big endian, stream_element_array)
  procedure ToNetworkFormat(
      Item   : in Octet_Array;
      Buffer : out Stream_Element_Array) is
  begin
    if Item'Length /= Buffer'Length then
      raise Constraint_Error with "Item and Buffer lengths do NOT match!";
    end if;

    if Default_Bit_Order = Low_Order_First then
      for I in 0 .. Item'Length - 1 loop
        Buffer( Buffer'Last - Stream_Element_Offset(I) ) := Stream_Element(Item(Item'First + I));
      end loop;
    else
      for I in 0 .. Item'Length - 1 loop
        Buffer( Buffer'First + Stream_Element_Offset(I) ) := Stream_Element(Item(Item'First + I));
      end loop;
    end if;
  end ToNetworkFormat;

  procedure FromNetworkFormat(
      Buffer : in Stream_Element_Array;
      Item   : out Octet_Array) is
  begin
    if Item'Length /= Buffer'Length then
      raise Constraint_Error with "Buffer and Item length do NOT match!";
    end if;

    if Default_Bit_Order = Low_Order_First then
      for I in 0 .. Buffer'Length - 1 loop
        Item( Item'Last - I ) :=
          Unsigned_8( Buffer( Buffer'First + Stream_Element_Offset( I ) ) );
      end loop;
    else
      for I in 0 .. Buffer'Length - 1 loop
        Item( Item'First + I ) :=
          Unsigned_8( Buffer( Buffer'First + Stream_Element_Offset( I ) ) );
      end loop;
    end if;
  end FromNetworkFormat;

  -- Integer_8
  procedure ToNetworkFormat(
      Item   : in Integer_8;
      Buffer : out Stream_Element_Array) is
  begin
    ToNetworkFormat( Cast( Item ), Buffer );
  end ToNetworkFormat;
  procedure FromNetworkFormat(
      Buffer : in Stream_Element_Array;
      Item   : out Integer_8) is
    octets: Octets_1;
  begin
    FromNetworkFormat(Buffer, octets);
    Item := Cast( octets );
  end FromNetworkFormat;

end SMG_comms_types;

Something that irks me every time I look at the above: those for loops that convert octet by octet to Stream_Element. This is not only ugly but also rather inefficient, especially given that it's potentially the *second* time when those octets are read one by one (the first time being at the conversion from a protocol type - especially one of the more complex types - to an array of octets). However, I have no idea how to do that conversion from array of octets to array of Stream_Element in one single move! Do you know a better way to do this? A direct assign fails because the cast from one type to another would be on the array type rather than individual elements type. And I'm rather reluctant to work directly with Stream_Element as the basic type because this type is implementation dependent and outside my direct control - so I can't actually really know *what* it is.

The above being said regarding Stream_Element, it is important to note that the code above (and almost all the code for a network communication protocol) is anyway, strictly speaking, rather tightly linked to GNAT since it relies on Stream_Element being exactly 8 bits long. And to make this clear, here is the full trail I followed to make sure that I can indeed simply convert an octet (i.e. 8 bits) to a Stream_Element and the other way around while preserving exactly the number of bits specified in the protocol for each type: first, GNAT implements Stream_Element in a-stream.ads as follows:

type Stream_Element is mod 2 ** Standard'Storage_Unit;

Then, the definition of Standard'Storage_Unit for GNAT, which reads that Standard'Storage_Unit always has, according to the GNAT reference manual, the same value as System.Storage_Unit. In turn, System.Storage_Unit is indeed declared in GNAT's system.ads as a constant with value 8, so a Stream_Element in GNAT will indeed have exactly 8 bits:

Storage_Unit : constant := 8;

Moving on, the next step is to write the client-server part even if only a test version for now. Initially I took the easy way out here and simply wrote the separate server and client, each listening/sending one single packet. Running those on different machines worked perfectly fine. This is both fine and needed for a reasonable basic test of the whole thing, sure. However, at the moment as I'm just starting on this I'd rather *not* faff about with 2 machines each and every time I change or add something to this prototype protocol implementation. Moreover, this server/client part is perfect to experiment as well with threads4 in Ada - a topic that I'm still struggling to learn so perfect to practice! Therefore, in the basic test, server and client are implemented as different tasks (Ada's "threads") of the same main program - obviously, it follows that client and server will send data to one another on the same, local machine. This is of course not ideal nor sufficient as test in the long term but it'll do nicely for now and until the basic layer of the protocol at least is more fleshed out. The code in test_comms.adb:

 -- S.MG, 2018
 -- prototype implementation of S.MG communication protocol

with GNAT.Sockets; use GNAT.Sockets;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Streams; use Ada.Streams;
with Interfaces; use Interfaces;

with SMG_comms_types; use SMG_comms_types;

procedure test_comms is
  Port_No : constant := 2222;

  task type Client is
    entry Send;
  end Client;

  task type Server is
    entry Listen;
    entry Ready;
  end Server;

  task body Client is
    Sock: Socket_Type;
    Address: Sock_Addr_Type;
    Data: Ada.Streams.Stream_Element_Array(1..10) := (others => 42);
    Last: Ada.Streams.Stream_Element_Offset;
    N   : Integer_8 := -36;
  begin
    accept Send; -- task WILL block here until asked to send
    Address.Port := Port_No;
    Address.Addr := Inet_Addr("127.0.0.1");
    Create_Socket(Sock, Family_Inet, Socket_Datagram);

    ToNetworkFormat( N, Data(1..1));
    Send_Socket(Sock, Data, Last, Address);
    Put_Line("Client sent data " & "last: " & Last'Img);
  end Client;

  task body Server is
    Sock: Socket_Type;
    Address, From: Sock_Addr_Type;
    Data: Ada.Streams.Stream_Element_Array(1..512);
    Last: Ada.Streams.Stream_Element_Offset;
    N : Integer_8;
  begin
    accept Listen; -- wait to be started!
    Put_Line("Server started!");
    -- create UDP socket
    Create_Socket( Sock, Family_Inet, Socket_Datagram );

    -- set options on UDP socket
    Set_Socket_Option( Sock, Socket_Level, (Reuse_Address, True));
    Set_Socket_Option( Sock, Socket_Level, (Receive_Timeout, Timeout => 10.0));

    -- set address and bind
    Address.Addr := Any_Inet_Addr;
    Address.Port := Port_No;
    Bind_Socket( Sock, Address );

    accept Ready; -- server IS ready, when here
    -- receive on socket
    begin
      Receive_Socket( Sock, Data, Last, From );
      Put_Line("last: " & Last'Img);
      Put_Line("from: " & Image(From.Addr));
      Put_Line("data is:");
      for I in Data'First .. Last loop
        FromNetworkFormat(Data(I..I), N);
        Put_Line(N'Image);
      end loop;
    exception
      when Socket_Error =>
      Put_Line("Socket error! (timeout?)");
    end;  -- end of receive

  end Server;

  S: Server;
  C: Client;
begin
  S.Listen;
  S.Ready; -- WAIT for server to be ready!
  C.Send;  -- client is started only after server!
end test_comms;

Tasks in Ada can be defined as types as above. This is not mandatory - one can equally well simply define the tasks and they'll run in parallel with the main begin-end block. However, Task types are effectively needed if one wants to be able to explicitly and potentially dynamically create several workers of the same type. Since I'll need this later for sure, I might as well practice it at any occasion, so there they are, the Client Task type and Server Task type. To make sure that the server is ready *before* the client sends anything, I'm using the rendez-vous communication method that Ada provides: each "entry" of a task is basically a rendez-vous point between the task itself that "accepts" that entry at some specified point in its body and a caller task that "calls" that entry from outside. The main body of test_comms illustrates this: S and C start in parallel with the main body of test_comms but they both stop almost immediately as they wait on their first rendez-vous points (accept Listen for the Server type and accept Send for the Client type). The main body first calls S.Listen, effectively releasing the S (Server type) task from its wait. Immediately after that, the S.Ready entry is called so that now the main body is actually waiting for S to get to its "Ready" entry - basically to finish setting up the socket. Once S got to its Ready entry, the main body can go further and the next statement calls C.Send that releases the client for its wait. The client will send therefore its data and promptly finish, while the server (that was running in parallel all this time) will finally receive the data, process it and finish as well. Go ahead, give it ago and let me know if there's anything funny going on!

To compile all the above with one neat gprbuild call, there is of course a .gpr file:

-- S.MG, 2018
 -- prototype implementation of S.MG communication protocol
 -- http://trilema.com/2018/euloras-communication-protocol-restated/

project SMG_comms is
  for Languages use ("Ada");

  for Source_Dirs use ("src");
  for Ignore_Source_Sub_Dirs use (".svn", ".git", "@*");

  for Object_Dir use "obj";
  for Exec_Dir use ".";

  for Main use ("test_comms.adb");

  package Builder is
    for Executable ("test_comms.adb") use "test_comms";
  end Builder;

  package Compiler is
    for Default_Switches ("Ada") use ("-O2");
  end Compiler;

end SMG_comms;

An example of running the test_comms executable produced by gprbuild:

smg_comms$ ./test_comms
Server started!
Client sent data last:  10
last:  10
from: 127.0.0.1
data is:
-36
 42
 42
 42
 42
 42
 42
 42
 42
 42
smg_comms$

On a slightly different note, I had a bit of an internal debate on whether it's appropriate or not to still release this as a V tree given that it's work in progress and absolutely nowhere near a reference object of any sort or even a fully working item. I came to view V however as simply a versioning system rather than a "set in stone only the end products" sort of thing - for that matter what end products anyway, it's at most, in the happiest of situations, seed products rather than end products. So all the above code is the genesis of smg_comms and it's simply a tiny, far from perfect seed that will hopefully grow into something useful while preserving in its v-tree the whole history of that growth:


  1. Due to a large extent to ave1's work on forcing it into some useful shape so that it builds on a sane, musl-based system. 

  2. The Socket_Datagram mode to be set for UDP communications is at least mentioned in the examples although the rest of differences in effectively comunicating something are left to be discovered. 

  3. My Ada reference book is Barnes, John, "Programming in Ada 2012", Cambridge University Press, 2016, ISBN 978-1-107-42481-4. 

  4. On-demand, resilient threads are crucial for Eulora's server and I'm not yet confident at all that I really fully grasp Ada's mechanisms so I'm pushing it to the front, reading on it and otherwise banging my head on it at any and all occasions - how else to figure it out faster? 

September 13, 2018

Atunci ca si acum ca-ntotdeauna

Filed under: Lyf — Diana Coman @ 11:27 a.m.

Pentru ca unele lucruri chiar nu se schimba indiferent cat calatoresti in timp, in spatiu ori in alte dimensiuni de nici nu-s descoperite inca, pun aici cuvintele cele adevarate, sa fie de referinta1 adica sa am unde trimite tinerele sperante pline de... a-vant :

reclama_oua_1944


  1. Autorul original - al reclamei ori al imaginii scanate macar - nu-l stiu si n-am reusit sa-l descopar ca altminteri circula imaginea dar nu zice nimeni nimic ca de unde a luat-o sau a gasit-o sau cum e. Eu de gasit am gasit-o pentru ca am cautat-o anume, dar nu-i in nici un caz feisbuc acum sursa la asa ceva. Daca stiti anume cine a scanat imaginea si unde, ziceti la comentarii aici.  

September 4, 2018

Pura Vida Like No Other

Filed under: Tgdyk tgdyk — Diana Coman @ 9:11 p.m.

Costa Rica is this enchanted land that has it all: balmy1 weather, sunny skies, warm waters, lush hills and heady mountains, cheeky monkeys and cute crabs, the friendliest people you ever saw and a very good dose of pura vida. This pura vida is the locals' own version of happiness, honey and spice and all the things nice and it really looks quite like this:

crocodilii_zambitori

There, have you ever seen that wonder before? The very smiley crocodiles of Costa Rica! And not only very smiley, but very friendly too for they won't eat those fish that swim - happily, pura vida! - around their tails. It's true that the smile is just a way to soak in more sun and it's true that fish are simply not worth the bother for those two very full crocodiles. Nevertheless, just try and convince those fish of such ugly thoughts and that crocodiles aren't really just being friendly and nice and good neighbours and all that - you psycrocopat!

Fish aside, if you look carefully at those tico crocodiles, you might notice also something else: the one on the shore has a rather short tail and the one in the water is missing the front paws entirely, now how could that be, how could such horrible things happen in this land of beauty, calm and sunshine? Well, they didn't happen through malice and ugly intent, no; they happened through... ineptitude, ain't that much better? In short, one crocodile insisted on fighting with those who were better at it and a bit of tail lost here and there did not make it change behaviour for it couldn't possibly change - it just was. The other crocodile kept eating some farmer's cattle and the farmer was very friendly and humane so he didn't kill the crocodile - he just chained it so well and so competently that the chains entirely destroyed its front paws essentially ensuring the crocodile would starve left by itself as it can't really swim properly anymore and it can't really move much on land anymore either. Don't you love those kind hearted people that won't kill an animal even when it's a pest?

Happily though, Costa Rica certainly has much more than crocodiles and it turns out I really actually quite like its birds, from owls and mini-eagles to tiny parrots. For they are not even just any birds really but the most curious and rather intelligent birds - some would literally come to check you out, to see for themselves from up close this weird huge bird that won't fly and is not even coloured properly with some real contrast! And even from a cage2, one toucan bird came to say hi and have an upside down look, perhaps that way it might - who knows! - make head and tail of me:

A very curious Toucan bird saying hi.

When speaking of animals of Costa Rica, one can easily go on for ages. There are also owls of various sorts and macaws and parrots and snakes and monkeys and crabs and iguanas and frogs and many others that I don't even really know the name of. And almost everything is either brightly coloured or otherwise well camouflaged in dull sandy colours. Tiny crabs will vanish in the sand as soon as they realise that you spotted them and small pebbles will suddenly wake up and start moving as soon as you went past them. From the trees above, monkeys will suddenly dart down and grab anything they find - whether they need it or not is something they don't bother asking themselves until after they got it since dropping stuff from high up comes at no cost whatsoever to them. From under the rocks below, iguanas and all sorts of other reptiles will come out in the morning and take their favourite place for soaking sun up. And from all sides, the ocean will brush the shore rather savagely with a strong push of breaking foam and an even stronger suck of waters back, sand and shells and anything else included. It's only in smaller, mini-gulf areas that are protected between rocks where waves are broken way before they make it to the shore so that they end up as tiny, gentle ripples only. A bit like that everywhere - in smaller, protected areas, the ocean may seem more like a little sea and the world may seem more like a fairytale.

But let's come back to the kind, friendly and totally innocent people of Costa Rica for what would the land and all the wondrous nature even be without the people! Ticos are truly friendly beyond anything you've likely ever saw - the whole country really feels more like one big village where one knows if not everyone else then surely someone who knows someone and so on until... one feels and pretty much acts like one knows everyone else. And just like in one big village, nobody bothers with street names or house numbers or indeed addresses of any kind - everyone is expected to also know where everything is or at best ask for ...directions on how to get there! So your address ends up being not a short ugly thing such as street name and house number but a long and rather intricate description of how to get there with approximate 100 metres before this and 1km towards that and past the one but before the other and green gate3 on the left but not first but second! And you'd think given this habit that they would have at least the basic idea to keep gate colours as diverse as possible at least within short distances or if not that then the pride to make each of their houses properly stand out with some crazy, unique and obvious - even monstruous if need be - thing at the gate! No, not the friendly, innocent ticos, why would they do such a thing? So no, not much in terms of specific or unique for houses and no attention whatsoever to street names or numbers even when they exist. For everyone knows where everything is and directions are just as good as addresses, remember?

Weirdly enough, the direction-instead-of-address even works of sorts - it works that is most of the time, for it requires of course a local to know where all sorts of small shops, car dealers and weird deposits actually are. If you are not a local or your driver is not a local4 then you are lost anyway, directions or no directions. And so you... ask of course and you get an answer - there's always an answer - but that doesn't mean it is the *right* answer! For you see, they want to be helpful and they won't let such small things as not being able to help stand in the way of their wish to be helpful!

At times however it's true that their being helpful is helpful indeed - especially at times when one didn't even imagine there would be a need for any sort of help! After witnessing a lot of the local traffic, I'd say I would probably need local help even with that - and in all fairness, I really preferred to rely on local hired help for all the driving. Even so, it took me some time to realise that they really honked their horn every time they came close to a crossing of roads - traffic lights or no traffic lights, it does seem in hindsight that one would do well to announce they are coming since nobody bothers necessarily with street markings, signs or indeed lights of any kind. And then the traffic jams and the unexpected turns or stops or what have you. The pedestrians walking on the motorway, the vehicles of all descriptions and no descriptions. After tico traffic, I surprised myself after landing in London since I spent the time admiring from my taxi the ordered progress of british cars along the roads - even now that I write it, I can't quite believe it but at the time it had a certain attraction given the stark contrast of previous days.

At any rate, in terms of getting one out of the trouble that is purely local, there is indeed nobody better apt than a local to help. Imagine this little wonder of a direct bus going straight from the capital San Jose all the way to Manuel Antonio national park, on the Pacific coast. Everything nice and tidy and even ordered by tico standards with seats numbered and even assigned by those same numbers - I honestly wonder why wouldn't they give the seat the same style as the addresses sort of walk about 5 steps and then 2nd on the right with the pink arm rest or something. So taking the bus from San Jose is basically no trouble at all, there's a bus terminal and a ticket station and the bus even leaves on time, goes as stated, arrives on time! But then, at the other end, in Manuel Antonio, they don't sell tickets *at all* - you need to go instead some 10km away to the little town of Quepos to buy any tickets because.... well, I don't know, apparently nobody thought that someone would actually want to take the bus back, going away from Manuel Antonio! Or perhaps tickets are really too advanced for selling in anything smaller than Quepos and what does it matter that the bus really leaves from somewhere else?

But let not any of those small details of ineptitude spoil anything for you - pura vida, remember? People are happy and friendly and monkeys are noisy and a bit of a pest and overall everything is perfect, especially as long as you don't really try to change it. Oh, and to make that clear, there is of course cultural life too and even one that depicts - rather truthfully I'd say - the local pura vida from at least one angle if a rather... obtuse angle:
costa_rican_gone_with_the_wind

In other rather greedy recollections, there'd be of course the rum, notwithstanding the fact that it's venezuelan, not costa rican at all. But even before that and certainly more local than that, there is the cocoa and therefore the chocolate that is simply delicious. And the coffee that is so good that even I - who don't really drink much coffee otherwise - still drank coffee in Costa Rica at pretty much any opportunity without any regrets or second thoughts. A certain fig cake there is delicious and some cocktails can be enormous. Some of them really are in fact more like semi-liquid icecreams with alcohol poured in - for better or worse. The fish is always good and - if you ask them to leave the darned salt out of it - well cooked almost always. The local fruit is about 10 times better than anything of same sort I ate anywhere else and I say this although I don't really like unfortunately exotic fruit - to give you some idea, the pineapple there is simply too ... sweet for me! I'm weird like that though and other than the fact that I just don't much like those particular fruits there's otherwise nothing to hold against costa rican avocado, pineapple, mango, coconuts and papayas.

Even in spite of all the monkeys and racoons and iguanas and whatever else the jungle harbours, the best part of it all is for me the water, of course. The warm water and the sun and the sand and all that joy that swimming or even simply jumping the waves can bring. Joy I said, not serenity, for the ocean I find doesn't hold much serenity at all, not with those huge waves, not with the rip current, serenity is just not an ocean thing despite the one thousand words all sorts of pictures might still whisper:

The Pacific ocean at Manuel Antonio, Costa Rica.
Manuel Antonio beach, Costa Rica.


  1. The notion is still debated really: what feels balmy for the first days turns out to be rather too hot after a few days and what feels hot away from water seems all of a sudden rather fine next to water so don't take my word for it - use your own thermometer!  

  2. While I saw toucan birds in the wild too, I couldn't quite get a clear picture of one in the wild, sadly. 

  3. Porton Verde - this is now a character in my house, the Porton Verde! 

  4. We had once this taxi driver from the capital who insisted they knew the place when I asked before getting in and then of course, they didn't but they had no problem with it since in their mind I could just act as a GPS, why not? I really don't recall getting that annoyed with a taxi driver in ages and just like last time more than 10 years ago it ended in just asking them to stop exactly there and then taking another taxi, yes, what else. 

August 4, 2018

A Collection of Pearls as Well as Ever Sadder Epitaphs

Filed under: Open Sores — Diana Coman @ 11:39 p.m.

Motto: Gura pacatosului, adevar graieste.

Deep inside the muck that passes for code among the open source tribes, there are pearls left not before the swine but rather plainly after them1. Like any pearls, they are the fruit of pain avoided and postponed, the signs of the beginning of defeat, the ever sadder epitaphs:

//@@@ Dirty, hack, this might be in a diffrent thread
//@@@ need to syncronize this in some way. But at least
//@@@ by moving this here the client code dosn't call
//@@@ SendOut anymore.

Oh, how truthful it starts, for it is indeed dirty and a hack and it "might be" something else "in some way" - that way being of course if only someone else wrote it! "But at least" it's written there and then never read or acted upon again of course, for how else would code be muck and shit accumulate at such tremendous speeds to make all those half a million lines of code?

 // REVERTED 3/8/03 Until I can figure out why this is causing client conencts to fail - Andrew Mann (Rhad)
// If we don't know who this connection is, don't handle ACKs
//if (!connection)
// return false;

It's 2018 and I'm sure he has figured it all out by now, right? The best way to figure things out is by avoiding them. Only for now, only a bit, only in "some way", only temporarily, of course. OF COURSE. And the best way to clean your house is by sweeping the dust under the carpet, don't you know?

// XXX: This is hacky, but we need to send the message to the client
// here and now! Because in the next moment he'll be deleted

"Where there is a need there is a right" or how did it go? The fact that you *need* to send a message in an ill-suited place at the wrong time to an idiot client and so on are ALL signs of problems to be sorted out not reasons for piling the shit higher and higher!

 // TODO: Hack, for now just get the y value and sector from the first point.

There, the great discovery of this year's lazy bums just as lazy as last year's lazy asses: don't do today what you can postpone indefinitely! And if it's on a todo list, then it doesn't need to actually be done! If I write that I'll do it then it's just as good as if I did it and way less work so it's win-win-me, isn't it? Especially since nobody will dare laugh at me for it since that's discrimination and a big no-no and I'll get all upset and they'll hurt my feelings.

// HACK TO GET AROUND BAD INCLUSION OF PSCHARACTER.H IN DRMESSAGE.H KWF

This one truly reminds me of a children's story: a granny was once asked how many people were there at the party she had just attended. And she truthfully replied: only 1 person; for there was an old dirty barrel blocking the entrance and everyone got around it except for this last man who actually moved the barrel out of the way and only then got in.

What can I tell you, they used to teach this stuff in kindergarten!

 // Hack to work around the weird sector stuff we do.

This is the very way hacks reproduce until there is nothing left but a big pile of hacks precariously stacked on one another all the way to the moon. The hack because of the hack because of the hack because of the... Just stop hacking already and clean the darned shit from your house, you know? Why do you keep shitting where you eat?

// Special case for string, because we have to specify the namespace
// std::string, which doesn't play nicely with our FLAG__namespace hackery.

Hack and... counter-hack! If hacking breeding more hacking and shit growing up to your eyeballs wasn't already clearly and plainly the only result of this insanity. What does it take for you to stop this stupid approach with the special case for the extraordinary situation of the most unique item on the singularity of shit?

/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
* this will of course break if we're included before OpenSSL headers...
*/

You know it's broken but you ... do it anyway? The once inconceivable, the un-human, is that the modern human? Why, just why would anyone do such a thing knowingly?

/** @@@ Hack: please someone tell me how to do this better? */

Perhaps one of the saddest of them all: he is asking, you know? Perhaps in the wrong place, perhaps poorly stated, perhaps at the wrong moment, perhaps even only half-hearted but nevertheless... he asks for some guidance away from the swamps! But who answers, who is there to even read his comments at least if not his code? Of all the thousands pairs of eyes, none even blinks in recognition, not even once and the question remains there unanswered, the hack stays in place, the cry for help goes unheard and unnoticed for there is nobody to hear it. The thousands pairs of eyes stare without seeing anything for they are all little more than painted eyes on painted masks on painted cardboard in the painted world. Pure insanity this brave new world, the very stuff nightmares are made out of.

There truly is no worse loneliness than the loneliness of those trying to be people while lost among the crowds. For crowds are never, ever, people. And more importantly perhaps, out of necessity, crowds will always and invariably choose to mend and make do, just as reflected in all those comments above, never to clear away the rot that is left therefore to accumulate and fester and stink and drown everything. So next time *you* make your choice between the expensive exposure and fix of the rot on one hand and the mend and make do on the other, think perhaps also of that loneliness of the person in the crowd and of what it truly means to be - to become! - only one of the many, many identical pairs of unseeing eyes in the crowd.


 


  1. Hey, swine have rights too! What are you getting offended about? 

July 17, 2018

Discriminatory Code Sharing

Filed under: TMSR — Diana Coman @ 2:10 p.m.

While the world at large is making itself busy with the current fashion of discrimination hunting and public pillorying of any offenders it can get its public hands on, TMSR is peacefully and earnestly discussing in the forum the introduction of a new code release paradigm that is quite as discriminatory as it can be and as a result to rather significant benefit to all. The initial proposal as stated by Mircea Popescu in #trilema has the following parts (split and formatted from the logs in a way that I find easier to read):

the following code release paradigm :
client (code) author
a) releases code encrypted to l1, signed and deeded (so basically, gpg -aer asciilifeform -r ave1 -r etc) ;

b) releases precompiled binaries for allcomers.

advantages:
1. permits us to control binaries, which means stuff like http://btcbase.org/log/2018-07-16#1834888 (which i'm very much impressed with, btw) ;

2. permits to reserve some interest for the author, because the strategic thinking over at minigame is that we'll want client competition (from skinning all the way to all the way) and remuneration by installs (hence all that hash dance in the new c-s protocol) ;

3. very clearly quashes the idiocy of rms-ism AND ers-ism ("open source" bla bla), and makes the strong political statement that indeed there is a difference between nose breathers and mouthbreathers and so on.

disadvantage:
this only works if we can rely on l1 to keep a secret ; which means things (such as, that it can't be as big, for instance).

The discussion can be found in the logs but it can be a bit difficult to follow as it spills over into next day and into other topics on the way. The initial focus was on the issue of "keep a secret" and then on that of "controlling binaries". While both those aspects are worth discussing and are certainly covered to some extent in the log throughout yesterday, they are actually NOT at all central to the proposal as I came to understand it at length. And the discussion perhaps focused on those at first mainly because the speakers - both I and Stanislav - have more practice with the technical perspective and so we read the proposal first through that lens. However, as I kept prodding the issue with questions, various bits and pieces fell into place for me and the whole thing started making more sense. Specifically, this is my current understanding of this proposal:

Discriminatory Code Sharing

The proposal is simply a clear and pointy (i.e. with actual practical power and means to use this power) discrimination between:

a. the general "public" who has access to binaries and nothing else.

b. qualified individuals (l1) who have access to sources.

Note the mass noun in a. and the distinct persons in b.

Note also that the a/b distinction above is a political issue first and foremost. It *does not matter* nor it could possibly matter if some non-l1 somewhere gets at some point his hands on some code or the other. So it sees it. So what? For as long as the "seeing" happens outside the walls of TMSR or otherwise put outside the structure of authority, there is no meaning to it. In practical terms, they can of course see the code, come within the walls and contribute as a result and then what's the problem or the loss? Or they can herp and derp outside and be ignored by TMSR just as they were before they found that code in the woods, so again what's the problem or the loss?

Essentially, code is to be shared but not with anyone able to push some keys. Code is to be shared with and even offered to those who can do something meaningful with it - and only to those. What they decide to do with it, if anything, is of course their own call entirely.

There are significant advantages to this approach:

1. It makes explicit and it gives more meaning to an existing and unalterable difference between "users of software": some can and will read source code, others will just execute whatever they download. Those who consider themselves in the first category but possibly unjustly lumped at the moment with the second, have the option of doing some work and getting into l1.

2. It offers quite a few things to those who actually write useful code:

  • a way of getting help from those most able to give it;
  • as much protection as there currently is anywhere to be found against the significant and eternal pressures of the mindless horde1 as well as against the very real monkeys who are always looking to pick up the fruit of someone else's labour when it's ready;
  • a clearer and arguably easier avenue to making a name for themselves and in the process finding their own place, be it in l1, l2, lx or outside the walls entirely.

3. It adds more meaning (power and responsibility, what else) to the l1 status.

4. It puts more pressure on the need for reproducible builds since the practical and technical aspects of most of the above relies to some extent on those and the actual exercise of the new powers will inevitably run into the issue of non-reproducible builds (as well as any other relevant technical issues that are perhaps yet to be revealed as people stumble upon them).

The only disadvantage stated from the beginning was the fact that the approach is unlikely to scale very well as the size of l1 increases - there needs to be a rather close agreement within l1 at the very least on the core aspect here: code is not secret but sharing it is a responsibility and choosing the recipients is a matter not to be taken lightly.

I can perhaps see a potentially different issue with submitted code that keeps growing in volume. However, I'd expect that it is a bit too early to worry about that and the solution is more likely to be naturally found - if nobody actually reads it, there is no effect. For the code's author it's just as if the code wasn't even submitted in the first place if not even worse since he might easily land in the soup for being an idiot who can't read the log and doesn't understand at all how lines of code are weighed in the first place.

Based on my above understanding of this proposal, I must say that I'm all for it. From all I see, it's a rather significant improvement for everyone even remotely touched by it and at relatively little real cost to anyone involved.

It might be of course that I misunderstood the proposal in parts or entirely in which case I very much want to hear in the comments below where I'm mistaken.


  1. Also known as the horde of idiots, mountain of idiots, sewer rats and so on. 

July 14, 2018

Cutting MySQL into Musl Shape

Filed under: Coding — Diana Coman @ 3:40 p.m.

As I'm apparently the adventurous type or in fewer words an ice-breaker, I got to see all the ways in which MySQL fails to compile on a musltronic1 gentoo2. Note that there aren't that many versions of MySQL that portage knows about in the first place (exactly 5 versions: 5.5.60, 5.6.38, 5.6.39, 5.6.40, 5.7.22), mainly because of the nonsense proposition that "oh, we moved on to something new and shiny on which we got to stick another label and another name, be it mariadb". To quote specifically from mariadb itself when built3:

* Starting with version 10.1.8, MariaDB includes an improved systemd unit named mariadb.service
* You should prefer that unit over this package's mysqld.service.

Do you hear that? I won't even touch on the systemd nonsense but just read over and over again that part that says *you should prefer that unit* and nothing more. And tell me how can one write such a thing in the configuration files of a piece of software and then still have claim to ever be given the time of the day, not to mention to not being laughed out of town. And note that being laughed out of town is the best case there because frankly I find that offensive like hell rather than funny in the least.

Anyway, discarding with much pleasure the thing that "everyone" says I should prefer, here are the ways in which the various MySQL versions fail to emerge:

5.5.60: this version of MySQL pulls in openssl no matter what; even when libressl flag is added; even when -openssl is specifically added too; I just couldn't get it to leave openssl alone and so it's totally dead in the water. Not to mention that openssl then conflicts with libressl, so it's totally out of the question. RIP.

5.6.38: this was the preferred version so it was tried first, with a mask on anything greater than this aka >dev-db/mysql-5.6.38 written in /etc/portage/package.mask; it fails to compile because deep inside mysql code the stacktrace.c file relies on some thd_lib_detected variable and THD_LIB_LT constant to find out what implementation of threads it is running with. It was the first time I even saw those 2 things, a grep in MySQL code did NOT turn them anywhere else and then a quick dive into docs and everything else failed to find them anywhere *else* than in MySQL code. So I'm not even sure where are they meant to be set exactly, but given how the code compiles fine on a glibc system and fails miserably on the Musl system, I suspect it's some glibc-specific approach that got baked into this tiny corner of MySQL. Big mistake for the tiny corner, since the solution is to cut it away, of course. Anyway, the fail:

/var/tmp/portage/dev-db/mysql-5.6.38/work/mysql/mysys/stacktrace.c: In function 'my_print_stacktrace':
/var/tmp/portage/dev-db/mysql-5.6.38/work/mysql/mysys/stacktrace.c:360:27:
error: 'thd_lib_detected' undeclared (first use in this function)
sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
^
/var/tmp/portage/dev-db/mysql-5.6.38/work/mysql/mysys/stacktrace.c:360:27:
note: each undeclared identifier is reported only once for each function it appears in
/var/tmp/portage/dev-db/mysql-5.6.38/work/mysql/mysys/stacktrace.c:360:47:
error: 'THD_LIB_LT' undeclared (first use in this function)
sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;

5.6.39: this is the version pulled by portage without any masking or keywords; it fails just like 5.6.38 with loud complaints about the unknown thd_lib constant & variable:

/var/tmp/portage/dev-db/mysql-5.6.39/work/mysql/mysys/stacktrace.c:360:27:
error: 'thd_lib_detected' undeclared (first use in this function)
sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
^
/var/tmp/portage/dev-db/mysql-5.6.39/work/mysql/mysys/stacktrace.c:360:27:
note: each undeclared identifier is reported only once for each function it appears in
/var/tmp/portage/dev-db/mysql-5.6.39/work/mysql/mysys/stacktrace.c:360:47:
error: 'THD_LIB_LT' undeclared (first use in this function)
sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;

5.6.40: this fails quite the same as the 5.6.38 and 5.6.49 above:

/var/tmp/portage/dev-db/mysql-5.6.40/work/mysql/mysys/stacktrace.c: In function 'my_print_stacktrace':
/var/tmp/portage/dev-db/mysql-5.6.40/work/mysql/mysys/stacktrace.c:360:27:
error: 'thd_lib_detected' undeclared (first use in this function)
sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
^
/var/tmp/portage/dev-db/mysql-5.6.40/work/mysql/mysys/stacktrace.c:360:27:
note: each undeclared identifier is reported only once for each function it appears in
/var/tmp/portage/dev-db/mysql-5.6.40/work/mysql/mysys/stacktrace.c:360:47:
error: 'THD_LIB_LT' undeclared (first use in this function)
sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;

5.7.22: this version requires the ~amd64 keywords on my proto-cuntoo so it's supposedly "at your own risk" grade. It fails at configuration stage with CMake barfing about a lack of mysys timer:

CMake Error at configure.cmake:573 (MESSAGE):
No mysys timer support detected!
Call Stack (most recent call first):
CMakeLists.txt:451 (INCLUDE)

And then I threw my hands up in despair at it all, took the plunge into MySQL code and Gentoo's very useful ebuild command4, cut away the misbehaving part and had the pleasant surprise that it was actually enough to make the whole thing work! After which I spent of course another few hours just checking the whole thing through because by now I am very, very suspicious when it's relatively easy to fix something.

The good news is that MySQL can be made to work on a musltronic system with just a small snip of the "safe printing" of a stacktrace - as I'm not terribly concerned at this time about MySQL's own stacktrace printing, I didn't really spend the time to *fix* the code although I'm sure it can be done with a bit of study of threads in Musl. For now though I am content to just delete that code and yes, have a MySQL that won't print its stacktrace. Specifically, here are the steps to get MySQL going on a proto-cuntoo system:

1. Get the source code by instructing ebuild to "fetch":

ebuild /usr/portage/dev-db/mysql/mysql-5.6.38.ebuild fetch

2. Unpack it:

ebuild /usr/portage/dev-db/mysql/mysql-5.6.38.ebuild unpack

3. Simply delete the contents of method my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)  in /var/tmp/portage/dev-db/mysql-5.6.39/work/mysql/mysys/stacktrace.c and save the file. Leave the empty shell of the method there since it IS called (yes, I checked). Ideally one would fix the code I guess, but atm I really don't see this worth the time since the moment mysql fails that badly I seriously doubt I'll want to spend the time investigating its stack trace - it's more likely I'll throw it out the window entirely. At any rate, as this is not a "fix" by any measure, I'm not making it into a patch so you'll have to run through those steps rather than just emerge.

4. With the code thus modified, ask ebuild to go ahead and compile, install and then merge the result into the live file system, so three different commands to be run one at a time:

ebuild /usr/portage/dev-db/mysql/mysql-5.6.38.ebuild compile
ebuild /usr/portage/dev-db/mysql/mysql-5.6.38.ebuild install
ebuild /usr/portage/dev-db/mysql/mysql-5.6.38.ebuild qmerge

5. It's done; run your usual emerge --config=dev-db/mysql-5.6.38 and set the root password, create databases and users, as you need.

And there it is, I can happily report that MySQL 5.6.38 is now compiling and running quite happily on a fully musltronic system!


  1. Aka Musl-based rather than glibc-inflated. 

  2. Also known as proto-cuntoo since that's exactly what it is: an alpha version of trinque's cuntoo.  

  3. Yes, I built this one too and it builds fine. No, I won't use it though. 

  4. Man page for ebuild most recommended read! 

July 10, 2018

Some Branching Troubles on Existing V Trees

Filed under: Coding — Diana Coman @ 10:03 p.m.

In theory - when there IS a theory! - everything is neat, simple and takes almost no time1. Today's everything started similarly neat and simple with a clear goal that was not meant to take much time: finding a better home for my Keccak implementation.

To clarify the issue here: currently Keccak is part of EuCrypt mainly because at the time of its implementation there simply was no better place for it. But meanwhile phf integrated Keccak into his vtools, esthlos is actively searching for the best way to use Keccak hashes as part of his own V implementation and Arjen (ave1) has released a zero foot print (ZFP) library that is delightfully effective at eliminating bloat. And on top of all this, V itself is moving forward with more clarity and better practices: there shall be a manifest file, there shall be Keccak hashes instead of sha512. Combined, all those developments really point and prod at the simple fact: Keccak both needs and can get a better home now - namely a home as a branch off ave1's zfp tree!

Branching off an existing V tree is meant to be a straightforward task: press the original tree to the desired leaf, add SMG.Keccak, produce new patch, test that it sits indeed at desired place in the tree and it presses fine, write it all up, release and enjoy. But it didn't take long to get into trouble:

  1. To start with, it turned out that current Keccak can not yet use ZFP because its OAEP wrapper requires Interfaces.C and ZFP does not yet support it. Nevertheless, this is noted and added to the README next to the code but it's not in itself a game stopper: the runtime library to be used is anyway specified with the --RTS switch when invoking gprbuild so there is no need to change anything at a later time when ZFP supports Interfaces.C; moreover, the OAEP wrapper is really just a convenience wrapper so it can be removed if the user desires a stripped down pure Keccak in Ada.
  2. Then, vtools and v.pl seemed to not want to play nice together and they sputtered all sorts - this was the easy part to solve though as it turned out I had forgotten to chop the vtools branches properly and keep only one set of patches. Thanks to spyked and phf (and via the logs of course), the needed jolt to my memory was provided, the previous log discussion found and linked, the problem solved: as a result, I had again (as I even remembered I used to have at some other point) the spiffy2 vtools working smoothly and producing the desired Keccak-hashed vpatch.
  3. And then it turned out that I can't quite attach my shiny new vpatch to ave1's tree because my vpatch uses Keccak hashes while his other vpatches are still using sha512 and the combination is of course rather unsanitary.
  4. Adding to the above, I also have quite some trouble in finding a way to properly attach my Keccak patch to the current leaf in ave1's simple tree. Since there isn't a manifest file, I can't take the easy route of not even worrying about this issue and simply add the corresponding line for my patch to this file, knowing it'll come neatly after the current leaf. And it turns out that the difficult solution of making sure I change some file changed by the current leaf is also rather dubious because zfp_2_noc.vpatch changes only a few code files that Keccak really has NO business whatsoever in touching *at all*.
  5. A relatively minor issue by comparison with the ones above but still promising to give headache in the future is the fact that current zfp doesn't actually have its own top directory. So where exactly should I plonk smg_keccak folder in there?

What can I do?


  1. There's a reason many people like theories, especially at a safe distance from practice. 

  2. It's Stanislav's term but it fits best here! 

June 26, 2018

Eulora's Own CR50

Filed under: Eulora — Diana Coman @ 9:29 p.m.

Possibly similar to the CR50 item Stanislav has been torturing recently, a green "Microchip" of unknown internals and dubious usefulness has finally been teased out of the reluctant and downright hostile Euloran soil. It took only a bit more than 3 years of pounding said soil.

On the plus side, it seems to be quite valuable at somewhere around 110`000 ECu (aka 11`000 satoshi atm) base value. On the more usual *other* side, there is no known use for it at the moment1 and it came out very low quality too, not to mention potentially booby trapped for all one knows:

Eulora's own CR50! Microchip!!1

The floating Microchips!

At any rate, I hereby dedicate this very first lot of Microchips to Stanislav Datskovskiy. May all his quests be successful and take considerably less than it took me to find this item!


  1. It wasn't needed until now, which is of course "no indication of future performance". 

« Newer PostsOlder Posts »

Theme and content by Diana Coman