Getkey's blog Interesting stuff, computer related or not 2017-03-13T22:15:56.000Z WundrBar review 58c71a1c465fb53ec6d85e51 2017-03-13T22:15:56.000Z <p><a href="https://order.queal.com/bar/">WundrBars</a> were created to provide the same things as their powder counterpart, in a more convenient format.</p> <p>Before you read this article, you should know that Queal contacted me to ask me if I wanted to review the WundrBars. Because I’m interested in trying out soylent-likes, I gladly accepted, and they sent me some (thanks Laurens!). I’ll try not to be biased though.</p> <p><img src="bar.jpg" alt="wundrbar"/><br/><img src="bar2.jpg" alt="wundrbar"/></p> <h2 id="shipping-and-packaging">Shipping and packaging</h2> <p>Less than a week. Very fast!</p> <p>I think the wrapping paper looks cheap (see the pictures), but what really matters is inside, eh?</p> <h2 id="taste-and-texture">Taste and texture</h2> <p>I only tried the “choco-vanilla” version but there is also another flavor available: “choco-hazelnut”.</p> <p>The texture is akin to nougat. The taste is not that far either, probably due to the vanilla. However it tastes nothing like chocolate.<br/>It is quite sweet but looking at the <a href="https://order.queal.com/bar/">nutritional informations</a> it seems that this is only an impression.<br/>There are some little puffed grains that add crisp to the texture. It is in my opinion a very good idea.</p> <p>The surprising thing is that if you eat too much of it at once (I’d say more than a half), you start to notice a slightly salty aftertaste. It’s still eatable but not as enjoyable. So I recommend taking time when eating, or not to eat the whole bar at once. I actually like to have it on my desk while I work, so that I can take a few bites there and there.</p> <p>It doesn’t feel dry, but made me thirsty nevertheless. I make sure to have a water bottle around when eating.</p> <h2 id="nutritional-aspect">Nutritional aspect</h2> <p>The bars are not as nutritious as the powder: 400kCal versus 700kCal for a powdered meal. But I have been surprised how much energy is packed in these tiny bars. I skied intensely for 3 hours without being hungry, having only eaten one bar for breakfast.</p> <p><img src="front.jpg" alt="ski wundrbar front"/><br/><img src="back.jpg" alt="ski wundrbar back"/></p> <h2 id="bar-vs-powder">Bar vs. powder</h2> <p>The bar format is certainly more convenient than the powder. I ate a WundrBar while walking towards my university without any problems. That wouldn’t have been the case with a powder meal – trust me, I tried too.</p> <p>It is also something you can carry around easily, whereas the powder needs to be carried with a shaker.</p> <p>The price is higher than powder meal. It’s 2.5€ a bar, however a bar is not a full meal.<br/>If you only ate that in a day you’d need 5 bars, which costs 12.5€, versus 7€ for a day worth of Queal powder.</p> <p>I don’t think it would have replaced powder meals for me but when in a rush I’d probably have grabbed a bar if it costed less. Unfortunately I’m a student with limited financial resources so I’ll do without!</p> Getkey getkey@getkey.eu Jake review 589a452c3f7f160945bf716f 2017-02-07T22:07:40.000Z <p><a href="https://jakefood.com">Jake</a> is a Soylent-like manufactured in the Netherlands (like many of them it seems!).<br/>It’s the first one I bought because unlike most of their competitors you can order only one meal, which is perfect to try it out.</p> <h2 id="shipping">Shipping</h2> <p>It took about a month to arrive. At some point, after waiting a few weeks, I was so eager to try a Soylent-like that I ordered some <a href="https://getkey.eu/blog/5839f763/queal">from a competitor</a>, and it actually arrived before.</p> <h2 id="the-price">The price</h2> <p>You can have the sample meal for 5€.<br/>When you buy in bulk it’s about 3€. The more you buy the cheaper it gets so <a href="https://jakefood.com/product/jake-original/">see for yourself</a>.</p> <p>It’s bit more expensive than the other 3 brands I tried, but still reasonable.</p> <h2 id="the-meal">The meal</h2> <p>It’s vegan and lactose-free, which doesn’t appeal particularly to me but it may to you.</p> <p>The taste is… terrible. It is awfully sweet, so much that it makes it a bit nauseating.<br/>It’s kind of like porridge, but with whole a bag of sugar poured into it.</p> <p>The texture on the other hand is fine.</p> <p>I had it at lunch and I wasn’t hungry until dinner so it seems nutritious.<br/>But keep in mind I only had one meal of it, that I only finished for science. Unfortunately my love for science isn’t strong enough for me to try it for a longer period of time.</p> <h2 id="the-packaging">The packaging</h2> <p>The packaging is pretty good. It’s sent in a fancy box.<br/>The bag itself has all the relevant informations in the back, as you can see in the pictures.</p> <p>Also, one bag is one meal. So there is no trouble figuring out proportions, which can be tedious at first. And it’s a bit less work too.</p> <p><img src="jake_box.jpg" alt="box of Jake"/><br/><img src="jake_back.jpg" alt="bag back"/></p> Getkey getkey@getkey.eu WebRTC: the future of web games 5862b0cf3f7f160945bf716e 2016-12-27T18:19:59.000Z <p>At some point in <a href="https://github.com/KordonBleu/jumpsuit">JumpSuit</a>‘s development I realized it was impossible to create the game we envisioned: WebSockets are just too slow, because they sit on top of TCP.</p> <p>While it is possible to write moderately fast-paced games with them, such as the enormously successful <a href="https://agar.io">Agar.io</a> and <a href="http://slither.io/">Slither.io</a>, if you need low-latency, WebSockets won’t cut it.</p> <p>So I started looking for alternatives.</p> <p>WebRTC is currently the only way a browser can exchange with the outside world in UDP-like fashion – disregarding Flash. While it is fairly recent, <a href="http://iswebrtcreadyyet.com/">browser support</a> is decent enough that Facebook Messenger, Skype and Google Hangouts started using it, to only name a few.</p> <p>However, WebRTC has been designed to do P2P VoIP on the browser, not to create game servers. But surprisingly, games benefit greatly from these same features which are essential to VoIP.</p> <h2 id="data-channels-are-awesome">Data channels are awesome</h2> <p>Along with audio and video, WebRTC makes it possible to create <code>DataChannel</code>s that allow sending arbitrary data.</p> <p>While audio and video is transmitted through <a href="https://en.wikipedia.org/wiki/Real-time_Transport_Protocol">RTP</a>, data channels use <a href="https://en.wikipedia.org/wiki/Stream_Control_Transmission_Protocol">SCTP</a>.<br/>SCTP is great because it’s configurable: you can choose whether you want datagrams to be ordered and/or reliable.</p> <p>Fast paced games use UDP because it’s fast, at the expense of orderedness and reliability.<br/>But some datagrams still need to be sent reliably, for example chat messages. Dropping chat messages is definitely <em>not okay</em>! So when using UDP, we end up having to implement reliability on top of it (why we can’t use both TCP and UDP at the same time is outside the scope of this article, but you can <a href="http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/">read the explanation here</a>).</p> <p>Because SCTP is configurable, we can open multiple data channels with different settings, which saves us tons of work!</p> <p>Typically we have:</p> <ul> <li>an unreliable and unordered data channel for game state data and user inputs</li> <li>a reliable and ordered data channel for chat messages, scores and deaths</li> </ul> <h2 id="network-architecture">Network architecture</h2> <p>Okay so let’s say we want a <a href="http://gabrielgambetta.com/fpm1.html#authoritative-servers-and-dumb-clients">client-server</a> architecture, like most modern games.<br/>WebRTC connects peers together. Since it is a protocol for the web, peers are generally browsers – but nothing says your game server can’t be a peer!<br/>There are various libraries that make it possible to use WebRTC on the server. Most of them are wrappers over <a href="https://webrtc.org/native-code/">Chromium’s code</a>.</p> <p>We also want multiple game servers: if the game we are writing is successful, we can expect the load to be too high for a single server. Additionally, we may want to make it possible for random users to host game servers (that’s what we did with JumpSuit). This is advantageous because you won’t have to pay for hosting, and if it is possible for users to make mods, that will increase the longevity of the game. The downside is that you don’t control hundredpercently the gameplay of your game.</p> <p>Generally this is done by having a master server that knows the address of all game servers. To achieve this with a minimal amount of configuration, we can have games server register directly to it.<br/>Then, clients will connect to the master server to request game server addresses.</p> <p>WebRTC peers initially don’t know each other, so they need some way to be introduced. Connection is achieved by exchanging metadata such as addresses, supported codecs (remember, this is a VoIP protocol), etc., in the <a href="https://en.wikipedia.org/wiki/Session_Description_Protocol">SDP format</a>.<br/>WebRTC doesn’t specify how these information are exchanged. It is possible to let the user <a href="https://github.com/ldecicco/webrtc-demos">copy-paste it</a> for example. But I’m sure you’ll agree that’s impractical. So we will create a server that will relay this information through WebSockets. This is called a signaling server. It’s kind of equivalent to a <a href="https://en.wikipedia.org/wiki/BitTorrent_tracker">BitTorrent tracker</a>.</p> <p>Our signaling server is special: it’s also a master server!<br/>When a browser connects to it, the master server sends a list of servers identified by a unique ID, along with other informations about them (such as the geographical location, the game mod, etc.).<br/>Once they are ready, browsers request to be connected to the game server they have chosen. They accompany this request with their SDP, which the signaling/master server routes to the game server. Upon reception, the game server sends its own SDP to be routed to the browser. After some back and forth, the connection is established.</p> <p>This is how our network will look like (black: WebSockets, orange: RTCPeerConnections): <img src="network-topology.svg" alt="network topology"/></p> <p>I created <a href="https://github.com/KordonBleu/enslavism">Enslavism</a>, a framework that make it easy to create such an architecture.</p> <h2 id="other-webrtc-niceties">Other WebRTC niceties</h2> <h3 id="nat-traversal">Nat traversal</h3> <p>As discussed above, the master server’s role is to make the client and a game server communicate, by giving the address of the game server to the client. The thing is, since game server register directly to the master, the address can be valid from the master’s perspective, but not from the client’s.<br/>For example, in prod we had our master server and one game server on the same host. To the master, the game server’s address was therefore <code>127.0.0.1</code>, but of course this address was useless to the client.</p> <p>So we implemented something to pick the correct IP – which was quite some work because of the amount of cases. Well I’m not gonna lie, our thing only worked for common ones.</p> <p>On the other hand, <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Connectivity#What_is_an_ICE_candidate">picking the best IPs</a> is part of the WebRTC connection process, and it’s automatic, so we don’t have to do it ourselves!</p> <h3 id="encryption">Encryption</h3> <p>We had another problem: we wanted our game to be served with HTTPS. And we wanted everyone to be able to host a server, <strong>easily</strong>.<br/>Players were supposed to connect to third party WebSockets on our webpage. But due to <a href="https://en.wikipedia.org/wiki/Same-origin_policy">SOP</a>, players cannot connect to an insecure WebSocket from a HTTPS page.</p> <p>Obviously, we didn’t want people hosting servers to have to go through the involved steps to be issued a TLS certificate. The best we were able to do was to serve the page itself through HTTP, and every resource through HTTPS. Not perfect, but better that nothing.</p> <p>In prod we had to replace every relative reference to a resource with an absolute reference to <code>https://jumpsuit.space</code>, because otherwise it would have fetched it trough HTTP. Conversely, in dev we needed our server to patch the reference to include the resource from the machine itself.</p> <p>This problem is nonexistent with WebRTC, because it <a href="https://webrtc-security.github.io/#4.3.">is secure</a> by default.</p> <h2 id="last-words">Last words</h2> <p>I hope this blog post made you consider using WebRTC for your next web game. I see a lot of potential for it.<br/>I have to warn you though, the server-side WebRTC libraries are not very mature yet. I advise you to do thorough research before building your game.</p> <p>29/12/2016 edit: <a href="https://news.ycombinator.com/item?id=13264952">Hacker News</a> discussion.</p> Getkey getkey@getkey.eu Queal 5839f7636868d169a8a13e40 2016-11-26T20:58:11.000Z <p><a href="https://en.wikipedia.org/wiki/Soylent_%28food%29">Soylent</a> is something I’ve wanted to try for a while, but I only got around to it recently (mostly because I don’t live with my parents anymore).</p> <p>Basically, it’s a powder you blend with water. And BAM, here is your meal.</p> <p>Unfortunately, Soylent is not available in Europe. However, there are plenty of alternatives!<br/>In this series of blog posts, I will try as many as possible - well, not the shady or expensive ones. At the time I write this, I have already tried 3 brands.</p> <p><a href="https://queal.com/">Queal</a> is the first brand I tested, because they are, though not leader, <a href="https://www.instant.ly/report/5762d6e6e4b077dda75559cb#570150e1e4b01f436648be68">well established on the market</a> and to me they seemed more serious and concerned about the quality of their product than some of their competitors.</p> <h2 id="shipping">Shipping</h2> <p>From the Netherlands to France: 5 days! Pretty good if you ask me.</p> <h2 id="the-meal">The meal</h2> <p>I chose the <a href="https://order.queal.com/order/">Taste taster</a>. It contains a bit of every taste.<br/>Sadly the minimum amount of Queal you can buy is worth 49€, I don’t know if it costs them too much to send small quantities, but I’m sure many potential customers are driven off because of this.</p> <p>The taste is not bad. It’s not good either. It tastes a bit like wheat.<br/>For lunch or dinner, it’s acceptable, for breakfast it’s actually pretty good. I especially like the “Cool Chocolate” taste.</p> <p>After drinking it for the first time, I felt full, but I still wanted to chew. It’s weird to have something completely liquid as a meal. Once you get used to it, you start to fell less the need to chew, but I recommend a chewing-gum after your meal until you get accustomed.</p> <p>My gut bacteria had to adjust. I had more gas than usual for a few day, then it got better.</p> <p>Nowadays I mostly take it the morning. I have been able to reduce the time my breakfast takes from 10 minutes to 3 minutes. I’m very much not a morning person so being able to spend 7 more minutes each day in my bed is quite nice.<br/>I also sometimes take it when I know I won’t have enough time for lunch. It’s less expensive than buying a sandwich, healthier and it takes less time!</p> <h2 id="the-portions">The portions</h2> <p>At first I had trouble figuring out how much to eat. Queal comes in tiny bags, each of which contain 3 meals (for an average person).<br/>It is not easy to figure out what are the proportion of water and powder, and the website doesn’t provide much information.<br/>I found an old YouTube video though, where they said it was about 3.5 spoons.<br/>After after some trial and error, I found that 4 spoons suit me better.</p> <h2 id="the-shaker">The shaker</h2> <p>The shaker is pretty good. It has a spiraling wire near the opening, that blends the powder with the water when you shake it. I have seen previous iterations of the shaker where the whisk was a little ball, independent from the shaker. <del>It must have been much less handy.</del> 02/02/2017 edit: I since then had the opportunity to try one such shaker, it’s actually not bad. Stay tuned, I’ll talk about it in a future review!</p> <p>There is a little problem though, in some configurations, some of the powder gets stuck in a hollow in the cap. It happens when the blades of the shaker are right in front of the hole. So just slide it so it isn’t.</p> <p><img src="shaker.jpg" alt="Queal shaker"/></p> Getkey getkey@getkey.eu Hoisting in JavaScript 5734cb21752f56fc41ac0577 2016-05-12T18:27:45.000Z <p>This behavior can surprise beginners to JavaScript, and also, I admit, people like me who learned JavaScript by doing.<br/>So what is hoisting about? Concisely put, it means that every variable declared in a scope is actually declared when entering the scope, <strong>no matter where</strong> you choose to put the declaration.</p> <p>In the following examples I’m going to create a function to define a scope, but this can be applied to every scope, the global scope, a scope you define with <code>{</code> and <code>}</code>, etc.</p> <pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">var</span> bar = <span class="hljs-literal">true</span>; foobar = <span class="hljs-string">"baz"</span>; <span class="hljs-keyword">var</span> foobar; } </code></pre><p>Even in strict mode, this will work because it is equivalent to</p> <pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">var</span> bar, foobar; bar = <span class="hljs-literal">true</span>; foobar = <span class="hljs-string">"baz"</span>; } </code></pre><p>It is important to note that only declarations are hoisted, not initializations.</p> <pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(bar); <span class="hljs-comment">// undefined</span> <span class="hljs-keyword">var</span> bar = <span class="hljs-string">"foobar"</span>; <span class="hljs-built_in">console</span>.log(bar); <span class="hljs-comment">// "foobar"</span> } </code></pre><p>That was what you would expect, but what about this example?</p> <pre><code><span class="hljs-keyword">var</span> foo = <span class="hljs-number">50</span>; <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">var</span> foo = foo + <span class="hljs-number">1</span>; <span class="hljs-built_in">console</span>.log(foo); <span class="hljs-comment">// NaN</span> } </code></pre><p>This is, in fact, the same thing as</p> <pre><code><span class="hljs-keyword">var</span> foo = <span class="hljs-number">50</span>; <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">var</span> foo; <span class="hljs-comment">// at this point `foo === undefined`</span> foo = foo + <span class="hljs-number">1</span>; <span class="hljs-comment">// and `undefined + 1` is NaN</span> <span class="hljs-built_in">console</span>.log(foo); <span class="hljs-comment">// NaN</span> } </code></pre><p>In order to prevent bugs because of this behavior, some developers such as Douglas Crockford recommend that “the <code>var</code> statement should be the first statement in the function body”. I believe this is a bit extreme and it makes the resulting code unorganized. I think it is better to be careful, knowing this rule. You decide.</p> <h2 id="-var-function-and-function-"><code>var</code>, <code>function</code> and <code>function*</code></h2> <p>As we have just seen; before being initialized, a variable declared with <code>var</code> hold the value <code>undefined</code>.</p> <p>It is worth noting that function <strong>declarations</strong> are hoisted, which means that they are <strong>not set to <code>undefined</code></strong>.</p> <pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span>(<span class="hljs-params"></span>) </span>{ baz(); <span class="hljs-comment">// "I am hoisted :D"</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">baz</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"I am hoisted :D"</span>); } } </code></pre><p>Function expressions however, are not. They follow the same rules as everything declared with <code>var</code>.</p> <pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(foo); <span class="hljs-comment">// undefined</span> <span class="hljs-keyword">var</span> foo = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ } } </code></pre><pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">var</span> gen = foo(); <span class="hljs-built_in">console</span>.log(gen.next().value); <span class="hljs-comment">// 0</span> <span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">foo</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) <span class="hljs-keyword">yield</span> i++; } } </code></pre><p>Generator functions declarations behave like function declarations.</p> <h2 id="-let-const-and-class-"><code>let</code>, <code>const</code> and <code>class</code></h2> <p>As we have seen this <del>awful</del> behavior leads to errors. To prevent them, the new ES6 keywords are subject to the TDZ (Temporal Dead Zone). Before the <code>let</code>, <code>const</code> or <code>class</code> statement, instead of being initialized to <code>undefined</code>, variables are actually not initialized.<br/>Because something set to <code>undefined</code> may be initialized, remember? It’s just that it has the value <code>undefined</code>.</p> <pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(foo); <span class="hljs-comment">// ReferenceError: foo is not defined</span> <span class="hljs-keyword">let</span> foo = <span class="hljs-literal">true</span>; } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">barbar</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(foo); <span class="hljs-comment">// ReferenceError: foo is not defined</span> <span class="hljs-keyword">const</span> foo = <span class="hljs-literal">true</span>; } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">barbarbar</span>(<span class="hljs-params"></span>) </span>{ baz = <span class="hljs-keyword">new</span> Foo(); <span class="hljs-comment">// ReferenceError: Foo is not defined</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span> </span>{ } } </code></pre><p>So if you try to access it, you get a <code>ReferenceError</code>, the same way you get an error accessing a variable you haven’t declared.</p> <p>As a sidenote, anything defined with <code>let</code>, <code>const</code> and <code>class</code> is still <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let">hoisted</a>.</p> Getkey getkey@getkey.eu SMS Watchdog 56d895c9fda0924e05d6cd7f 2016-03-03T19:51:37.000Z <p>My mobile carrier offers access to an <a href="https://mobile.free.fr/moncompte/">API that can send SMS</a> to its users. With systemd’s timers, I have been able to make a script that warns me when the load on my server is too high!<br/>Basically, timers work by stating a service repeatedly; which in turn starts a script in this case.<br/>This shell script is responsible for checking the load and sending a SMS. Of course, you can have it send you a mail too. Or tweet it, or whatever - sky’s the limit.</p> <h2 id="the-script">The script</h2> <p>This shell script is in charge of checking the load average and sending a SMS if it’s too high.</p> <p>It is easy to get the load average of the last 5 minutes with the command <code>cat /proc/loadavg | awk &#39;{print $2}&#39;</code>, but we must adjust the trigger depending on the amount on cores on the computer. To do so, <code>nproc</code> works fine, or more portable: <code>grep processor /proc/cpuinfo -c</code> (checks the amount of occurrence of the word “processor” in <code>/proc/cpuinfo</code> and thus the amount of cores).</p> <p>Eventually we compare the load and the trigger limit. There’s a pitfall though: the shell (<code>bash</code> and <code>sh</code> as far as I know, I’ve heard it’s different for zsh) does not work on floating point number, so we need to pipe this computation to <code>bc</code>.</p> <p>Here’s the script I come up with:</p> <pre><code class="lang-sh"><span class="hljs-meta">#!/bin/sh</span> <span class="hljs-built_in">limit</span>=125 <span class="hljs-comment"># Percentage of total load</span> core_nbr=$(grep processor /proc/cpuinfo -c) <span class="hljs-comment"># Amount of core. Equivalent to $(nproc) but more portable</span> trigger=$(<span class="hljs-built_in">echo</span> <span class="hljs-string">"(<span class="hljs-variable">$limit</span> / 100) * <span class="hljs-variable">$core_nbr</span>"</span> | bc <span class="hljs-_">-l</span>) <span class="hljs-comment"># trigger limit, which depends of how many cores you have</span> load=$(cat /proc/loadavg | awk <span class="hljs-string">'{print $1}'</span>) <span class="hljs-comment"># Load average of the last minute</span> <span class="hljs-keyword">if</span> [ $(<span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$load</span> &gt; <span class="hljs-variable">$trigger</span>"</span> | bc) = <span class="hljs-string">"1"</span> ]; <span class="hljs-keyword">then</span> <span class="hljs-built_in">echo</span> <span class="hljs-string">"The load average is very great, I should send you an e-mail"</span> message=<span class="hljs-string">"There is something wrong with your server. The load average is <span class="hljs-variable">$load</span>.%0D%0AAs a reminder, the trigger limit is <span class="hljs-variable">$trigger</span>."</span> <span class="hljs-comment"># %0D%0A is a line break</span> curl <span class="hljs-string">"https://smsapi.free-mobile.fr/sendmsg?user=secret&amp;pass=secret&amp;msg=<span class="hljs-variable">$message</span>"</span> <span class="hljs-keyword">fi</span> </code></pre> <h2 id="timer">Timer</h2> <p><code>/etc/systemd/system/</code> is the directory where every manually added systemd file should go, so this is where you can create a service file called for example <code>getkey-sms-watchdog.service</code>.</p> <pre><code><span class="hljs-section">[Unit]</span> <span class="hljs-attr">Description</span>=Send a SMS if the load average is TOO DAMN HIGH <span class="hljs-section"> [Service]</span> <span class="hljs-attr">ExecStart</span>=/home/getkey/monitor_load_average.sh <span class="hljs-section"> [Install]</span> <span class="hljs-comment"># It's of no use making HTTP requests when there's no Internet access</span> <span class="hljs-attr">Requires</span>=network-<span class="hljs-literal">on</span>line.target <span class="hljs-attr">After</span>=network-<span class="hljs-literal">on</span>line.target </code></pre><p>Now, the timer. It must have the same filename as the service file, except of course the extension which must be “.timer”. So, let’s create <code>getkey-sms-watchdog.timer</code>:</p> <pre><code><span class="hljs-section">[Unit]</span> <span class="hljs-attr">Description</span>=Send a SMS if the load average is TOO DAMN HIGH <span class="hljs-section"> [Timer]</span> <span class="hljs-attr">OnBootSec</span>=<span class="hljs-number">10</span>min # Start first <span class="hljs-number">10</span> minutes after boot <span class="hljs-attr">OnUnitActiveSec</span>=<span class="hljs-number">5</span>min # Then restart every <span class="hljs-number">5</span> minutes <span class="hljs-section"> [Install]</span> <span class="hljs-attr">WantedBy</span>=timers.target </code></pre><p>You can enable all of this by running:</p> <pre><code class="lang-sh">sudo systemctl enable getkey-sms-watchdog.<span class="hljs-keyword">timer</span> # Start <span class="hljs-keyword">on</span> <span class="hljs-keyword">boot</span> sudo systemctl start getkey-sms-watchdog.<span class="hljs-keyword">timer</span> # Enable it <span class="hljs-keyword">for</span> this session, too </code></pre> <p>It is possible to check that the timer is working properly by running <code>systemctl list-timers</code>.</p> <p>And here is a pic of the result!<br/><img src="sms_watchdog_screenshot.png" alt="sms conversation screenshot" title="During a pretty intensive compilation!"/></p> Getkey getkey@getkey.eu Mon projet d'ISN : Mario Kombat 56085e5329d7a6b003df6e15 2015-09-27T21:23:31.000Z <p>Lors de ma dernière année de lycée, dans le cadre de l’option ISN, j’ai réalisé en groupe un projet sur lequel nous avons été notés au Bac (j’ai eu 20/20). À la fin de l’année nous devons rendre un dossier papier, que voici. Je le poste ici car il y a des choses intéressantes dans ce projet (les trucs sur la reliabilité), et de plus il peut sans doute aider les futurs lycéens à s’en inspirer pour structurer leur dossier.</p> <p>Par rapport au projet d’ISN, voilà les conseils que je peux donner:</p> <ul> <li>Mets-toi en groupe avec des gens de même niveau, sinon c’est galère. Si le travail est bien partagé c’est possible de faire des groupes hétérogènes, mais c’est dur de se coordonner</li> <li>Connais bien ton code: il y a toujours des gens qui font du copier-coller mais du coup il savent pas comment leur truc fonctionne et à l’oral ça se voit</li> <li>Faites un truc à votre niveau, sinon vous y arriveriez pas, vous auriez rien à montrer et de toute façon s’il vous reste du temps vous pourrez toujours <a href="https://en.wikipedia.org/wiki/Iterative_and_incremental_development">améliorer votre projet</a></li> <li>Parle vite, les 8 minutes de présentation sont très courtes</li> <li>Si t’es pas à l’aise, révise tes leçons, tu vas avoir des questions dessus</li> <li>Fais d’une pierre deux coup: prépare le dossier correctement, et adapte-le pour l’oral. En plus, tes idées seront bien mieux organisées</li> </ul> <p>Bref, voilà, tel quel, ce que j’ai rendu:</p> <h2 id="-quipe">Équipe</h2> <p>Yvan Le Duff<br/>Ahmed [édité]<br/>Julien Mourer</p> <h2 id="but-du-projet">But du projet</h2> <p>Au moment de commencer un projet, nous ne pensions pas nous mettre ensemble car nous n’avions pas la même expérience de la programmation. Nous avons finalement eu l’idée de créer un jeu en ligne. Cette idée nous a plu car elle avait l’avantage d’être intéressante pour tout le monde: Yvan et Ahmed étaient motivé pour faire le jeu en lui-même, quand à moi j’étais excité à l’idée de faire un serveur; d’autant plus que à peu près un an avant le début du projet j’avais déjà fait une tentative de serveur de jeu (bien plus simple: elle utilisait des WebSockets donc TCP) qui avait été un échec. Ce serveur fonctionnait, mais avait beaucoup d’erreurs de conceptions; j’étais donc décidé à recommencer cette tâche de la bonne façon. C’est ainsi que nous avons commencé “Mario Kombat”, un clone multijoueur de Street Fighter.</p> <h2 id="cahier-des-charges">Cahier des charges</h2> <p>Réaliser un clone multijoueur de Street Fighter.<br/>Les buts fixés pour le client sont les suivants:</p> <ul> <li>2 joueurs</li> <li>Contrôles: gauche, droite, sauter, frapper et parer</li> <li>Prédiction</li> </ul> <p>Les buts fixés pour le serveur sont les suivants:</p> <ul> <li>serveur asynchrone</li> <li>reliabilité</li> <li>serveur autoritaire</li> </ul> <h2 id="r-partition-du-travail">Répartition du travail</h2> <p>Ahmed et Yvan se sont principalement intéressé au moteur du jeu et au game design. Pour ma part je me suis plutôt occupé de la partie réseau, c’est à dire le serveur et le protocole. Évidement il s’agit d’un projet unique dont les différentes parties se recoupent donc nous avons tous été amenés à collaborer.</p> <h2 id="technologies-utilis-es">Technologies utilisées</h2> <h3 id="cot-client">Coté client</h3> <p>Nous avons utilisé Pygame, une excellente bibliothèque de développement de jeux en Python. Elle est la librairie de référence dans son domaine.</p> <h3 id="cot-serveur">Coté serveur</h3> <p>Nous avons utilisé:</p> <ul> <li>Asyncio: pour créer un serveur asynchrone.</li> <li>Protocol Buffers: pour formater les différents messages qui transitent du client au serveur.</li> <li>bitstring: pour le système de ack, il y a besoin de convertir des <code>int</code> en suite de bits et vice-versa.</li> </ul> <h2 id="mise-en-uvre">Mise en œuvre</h2> <h3 id="quel-type-de-serveur-">Quel type de serveur ?</h3> <p>La première chose à laquelle je me suis attaqué à été de créer un serveur. Étant donné que le game engine est écrit en Python, il m’a parut évident de créer ce serveur en Python lui-aussi, car comme vous allez le voir par la suite le game engine est partagé entre le serveur et le client.<br/>Je me suis documenté sur les technique utilisées pour communiquer en réseau avec Python, tout d’abord avec un approche basique avec une boucle principale qui attends que des sockets gérés par le système d’exploitation reçoivent des messages. Ensuite j’ai découvert qu’il était possible d’utiliser un serveur asynchrone grâce à la bibliothèque asyncio, ce qui m’a bien plût car j’ai de l’expérience avec un autre serveur asynchrone, Node.js. Les avantages que j’y ai vu sont les suivants:</p> <ul> <li>scale beaucoup mieux</li> <li>gère les ressources efficacement</li> <li>à mon avis, amène à coder de façon plus élégante</li> </ul> <p>Cependant, les tests que j’avais fait sur un serveur simple n’ont pas été perdus; je les ai réintégré dans le code du client. En effet, celui-ci n’a pas les même besoins que le serveur, asyncio serait ici superflu. Une implémentation simple est ici bien plus légère et élégante.</p> <h3 id="s-rialisation">Sérialisation</h3> <p>Une fois le serveur fonctionnel, j’ai pu m’atteler à la suite: la sérialisation. Jusqu’alors j’avais un serveur capable de recevoir les messages des clients et de les informer du game state à une fréquence définie (en l’occurrence 33ms). Il a donc fallu être en mesure d’utiliser ces messages. De nombreux types de messages peuvent être échangés entre le client et le serveur, par exemple les messages renseignant sur la position des joueurs, les messages du chat, etc.<br/>J’ai donc utilisé <em>Protocol Buffers</em> qui gère le formatage des donnés. Avant d’être envoyées, les données vont être formatées selon un certain schéma qui va permettre d’envoyer des message divers en un minimum de bits. Il faut être efficace en programmation réseau ! Ensuite, ces données sont déserialisées selon ce même schéma.<br/>Voici un exemple de “schéma”:</p> <pre><code class="lang-protobuf"><span class="hljs-class"><span class="hljs-keyword">message</span> <span class="hljs-title">Datagram</span> </span>{ <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Type</span> </span>{ INPUT = <span class="hljs-number">1</span>; CHAT = <span class="hljs-number">2</span>; NICKNAME = <span class="hljs-number">3</span>; } <span class="hljs-keyword">required</span> Type type = <span class="hljs-number">1</span>; <span class="hljs-keyword">required</span> Ack ack = <span class="hljs-number">2</span>; <span class="hljs-keyword">optional</span> <span class="hljs-built_in">uint32</span> reliable = <span class="hljs-number">3</span>;<span class="hljs-comment">// if we want to get back an ack</span> extensions <span class="hljs-number">4</span> to max; } <span class="hljs-class"><span class="hljs-keyword">message</span> <span class="hljs-title">Ack</span> </span>{ <span class="hljs-keyword">required</span> <span class="hljs-built_in">uint32</span> ack = <span class="hljs-number">2</span>; <span class="hljs-keyword">required</span> <span class="hljs-built_in">bytes</span> ackfield = <span class="hljs-number">3</span>; } <span class="hljs-class"><span class="hljs-keyword">message</span> <span class="hljs-title">Input</span> </span>{ extend Datagram { <span class="hljs-keyword">optional</span> Input input = <span class="hljs-number">5</span>; } <span class="hljs-keyword">required</span> <span class="hljs-built_in">uint32</span> key = <span class="hljs-number">1</span>; } <span class="hljs-class"><span class="hljs-keyword">message</span> <span class="hljs-title">Chat</span> </span>{ extend Datagram { <span class="hljs-keyword">optional</span> Chat chat = <span class="hljs-number">6</span>; } <span class="hljs-keyword">required</span> <span class="hljs-built_in">string</span> msg = <span class="hljs-number">1</span>; } <span class="hljs-class"><span class="hljs-keyword">message</span> <span class="hljs-title">Handshake</span> </span>{ extend Datagram { <span class="hljs-keyword">optional</span> Handshake handshake = <span class="hljs-number">7</span>; } <span class="hljs-keyword">required</span> <span class="hljs-built_in">string</span> nickname = <span class="hljs-number">1</span>; } </code></pre> <p>Une fois formatées, les donnés prennent la forme d’une suite de bytes comme ceci: <code>b&quot;\x08\x02\x12\x04\x08\x1e\x10d*?\n\x15\n\x0bJean-Pierre\x12\x06Salut.\n&amp;\n\x06P\xc3\xa9p\xc3\xa9\x12\x1cMregn\xc3\xa9 d&#39;mon temps...mrbmmr&quot;</code>, que l’on va pouvoir incorporer dans un datagramme UDP.</p> <p>J’ai beaucoup réfléchi avant de choisir <em>Protocol Buffers</em>. Voici mes critères de sélection:</p> <table> <thead> <tr> <th>Avantages</th> <th>Protocol Buffers</th> <th>Avro</th> <th>JSON</th> <th>Pickle</th> </tr> </thead> <tbody> <tr> <td>Standard</td> <td>Non</td> <td>Non</td> <td>Oui</td> <td>Oui</td> </tr> <tr> <td>Sécurité</td> <td>Oui</td> <td>Oui</td> <td>Oui</td> <td>Non</td> </tr> <tr> <td>Expérience préalable</td> <td>Non</td> <td>Non</td> <td>Oui</td> <td>Non</td> </tr> <tr> <td>Efficace</td> <td>Oui</td> <td>Moins que protobuf</td> <td>Moins que Avro</td> <td>Non testé</td> </tr> <tr> <td>Peu error-prone</td> <td>Oui</td> <td>Oui</td> <td>Non</td> <td>Non</td> </tr> <tr> <td>Bien supporté</td> <td>Oui</td> <td>Non</td> <td>Oui</td> <td>Non</td> </tr> </tbody> </table> <p>J’ai éliminé Pickle directement car les message reçus sont exécutés directement par Python, ce qui pose un énorme problème de sécurité pour un jeu en ligne. JSON n’était pas un bon choix au niveau de l’efficacité. J’ai beaucoup hésité entre Avro Et Protocol Buffers, mais ce dernier à une masse d’utilisateur très conséquente, donc un bon support, ce qui m’a convaincu.</p> <h3 id="reliabilit-">Reliabilité</h3> <p>Le serveur utilise UDP, qui est un protocole très rapide et bien adapté aux jeux en réseau. Mais ce protocole de transport a une caractéristique qui peut causer problème dans certaines situations: certains datagramme peuvent ne jamais arriver. Nous avions étudiés en cours les différences, avantage et inconvénient de ces protocoles. TCP lui assure que les messages (segments) sont bien reçus, mais est bien plus lent et consomme plus de bande passante. Il aurait été possible d’utiliser les deux: TCP pour les messages reliables et UDP pour le reste. Mais cette approche cause quelques soucis en pratique, détaillés <a href="https://www.isoc.org/INET97/proceedings/F3/F3_1.HTM">ici</a>. Il est donc plus malin d’implémenter la reliabilité (utilisée bien sûr uniquement pour certains messages) au-dessus de UDP.</p> <p>Pour s’assurer qu’un message avec un certain ID a été reçu, le receveur renvoie habituellement un ack (abréviation de acknowledgment), un message qui contient le même ID. L’envoyeur, à la réception du ack est assuré que le receveur à reçu son message.<br/>Mais que se passe-t’il si le ack est perdu ?<br/>Le système que j’ai utilisé est redondant: il envoie le ack plusieurs fois pour s’assurer qu’au moins un ack sera reçu. Pour cela, chaque message, quel qu’il soit contient une liste des 33 précédents acks.<br/>Pourquoi 33 ?<br/>Admettons que les acks envoyé sont des uint32. Il prennent donc 32 bits de place. Si l’on veut en envoyer 33 par paquet, cela va donc prendre 1056 bits, ce qui est loin d’être optimal.<br/>Pour stocker de multiples acks en peu de place, on ne va pas tous les entrer un à un mais plutôt entrer le dernier ack reçu suivi d’un bitfield (une suite de 0 et de 1). Chaque chiffre de cette suite représente si les acks précédents ont été reçu ou non dans l’ordre du plus récent au moins récent. Tout message contient donc -en plus du reste- un uint32, par exemple <code>5584</code> et un bitfield (géré par la librairie Bitstring), par exemple <code>00000000000000000000000001000001</code> qui sera traduit en décimal par <code>65</code>. On peut donc assurer la reliabilité en ajoutant seulement 64 bits supplémentaires à chaque paquet.</p> <h3 id="serveur-autoritaire">Serveur autoritaire</h3> <p>Un gros challenge avec Mario Kombat est qu’il s’agit d’un jeu d’action rapide. Lorsqu’il est joué en ligne, il va falloir éliminer les lags qui pourraient affecter le gameplay. Une solution naïve serait de calculer toutes le données chez le client puis de les envoyer au serveur qui les distribuerait aux clients. Cependant, il serait alors très facile à un tricheur d’envoyer les données qu’il veut, pour par exemple se téléporter. J’ai donc choisi de développer un architecture avec un serveur autoritaire, c’est à dire que les clients envoient uniquement les touches sur lesquelles ils ont appuyés, et le serveur se charge à partir de ces données de gérer la physique du jeu. Il va ensuite renvoyer le game state à tout les joueurs (par exemple: les positions de tout le monde, s’il sont en train de frapper ou de parer, etc.).<br/>Le problème de cette architecture, c’est qu’elle génère du délai car il faut attendre après chaque input d’être notifié des nouvelles positions physique des objets.<br/>Prenons l’exemple d’un client qui à 50ms de ping, ce qui est des assez bonnes conditions sur un réseau à grande échelle tel qu’Internet. Si le joueur veut frapper, il faudra attendre 100ms, le temps que le message parte vers le serveur et que le serveur envoie un game state mis à jour. Dans un jeu de combat de ce type, 100ms de délai sont très visibles et risque de rendre le jeu difficile à jouer. D’autant plus que pour cette simulation nous n’avons pas pris en comte les délais généré par le serveur: celui-ci ne rafraîchit le game state que toutes les 33ms.</p> <h3 id="pr-diction">Prédiction</h3> <p>Pour résoudre le problème sus-mentionné, nous avons implémenté de la prédiction coté client. Le principe est simple: le client suppose l’état du jeu avant d’en recevoir la confirmation du serveur. Dans l’exemple précédent, quand le jouer appuie sur la touche “frapper”, le client va afficher le personnage en train de frapper. Si tout ce passe bien, 100ms plus tard, il va recevoir du serveur la confirmation qu’il était bien en train de frapper. Mais le serveur à toujours le dernier mot: si le client à fait une erreur dans sa prédiction, il va devoir se mettre à jour avec le serveur. Bien que cela risque de se voir, cette situation arrive en pratique très peu souvent et ne posera donc pas problème.</p> <h2 id="difficult-s">Difficultés</h2> <p>J’ai eu beaucoup de mal à comprendre au premier abord la documentation de asyncio, cette librairie est très jeune (incluse dans la librairie standard lors de la sortie de la dernière version: 3.4) et il y a encore peu de documentation autre que la documentation officielle.</p> <p>Comme dit précédemment, Protocol Buffers est très bien supporté, seulement, il supporte uniquement quelques langages officiellement. Python l’est, mais dans sa version 2 qui est incompatible avec la version 3 que nous avons choisie pour ce projet.<br/>J’ai donc été amené à utiliser une librairie tierce, dans laquelle j’ai trouvé deux bugs, ce qui m’a causé quelques soucis. J’ai utilisé des workarounds pour arriver à ce que je voulais en dépit de ces bugs. J’ai aussi contacté l’auteur de cette implémentation de Protocol Buffers pour lui signaler et éventuellement lui proposer des solutions afin de fixer ceux-ci. Je n’ai pour l’instant pas eu de réponses.</p> <h2 id="annexe">Annexe</h2> <p>Le code du jeu est disponible <a href="https://github.com/Getkey/mario-kombat"><strong>ici</strong></a>. Avant d’y jouer il va vous falloir installer Pygame. Je déploierai un serveur à l’adresse suivante: <strong>getkey.eu:9876</strong>.</p> <h2 id="d-veloppements-futurs-">Développements futurs ?</h2> <p>Les concepts suivants pourront être ajoutés pour réduire encore plus la latence:</p> <ul> <li>Flow control: adapter le nombre de datagrammes envoyé par seconde à la connexion du joueur</li> <li>Réconciliation au serveur: pour minimiser les micro-téléportations du personnage du joueur qui peuvent apparaître lorsqu’il y a du lag</li> <li>Interpolation d’entités: pour supprimer les micro-téléportations des autres joueurs lorsqu’il y a du lag</li> <li>Compensation de lag: pour empêcher les deux techniques précédentes de créer des problèmes</li> </ul> <h2 id="lecture">Lecture</h2> <p>Si ces quatre dernières techniques éveillent votre curiosité, vous pouvez lire les <a href="http://gabrielgambetta.com/fast_paced_multiplayer.html">écrits de Gabriel Gambetta</a> ainsi que les <a href="http://gafferongames.com/networking-for-game-programmers/">articles de Glenn Fiedler</a>.<br/>Vous y retrouverez d’autre techniques que j’ai utilisé pour ce projet, et dont j’ai parlé. En effet, le travail réalisé pour ce projet est en bonne partie basé sur des concepts développés par ces auteurs, et je les en remercie.</p> Getkey getkey@getkey.eu A virtual webcam 55106b9fa21ed0040133c184 2015-03-23T19:38:07.000Z <p>There are a lot of fun things you can do with Linux. What I propose you today is to stream an arbitrary video as if it were your webcam and microphone output.</p> <h2 id="some-sort-of-disclaimer">Some sort of disclaimer</h2> <p>Okay, so the draft of this blog post has been sitting on my hard drive for months now, and if I don’t post it yet, I’ll never post it. The reason I didn’t is because it is incomplete, as there’s a tiny something I don’t understand. I lost interest in this so I won’t look for the solution myself, but if you find it you’re welcome to share it with me! Anyway, let’s see this.</p> <h2 id="setup-a-virtual-webcam">Setup a virtual webcam</h2> <p>First, install <a href="https://github.com/umlaeute/v4l2loopback">v4l2loopback</a>. It’s a kernel module for Linux we will use to create a virtual webcam.</p> <p>Then we will check for already existing webcams. Like almost every devices in UNIX, they’re located in <code>/dev/</code> and their names are <code>video</code> followed by a number.</p> <pre><code class="lang-console">$ ls <span class="hljs-regexp">/dev/</span> | <span class="hljs-keyword">grep</span> video video0 </code></pre> <p>We see here that I have one webcam: <code>video0</code>.</p> <p>Let’s load v4l2loopback:</p> <pre><code class="lang-console"><span class="hljs-meta"># modprobe v4l2loopback</span> </code></pre> <p>Now we’ll see if our virtual webcam is there:</p> <pre><code class="lang-console">$ ls /dev/ | grep video vide<span class="hljs-meta">o0</span> vide<span class="hljs-meta">o1</span> </code></pre> <p>Yes, it is!</p> <h2 id="setup-a-virtual-microphone">Setup a virtual microphone</h2> <p>Actually, we won’t create a microphone, we’ll create a soundcard. Microphones are handled by soundcards, which deal with the collected data.<br/>To create a virtual soundcard we will proceed similarly as we did with the webcam, first we list the connected soundcards:</p> <pre><code class="lang-console">$ cat /<span class="hljs-keyword">proc</span>/asound/cards 0 [Intel ]:<span class="hljs-title"> HDA-Intel</span> -<span class="hljs-title"> HDA</span> Intel<span class="hljs-title"> HDA</span> Intel<span class="hljs-title"> at</span> 0xfdff4000<span class="hljs-title"> irq</span> 27 1 [NVidia ]:<span class="hljs-title"> HDA-Intel</span> -<span class="hljs-title"> HDA</span> NVidia<span class="hljs-title"> HDA</span> NVidia<span class="hljs-title"> at</span> 0xfcffc000<span class="hljs-title"> irq</span> 17 2 [H2300 ]:<span class="hljs-title"> USB-Audio</span> -<span class="hljs-title"> HP</span> Webcam<span class="hljs-title"> HD</span> 2300<span class="hljs-title"> Hewlett</span> Packard<span class="hljs-title"> HP</span> Webcam<span class="hljs-title"> HD</span> 2300<span class="hljs-title"> at</span> usb-0000:00:1a.7-5,<span class="hljs-title"> high</span> speed </code></pre> <p>As you see, I have three soundcards.</p> <p>Next we load the kernel module:</p> <pre><code class="lang-console"><span class="hljs-meta"># modprobe snd-aloop</span> </code></pre> <p>And then, I got a new soundcard!</p> <pre><code class="lang-console">$ cat /<span class="hljs-keyword">proc</span>/asound/cards 0 [Intel ]:<span class="hljs-title"> HDA-Intel</span> -<span class="hljs-title"> HDA</span> Intel<span class="hljs-title"> HDA</span> Intel<span class="hljs-title"> at</span> 0xfdff4000<span class="hljs-title"> irq</span> 27 1 [NVidia ]:<span class="hljs-title"> HDA-Intel</span> -<span class="hljs-title"> HDA</span> NVidia<span class="hljs-title"> HDA</span> NVidia<span class="hljs-title"> at</span> 0xfcffc000<span class="hljs-title"> irq</span> 17 2 [H2300 ]:<span class="hljs-title"> USB-Audio</span> -<span class="hljs-title"> HP</span> Webcam<span class="hljs-title"> HD</span> 2300<span class="hljs-title"> Hewlett</span> Packard<span class="hljs-title"> HP</span> Webcam<span class="hljs-title"> HD</span> 2300<span class="hljs-title"> at</span> usb-0000:00:1a.7-5,<span class="hljs-title"> high</span> speed 3 [Loopback ]:<span class="hljs-title"> Loopback</span> -<span class="hljs-title"> Loopback</span> <span class="hljs-title"> Loopback</span> 1 </code></pre> <p>It’s the one called Loopback, remember its number: 3.</p> <h2 id="stream-video-to-the-virtual-webcam">Stream video to the virtual webcam</h2> <h3 id="video-only">Video only</h3> <p>We’ll use <code>ffmpeg</code> to extract a stream from a file and input it to the virtual webcam, in this case <code>/dev/video1</code>. You don’t have to, but you should read at least its synopsis.</p> <pre><code class="lang-console">$ ffmpeg -re -<span class="hljs-selector-tag">i</span> <span class="hljs-string">'your/file.avi'</span> -f v4l2 /dev/video1 </code></pre> <p>If it doesn’t work, you’ll have to explicitly set options for the input file, read <code>ffmpeg</code>‘s manpage to know those.</p> <h3 id="sound-only">Sound only</h3> <p>Ok, this is the part I’m unsure about. I don’t get why I have to specify <code>,1</code> in <code>hw:3,1</code> . If this setting doesn’t work for you, well, try trial and error. And I you know why it’s this and not anything else, I’ll be glad to hear why!</p> <pre><code class="lang-console">$ ffmpeg -<span class="hljs-selector-tag">i</span> some/test/file<span class="hljs-selector-class">.mp3</span> -f alsa hw:<span class="hljs-number">3</span>,<span class="hljs-number">1</span> </code></pre> <h3 id="both-sound-and-video">Both sound and video</h3> <p>First, list your streams with <code>ffprobe</code>, you’ll get something like this:</p> <pre><code class="lang-console">$ ffprobe your/file.avi Stream #0:0: Video: mpeg4 (Advanced Simple Profile) (XVID / 0x44495658), yuv420p, 512x384 [SAR 1:1 DAR 4:3], 1005 kb/s, 29.97 fps, 29.97 tbr, 29.97 tbn, 29.98 tbc Stream #0:1: Audio: mp3 (U[<span class="hljs-string">0</span>][<span class="hljs-symbol">0</span>][<span class="hljs-string">0</span>] / 0x0055), 48000 Hz, stereo, s16p, 133 kb/s </code></pre> <p>It means that the first stream of the first file (<code>#0:0</code>) is an video whereas the second (<code>#0:1</code>) is the audio stream.</p> <p>And then you can use this with ffmpeg’s option <code>-map</code> to specify where to output respectively the video stream and the audio stream:</p> <pre><code class="lang-console">$ ffmpeg -i <span class="hljs-string">"your/file.avi"</span> -<span class="hljs-keyword">map</span> <span class="hljs-number">0</span>:<span class="hljs-number">0</span> -<span class="hljs-keyword">f</span> v4l2 /dev/video1 -<span class="hljs-keyword">map</span> <span class="hljs-number">0</span>:<span class="hljs-number">1</span> -<span class="hljs-keyword">f</span> alsa h<span class="hljs-variable">w:3</span>,<span class="hljs-number">1</span> </code></pre> <p>And that’s it! now you have a virtual webcam and a virtual microphone you can use, for example, to stream videos on videochats.</p> Getkey getkey@getkey.eu Privilege escalation with setuid 541346ddaf9c9a2a7f4068f4 2014-09-12T19:17:49.000Z <h2 id="what-are-setuid-and-setgid-">What are setuid and setgid?</h2> <p>When applied on executable (and shell scripts if it’s not disabled), setuid is a mechanism in UNIX systems to allow an user to execute a program with the owner’s permissions. Setguid is the same principle, but we get the group permission instead of the user’s.<br/>If you want too know more about it or setgid (that we won’t use), read the <a href="https://en.wikipedia.org/wiki/Setuid">Wikipedia article</a>.</p> <p>In this article we will create a C program we will run as a normal user, and thanks to setuid it will spawn for us a shell (as root!).</p> <h2 id="the-code">The code</h2> <p>Here’s the code:</p> <pre><code class="lang-C"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;unistd.h&gt;</span></span> <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{ setuid(<span class="hljs-number">0</span>); execl(<span class="hljs-string">"/bin/bash"</span>, <span class="hljs-string">"bash"</span>, (<span class="hljs-keyword">char</span> *)<span class="hljs-literal">NULL</span>); <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; } </code></pre> <p><code>#include &lt;unistd.h&gt;</code> This library is needed to get <code>setuid()</code> and <code>execl()</code>.<br/><code>setuid(0)</code> We get privileges from the user 0, ie root.<br/><code>execl(&quot;/bin/bash&quot;, &quot;bash&quot;, (char *)NULL);</code> Our program executes <code>/bin/bash</code>. The parameter <code>&quot;bash&quot;</code> is the filename of the program we execute, passing it is a convention.<br/><code>(char *)NULL)</code> The manual says our last argument must be a null pointer. This weird formula is the multiplatform version.</p> <p>That’s it. Pretty simple, uh?</p> <h2 id="let-s-try-it-">Let’s try it!</h2> <p>Okay, now that we have our C source, we compile it:<br/><code>$ gcc -Wall trickyty.c -o trickyty</code> (my source file is trickyty.c).</p> <p>Remember? The program must be owned by the setuided user, in this case: root.</p> <pre><code class="lang-console"><span class="hljs-variable">$ </span>sudo chown root trickyty </code></pre> <p>And the program must have the setuid bit turned on.</p> <pre><code class="lang-console"><span class="hljs-variable">$ </span>sudo chmod u+s trickyty </code></pre> <p>A little check to see if everything’s good:</p> <pre><code class="lang-console">$ ls -l trickyty -rwsr-xr-x<span class="hljs-number"> 1 </span>root users<span class="hljs-number"> 6894 </span>11 sept. 22:05 trickyty </code></pre> <p>See the <code>s</code> in the permissions? It’s the setuid bit.</p> <p>Time to execute our program!</p> <pre><code class="lang-console"><span class="hljs-variable">$ </span>./trickyty <span class="hljs-comment"># whoami</span> root </code></pre> <p>Yes, we are root now!</p> <p>Note that if you put your program on a removable drive and plug it in another computer, it won’t work if said drive is mounted with the <code>nosuid</code> option.</p> Getkey getkey@getkey.eu Hyphens in UNIX's filenames 53e4d7e0af9c9a2a7f4068f3 2014-08-08T14:00:00.000Z <p>Today I discovered an interesting UNIX design flaw. UNIX deals badly with files starting with <code>-</code>. Let’s mess around!</p> <p>Warning: do like me, create a new directory and <code>cd</code> into it.</p> <pre><code class="lang-console">$ mkdir tests &amp;&amp; cd tests $ <span class="hljs-keyword">touch</span> -r <span class="hljs-keyword">touch</span>: usage: <span class="hljs-keyword">touch</span> [-alm] [-t time_t] &lt;<span class="hljs-keyword">file</span>&gt; </code></pre> <p>Okay, so I can’t create a file starting with a <code>-</code>, because <code>touch</code> thinks it’s an argument. There are several ways around to create this file:</p> <ul> <li><pre><code class="lang-console"><span class="hljs-variable">$ </span>touch ./-r </code></pre> <p>Here you give it a path, so that the first argument <code>touch</code> gets is not a <code>-</code>. The path here (<code>./</code>) is a relative path, it’s the directory I’m currently in.<br/>That’s the best method, but there are others.</p> </li> <li><pre><code class="lang-console">$ touch <span class="hljs-comment">-- -r</span> </code></pre> <p>Some touch implementations allow the user to write <code>--</code> between the options and the filename. This method doesn’t work everywhere, not with BusyBox for example, that’s why I prefer the method above.</p> </li> <li><pre><code class="lang-console"><span class="hljs-variable">$ </span>touch r <span class="hljs-variable">$ </span>mv r -r </code></pre> <p>This also works.</p> </li> </ul> <p>Okay, whatever the reason to create that file is, I finally have it. Yay!<br/>Create a directory, we’ll see after why.</p> <pre><code class="lang-console"><span class="hljs-symbol">$</span> mkdir tre <span class="hljs-symbol">$</span> ls -l ----rwxr-x <span class="hljs-keyword">system</span> sdcard_rw <span class="hljs-number">0</span> <span class="hljs-number">2014</span><span class="hljs-number">-08</span><span class="hljs-number">-03</span> <span class="hljs-number">15</span>:<span class="hljs-number">22</span> -r d---rwxr-x <span class="hljs-keyword">system</span> sdcard_rw <span class="hljs-number">2014</span><span class="hljs-number">-08</span><span class="hljs-number">-03</span> <span class="hljs-number">15</span>:<span class="hljs-number">22</span> tre </code></pre> <p>Everything’s there, that’s cool, but now I want to delete everything in the directory, except subdirectories.</p> <pre><code class="lang-console"><span class="hljs-symbol">$</span> rm * <span class="hljs-symbol">$</span> ls -l ----rwxr-x <span class="hljs-keyword">system</span> sdcard_rw <span class="hljs-number">0</span> <span class="hljs-number">2014</span><span class="hljs-number">-08</span><span class="hljs-number">-03</span> <span class="hljs-number">15</span>:<span class="hljs-number">22</span> -r </code></pre> <p>Wait, what ? <code>-r</code> should have been deleted, not the directory <code>tre</code>!<br/>In fact, when I run that command, the shell transforms <code>*</code> into the list of files in the directory, then gives it to the program. In that case, there’s one file: <code>-r</code>, but the program <code>rm</code> has no way of knowing that <code>-r</code> is a file, not an argument. And even if you have other files in your directory, filenames starting with <code>-</code> always are first in the list of arguments, that’s standard.</p> <p>It’s the end of this article, let’s delete that file!</p> <pre><code class="lang-console">$ <span class="hljs-keyword">rm</span> -<span class="hljs-built_in">r</span> $ <span class="hljs-keyword">ls</span> -<span class="hljs-built_in">r</span> </code></pre> <p>Oh…<br/>Yes, method for creating and deleting that kind of files are the same, obviously this doesn’t work. But now it shouldn’t be hard for you to delete it, right?</p> Getkey getkey@getkey.eu