Archive for the ‘General’ Category

2018-05-03 python, multiprocessing, thread-ове и забивания

Thursday, May 3rd, 2018

Всеки ден се убеждавам, че нищо не работи.

Открих забавен проблем с python и multiprocessing, който в момента още не мога да реша чий проблем е (в крайна сметка ще се окаже мой). Отне ми прилично количество време да го хвана и си струва да го разкажа.

Малко предистория: ползваме influxdb, в което тъпчем бая секундни данни, които после предъвкваме до минутни. InfluxDB има continuous queries, които вършат тази работа – на някакъв интервал от време хващат новите данни и ги сгъват. Тези заявки имаха няколко проблема:
– не се оправят с попълване на стари данни;
– изпълняват се рядко и минутните данни изостават;
– изпълняват се в общи линии в един thread, което кара минутните данни да изостават още повече (в нашия случай преди да ги сменим с около 12 часа).

Хванаха ме дяволите и си написах просто демонче на python, което да събира информация за различните бази какви данни могат да се сгънат, и паралелно да попълва данните. Работи в общи линии по следния начин:
– взима списък с базите данни
– пуска през multiprocessing-а да се събере за всяка база какви заявки трябва да се пуснат, на база на какви measurement-и има и докога са минутните и секундните данни в тях;
– пуска през multiprocessing-а събраните от предния pass заявки
– и така до края на света (или докато зависне).

След като навакса за няколко часа, успяваше да държи минутните данни в рамките на няколко минути от последните секундни данни, което си беше сериозно подобрение на ситуацията. Единственият проблем беше, че от време на време спираше да process-ва и увисваше.

Днес намерих време да го прегледам внимателно какво му се случва. Процесът изглежда като един parent и 5 fork()-нати child-а, като:
Parent-а спи във futex 0x22555a0;
Child 18455 във futex 0x7fdbfa366000;
Child 18546 read
Child 18457 във futex 0x7fdbfa366000
Child 18461 във futex 0x7fdbfa366000
Child 18462 във futex 0x7fdbfa366000
Child 18465 във futex 0x7fdbf908c2c0

Това не беше особено полезно, и се оказа, че стандартния python debugger (pdb) не може да се закача за съществуващи процеси, но за сметка на това gdb с подходящи debug символи може, и може да дава доста полезна информация. По този начин открих, че parent-а чака един child да приключи работата си:


#11 PyEval_EvalFrameEx (
f=f@entry=Frame 0x235fb80, for file /usr/lib64/python2.7/multiprocessing/pool.py, line 543, in wait (self== 1525137960000000000 AND time < 1525138107000000000 GROUP BY time(1m), * fill(linear)\' in a read only context, please use a POST request instead', u'level': u'warning'}], u'statement_id': 0}]}, None], _callback=None, _chunksize=1, _number_left=1, _ready=False, _success=True, _cond=<_Condition(_Verbose__verbose=False, _Condition__lock=, acquire=, _Condition__waiters=[], release=) at remote 0x7fdbe0015310>, _job=45499, _cache={45499: < ...>}) a...(truncated), throwflag=throwflag@entry=0) at /usr/src/debug/Python-2.7.5/Python/ceval.c:3040

Като в pool.py около ред 543 има следното:


class ApplyResult(object):

...

def wait(self, timeout=None):
self._cond.acquire()
try:
if not self._ready:
self._cond.wait(timeout)
finally:
self._cond.release()

Първоначално си мислех, че 18546 очаква да прочете нещо от грешното място, но излезе, че това е child-а, който е спечелил състезанието за изпълняване на следващата задача и чака да му я дадат (което изглежда се раздава през futex 0x7fdbfa366000). Един от child-овете обаче чака в друг lock:


(gdb) bt
#0 __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
#1 0x00007fdbf9b68dcb in _L_lock_812 () from /lib64/libpthread.so.0
#2 0x00007fdbf9b68c98 in __GI___pthread_mutex_lock (mutex=mutex@entry=0x7fdbf908c2c0 ) at ../nptl/pthread_mutex_lock.c:79
#3 0x00007fdbf8e846ea in _nss_files_gethostbyname4_r (name=name@entry=0x233fa44 "localhost", pat=pat@entry=0x7fdbecfcb8e0, buffer=buffer@entry=0x7fdbecfcb340 "hZ \372\333\177",
buflen=buflen@entry=1064, errnop=errnop@entry=0x7fdbecfcb8b0, herrnop=herrnop@entry=0x7fdbecfcb910, ttlp=ttlp@entry=0x0) at nss_files/files-hosts.c:381
#4 0x00007fdbf9170ed8 in gaih_inet (name=, name@entry=0x233fa44 "localhost", service=, req=req@entry=0x7fdbecfcbb90, pai=pai@entry=0x7fdbecfcb9f0,
naddrs=naddrs@entry=0x7fdbecfcb9e0) at ../sysdeps/posix/getaddrinfo.c:877
#5 0x00007fdbf91745cd in __GI_getaddrinfo (name=name@entry=0x233fa44 "localhost", service=service@entry=0x7fdbecfcbbc0 "8086", hints=hints@entry=0x7fdbecfcbb90, pai=pai@entry=0x7fdbecfcbb78)
at ../sysdeps/posix/getaddrinfo.c:2431
#6 0x00007fdbeed8760d in socket_getaddrinfo (self=
, args=) at /usr/src/debug/Python-2.7.5/Modules/socketmodule.c:4193
#7 0x00007fdbf9e5fbb0 in call_function (oparg=
, pp_stack=0x7fdbecfcbd10) at /usr/src/debug/Python-2.7.5/Python/ceval.c:4408
#8 PyEval_EvalFrameEx (
f=f@entry=Frame 0x7fdbe8013350, for file /usr/lib/python2.7/site-packages/urllib3/util/connection.py, line 64, in create_connection (address=('localhost', 8086), timeout=3000, source_address=None, socket_options=[(6, 1, 1)], host='localhost', port=8086, err=None), throwflag=throwflag@entry=0) at /usr/src/debug/Python-2.7.5/Python/ceval.c:3040

