notryan - blog https://blog.notryan.com A text-only blog about technology... and stuff. https://blog.notryan.com/rss.c Thu, 04 Jan 2024 20:16:56 -0800 Plaintext Blogs https://blog.notryan.com/001.txt =============================================================================== blog.notryan.com/001.txt Tue, 21 Jan 2020 Ryan Jacobs 06:15:00 -0800 Plaintext Blogs . . . . . . . . =============================================================================== I've tried to start a blog several times, but I always get fed up with the formatting and/or the build process. See, I'm always thinking about longevity. I'm thinking about: how should I build something to last? Well, text lasts forever. So I should stick to Markdown right? Tentatively, that answer is yes. But then, I get stuck in the build process again. Which Markdown compiler should I use? How do I plan on styling the resultant HTML. When I embed images, will they fit cleanly on the screen? I want to store the original 3.5 MB JPEG, but that doesn't seem okay for web... so I need/should incorporate plugins to compress them. For a while, I settled on Eleventy for all of this. And it looked great! But... it wasn't perfect... And I'm not exactly sure why yet. I can't quite put my finger on it yet, but I will follow up when I can. I think it's something to do with longevity. I'm not 100% confident that the framework and its dependencies will be around in 10 years. It's so many layers of complexity to deliver text in a pretty manner. But for right now, I am settling on this medium: words on a screen. I am settling on files with .txt extensions. Specifically, UTF-8 files with mainly ASCII characters (and Unix line-endings). My ideal blog has a couple of facets. Ideally, I will have a series of "threads". For example, I want to try a week without artificial electrical lighting in my bedroom. And I also want to post intermittently on my DIY laundry machine detector. But I'm afraid that it will be hard to follow these intertwined (in respect to time) posts. (Blogs are typically sorted by datestamps.) So I'm proposing two types of blog entries: epoch-oriented and thread-oriented. Anyways, I'm glad I wrote this down. I'm glad that I'm writing again. --- As much as I enjoy the avoidance of build systems, I created a dead simple one for this blog. In this case, the benefits of having an index of entries outweighs the cost of inaccessibility. Here are the specifications for my blog, as it exists in the version-controlled source repository: I have a folder with .txt files. The blog entries are named 1.txt, 2.txt, 3.txt, etc. A script named `build.sh` produces an HTML file `index.html` that contains hyperlinks to the blog entries. The links' text content use the scraped titles in the .txt file headers. The header ends when we encounter three or more dashes. The title is the line before the dashes. Look at the top of this entry for reference as to what a header looks like. Right now there are only four lines, so my script just grabs the fourth line for the header. In the future, some dynamicism might need to be added if I decide to add optional header fields. (Check out the script by visiting https://blog.notryan.com/build.sh) I have decided to not name files by their blog title for a couple of reasons. First of all, sorting gets tricky when the filenames can be anything. I want everything to be in chronological order when I type `ls` into my shell. Sure, I could prefix the filename with a datestamp such as "21_Jan_2019" but this wouldn't work because `ls` has no concept of months or date formats. "2019-01-21" would probably work. However, my second gripe is that blog titles/dates can change. It's rare, but sometimes I want to change a title. There are two titles to change: the internal one within the file contents and the filename itself. Since the URL is based on the filename and not the internal blog title, the supposed permalink doesn't change (nor should it). Permalinks aren't supposed to change. If I email a particular post to a friend, they should still be able to click on that link a year from now. The easiest away to get around this is to have a unique non-changing name/id for each post. That link should be valid forever. https://example.com/blog/421 should always point to that entry, even if I change the posting date or the title. `https://example.com/blog/how-to-write-fizz-buzz` is bad. If I decide after posting that "FizzBuzz" should be one word, then I need to change the title (or else I won't sleep at night). I will need to first change the title internally, which is fine. But then when it comes to updating the filename, the URL will change too. Sure, there are all types of patching I could do. I could create a symlink to redirect `how-to-write-fizz-buzz.txt` to `how-to-write-fizzbuzz.txt`. I could also just leave the filename alone and ignore the slightly different URL. Anyways, these all seem like kludges to me. It might be slightly worse for SEO, but it'll be a hell of a lot easier for maintenance to save my blog entries as numeric ids. Plus, if some *nix freak wants to download my blog programmatically, they can run `wget https://blog.notryan.com/{1..99}.txt`. On my to-do list: embedding images in a backwards compatible way. I want to keep my 80 columns of text width format, so I'll probably render images at 80em or 80ch. I will most likely produce a corresponding HTML file that is a one-to-one copy of each .txt document. Detected URLs will become hyperlinked <a> tags and images will be rendered as <img> tags. This is starting to sound an awful lot like Markdown... but I swear it's not. I want something that uses text for everything except for features that are impossible to implement in text, such as images. Bullet points and headers are definitely possible in ASCII. Hell, flowcharts are possible in ASCII. ]]> Tue, 21 Jan 2020 06:15:00 -0800 001.txt Some Candle Volts https://blog.notryan.com/002.txt =============================================================================== blog.notryan.com/002.txt Wed, 22 Jan 2020 Ryan Jacobs 06:36:00 -0800 Some Candle Volts . . . . . . . . . =============================================================================== A friend laughed at me at a party when I told him that I get turned on by solid-state electronics. But I do! They're great for longevity. I hate relying on moving parts. Hard drives scare the shit out of me. Loud whirring fans annoy me to no end. They're cool and all, but *no moving parts* is the holy grail. Anyways, yesterday I received a pack of 10 Peltier junctions. Their primary purpose is to produce a temperature differential between the two sides, e.g. cool something without compression. But they work in both directions, kind of how like a motor can be driven with a voltage *or* produce EMF themselves when driven by an external force. Peltier junctions can be used used to create voltages from temperature differentials. I used one (along with some thermal paste and a beefy heatsink) to produce about 1.5 V from a lit candle I purchased from Target! Granted, the 1.5 V dropped to 0.6 V after a couple of minutes, as the temperature saturated the junction. Adding a little bit of water to the "cold" side using a dropper caused the voltage to bump back up to 1 V for about 30 seconds. A larger cooling body would probably allow you to harvest more energy until it saturated as well. ]]> Wed, 22 Jan 2020 06:36:00 -0800 002.txt Reclaiming the Cell Phone https://blog.notryan.com/003.txt =============================================================================== blog.notryan.com/003.txt Sat, 04 Apr 2020 Ryan Jacobs 21:30:00 -0700 Reclaiming the Cell Phone . . . . . . . . . . . . . =============================================================================== There are two projects I want to kick off soon. Number one is removing all technology from my bedroom. (Maybe only for certain hours to force me to concentrate my usage on actually useful activities? Or maybe I'll pick up a beatup x61 Thinkpad that can't do anything other than text.) And number two is migrating away from my iPhone. I would love, love, love if I had my dream cell phone. I've dabbled in using Nokias and AT&T's ZTE device. I love them but I can only last about a month on them before some pain point irks me. Here are the features of my dream cell phone: Must have: * Completely open-source hardware, firmware, software. * QWERTY keyboard * Screen size 2.4 inches + Maybe e-ink * Max talk time: 24 hours. Max music playback: 48 hours. Standby time: 30 days. * Vibrate only. No ringer. No alarms. I hate being embarrassed by oft forgotten alarms and ringtones. * Built-in graphs of SMS/voice usage over the course of a month (so I can budget it). * Use a Twilio number as my real number, that forwards between my phone's local SMS number. Then I can text people via a web app and or a CLI app still as "me". I can implement a sort of ACK/Mailbox protocol to ensure that my device is in sync with the official message log. Some consensus protocols may be required to prevent out-of-order messaging. Pretty much a dead simple one-sided implementation of Apple's famed iMessage integrations. I'm not talking about text bubbles and deliver/read receipts though. I love being able to send texts on a Mac just be signing in. But it would be better if it was over the web too. Nice to have: * Able to create a LTE hotspot. * Wireless Qi charging * Able to SSH into any remote machine and use the full QWERTY keyboard. This might require a control key, etc. That's all I can think of right now. ]]> Sat, 04 Apr 2020 21:30:00 -0700 003.txt 3 Months w/o a Smartphone https://blog.notryan.com/004.txt =============================================================================== blog.notryan.com/004.txt Tue, 14 Apr 2020 Ryan Jacobs 19:00:00 -0700 3 Months w/o a Smartphone . . . . . . . . . . . . . =============================================================================== It's been a while since I've posted. (Aside, I'm convinced that there must be some *Law of Blogs*, that states all blogs must write that particular sentence at some point.) I did it. I successfully went without a smartphone for over three months. I owe a significant part of that success to shipping my phone back up to Sacramento, where my parents live. The experience wasn't too bad. Here's what I learned from using my Nokia 3110 full-time for a few months: * I *can* watch YouTube. But it's annoying and low quality. * I can read Hacker News... but it's annoying and slow. * Gmail in HTML mode works great. I would go as far as to argue that * it's more usable and snappy than the JS-bloated version. * Battery life was awesome. I charged my phone about twice a week. * Felt less distracted. * I still could Google anything I wanted, but it was *just tedious enough* to prevent me from getting sucked into "research binges" Notable problems: * Ordering Uber/Lyft rides sucked. I found an online service called GoGoGrandparent that allowed me to call, and they would order a rideshare on my behalf and charge a percentage fee. * Not having iMessage sucked, but... I caved in and purchased a mid-2010 Mac Mini and setup VNC so that I could remote in and use my group chats when necessary. I wrote some Node.js code to shutter messages back and forth to my dumb phone -- which I will post about later. Honestly, not too bad, considering MacOS stores its messages in a SQLite database. I used Twilio's API to relay the messages. ]]> Tue, 14 Apr 2020 19:00:00 -0700 004.txt Returning to LA https://blog.notryan.com/005.txt =============================================================================== blog.notryan.com/005.txt Mon, 27 Apr 2020 Ryan Jacobs 02:15:00 -0700 Returning to LA . . . . . . . . =============================================================================== Tonight I flew into LA. It's weird coming back from a small town. Masks are now mandatory here apparently. In the airport, there is an eerie on-edge vibe. You feel guilty for sitting around. It is hinted at you to keep moving, not to stay put, to leave. Which makes sense I guess. On my flight, I read some Erlang material I scraped before boarding. It's "Learn You Some Erlang..." by Fred Hebert. His whole online e-book (HTML) scraped flawlessly, and weighs about 6 MB. I really appreciated that. I used `wget -mpkEnp https://learnyousomeerlang.com/content`. It worked perfectly. /ipfs/Qme7aKWACFpG2pp4CaBUmn77cSgn6MscUsZDKyRJGaFjrE/learnyousomeerlang.com --- If you're mindful of Internet longevity, you will do a couple of things: 1. Make your content easily scrapeable. Keep pages light. Don't overuse CDNs. Keep references relative and local. 2. If you can manage, embed your styles and your JS. (Even better, don't use JS?) Single file .html sites are great for archiving. You can ctrl+s the page. Or throw in a curl or wget, without having to set flags that trawl through the DOM in search of references. --- Also, I've subscribed to Hebert's RSS feed. I have just "discovered" RSS. I think it's awesome. I'm going to attempt to create an RSS generator for my blog. I have a couple of RSS feeds linked in my Thunderbird account, and honestly, it's goddamn near perfect. News comes to me, when I want to hit the refresh button. There is no endless scrolling through feeds of hyper-optimized always-novel content. It's my curated list... and slower? I'm enjoying it. I'm also subscribed to 4-5 different HNRSS.org feeds. One is based on keywords for topics I'm interested in. Another is set to only return the most popular posts (comments >= 250 || points >= 500). It keeps the noise down at the expense of missing out on some gold. But at least I can skip reading HN for a few days, and still have the good ones show up in my reader. If I have time, I will occasionally browse through HN manually. But it's good to know I won't miss the "big ones". Newsboat is another great CLI client. I've been using that to read the Archlinux News feed before I run system updates. Sometimes there are gotchas that the maintainers warn you about. HNRSS is open-source. One time it went down. (Nothing wrong with that, it's free and someone is paying for a server to host it.) But... I'm trying to think of an easy way where additional people could donate their server resources to mirror it to prevent downtime. This works great for static applications. But for something dynamic like this... we might need some consensus/verification algorithms. Might get tricky. But I will keep thinking about it. Signing off.. Ryan ~2:40-ish (I'm tired.) ]]> Mon, 27 Apr 2020 02:15:00 -0700 005.txt Some Things that are Speedy https://blog.notryan.com/006.txt =============================================================================== blog.notryan.com/006.txt Wed, 29 Apr 2020 Ryan Jacobs 01:25:00 -0700 Some Things that are Speedy . . . . . . . . . . . . . . =============================================================================== Oh my. I've had two major epiphanies today. libvirt+kvm is wayyyyy better than Virtualbox. I'm migrating everything there now. My Android VM is incredibly snappy now. The mouse integration is better too. And... Void Linux is also really snappy. There's no lag when opening Vim or htop.... I didn't even realize there was latency before, but now side-by-side I can tell that Ubuntu/Arch Linux both have slight lag when launching command-line applications. This might be a side-effect of musl. I'm going to order an SSD soon and install it on my laptop as my main distro for a bit. ]]> Wed, 29 Apr 2020 01:25:00 -0700 006.txt ./header.c >007.txt https://blog.notryan.com/007.txt =============================================================================== blog.notryan.com/007.txt Sun, 03 May 2020 Ryan Jacobs 09:59:00 -0700 ./header.c >007.txt . . . . . . . . . . =============================================================================== Heyo! This is gonna be a quick post. I've upgraded my text-only blog with a new tool written in C! It's called header.c, and uh, well it generates this snazzy header you see here. I'm still using my `c` script I wrote ages ago. You can check it out here: https://github.com/ryanmjacobs/c. The whole source code is pretty grokable. I execute it like this: $ ./header.c 'Title of New Blog' > 123.txt Ha! C in script form. Who would've known? --- If I were to list my current directory, it would look something like this: $ ls -l total 44 -rw-r--r-- 1 ryan ryan 5839 May 3 07:10 001.txt -rw-r--r-- 1 ryan ryan 1610 May 3 07:10 002.txt -rw-r--r-- 1 ryan ryan 2301 May 3 07:10 003.txt -rw-r--r-- 1 ryan ryan 1987 May 3 07:10 004.txt -rw-r--r-- 1 ryan ryan 3179 May 3 07:10 005.txt -rw-r--r-- 1 ryan ryan 1012 May 3 07:10 006.txt -rw-r--r-- 1 ryan ryan 421 May 3 09:59 007.txt -rwxr-xr-x 1 ryan ryan 697 May 3 07:10 build.sh -rwxr-xr-x 1 ryan ryan 1213 May 3 07:10 header.c -rwxr-xr-x 1 ryan ryan 2832 May 3 02:45 server.c -rwxr-xr-x 1 ryan ryan 95 May 3 07:10 watch_build.sh Feel free to look around! Just punch in the url to view the source on any of my build files. --- Note: Right now there are a couple of weird quirks... They aren't bugs because they're intentional. Anyways, one of them I find kind of funny: I don't allow titles with an even number of characters. ... because those titles don't allow for a perfectly centered dotted underline. Having it lopsided by one character would annoy the hell out of me! I restrict myself to titles where strlen(input) % 2 == 1. --- Next on my bucket list: RSS.c :) ]]> Sun, 03 May 2020 09:59:00 -0700 007.txt My Best 4 Hours https://blog.notryan.com/008.txt =============================================================================== blog.notryan.com/008.txt Mon, 04 May 2020 Ryan Jacobs 22:44:00 -0700 My Best 4 Hours . . . . . . . . =============================================================================== Very briefly, I am going to explain how I allocate my time towards education, work, and personal projects. Time is limited. We all know that. The quality of our time is limited too. There is a nuanced difference between several sections of our day. I like to assume eight hours of sleep, and split the remaining sixteen hours into four quarters. My best four hours are the second four hours of my day. I try not to waste them. If I have a mentally challenging task at hand, I promise myself this: I will give it my best four hours. Nothing more than that. Just the bare minimum. I find that this small promise is enough to get me moving. If I _really don't want_ to get the task done, (because you know, procrastination is a cruel beast), then I promise myself I will use only *one* of my best four hours. I tell myself, "Just one, how bad could it be? You can have the rest of the day off. Just give it one of your best four hours." Maybe that one hour turns into two or three, but at least I did at least one. And that's normally enough to be proud of. When are your best four hours? ]]> Mon, 04 May 2020 22:44:00 -0700 008.txt 100 Lines of C, in a Closet https://blog.notryan.com/009.txt =============================================================================== blog.notryan.com/009.txt Tue, 05 May 2020 Ryan Jacobs 05:40:00 -0700 100 Lines of C, in a Closet . . . . . . . . . . . . . . =============================================================================== UPDATE: Wow this garnered a lot more traffic than I anticipated. I'm going to post an update in a follow-up post that breaks down the steps of implementing server.c. I've got some interesting hints for y'all on path traversal. Additionally, the server is now safe against random netcat garbage that doesn't conform to the HTTP/1.1 spec. This is achieved by rejecting requests that don't meet the basic criteria: begins with "GET ", contains at least one more space, does not include any '/' characters. Also, I've just converted the server to use fork() in addition to accept(). The throughput has dropped from 20k req/s down to 8k... because of the process forking overhead. But now we can handle concurrent requests. I think it is a worthy trade-off. ------------------------------------------------------------------------------- Heyo! I think I'm all done. I've reached a feature completeness I'm proud of. This blog is now nearly entirely self-hosted. I am running it on a Thinkpad T440p laptop in my closet! View the source code at https://blog.notryan.com Here's what the stack looks like: * KVM Virtual Machine -> Void Linux * It can do live migrations to any device on my LAN, with zero downtime. KVM is really cool! It transfers the RAM continuously until it's fully synced. This takes about 30 seconds. * The VM's disk storage is on a NFS-mounted DRBD (Distributed Replicated Block Device). If you haven't heard of DRBD before, boy, are in you luck. Oh, it's just some fantastically reliable block device replication software that operates as a kernel module. And what's that? It's been in the mainline tree since around the 2.6 kernel release. So you probably already have it! Just install the userspace tools. * server.c HTTP server (https://blog.notryan.com/server.c) * Let's Encrypt (via Redbird) * FRP (fast reverse proxy) -> Vultr VPS (207.246.103.60 ingress IPv4) * $3.50/month is the cheapest price for a machine with an IPv4 address that can act as my ingress for *everything*. It looks at the HTTP `Host:` header to determine how to route requests to different VMs. In theory, I could open a port on my local router and have the ISP act as the ingress. But... I'm not super comfortable with exposing my WAN's IP address in case someone decides to DDOS my network. ------------------------------------------------------------------------------- SECTIONS 1. What else is running in my closet? 2. server.c 3. Moving away from GitHub 4. Moving away from Netlify / Cloudflare 5. rss.c 6. Future Plans ------------------------------------------------------------------------------- What else is running my closet? * https://videos.rmj.us * https://notryan.com * https://notryan.com/pdf * WebFPGA (https://beta.webfpga.io) * WebFPGA Forum (https://forum.webfpga.com) I'm honestly amazed by how snappy the Discourse forum is on my home network ISP (Spectrum, Los Angeles). Also, go ahead and run a synthesis job on the WebFPGA IDE -- it's even faster on our local servers. Look at this way, cloud VPSs are a total rip-off in terms of compute power. The two reasons I would rent a VPS is: uptime and network access. Having a publicly reachable IP address is a must-have for any networked application. Most VPS providers charge $5/month for one vCore and 512 MB of RAM. I can buy a used Thinkpad T440p off eBay for a little over $100. It has 8 vCores and 8 GB of RAM. It has a battery life of four hours. If someone happens to trip the breaker, the laptop won't die. It's like having an automatic UPS built into the server! By moving everything to on-premise machines, I've cut the WebFPGA server bills from $80/month (DigitalOcean) to $3.50/month for the IPv4 ingress. I have a full Kuberenetes install on-premise hosting the backend. Yes, there might be downtime. But the power has gone out only twice in three years. And the internet has never gone out. I have redundancy plans. I can spin up the same cluster setup within 10-15 minutes of being notified. But honestly, I used to view downtime as the end of the world, but I've discovered that most users are relatively congenial about it. That's not an excuse to slack though! We all dream of 100% uptime. I'm honestly okay with 99.9% uptime; that's about 9 hours per month. Not bad. ------------------------------------------------------------------------------- server.c ryan@kk ~ $ wrk http://localhost:8080 Running 10s test @ http://localhost:8080 2 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 427.45us 230.79us 5.64ms 87.28% Req/Sec 9.09k 1.03k 14.45k 63.68% 181879 requests in 10.10s, 198.26MB read Requests/sec: 18008.57 Transfer/sec: 19.63MB I've made some assumptions when developing this server. So there are a few _quirks_. Namely, the server has two content-type modes. It either serves index.html as `text/html`... and everything else as `text/plain`. Additionally, it uses blocking input/output: accept()->read()->write()->shutdown(). Someone could... block the next user from fetching by running `nc remote.name 80` without sending any data, blocking the server from any requests. But since this server is behind a proxy that looks at the HTTP header's for the `Host:` field... we can assume that our own proxy won't screw us over. Maliciously long requests won't harm us. ------------------------------------------------------------------------------- Moving away from GitHub Pushing to Github is perceptibly slow compared with pushing via SSH to a VPS. Plus using your own machines allows you to do *immoral stuff*, such as pushing 100 MB files, if you feel like it. I have versioned controlled, quite a few mega-repos where the primary content is not text files at all. Shame me all you want, but being able to time-travel through my photo/video collections is fantastic. I don't really care that my 2 GB repo takes 4 GB on disk... Tangents aside, here is the time it takes to push a text file to Github versus my VPS. (Note: the VPS pathway is client->Vultr->VPS) # Time it takes to push a change to a simple text file. ryan@kk ~/blog.notryan.com $ time git push origin real 0m5.123s ryan@kk ~/blog.notryan.com $ time git push mir real 0m1.423s ------------------------------------------------------------------------------- Moving away from Netlify / Cloudflare Previously, my static site deploy methodology was to push to Github, then have Netlify automatically pick that up, build and deploy. However... Netlify uses CDNs which takes time to propagate. On top of that, their build process is not the most efficient for my use case because they do a full git clone and spin up what I assume to be a Docker container that installs Node.js/Ruby/etc. Average time to visibility was about 2 minutes. A small part of that is Cloudflare caching the website "for speed". I've disabled my Cloudflare proxy. I don't want the Internet to get too reliant on these guys, so I'm doing my part to self-host. Now, my current process builds and deploys in less than a second. And my site is live immediately. I'm not anticipating thousands of requests per second and global access equality. I don't really need CDNs... Sorry if my site takes 100ms longer to load where you live. My current build is as such: git push -> triggers a git post-update hook -> git restore . -> git pull -> ./build.sh This goes for my entire site. Not just my blog. It's nice because it's only pulling the minute changes I made. The build scripts happen so fast that I don't even bother forking the process. When I deploy, I see the full log in my client's terminal. For example, this push went live in less than a second: ryan@kk ~/blog.notryan.com $ git push Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 4 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 1.50 KiB | 1.50 MiB/s, done. Total 4 (delta 3), reused 0 (delta 0), pack-reused 0 remote: From /home/ryan/_enc/notryan.com remote: 0c9c211d..aa11aa43 master -> origin/master remote: Merge made by the 'recursive' strategy. remote: blog/009.txt.draft | 48 +++++++++++++++++++++++++++++++++++------ remote: 1 file changed, 42 insertions(+), 6 deletions(-) To mir:_enc/notryan.com.git 0c9c211d..aa11aa43 master -> master ------------------------------------------------------------------------------- rss.c Ah! Good 'ol RSS. I've recently "discovered" RSS myself, (which some people might find insane.) I think it's gosh darn amazing. I've converted all of my YouTube subscriptions to RSS, and they show up in Thunderbird when they post a new video. I don't have to deal with YouTube's distracting/time-consuming sidebar recommendations ever. The video link and title just shows up in my RSS reader -- then I can use `mpv` to watch the video. Anyways, I wanted to offer spec-adherent RSS on my site. I've created a C program to do exactly that. Subscribe to be notified of future posts! https://blog.notryan.com/rss.c https://blog.notryan.com/rss.xml ------------------------------------------------------------------------------- Future Plans I'm thinking about converting server.c to use poll() instead of blocking syscalls. I don't want to introduce too much complexity though. I like poll()'s function prototype a lot more than select()/epoll(), so I will probably stick with that. The tricky part is figuring out how to sync two threads. I would prefer to use a simple fork() call, but the processes won't have shared memory... anyways, that's for a future time. Features that would be nice to have: * HTTPS * HEAD requests * Content-Type determined by file extension, so I can serve images properly ------------------------------------------------------------------------------- Anyways, thanks for reading! -- (Most definitely not) Ryan ------------------------------------------------------------------------------- https://www.reddit.com/r/programming/comments/gdxh3w/http_blog_server_100_lines_of_c_in_a_closet/ https://www.reddit.com/r/C_Programming/comments/gdy2av/serverc_100_lines_of_c_in_a_closet/ ]]> Tue, 05 May 2020 05:40:00 -0700 009.txt rss.c : Article Rendering https://blog.notryan.com/010.txt =============================================================================== blog.notryan.com/010.txt Wed, 06 May 2020 Ryan Jacobs 01:30:00 -0700 rss.c : Article Rendering . . . . . . . . . . . . . =============================================================================== I've just updated rss.c to render the entire blog post inside the <description> tag. RSS readers should render everything neatly now -- in the format of the gods: 80-character-wide monospace plaintext. Aside from that, I'm geniunely curious as to how many people added this feed to their reader. I think that's part of the appeal of RSS -- it doesn't offer all of those hyper-optimizing metrics by default. It puts the onus of viewership on the client, rather than the originator of the content. With RSS, it's no longer up to Google/Facebook/Twitter/Reddit algorithms to determine what content to shove in front of our eyeballs. That's kind of nice. If I modify my server.c file to log requests, then I suppose I could gather metrics on how often the rss.xml file is being polled. Anyways, I am curious -- shoot me an email if you had this automatically show up in your feed. And if you have a blog, send me your RSS feed too! I'd like to subscribe. I think RSS is almost a litmus test for quality content. XKCD offers RSS so it must be good. -- Ryan ]]> Wed, 06 May 2020 01:30:00 -0700 010.txt I am a Programmer https://blog.notryan.com/011.txt =============================================================================== blog.notryan.com/011.txt Wed, 06 May 2020 Ryan Jacobs 06:06:12 -0700 I am a Programmer . . . . . . . . . =============================================================================== ----- "What does Uncle Jim do for work again?" "He's a software engineer." "What's that?" "He writes code for computers. He instructs them to do all sorts of things: to open files and crunch numbers and notify people. The industry calls it 'soft'-ware because it's malleable. Someone has to write down the words, but they can go back and change them if they want to." "Oh, so he writes his 'soft'-ware by programming computers? I see. Isn't that just a programmer? Jack said his dad was a programmer." "No, no, no, Uncle Jim is _software engineer_. It's different. It's like comparing a car mechanic to an automotive engineer." "Oh okay, I think I'm getting it... Can you explain exactly what makes a software engineer different from a programmer?" "Sure, a software engineer _thinks_ about their code. They plan everything out. They consider the edge cases. They anticipate load. They ensure backwards compatibility. They plan ahead." "Oh, so a software engineer is just a good programmer." "Yes, something like that." ----- I am a programmer. I am not a code crafter, a pixel pusher, or a thought weaver. Call me what I am: a programmer. What's wrong with calling ourselves that? Why do we need to be called architects and developers? I'd like to put programmer on my resume. Just a thought. ----- Also fyi, I'm going to calm down my posting... I'm just really excited about how well my new blogging system is working. HTTP and RSS from scratch :) I will probably post around once a week with some substanial content. Some topics to look forward to: * A review on Void Linux * KVM live migrations, failover versus takeover * DRBD (Distributed Replicated Block Device) tutorial * A look on containers versus virtual machines, and how sometimes VMs are wayyyy better * My plans to offer uber-cheap $1/month publicly-reachable VPS systems to the public -- Ryan ]]> Wed, 06 May 2020 06:06:12 -0700 011.txt Revel in Its Difficulty https://blog.notryan.com/012.txt =============================================================================== notryan.com/blog/012.txt Fri, 08 May 2020 Ryan Jacobs 09:40:12 -0700 Revel in Its Difficulty . . . . . . . . . . . . =============================================================================== Here is a guide on how to learn the hard things. You sit down to read a textbook. It's going well. The first couple of chapters are all right. But then it gets hard. It gets *really, really* hard. How the hell did it get so incredibly confusing all of the sudden?! You were _just_ on chapter 2 and _that_ wasn't bad. This is only the next chapter! But alas, chapter 3 appears insurmountable. And... here's why: You went too fast. I know it didn't seem like it. But you did. And you didn't test your knowledge. You didn't _really know_ chapters 1 and 2. Go back. Start with page 1. Read it. Question it. Keep stumbling until it clicks. Then move on to page 2. Ask yourself questions. If you need to, go reference page 1. When you are done with page 2, go to page 3 and do the same. And then to page 4. And so on and so on. Oh what's that? You're still stuck? Then break it down into paragraphs. Pinpoint *specifically* what you do not know. Really, I mean it. You need to _know what you do not know_. Do some research on those topics. Get yourself unstuck! Do *as many exercises as you can*. These will convince you that, again, you do not in fact understand chapters 1 and 2. But that's great! This is the goal. The goal is to put yourself in a state of semi-confused stupor as *often* as you can tolerate. Go long stretches in it. Learn to relax in it. *Revel in its difficulty!* Difficulty means that you are doing it right. It means that you are making progress, and not only that, but that you are going to continue to make progress because you are operating with good habits! You won't fizz out at chapter 3 anymore. When I ran cross country, my coach used to train us in a mode that he called "comfortably hard". That's where you should be 80% of the time. And the rest... well that's up to you. Maybe go out and discover some hard things to add to your bucket list. Do some exploratory work. Textbook learning is inductive. You need to have already mastered page N before you even _think about reading_ page N+1. And, on top of that, page N might not be enough if the book was poorly written! You might need to reference books X and Y while reading Z! You might need to Google some ideas. You might need to ask questions. But as long as you are making progress towards N+1 every day, _your_ N will be increasing. It will be "strictly increasing", as the mathematicians say. Learning takes time. Learn to accept this fact. Learn to break your task into sizeable bits. And I really do mean sizable. A page at a time is all you need. Best of luck, Ryan P.S. KVM goodness is coming soon! ]]> Fri, 08 May 2020 09:40:12 -0700 012.txt Minimalist HTML https://blog.notryan.com/013.txt =============================================================================== notryan.com/blog/013.txt Fri, 08 May 2020 Ryan Jacobs 14:54:20 -0700 Minimalist HTML . . . . . . . . =============================================================================== This article is about HTML5. Note: Some of these *might* break spec, but are so commonplace that they might as well be in here. For example, <title> is required by the HTML spec, but 99% of all browsers will make up something for you if it isn't supplied. Note: I wouldn't use this advice on production websites. But for quick development, here are some tips that help me. ------------------------------------------------------------------------------- Update 1: Why? Well maybe you want to write a temperature display in the least amount of HTML, packing a lot of punch onto an ESP8266 or similar device -- and... have it work on a modern browser for easy debugging and flashing. That's one idea. Other reasons include being a minimalist punk. Update 2: Huh. This spawned a lot of discussion on HN. And I've learned a decent bit today. I'll post a follow-up soon for posterity's sake. Two things real quick. I implied that you could drop closing tags for _all_ tags, but in reality, this only works for _some_ tags. Look up "Content Categories" as for why. Secondly, the <doctype> tag *is* mandtory for the HTML5 spec. I already mentioned this, but its importance was not stressed enough. To trigger HTML5 specific-behavior, you will need to include it. Your document will _probably_ render without it, but it might not render what you intended. Omiting it will cause the browser to render the page in "quirks mode". Again, it all depends on what you are doing. Update 3: Someone posted this article on Reddit. Here's a couple of additional tips that I've learned by reading through the comments: * You can set the text encoding type via an HTTP response header instead of using <meta charset="utf-8">. Use "Content-Type: plain/text; charset=utf-8" * On modern mobile devices, you actually do not need 'initial-scale=1' anymore. You can get away with: <meta name=viewport content="width=device-width"> Omit the quotes if you'd like to. It will still be valid HTML5. ------------------------------------------------------------------------------- Here we go: * Text outside of tags is acceptable in modern browsers. * <!DOCTYPE html> *is* required by the HTML spec (but not the XHTML spec). Most of browsers will not care if you omit it. It was created for backwards compatibility with prior HTML versions. You can omit it in minimal documents. * <html>, <head>, <body> are not required by modern browsers. Your document will render fine without them. You don't need to wrap your document with <html> and <body>. * You don't need to close your tags. For example, create a document, add <p>, add some content, and then end the document without providing the closing </p> tag. The browser will construct a DOM with a <p></p> element. Closing tags will be generated for you, in a nested fashion. This lets you to do things like this: <html> <head> <meta http-requiv="refresh" content="0; https://example.com"> (Although, meta redirects aren't even spec compliant with W3C... but alas, that's a can of worms for another day...) * Quotes are optional for tag attributes. For example, <a href=example.com> (Of course, there must be no spaces, etc.) * Both single-quotes and double-quotes are valid for tag attributes. This is useful for producing valid HTML output in programs without resorting to escaped double-quote. For example, in the C language: printf("<h1 style='color: green'>Hi there!</h1>\n"); * If you do not define <meta charset="utf-8">, then most browsers will default to ASCII or Windows-1252. So if you are confidently in the ASCII range, skip the declaration. * Using a preformatted block (<pre>) of links is a handy way to introduce automatic line breaks. For example, this will render nicely: <pre> * <a href=#>link 1</a> * <a href=#>link 2</a> * <a href=#>link 3</a> </pre> Though, keep your links short and be mindful that your text will not wrap. I like using this technique to generate stupid simple index.html files in BASH: #!/bin/bash gen() { echo "<pre>" for f in *; do echo "* <a href='$f'>$f</a>" done echo "</pre>" } gen | tee index.html This works with filenames containing spaces... but not single quotes. Modify it for your use cases. * Add this tag to support mobile views: <meta name=viewport content="width=device-width, initial-scale=1"> This snippet is copy and pasted a whole lot around the web. Most people don't explain how it actually functions though. "width" sets the initial width to the mobile's physical display width in 100% pixels. This is instead of a virtual viewport. This will ensure that the max-width property works properly. Tags such as <p> have an implicit `max-width: auto`. Now their content will flow properly and wrap to the display's dimensions. "initial-scale" sets the initial zoom to a more sensible value, so that high DPI screens (i.e. smart phones) will fill the screen properly. * You can skip out on "http:" or "https:" when defining your references by using the shorthand notation "//" which means "use the current protocol". For example: <a href="//github.com/someuser/repo">here is a link</a> ------------------------------------------------------------------------------- Thanks for reading. Last of all, if you are currently reading on a mobile device, this website was served to you via server.c, which you can find at the root of this site. I detected your User-Agent as mobile and served you an HTML version of this text document to prevent text wrapping. The HTML document was produced as "Minimal HTML" by mobile.c, which you can also find at the root of this site. I apologize if 80-column text is hard to read on your phone. But I don't want to deal with two different versions of my site. I like plaintext. I like formatting it exactly how I want. You're seeing it like you would have on the desktop. UPDATES: #1 - 5:45 PM, 5/8/20 - Description on mobile viewports and a why bit. #2 - 7:40 PM, 5/8/20 - Blurb about corrections and a follow-up. #3 - 2:00 PM, 5/9/20 - Include tips from Reddit at the top. Add "//" tip. ]]> Fri, 08 May 2020 14:54:20 -0700 013.txt Whoops... 000.txt https://blog.notryan.com/014.txt =============================================================================== notryan.com/blog/014.txt Sat, 09 May 2020 Ryan Jacobs 09:15:00 -0700 Whoops... 000.txt . . . . . . . . . =============================================================================== Hi all, Good morning from the west coast -- and happy weekends to you all! So uh... you might have received an RSS notification about a free prize, which was a half-accident, so I'll meet you in the middle on this one. Before I get too many emails, first let me explain what happened. tl;dr Email me before 11:59 PM UTC and get a 50%-off WebFPGA coupon? Sorry... --- Alright, so I was trying to be clever. My goal was to create a hidden post under the guise of "000.txt" with a hint telling people to email me for a prize. However, in my rss.c generator, I mistakenly started my loop at i=0 instead of i=1. See the snippet below: // p_item means print_item by the way... for (int i = 0; i < 1000; i++) p_item(i); Anyone who polled the rss.xml feed last night received a notification of the "hidden" file. Not very "hidden" eh? --- I was inspired to create a hidden file after witnessing the torrent of exploit testing against server.c. Man, people get really creative when there's a minimalist 100-line C server exposed on the public web.... After seeing people testing server.c with different exploitation techniques, I thought it would be interesting to write up a post about what people have tried so far, and why it has or hasn't worked. So I started logging requests. By the way, as far as I know, path traversal does not work. I have a check that rejects all requests that contain a slash with a "405 Not Allowed" error. This is fine with me because server.c is surrounded by files to serve in the same directory only. Anyways, you can stop trying to grab my /etc/passwd! $ grep etc/passwd notryan.com.log 1589012593: 0,etc/passwd 1589012660: 0,etc/foo 1589012732: 0,etc 1589012734: 0,etc/f 1589012763: 0,etcpasswd 1589012773: 0,etc/passwd 1589036300: 0,etc/passwd 1589036306: 0,etc/passwd However, this snippet did work and caught me by surprise. I've now since blocked dotfile requests. $ curl https://blog.notryan.com/.gitignore bin a.out log *.log rss.xml index.html *.txt.html This request exposes potential files to fetch. That scared me a little bit, but there's not much danger in this case. In fact, there is little enough danger than I am posting the original contents. Most of those files people already knew about because their browsers were fetching them by default. --- Here is another attempt I saw: $ grep '\.\.' notryan.com.log 1588940973: 0,............etcpasswd 1588940978: 0,..........etcpasswd 1588940981: 0,........etcpasswd 1588940984: 0,......etcpasswd 1588940987: 0,....etcpasswd 1588940990: 0,..etcpasswd 1588941909: 0,%2fetc%2fpasswd 1588941910: 0,..%2f..%2fetc%2fpasswd Notice the HTTP URL-encoded entities, e.g. "%2F" to indicate a "/". However, if you read the source code for server.c, you will notice that I didn't implement this translation. This keeps us safe from people passing in URL-encoded slashes and dots, etc. But the main reason that this "feature" is missing is because I didn't have the space to implement it... Keeping your codebase small oftentimes has the pleasant side-effect of reducing attack surfaces. Here is a mapping of URL-encoded characters for those curious: ! # $ & ' ( ) * + , / : ; = ? @ [ ] %21 %23 %24 %26 %27 %28 %29 %2A %2B %2C %2F %3A %3B %3D %3F %40 %5B %5D --- Okay. Back to the prize bit. There was one lucky person around 10 PM last night who emailed me inquiring about the prize, which shocked me. I honestly thought he found it that quickly! But then I realized my mistake and quickly corrected the code in rss.c, but at that point it was too late. I've since received about 5 emails since waking up this morning. For the first person, I have given away a coupon code for a free standalone WebFPGA device and free shipping. That was the original prize. For the rest of you, email me before midnight UTC for a 50%-off coupon, (if you are interested that is). I know it isn't much, but it is something. 50% is meeting you guys in the middle. It's the best I can do right now. But regardless, if you _are_ interested, I'm always excited to get people started with FPGAs! If you're not familiar with them, feel free to shoot me an email. They're awesome and will probably be in the near future of consumer computing. We are pushing the limits of Moore's Law and FPGAs are a specialized solution that could help us delay it for a few more decades. FPGAs allow for on-the-fly creation of specific hardware. Think of: game engine accelerators or virtual machines running in hardware... FPGAs are kinda like reprogrammable graphics cards. They have similar use cases, but FPGAs are very flexible. You can implement CPUs, Networking Switches, and GPUs, among other things. Instead of merely emulating an Atari, you can design the Atari 2600's CPU yourself! (It's version of the 6502 for those curious.) --- In other news, check out https://blog.notryan.com/stats.html I had some fun creating that last night by parsing the log results of server.c Anyways, that's all for today. Sorry if I disappointed any of y'all. On a side note, I'm thinking of ways to create an *extremely basic* commenting system while still keeping this blog in plaintext. I've got a couple of ideas kicking around, but we'll see what I come up with. It'll probably be something like: blog.notryan.com/blog/014.txt.comments Comment submittal might be through email. I've always wanted to write my own SMTP server... -- Ryan ]]> Sat, 09 May 2020 09:15:00 -0700 014.txt