(gdb) frame 3
#3 0x00007fdbf8e846ea in _nss_files_gethostbyname4_r (name=name@entry=0x233fa44 "localhost", pat=pat@entry=0x7fdbecfcb8e0, buffer=buffer@entry=0x7fdbecfcb340 "hZ \372\333\177",
buflen=buflen@entry=1064, errnop=errnop@entry=0x7fdbecfcb8b0, herrnop=herrnop@entry=0x7fdbecfcb910, ttlp=ttlp@entry=0x0) at nss_files/files-hosts.c:381
381 __libc_lock_lock (lock);
(gdb) list
376 enum nss_status
377 _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
378 char *buffer, size_t buflen, int *errnop,
379 int *herrnop, int32_t *ttlp)
380 {
381 __libc_lock_lock (lock);
382
383 /* Reset file pointer to beginning or open file. */
384 enum nss_status status = internal_setent (keep_stream);
385

Или в превод – опитваме се да вземем стандартния lock, който libc-то използва за да си пази reentrant функциите, и някой го държи. Кой ли?


(gdb) p lock
$3 = {__data = {__lock = 2, __count = 0, __owner = 16609, __nusers = 1, __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, __next = 0x0}},
__size = "\002\000\000\000\000\000\000\000\341@\000\000\001", '\000' , __align = 2}
(gdb) p &lock
$4 = (__libc_lock_t *) 0x7fdbf908c2c0

Тук се вижда как owner-а на lock-а всъщност е parent-а. Той обаче не смята, че го държи:


(gdb) p lock
$2 = 0
(gdb) p &lock
$3 = (__libc_lock_t *) 0x7fdbf9450df0
(gdb) x/20x 0x7fdbf9450df0
0x7fdbf9450df0
: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fdbf9450e00 <__abort_msg>: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fdbf9450e10 : 0x00000000 0x00000000 0x00000000 0x00000000
0x7fdbf9450e20 : 0x00000000 0x00000000 0x00000000 0x00000000
0x7fdbf9450e30 : 0x001762c9 0x00000000 0x00000000 0x00000000

… което е и съвсем очаквано, при условие, че са два процеса и тая памет не е обща.

Та, явно това, което се е случило е, че докато parent-а е правел fork(), тоя lock го е държал някой, и child-а реално не може да пипне каквото и да е, свързано с него (което значи никакви reentrant функции в glibc-то, каквито па всички ползват (и би трябвало да ползват)). Въпросът е, че по принцип това не би трябвало да е възможно, щото около fork() няма нищо, което да взима тоя lock, и би трябвало glibc да си освобождава lock-а като излиза от функциите си.

Първоначалното ми идиотско предположение беше, че в signal handler-а на SIGCHLD multiprocessing модула създава новите child-ове, и така докато нещо друго държи lock-а идва сигнал, прави се нов процес и той го “наследява” заключен. Това беше твърде глупаво, за да е истина, и се оказа, че не е…

Около въпросите с lock-а бях стигнал с търсене до две неща – issue 127 в gperftools и Debian bug 657835. Първото каза, че проблемът ми може да е от друг lock, който някой друг държи преди fork-а (което ме накара да се загледам по-внимателно какви lock-ове се държат), а второто, че като цяло ако fork-ваш thread-нато приложение, може после единствено да правиш execve(), защото всичко друго не е ясно колко ще работи.

И накрая се оказа, че ако се ползва multiprocessing модула, той пуска в главния процес няколко thread-а, които да се занимават със следенето и пускането на child-ове за обработка. Та ето какво реално се случва:

– някой child си изработва нужния брой операции и излиза
– parent-а получава SIGCHLD и си отбелязва, че трябва да види какво става
– главния thread на parent-а тръгва да събира списъка бази, и вика в някакъв момент _nss_files_gethostbyname4_r, който взима lock-а;
– по това време другия thread казва “а, нямам достатъчно child-ове, fork()”
– profit.

Текущото ми глупаво решение е да не правя нищо в главния thread, което може да взима тоя lock и да се надявам, че няма още някой такъв. Бъдещото ми решение е или да го пиша на python3 с някой друг модул по темата, или на go (което ще трябва да науча).

2018-03-29 ТУЕС

Thursday, March 29th, 2018

(това трябваше да го напиша преди седмица, ама работа, умора, други оправдания)

Някога бях чувал историята (за която не намерих потвърждение и май трябва да поровя още малко), че всички ресторанти в България, без значение какви са, трябвало да предлагат шопска салата и още нещо, за да са сертифицирани, че може да работят (не помня дали другото беше пържени картофи или кебапчета). Това звучи малко странно за да речем китайски или суши ресторант…

На подобен принцип МОН искаше да придърпа ТУЕС (училище, което реално е под шапката на ТУ) към себе си и да го уеднакви с останалите (още подробности има на сайта на асоциацията на завършилите там). Аз съм от хората, които и една добра дума не могат да измислят за ТУ-София (самия университет, студентите там не са виновни за състоянието и управлението му, само са пострадали от това), но да се отнеме автономията на ТУЕС ми се вижда твърде лоша идея.

Работил съм с хора, завършили къде ли не – random ПМГ-та, езикови гимназии, СМГ, НПМГ, ТУЕС и НПГ-КТС в Правец (което май вече са го придърпали), и ако трябва да избирам с хора откъде трябва да работя, поне за момента ТУЕС е на първо място. Хората от там имат желание да вършат работа и им е интересно, което изглежда да е доста по-рядко срещано в останалите. Заради това и написахме от името на ФОП (фондацията зад OpenFest) писмо по темата. Ходих и преди седмица да помагам (съвсем малко) във видеото и т.н. на HackTues и в един момент, гледайки какво става там реших, че това изглежда като правилната гимназия, в която Иги да иде да учи, като порасне…

А е късно да пиша по темата, понеже поне засега това изглежда да свърши работа и засега нещата ще са ок.

“Филтри и предразсъдъци”

Wednesday, March 21st, 2018

Около чл. 13 в петък ще се организира дискусия по темата, на 23.03 (петък) от 15:00 в Сохо (и ще се излъчва на живо). Казва се “Филтри и предразсъдъци: Технически аспекти на предварителното филтриране на съдържание онлайн”.

2018-03-17 малък видео setup

Saturday, March 17th, 2018

Събирам (засега основно в главата си) setup за видео streaming и запис в hackerspace-овете в България. Изискванията са:

– минимална инвестиция в нов хардуер;
– (сравнително) лесно за използване (предполагам, че хората там са поне донякъде технически грамотни);
– възможност за stream-ване на текущите платформи, и може би и в тяхната си страница;
– запис/архивиране;
– поносимо качество.

Целта на setup-а е да се справи с най-простия тип събитие, което е един лектор с презентация.

Компонентите са следните:

– запис на звука – може да е от въздуха, но по-добре една брошка на лектора, + запис на залата по някакъв начин, за въпроси и т.н.;
– усилване на звука – дори в малка зала е добре да се усили звука от лектора и да се пусне на едни колони, най-малкото има feedback дали си е пуснал микрофона;
– видео запис – да се запише видеото от презентацията и може би самия лектор как говори. Това има варианта с камера, която снима лектора и екрана, или screen capture, директно от лаптопа му (или някой по-сложен setup, за който вероятно няма смисъл да пиша);
– streaming – да се извадят аудио/видео сигнала в/у някакъв протокол и да се stream-нат до някоя услуга;
– restreaming – услугата да го разпрати навсякъде и може би да го запише.

Вариантите за компоненти/setup-и в главата ми са следните:

– ffmpeg команда, която stream-ва екрана + звук от звуковата карта, в която има един свестен микрофон – това го имаме в няколко варианта, тествани и работещи (за windows и linux), трябва да ги качим някъде. Това е най-бързия начин, почти не иска допълнителен хардуер (освен един микрофон, щото тия на лаптопите за нищо не стават). Микрофонът може да е например някоя bluetooth/usb слушалка, или просто от слушалки с микрофон, да е близо до главата на лектора. Може да е от стандартните брошки, които се използват по различни събития, аз имам една китайска цифрова, дето в общи линии ме радва и е около 200-и-нещо лева от aliexpress;

– проста малка камера, която може да записва видео от екрана и звук, която може да бълва и по IP някакси. Това в общи линии са gopro-та (ако се намери как да им се пъхне звук) и още някакви подобни камери, които нямат особено добро качество (особено на звука, та задължително трябва външен микрофон), но на хората и се намират.

– проста камера, която обаче не може да бълва по IP, и има HDMI изход. Това е от нещата, които на хората им се намират по някакви причини, и в тая категория са половината DSLR-и и фотоапарати (които не прегряват след дълга (2-часова) употреба), gopro-та и нормален клас камери. Това се комбинира с устройство, което може да capture-ва HDMI и да го stream-ва, където засега опцията е един китайски device.

– streaming service – човек може да ползва youtube, моя streaming, или ако се мрази, facebook. Много места би трябвало да могат да си пуснат нещо просто при тях (например един nginx с модула за rtmp), да stream-ват до него, то да записва, и от него да restream-ват на други места и да дават някакъв лесен начин на хората ги гледат (с едно video.js/hls.js, както последно направихме за openfest).

Та, за момента основните неща, които издирвам са:

– евтини и работещи микрофони;
– евтини работещи камери с hdmi изход (или с ethernet порт, тва с wifi-то е боза), които да са switchable м/у 50hz и 60hz;
– hdmi capture вариант.

Приемам идеи, и ще гледам да сглобя едно такова за initLab.

2018-03-13 китайски лаптоп

Tuesday, March 13th, 2018

(те всичките лаптопи се правят в Китай вече, ама не ми хрумва как да го кръстя иначе)

Преди някакво време разбрах за един проект на ентусиасти от Китай за нови дъна за стари лаптопи. От много време ми липсваше 4:3 дисплея, T420 от време на време ми беше бавен (дори с 16GB памет и SSD), по-новите thinkpad-и са с гадна клавиатура, а Retro проекта в крайна сметка не беше customizable и не беше приемлив (с тая NVidia карта и широк дисплей, да не говорим за цената).

Поръчах си един t60p от ebay, и след като дойде тръгнах да си поръчвам дъното. От форума на хората и някаква facebook страница намерих контакти, писах си с един човек, който ми предложи директно лаптоп, но аз си поръчах само дъното (in hindsight, да си бях взел цял лаптоп). Няколко неща по темата с поръчването:
– опциите бяха SWIFT и western union. Не ми се разхождаше, та го направих по SWIFT, и там се оказа, че има допълнителни такси, които взимат от получателя (които не могат да вземат от мен);
– За освобождаване от митница ми поискаха следните неща: фактура (която поисках да ми издадат, щото нямаше) която включва и цената и транспортните разходи, EORI номер, пълномощно да ме представляват и документ за направеното плащане (изискване на митниците за стоки от Китай и Хонг Конг, пише “SWIFT или PayPal”);
– EORI номер може да си издадете безплатно, ако имате електронен подпис и търпение (бях си издал за нещо друго, отне около седмица);
– DHL могат да пратят как изглежда митническата декларация, да си я платите с един online превод и да си получите нещата (иначе искат 24 лв да направят превода те);

Дъното беше $780 и доставка, вариантът за това дъно с цял лаптоп (без памет) беше $980 за 1400×1050 матрица и $1100 с 1600×1200 матрица (нови, IPS, по думи на продавача).

Хората си имат и форум, в който има и инструкции за сглобяване (google translate е ваш добър приятел за тия страници). При мен сглобяването се забави, понеже се оказа, че има вариант на T60p, който е с 16:10 матрица, за който дъното не става, и аз съм взел точно такъв, та си поръчвах нов и чаках да пристигне.

Последва сглабянето с помощта на добрите хора от adsys (на които им отрових живота, щото се оказа доста пипкава работа):
– има малко рязане по кутията (има го описано във форума, със снимки);
– болтовете за закачане са по-малко, дупките на някои са запушени;
– на дъното до конектора за монитор има превключвател за типа на дисплея (1024×768 или по-голям);
– трябва ви DDR4 памет;
– най-вероятно wifi картата от преди няма да ви върши работа, аз си взех моята от T420-ката, и малко трябваше да се лепне с тиксо, понеже е половината слот и нямам преходник;
– CD-то от T60 няма да влезе, понеже е PATA, а конектора на дъното е SATA (не, че ползвам CD). Трябва да си измисля нещо за запушване на дупката;

Неща за дооправяне:
– поне за момента под linux GPU-то не работи (забива на boot), и за това си ползвам xfwm4 вместо compiz, submit-нал съм bug report;
– горните бутони на touchpad-а спират да работят след suspend/resume, направил съм един fix, ама трябва да събера желание да рестартирам.

Моята работна среда на 4:3 се усеща доста по-приятно и най-накрая мога да си пусна email клиента в режим като преди (отляво списък папки, отдясно разделено на две – отгоре списък писма, отдолу отвореното писмо, вместо три вертикални колони, дето едвам пасваха). Също така с тоя процесор вече firefox-а се движи почти прилично, като си оправя и GPU-то, вероятно всичко ще лети.

2018-03-09 чл. 13

Friday, March 9th, 2018

(Даже вестниците вече писаха за това, крайно време е да довърша тоя post)

Та, има “нова” директива на ЕК, за унифициране на законите за авторските права из европейския съюз.
(нова – на 10на години е, ама чак сега се опитва да влезе, и има някакви бегли шансове да се вкара по времето на нашето председателство)

В нея има количество глупости, но частта, с която имам занимание е чл. 13, който в общи линии казва “internet/hosting доставчиците са отговорни за съдържанието, което се качва при тях и трябва да го филтрират”. Не знам за вас, но за мен цялото нещо е твърде много deja vu, в последните 20на години все някой се опитва да пробута нещо подобно, в някакъв вид. Това без значение, че няма как да се направи работеща система, без значение, че всъщност е инфраструктура за цензура (но по-мощна от тази, която има в закона за хазарта) и че в крайна сметка няма да доведе до подобрение за когото и да е, освен може би хората, които продават “филтриращи” системи.

Един от хубавите доводи за това, че такава система няма как да стане идва от wikipedia – има две правителства, които са им поискали да филтрират съдържание, Иран и Китай. Не знам за колко са добре технологично иранците, но ми се струва, че китайците ако можеха, вече щяха да са направили работеща такава система и нямаше да занимават wikipedia. Нещата, които аз съм виждал, са неефективни и с достатъчно грешки (и false positives, и false negatives), че да са неизползваеми за среден размер сайт, понеже така и така някой трябва да преглежда проблемите.
(Вероятно не съм единствения, дето поради идиотщини на youtube постоянно има отворени няколко copyright dispute-а. В един момент човек решава да си ползва собствен streaming и да не го занимават с такива неща…)

Та, има една инициатива по темата това да не влезе, article13.bg, към които съм се включил. Подкрепя ги фондация “Отворени проекти”, initLab и всякакви други добри хора. Вижте, подкрепете, споменете на всички, дето ще ги засегне (всички хостинги, например…).

2018-02-08 FOSDEM

Thursday, February 8th, 2018

Спимисе.

В понеделник сутрин се прибрахме от FOSDEM 2018, където правихме видео. Нямам много структурирани спомени, та разни бележки на едно място:

ULB (университетът, в който е FOSDEM) са страшна работа със сигурността, няколко пъти ни заключваха в зали/сгради. И понеже там като цяло хората говорят всякакъв език, стига да е френски, постоянно трябваше да звъним на локалните хора от екипа да се обаждат на охраната да ни отключват. Интересно дали можем да се доберем до тяхната система за контрол…

По време на setup-а се оказа, че имаме един juniper switch за видео laptop-ите. Докато седяхме в NOC-а и си говорехме, че трябва да се конфигурира, влезе един доброволец и каза “аз съм за видео екипа, казаха, че има нещо за кримпване” “можеш ли да конфигурираш juniper switch-ове?” “ами да, занимавал съм се”, след което го затворихме в сървърното и успя да излезе от там чак вечерта…

В първия половин час на конференцията някой се обади по irc – “абе, защо там пише 2017 в ъгъла?”. Оказа се, че фонът е приготвен и commit-нат, но не е бил налян на voctop-ите, та имаше едно много бързо pscp. Във финалната лекция това го споменаха, а преди това няколко човека обикаляха с няколко листа и предложения как да го коригираме (например да напишем 2017++ …).

За 20 минути успяхме в една от залите да сглобим setup, с който лектор да изнесе лекция remote, но па той не можа да се свърже. Жалко, щеше да е интересен експеримент.

Времето в Брюксел беше отвратително – вятър, дъжд, и точно следобяда слънце, че да ми пече в монитора.

Игнат за малко беше на FOSDEM и даже му показах сървърното. Ако го бях пуснал да полази там, дали щеше да спре всичко в рамките на 5 минути…

Като цяло проблемите от нашата техника бяха малко, от тая на университета – доста (аз дебъгвах setup-а в една зала и още не мога да си обясня как е работел досега), но най-големия проблем си остава, че хората не си включват микрофоните… Може би трябва за някакви такива случаи да помислим за някаква система, която чете по движенията на устните и прави субтитри. За догодина задължително monitoring на аудионивата на stream-овете.

Трябва да си намерим полет на връщане, за който да не трябва да ставаме в 6:30, не е човешко.

И понеже все ме питат дали съм гледал една или друга лекция – може би съм един от малкото хора, дето хем са били там, хем не са гледали абсолютно нищо :)

2018-01-28 чукове

Sunday, January 28th, 2018

“Не го насилвай, вземи по-голям чук”

Каня се от много време да направя debugging workshop, и около мисленето как точно да стане днес стигнах до интересен извод за инструментите, дето ползвам и си правя за дебъгващи цели и като цяло за разни мои начини на работа.

Чукът е хубаво нещо. Какъвто и проблем да имаш, след удара с чука резултатът има същия вид (сплескан) и донякъде ми се вижда като хубава метафора за начина, по който оправям някакви проблеми. Той може да се опише като “най-краткия и прост начин за достигане на нужното крайно състояние, без да има особено значение какво е началното.

Като за пример, тия дни ми се налагаше да подменя едно парче софтуер в 50-тина клъстера, като всеки от тях имаше м/у 3 и 50 машини. Понеже инструментите, които имам са pssh и pscp, се оказа най-лесно на един пас да копирам нужните файлове по всички сървъри, и на втори пас да се логне pssh и ако трябва, да копира където трябва, иначе просто да изтрие това, което бях копирал. Някакъв по-подреден начин би било да извадя списък на всички машини, на които има нужда да се направи действието и да го направя само там, но щях да го напиша и направя по-бавно, отколкото по грубия и бърз начин.

По подобен начин за друг инструмент си бях написал скрипт, който го налива в цял клъстер и отделен, който го update-ва. В един момент осъзнах, че това е тъпо и направих инсталатора така, че да не му пука, ако има вече нещо инсталирано и просто спокойно да може да слага отгоре (както и ако го прекъсна и го пусна пак, да свърши пак нужната работа). Крайният резултат беше, че общото количество код намаля.

Принципът изглежда да може да се приложи към любимите ми начини за дебъгване – това, което ползвай най-често е strace, което спокойно може да се опише като един от най-тежките чукове за дебъгване. Почти без значение какво дебъгвам – компилиран C код, php, python, perl, java – успявам да видя симптомите и да се ориентирам какво става, въпреки че като цяло за всеки от тия езици има специализиран и вероятно доста по-нежен вариант да се гледа какво става.
(искам да отбележа, че има и други тежки случаи – имам колега, който за да смята някакви математически изрази от време на време вместо да си пусне някакъв калкулатор като bc, пуска gdb и прави в него нещо като “p 1024*1024*231/1.1”)

Замислил се бях дали това всъщност не е погрешно и че трябва да се избягва, и стигнах до извода, че не виждам друг работещ начин. Много често ни се налага да дебъгваме чужд код (който сме link-нали/който е под нас някъде/от който зависим, или просто това са ни изсипали) и вариантът да го прочетем и разберем не е опция, понеже в наши дни почти няма проекти, които да могат да бъдат изчетени и опознати за под седмица-две (рекордно малкият код, който в една от фирмите, в които съм работил и търкаляше основните услуги беше около 20000 реда, което е горе-долу в човешките възможности, и пак ще отнеме доста време да се разгледа, а фирмата в това отношение беше сериозно изключение). Това води до нуждата за всякакви помощни средства, за да можем да се справим, понеже човешката глава има сериозни ограничения по темата, и тук на помощ ни идват чуковете, с които всеки проблем може да бъде сведен до пирон (или хлебарка, която трябва да се прасне достатъчно силно).

(да не говорим, че хората искат да пишат умно, и колкото по-умно пишат, толкова по-трудно се дебъгва това, което са сътворили)

2018-01-20 Сървърни социални служби

Saturday, January 20th, 2018

Разни случки от последните година-две:

– седя си аз на един хакатон, и всичко ми се отваря бавно. Поглеждам защо – раздадени са ми ipv6 мрежа и gw, пингва се, но няма ipv6 свързаност, и всичко се опитва в началото да ползва v6, отказва се и минава на v4. Издирват някакси админа, той отговаря “ами аз не съм пускал такова нещо” и т.н., поглеждам – mac адреса на default gw по v4 и тоя, от който ми идват router advertisement-ите е същия.

– “Хора, гръмна ви диск.” “Хора, гръмна ви друг диск.” “Хора, гърмят ви дискове с гигантска скорост, скоро няма да има де да си държите данните.” “Няма де да си държите данните, къде са ви replacement дисковете”…

– Предават се някакви сървъри на нови админи. Логва се стария да покаже нещо, и на конзолата се вижда “Last login преди 8 години”, машините не са update-вани (Debian 4-5).

– “Някой ви е влязъл в сървъра през ipmi-то, направил си е root account и е пуснал minerd. Моля сменете си паролите на IPMI-тата и ги филтрирайте от internet-а, даже производителя им (supermicro) казва, че тия неща не са толкова сигурни.”. Повторение на това – още два пъти в следващите 7-8 месеца, при същите хора.

Има много други такива случаи, но мозъкът ми вече отказва да ги приеме. Ще ми се да направим сървърни социални служби, дето като някой не си се грижи за нещата, да им назначава със съд адмиини, дето да ги поддържат, и на които да плаща собственика на сървърите/мрежата. Безхаберието трябва да е наказуемо, особено в размерите, в които го виждам от време на време…

2017-12-29 Първи лабов podcast

Friday, December 29th, 2017

Официална страница на podcast-а.

Който иска да го свали, ето преки връзки в три формата:

https://vasil.ludost.net/labpodcast-20171228.ogg
https://vasil.ludost.net/labpodcast-20171228.mp3
https://vasil.ludost.net/labpodcast-20171228.flac

2017-12-27 34c3 ден 1

Thursday, December 28th, 2017

Успявам да гледам малко лекции от 34c3 (програма, streaming).

Откриването на Charlie Stross (който ми е от любимите автори) беше доста интересно, с наблюдението, че корпорациите могат да се разглеждат като начална форма на изкуствените интелекти и всякакви интересни следствия от това, струва си да се отдели малко време и да се гледа (не знам дали ще го качи в блога си).

Лекцията за геймифицираната система за социален кредит в Китай не ми каза нещо ново и не беше особено добре представена, но е добре човек да почете за ситуацията.

Харалд Велте разказа за internet-а и BBS-ите от едно време (само че в Германия), като цяло все неща, с които едно време сме си играли. Иво ме пита дали не можем да направим някаква такава лекция или да намерим история на случвалите се неща в България. Мислех си, че вече има такова нещо, ама не мога да го намеря, някой да се сеща за хубава история на ония времена?

Лекцията за Иран имаше малко полезна информация в нея, но основно не си заслужаваше. Лекцията за Саудитска Арабия също нямаше много съдържание.

Лекцията за “Low Cost Non-Invasive Biomedical Imaging” за момента ми е любима, и трябва да си вземем едно такова нещо за в лаба. Звучи като технология, с която си струва да си играем и която може много да подобри работата на всякакви лекари.

“Defeating (Not)Petya’s Cryptography” имаше полезни моменти.

Като успея да изгледам още някакви неща, ще пиша и за тях. Който иска, може директно да ходи в initLab да гледа, тъкмо ще има с кой да коментира :)

Update: “The Ultimate Apollo Guidance Computer Talk” се оказа страхотно, особено архитектурата на нещото, която има вид на скалъпена с тел и тиксо.

2017-12-25 равносметка

Monday, December 25th, 2017

Седя и си мисля за писането равносметка за годината…

В някакъв ред, какво се случи тая година:

– Роди се Ба’ал (официално известен като Игнат);
– Направихме OpenFest 2017, който въпреки новото място мина доста по-лесно;
(write-up-а за мрежата му се надявам да го изкарам тая година)
– Основа се “Да, България” (на която съм член);
– Избута се и FOSDEM 2017 (и следва 2018, където даже ще водя звяра);
Ожених се;
– Омъжихме и Яна, и разни други хора (май се събраха три сватби тая година);
– Почнах работа в StorPool (и сега интервюирам повече за админи, отколкото за developer-и, и всеки ден откривам как нещо от света около мен не работи);
– Свършихме някакви неща с лаба, като последното е да си имаме podcast студио (в което може да запишем тая година един лабов такъв);
– С Мариян си взехме половин rack в 3DC и си събрахме техниката на едно място, с наш ASN и връзки. Някой ден трябва да го разпиша по-подробно;
– Организирах/правих/помагах в stream-ването и видеото на поне 10 събития;
– Почина най-малката ми братовчедка.

Имам един файл, който е в git и в който си пиша какво имам да правя (нещо като календар, ама допотопен), и май не съм имал много време да си почивам тая година. Може да се опитам догодина…

2017-12-18 ARP в Linux

Monday, December 18th, 2017

Почнал съм да събирам списък “неща, на които разчитам и не работят”. Ето едно от тях, в което се ударих преди малко – arp-а на linux kernel-а.

(след като тоя протокол и поддръжката му ги има от години и всички го ползват, някакси очаквам да не ме ритат в кокалчетата)

Преди няколко дни имах оплакване, че от определени места не се стига до marla. След малко тестове нещото сработи от самосебе си и не успяхме да го хванем. Тая вечер проблемът се появи пак, като интересното беше, че до други машини в същата мрежа имаше свързаност, само до marla – не.

Последваха стандартните неща – едно mtr до marla, едно до един от адресите, който не е от нашата мрежа, и нищо. Слушайки на интерфейсите, виждах да влиза трафик, но не виждах нищо да излиза.

Един ip r get каза следното:

77.246.xxx.xxx via 193.169.198.179 dev eth3.1030 src 193.169.198.230

193.169.198.179 е inetbg.bix.bg, които са доставчика на човека. Пинг до това ip нямаше, нямаше и arp entry за него и моята първа мисъл беше “тия па какво са объркали”. След което пуснах един tcpdump и видях следното:

22:06:48.470979 ARP, Request who-has 193.169.198.179 tell 185.117.82.66, length 28

Ако нещо ви се вижда да не е наред – прави сте. Не би трябвало да питам в тоя сегмент с адрес, дето съм извадил от съвсем друго място, и е доста очаквано, че някой няма да иска да ми отговори. Кратко търсене и спомняне ме доведе до /proc/sys/net/ipv4/conf/*/arp_announce, за което може да прочетете в ip-sysctl.txt в документацията на kernel-а.

За който не му се чете, параметърът по default е 0, което значи “сложи там за source ip някакъв адрес, който ти хареса”, 1 значи “гледай поне да е от същата мрежа” и 2 значи “избери внимателно”. Защо не е 2 default-а, не мога да си обясня (но преди малко беше изконфигуриран на двата router-а при нас да е така).

Допълнително на който му се забавлява, може да види какво пише за останалите arp опции и как се държи по default kernel-а, например че може да отговори на arp за един интерфейс от друг, без изобщо да му пука (и което по някакви твърдения отговаря на RFC-тата, което обаче не успях да открия). За всички, които искат смислено поведение на arp-а на linux kernel-а, препоръчвам следните sysctl-та:

net.ipv4.conf.all.arp_filter=1
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.all.arp_ignore=2

(тези са особено нужни ако имате сегмент, в който имате две мрежи и по два и повече физически интерфейса и искате някакъв контрол откъде и как ви върви трафика)

2017-12-13 разни

Wednesday, December 13th, 2017

И много неща на едно място, че все няма време за блогване.

Лабът организира голямо коледно LAN party, на 21.12, с всякакъв хардуер и игри.

Също така подредихме пак в лаба студио за записване на podcast-и, и дори записахме един тестов подкаст (записът е с много малко обработка, май трябва да се усили още малко). Като цяло може да се подобри малко софтуерната част (т.е. да отделя един час и да я поавтоматизирам), и да вземем още една стойка за единия микрофон (вместо да стои в едно диджириду, което е подпряно на стойка за китара), но изглежда да върши работа.

И финално лабово, насъбрали сме толкова странна техника, че обмислям workshop/състезание кой ще успее да подкара най-много неща. В момента ситуацията е такава, че мога да вържа VAX-а по оптика (което много ми се иска да направя тия дни, като имам малко време).

А на мен ми се спи. Тия дни успявам да събера някакъв сън, но като цяло трудно събирам наистина почивни weekend-и, в които основно да спя и да си почивам, та трябва да измисля нещо по въпроса, самия openfest ужасно ме умори (там имах няколко седмици без никаква почивка). Наскоро имах и един ден, в който събрах два пъти по 8 часа работа (второто беше да подредя видео и подобната техника от феста в лаба, че имаше нужда и заемаше място на неправилните места).

В работата е забавно, всеки ден откривам нови неща, които не работят и странни бъгове и дизайн решения в компоненти, които уж хората са тествали, ползват и са ок. От по-пресните примери е как continuous queries на influxdb при достатъчно бази и данни просто никога не могат да наваксат, защото са в един thread, който се вика дявол знае кога. Успях да ги заместя с 200 реда код на python (и разпитвайки google, не само аз съм така).

На книжния фронт една от основните новини е, че авторът на Worm е приключил последния си проект (Twig) и се е хванал пак да пише в света на Worm (казва се Ward), което е страхотно за всички, обичащи книгите по 5000 страници.

Тоя weekend има хакатон във ФМИ, за който услужихме от лаба с малко странна техника. Има ли някой, който може да пробута идеята на отборите да декодират радиопредаванията, с които наливат данни на таблата по спирките? Има нужния хардуер, вероятно със съществуващите неща като gnuradio няма да е сложно да се демодулира, и дори няма нужда да се доправя частта, с която може да се подават произволни надписи за показване по тия табла…

Върви подготовката за FOSDEM. След последните тестове (които правихме на един хакатон там на място) моя код, дето ползва openpgm не retransmit-ва, и за един ден дебъгване (и вкарване на print-ове на разни места и опити да разбера какво точно искат да кажат тия хора, които в разни функции с имена “провери-нещо-си” променят по генералния state и които доста намразих) не успях да намеря що не сработва. Обмислям да се скрия някъде по празниците и да го дебъгвам, или да измисля решение с TCP най-накрая.
(как може никой да не е написал multicast TCP. Трябва да го дадем за задача на някой, дето не знае, че не е възможно и да видим какво ще излезе…)

Спирам, преди това да е станало съвсем несвързано.

2017-11-27 записи от OpenFest 2017

Monday, November 27th, 2017

И изкарахме записите от OpenFest 2017. Може да се намерят в архива и в youtube.

Нещата се забавиха най-вече заради намазани записи и нуждата да възстановяваме от резервните (накратко, да имаш 3 backup-а е полезно).

2017-11-06 задача

Monday, November 6th, 2017

(по-подробно за феста – като се наспя)

За OpenFest 2017 за щанда на StorPool бях написал една задача, та който я реши, да получи тениска. Задачата звучи измамно просто и аз също не съм се усетил, че не е лесно решима за 10 минути.

Задачата е следната – имате директория с някакво количество файлове, да видите кои от тях са MD5 и кои – SHA1 колизии, и да дадете първите букви от имената им (4 файла за md5 и 4 за sha1). Моето решение беше във временна директория да се направят файлове с имена MD5 (и после – SHA1) сумите, в които да се напишат имената и SHA256 сумите на файловете с тая MD5 сума, и после с един sort на всеки файл лесно се вижда в кой има различни файлове (трябва да са еднакви по принцип). Ако е просто да се види коя е md5 сумата, може да се броят уникалните sha256 суми във всички файлове, да се види къде са колизиите.

Интересно ще ми е наистина ли е толкова трудна задачата (доколкото знам, за два дни само един човек я е решил за 10 минути).

Също така ми е интересно дали някой не е решил да пита google какви са checksum-ите на демонстрационните sha1/md5 колизии и да види дали аз не съм си събрал файловете по тоя начин…

Кодът, който генерира задачата е качен на https://vasil.ludost.net/progs/storpool-of-task.tgz. Вътре има gen.sh, който трябва да се пипне малко къде да прави файловете и който при пускане създава малко файлове и ви дава отговора. Не съм сложил другите неща (това, което се прави на login shell и нещото, което праща отговорите по slack на проверяващия), но те не са толкова интересни.

2017-10-26 policy routing с Linux

Thursday, October 26th, 2017

В последно време на няколко места по различни случаи ми се налага да подкарвам policy routing под Linux, та тук мисля да систематизирам защо и как.

1) Какво е policy routing

Съвсем просто, routing, който не се базира САМО на destination IP адрес. В linux това се реализира чрез правила (rules), които на база на нещо решават да се гледа друга routing таблица, не стандартната.

2) Защо ни трябва

Основният use case е когато имаме два или повече default route-а, и искаме да можем за трафик, който е дошъл от единия да излизаме навън пак през него. Примерът, който ще дам по-долу е с два internet доставчика, но при мен се налага като конфигурирам bgp с някой, да слагам policy routing за адресите, които са на самия link да си излизат от верния интерфейс, за да мога да вляза от там, ако нещо се е ошашкало по bgp-то.

3) Как се настройва за крайна машина

Примерът, който ще дам е какво правим, ако имаме два доставчика, които ще кръстя pesho и gosho (ако искате, PeshoNet и GoshoCom).

pesho ви е дал link, на който имате адрес 10.1.1.30/24 с default gw 10.1.1.1 и сте го вързали на eth0, gosho ви е дал 10.2.2.40/24 с default gw 10.2.2.254 и сте го вързали на eth1.

Давам настройките директно с команди, как да интегрирате това в настройките на дистрибуцията си варира твърде много (мога да кажа, че в debian с pre-up и down директиви в interfaces файла може да се направи цялото нещо).

Ако просто ги настроите директно, routing таблицата ще изглежда по следния начин:

~ # ip r
default via 10.1.1.1 dev eth0
default via 10.2.2.254 dev eth1
10.1.1.0/24 dev eth0  proto kernel  scope link  src 10.1.1.30
10.2.2.0/24 dev eth1  proto kernel  scope link  src 10.2.2.40

Това никаква работа не върши, понеже ако отвън дойде пакет за 10.1.1.30, може да излезе от другия link и обратно, а това доставчиците никак не го обичат и филтрират. За това просто в тая таблица оставяте само единия от двата default-а и продължаваме нататък.

Първо, харесваме си числата 1 и 2, даваме 1 на pesho, 2 на gosho, и ги описваме в /etc/iproute2/rt_tables (там има и други неща, това са редовете за добавяне):


...
1 pesho
2 gosho
...

Смисълът от това е, че можем да пишем неща като ip r show table pesho вместо ip r show table 1.

Имайки тези таблици, ги попълваме с каквито пътища имаме:

ip route add 10.1.1.0/24 dev eth0 table pesho
ip route add default via 10.1.1.1 table pesho
ip route add 10.2.2.0/24 dev eth1 table gosho
ip route add default via 10.2.2.254 table gosho

И след това пишем самите правила:

ip rule add from 10.1.1.30 iif lo table pesho
ip rule add from 10.2.2.40 iif lo table gosho

Тук има нужда от малко обяснение – “iif lo” означава “идващи от локалната машина”, останалото е в общи линии просто – ако source адресът е този, гледай конкретната таблица.

До тук е setup-а, ако имате просто една машина и нищо повече…

4) Как се настройва при NAT

Какво правим, ако имаме отзад една мрежичка, да кажем стандартната 192.168.0.0/24, на eth7?

Като за начало, трябва да добавим тази мрежа и в другите две таблици:

for t in pesho gosho; do ip route add 192.168.0.0/24 dev eth7 table $t; done

(някой би написал командите, но ми се е налагало да правя това за 10 таблици и почва да става досадно)

Съответно, да речем, че си имате едни прости правила за nat, които казват, че маскирате трафика навън:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

и някакво правило, че имате някакво web сървърче навътре на 192.168.0.100 порт 8080:

iptables -t nat -A PREROUTING -d 10.1.1.30/32 -i eth0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.168.0.100:80
iptables -t nat -A PREROUTING -d 10.2.2.40/32 -i eth1 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.168.0.100:80

Тук за изходящите връзки, ако решите да смените през кой доставчик, съществуващите ще тръгнат да излизат през новия път (и няма да работят), а ако имате входящи от този, през който не ви е текущия default route, пак ще се опитват да излязат от грешното място, понеже маскирането се случва някъде след routing-а. Решението е т.нар. “CONNMARK”, с който може 1) да маркирате определени връзки, 2) маркировката да се пренася в/у пакетите, и после 3) по маркировката да решавате коя таблица да ползвате.

Това се случва в mangle:

iptables -t mangle -A PREROUTING -i eth0 -m conntrack --ctstate NEW -j CONNMARK --set-xmark 0x1/0xffffffff
iptables -t mangle -A PREROUTING -i eth1 -m conntrack --ctstate NEW -j CONNMARK --set-xmark 0x2/0xffffffff
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff

Тези неща се превеждат като “по единия интерфейс маркирай с 1, по другия с 2, на вход сипвай маркировката от connection-а в пакета (restore-mark), на изход сипвай от пакета на connection-а” (взех ги от един готов save-нат iptables, за това са с тия пълни маски, мисля, че по принцип не бяха нужни). Другото, което трябва е да добавим routing правила, които да взимат решение коя таблица се гледа:

ip rule add fwmark 0x1 table pesho
ip rule add fwmark 0x2 table gosho

5) Load balancing, failover, такива неща

Това е голяма гадост. Писал съм преди по темата за fail-over. Като изключим gwping-а и може би една добавка ако той сменя връзката, понеже е умряла да трепе всичкия state в conntrack-а, нямам какво да добавя.

За load balancing бих препоръчал нещо сравнително статично, определени неща през единия доставчик и други през другия, с нещо, което ги трие, когато изпадне единия доставчик. Бях провеждал експеримент в initLab да правя 2 connection-а през единия доставчик и един през другия или някакви такива неща, резултатът беше доста неприятен.

2017-10-02 OpenFest-овски

Monday, October 2nd, 2017

И малко OpenFest-овски неща.

Имаме списък подадени лекции, от които да се направи програма. На програмния комитет му е полезно мнението на хората, та може да гласувате на vote.openfest.org какво би ви било интересно.

Събираме доброволци за всякаквите екипи. Може да дадете заявка директно тук, все ще ви намерим какво да вършите. Аз лично издирвам някакви хора да настроят малко IP телефони, че все не успявам да стигна до там…

Ще имаме отделен call for hardware, за разни неща, дето не ни достигат (за момента май основно по-големи телевизори и трябва да видя какво стана с радиостанциите).

(най-важния call – да дойдете и да се забавлявате мисля, че няма нужда да се обявява)

2017-09-05 апокрифи 2

Tuesday, September 5th, 2017

Насъбрали са се още апокрифи, та след първата част, ето и втора…

На един мобилен оператор му се строшило нещо по billing-а. Оказал се тежък проблем, и докато го решавали тумбата техничари, се оказало, че от другата страна нещата имат двучасов буфер за CDR-ите и почнали да се drop-ват. Последвали тайно обаждания “звъни където искаш, сега не се отчита”…

Случка, която най-вероятно е позната от личен опит на много хора – един админ щял да си ляга и написал “halt” на лаптопа си. Учудил се, след като 10на минути лаптопа не угаснал, погледнал и открил, че това го бил пуснал на един от сървърите. Последвало ходене в снега посред нощ да го включи обратно.

В древни ISP времена, едно ISP искало да пусне нов ADSL link нанякъде. Имали си един дебел телефонен кабел в мазето, който бил развързан частично на една глава. Та, обадили се те на БТК, дошъл някакъв ядосан чичко, той гледал 5 минути кабела, след което хванал един чифт, казал ядосано “На!” и си тръгнал. Имало 30-40 стърчащи чифта там…

Един друг древен интернет доставчик хванал един програмист да им напише dialer за техните услуги (някакво програмче, което да настрои модеми, account-и и т.н., та да не се мъчи крайния потребител). Та, приложението тръгвало с един wizard, в който първия въпрос бил на какъв език да работи, втория – “приоритет на thread-а”.

Седнали няколко студента да играят sokoban (явно им било скучно). Дошъл им на гости един техен приятел, състезател по информатика (щях да кажа бивш, ама то бивши няма), който видял играта, седнал и написал нещо, което разпознавало нивото на екрана и го решавало.

В още по-древни времена, когато стандартното набиране беше пулсово, един от админите на ISP си звъни на dialup-а и нещо не се връзва. Вдига телефона да чуе какво става и чува някакъв женски глас отсреща. Казва “ама аз очаквах да ми вдигне модем” и отговора отсреща бил “модем съм, модем съм, говори ми”. Бил се преплел със секс телефон…

Като пример, че хората не се научават, на ТРИ пъти DNS зоната на една фирма, host-вана в определено ISP спирала да работи за по няколко часа, защото тамошния админ я редактирал с notepad, записвал я с CR/LF редове, и не забелязвал как nameserver-а отказва да я разбира.

И за завършек, нещо от VFU:
Преди около година .bat + oracle-джийските програмисти от Софийската фирма Б.С. заминават в командировка до град Плевен за да сменят локалната компютърна система на една банка. Пристигат в града, влизат в местния офис на банката; казват, че идват от София; служителите съответно ги пускат; момчетата преконфигурират и преинсталират всичко; инструктират персонала как да работи с новия софтуер.
Каква била изненадата им, когато на излизане поглеждат нагоре и разбират, че са объркали банката!

pgmproxy

Sunday, September 3rd, 2017

На FOSDEM 2016 видео потоците в локалната мрежа бяха носени през UDP, което при загуби по мрежата водеше до разни неприятни прекъсвания и обърквания на ffmpeg-а.

След разговори по темата за мрежа без загуби, пакети, пренасяни от еднорози и изграждане на infiniband мрежа в ULB, бях стигнал до идеята да търся или нещо с forward error correction, или някакъв reliable multicast. За FEC се оказа, че има някаква реализация от едно време за ffmpeg за PRO-MPEG, която не е била приета по някакви причини, за reliable multicast открих два протокола – PGM и NORM.

За PGM се оказа, че има хубава реализация, която 1) я има в Debian, 2) има прилични примери и 3) може да има средно ужасна документация, но source е сравнително четим и става за дебъгване. Измъкнах си старото ttee, разчистих кода от разни ненужни неща и си направих едно тривиално proxy, което да разнася пакети между UDP и PGM (и stdin/stdout за дебъгване). Може да се намери на https://github.com/krokodilerian/pgmproxy, като в момента е в proof-of-concept състояние и единственото, което мога да кажа е, че успявам да прекарам през него един FLAC през мрежата и да го слушам :) Следват тестове в мрежа със загуби (щото в моя локален wifi са доста малко) и доизчистване, че да го ползваме на FOSDEM.