
WebWormHole: Send files quickly using WebRTC - pvsukale3
https://webwormhole.io/
======
Sean-Der
This is fantastic! Really nice work :)

The nice thing about WebRTC is this works (pretty much) everywhere! Someone
could throw up Python/Android/iOS/Go/Web/C++ Clients really easily. That is
really exciting.

Also just a HUGE fan of NAT Traversal/P2P in general. The less dependence we
can have on others for sharing our data the better.

~~~
jackewiehose
> The nice thing about WebRTC is this works (pretty much) everywhere! Someone
> could throw up Python/Android/iOS/Go/Web/C++ Clients really easily.

Huh, what did I miss?! How do you make a WebRTC-client in language-of-your-
choice? The last time I checked for C++ I only found answers like "look at the
chrome source". lol.

~~~
Sean-Der
Things have changed (alot!) the last two years have seen a couple
implementations come around.

* [https://github.com/pion/webrtc](https://github.com/pion/webrtc)

* [https://github.com/aiortc/aiortc](https://github.com/aiortc/aiortc)

* [https://gstreamer.freedesktop.org/documentation/webrtc/index...](https://gstreamer.freedesktop.org/documentation/webrtc/index.html)

* [https://github.com/rawrtc/rawrtc](https://github.com/rawrtc/rawrtc)

~~~
wpietri
Ooh, these are very cool. Do you know what sorts of things people are building
with them?

~~~
m3at
This is only a personal anecdote, I had two occasions to use it at work:

\- I wanted to setup ssh access to some machines in a complicated network in a
shared office, over which I had no control. After trying various NAT traversal
hacks, I realized the potential of WebRTC to do all that for me, and setup ssh
over webrtc. I made it from a bunch of hacks, but some people seem to have
built that properly now, ex: [https://github.com/mxseba/rtc-
ssh](https://github.com/mxseba/rtc-ssh)

\- I built some tech demos that needed to run on multiple OS and use the
webcam. Initially I relied on opencv, but I needed to dockerize things and
outside of Linux the webcam device passthrough is a pain. Instead I made a
simple webpage fetching the video feed and talking to a python backend (using
this great library:
[https://github.com/aiortc/aiortc](https://github.com/aiortc/aiortc)), and it
worked nicely. It also has been surprisingly easy to setup.

------
anderspitman
What makes this really interesting to me is that it uses a golang
implementation of WebRTC on the server side. When I was playing with
multiplayer networking in the browser ~1.5yr ago, there really didn't seem to
be a lot of options for WebRTC servers. Great to see some progress here.

Also, it sounds like it's using streaming rather than loading the entire file,
which would give it an advantage over
[https://file.pizza](https://file.pizza), which is what I usually recommend
for p2p transfers.

If you like these types of tools, but don't require p2p (or can't use it
because of NAT), I'll also plug my own
[https://patchbay.pub](https://patchbay.pub), which will let you do streamed
transfers with nothing but curl.

~~~
rakoo
I stumbled upon patchbay the other day and I thought it was really cool, now I
just need to find a good excuse to toy with it.

Just a heads up: the homepage still references the old index.html which you
say in your blog article might have the wrong paths. Indeed looking at the
docs all paths require a mode

~~~
anderspitman
Do you have an example of where it's incorrect? I'm pretty sure it's the right
index.html. Note that it's still very similar to the blog post.

~~~
rakoo
There is no mention of the req/res flow (someone could POST to /req, expecting
it to be a MPMC queue)

In the docs it seems MPMC queues should start with /queue, but it turns out
that anything that's not /pubsub or /req,/res just works, so is it really
needed ?

Also the doc doesn't specify that pb-method is available to get the
requester's method in the request/respond protocol

Anyway those are just minor things, thanks for the service it really rocks

~~~
anderspitman
Thanks! Several good points.

> In the docs it seems MPMC queues should start with /queue, but it turns out
> that anything that's not /pubsub or /req,/res just works, so is it really
> needed

/req/res was developed after the initial launch, since I had the idea later.
It represents the most general form of the entire concept, since you can
tunnel essentially any HTTP traffic through it. The plan is to change the
default protocol to /req, which is why I changed the examples to /queue, to
make the transition smoother. Lately I've been going back and forth on whether
it's a good idea to make the switch, since most of the time /queue is what I
want, and using /req/res involves complexity that isn't really in the spirit
of patchbay. But just today I decided another project I'm working on will need
the full HTTP capabilities, so I think I'm going to pull the trigger on it in
the next couple weeks. There are several independent implementations of the
/queue-style approach, so I think it's ok for patchbay.pub to take a slightly
more feature-full approach.

Thoughts?

~~~
rakoo
You're right that MPMC queue is a specific case of req/res where responder
doesn't switch to a channel for replying so it does make sense to switch to
it; nothing will be lost. You could even use the pubsub protocol by putting a
query param (pubsub=true), instead of reserving a whole path prefix just for
this protocol. I'd still keep pubsub because it's still useful in the general
case, especially since your initial itch to scratch, poor man's notification,
is done in pubsub mode

(Side question: why use pubsub for notification ? You wouldn't want to lose
the notification if no one is listening on the consumer side... but you also
want to possibly send it to multiple consumers at the same time. Maybe there's
space for something a bit different, like "As a producer I want to block until
at least one consumer is here; if there are multpile, send to all of them")

The only concern I'd have is that in the general case of req/res there's no
"easy" cli tool to parse the request headers and a potentially streaming body,
so it's harder to do a 1-liner (or a 5-liner) to process the input.

~~~
anderspitman
Thanks for the feedback

> You're right that MPMC queue is a specific case of req/res where responder
> doesn't switch to a channel for replying so it does make sense to switch to
> it; nothing will be lost

Not quite, unfortunately. The current implementation of req/res assumes the
first path segment is the responder "id", and everything after that is the
path to the file on that responder. So responders will shadow things and cause
potentially unintuitive behavior for users who just want an MPMC. There may be
ways to mitigate that though. I haven't though it through.

> You could even use the pubsub protocol by putting a query param
> (pubsub=true), instead of reserving a whole path prefix just for this
> protocol

That's actually exactly how it worked originally. Once I started adding more
protocols, I switched to the /proto/ api since it makes it clear right at the
beginning of the URL how it works, whereas query params are at the end of a
potentially long path. Still not 100% sure about this though. Been thinking
about switching to a pb-proto={res,queue,pubsub}.

> (Side question: why use pubsub for notification ? You wouldn't want to lose
> the notification if no one is listening on the consumer side... but you also
> want to possibly send it to multiple consumers at the same time.

In practice I actually haven't been using pubsub for notifications. MPMC is
almost always what I need. Since the chat example is mostly a toy, I'm really
not sure pubsub is earning it's complexity cost.

I suppose pubsub is still useful for streams of events (like webhooks) where
it's not necessarily a disaster if the event gets dropped, but you definitely
don't want the sender piling up blocked requests.

> Maybe there's space for something a bit different, like "As a producer I
> want to block until at least one consumer is here; if there are multpile,
> send to all of them")

That's an interesting idea. You'd still need a separate protocol for it,
because you have to read the entire message into memory in order to send to
multiple requesters, but it could be useful for sure.

> The only concern I'd have is that in the general case of req/res there's no
> "easy" cli tool to parse the request headers and a potentially streaming
> body, so it's harder to do a 1-liner (or a 5-liner) to process the input.

Yes, it pretty much requires a real script. I'm tempted to pull it out into a
completely separate thing, but it turned out that MPMC is almost completely a
subset of req/res, so it felt like a lot of duplication.

~~~
rakoo
Thanks for taking the time to reply!

> I suppose pubsub is still useful for streams of events (like webhooks) where
> it's not necessarily a disaster if the event gets dropped, but you
> definitely don't want the sender piling up blocked requests.

Yeah, it seems to me the semantics here is not so much pubsub but rather "at-
most-once". I think that kind of things makes sense for frequent updates where
you mostly care about the most recent value, so things like pings from a temp
sensor or stuff like that

> You'd still need a separate protocol for it, because you have to read the
> entire message into memory in order to send to multiple requesters

Actually, related to the previous point, that's an at-least-once thing: if
there is 1 (or multiple) consumers, send to all of them; if there is none,
wait for the first one, and once the first one is connected send to it. There
wouldn't be a need for much serializing in memory

Regarding req/res: it kinda feels like there's some overlap with the world of
CGI, it's basically the same issue; maybe it's possible to re-use or extract
some of the existing libraries ?

------
api
It's 2020, and people are elated to discover that it is possible to transfer a
file directly between two systems on the Internet.

True story: I was giving a guest lecture on network virtualization at UCI and
demoing ZeroTier. One student came up afterwords and asked me how traffic
could flow between systems without "a cloud." Evidently the idea that data
could just go directly from point A to point B was utterly, completely foreign
to the point that they weren't aware that the Internet could be used this way.

~~~
_jal
I blame NAT.

Treating end-users like second-class netizen consumers trained people to
"need" the cloud to do perfectly normal peer-to-peer things.

~~~
codethief
I'm not sure I would blame NAT. You can easily disable that.

What you can't disable is the asymmetry of consumer internet connections
(upload << download) and the fact that most consumer devices are not running
(or connected to the internet) 24/7.

~~~
yc12340
> I'm not sure I would blame NAT. You can easily disable that

This is predominately USA mentality. In the rest of the world widespread use
of carrier-grade NAT predates mobile networks by decades.

Many residential ISPs don't hand out public IPv4 addresses or require extra
payment for them. Some of those ISPs got their first IP block (or even single
address!) from someone and never bothered with whole "ask IANA for addresses"
thing. It is multi-layer NAT all the way down.

~~~
codethief
Hmmm I suppose my view is strongly biased then. I've lived outside the US most
of my life and have always had my own IPv4 address at home.

And sure, as IPv4 addresses are now exhausted, carrier-grade NAT is getting
increasingly common. But I would have said the issue started way before that.

> In the rest of the world widespread use of carrier-grade NAT predates mobile
> networks by decades. […] Some of those ISPs got their first IP block (or
> even single address!) from someone and never bothered with whole "ask IANA
> for addresses" thing.

Do you happen to have a source here? Because carrier-grade NAT predating
mobile networks by decades is news to me.

------
mirimir
WebRTC is problematic if you're using a VPN service, with the VPN client
running on the local machine. Quoting BrowserLeaks:[0]

> IP address detection using JavaScript. Starting work on WebRTC API, the web
> browser communicates with the STUN server and shares information about local
> and public IP addresses even if you are behind NAT and use a VPN or Proxy.
> This tool will show if your real public IP is leaking out.

However, if you run the VPN client on the router, there's no problem, because
the local machine has no public IP address, just LAN and VPN interface
addresses.

0) [https://browserleaks.com/](https://browserleaks.com/)

~~~
Sean-Der
Local IP leakage has been fixed! WebRTC uses mDNS candidates now, so there is
nothing that shows your 'local IP' anymore.

For 'Public IP' that sounds like a VPN configuration issue. Your WebRTC Agent
should be routing the STUN requests through the VPN (and getting that public
IP). But this effects all software/protocols, so don't think it is fair to
ding WebRTC for this!

[0] [https://bloggeek.me/psa-mdns-and-local-ice-candidates-are-
co...](https://bloggeek.me/psa-mdns-and-local-ice-candidates-are-coming/)

~~~
mirimir
OK. But the thing to do is test, using
[https://browserleaks.com/](https://browserleaks.com/) or whatever.

------
weaksauce
i like the approach of encrypting locally, uploading to the cloud and sending
the decryption key via a link.

that's the way firefox send does it

[https://send.firefox.com](https://send.firefox.com)

it's open source so you could run an instance of it if you wanted to.

~~~
tialaramex
This is a very different (and equally valid) use case. It does mean somebody
(in this case Mozilla) has to spend money on storage to deliver the service.

Wormhole-style systems don't need to store the data because it's flowing from
the sender to the recipient live.

------
nerdbaggy
I love that it uses chunks and streaming to transfer the file. So many of
these just try and load the entire file at once so you can’t transfer much.

~~~
anderspitman
Haven't looked through the code yet. How does it handle stream backpressure
with WebRTC?

~~~
ryanar
WebRTC has built in mechanisms to check how many bytes have been buffered
(RTCDataChannel.bufferedAmount), and you can register a low water mark
(RTCDataChannel.bufferedamountlow) that fires an event handle when the
buffered amount goes below that threshold (RTCDataChannel.onbufferedamountlow)
where you can resume sending.

WebRTC is sort of a combination of low-level and high-level APIs, but the
ability to control backpressure ends up being very useful.

~~~
anderspitman
Thanks. Does bufferedAmount work better than it does on WebSockets[0], because
I haven't had much luck with that.

[0]:
[https://github.com/websockets/ws/issues/492](https://github.com/websockets/ws/issues/492)

------
tptacek
This is neat, but it seems like unlike with "real" Magic Wormhole, the server
here can capture files by surreptitiously manipulating JS.

~~~
saljam
Absolutely true for the web interface if loaded from
[https://webwormhole.io](https://webwormhole.io). I'm open for any more
suggestions here!
[https://github.com/saljam/webwormhole/issues/13](https://github.com/saljam/webwormhole/issues/13)

Someone mentioned the command line client. One can also build and serve the
html/js/wasm from anywhere and it should still work, even with the same
signalling server. It has pretty lax CORS for this reason.

~~~
StavrosK
IPFS would be a solution here, since the files are content-addressed. You'd
have to fetch them locally, since a gateway could still manipulate the
content, but it's easier to find a gateway you trust.

~~~
anderspitman
Forgive my ignorance, but how would an IPFS gateway interfere here? If you
have the hash of the js file you need, you can verify the gateway gives you
the right one, correct? Or are you referring to the case where IPNS is used so
the actually content at the address can change?

~~~
StavrosK
If you go to the hassle of verifying the hash, yes, that's fine. I was talking
about just loading and using the page, which can be tampered with (because the
hash checking happens on the gateway).

------
mmm_grayons
Interesting note that this guy's choice of PAKE, Cpace, was chosen about a
week ago by the CFRG for use in IETF protocols. Cpace is new, but that's a big
vote of confidence for it.

~~~
aspenmayer
Nice spot, here's a link to the IETF draft spec for CPace mentioned.

[https://tools.ietf.org/id/draft-haase-
cpace-01.html](https://tools.ietf.org/id/draft-haase-cpace-01.html)

IETF post announcing the chosen candidates

[https://mailarchive.ietf.org/arch/msg/cfrg/LKbwodpa5yXo6VuND...](https://mailarchive.ietf.org/arch/msg/cfrg/LKbwodpa5yXo6VuNDU66vt_Aca8/)

Candidate selection process

[https://github.com/cfrg/pake-selection](https://github.com/cfrg/pake-
selection)

~~~
jedisct1
Implementation using libsodium
[https://github.com/jedisct1/cpace](https://github.com/jedisct1/cpace)

~~~
mmm_grayons
Hey, the libsodium guy! Thanks a million for your work on that; I've really
enjoyed using it. I actually ran across this the day after the CFRG meeting
and was happy to see a respected implementer had already written a C version.
Would you say it's mature enough to use yet?

------
coopsmgoops
Nice, I made one of these a few years ago
[http://passfiles.com](http://passfiles.com)

Yours is a bit more polished than mine though. I didn't use QR codes either
just good old fashioned urls.

~~~
gccxsse
There seem to be hundreds of these sites. They all do the same thing. Off the
top of my head I can remember [https://file.pizza](https://file.pizza)

~~~
rakoo
file.pizza and friends work on webtorrent, which doesn't do end-to-end
encryption

EDIT: just learned that WebRTC actually does end-to-end encryption by default,
so I'm wrong

------
jjice
I'm not as familiar with WebRTCPeerConnection as I'd like to be. Does it use
the STUN server to get it's real IP and after that we can establish a
completely peer to peer connection and now the webserver has no interaction
with WebRTCPeer stream?

If any of that is wrong, please enlighten me, I didn't realize peer to peer
connections could be as simple as this.

~~~
algesten
that's right. when establishing connection each side enumerates a bunch of
"ice candidates". which is everything from your local LAN to outside NAT ip
discovered via TURN servers (some restrictions due to privacy reasons).

once the ice candidates are exchanged each side starts spraying the other with
STUN messages to addresses ranked by "candidate pairs" that potentially could
make a connection until one is found.

this is simplified. there are mechanics like "trickle ice" and fallbacks to
proxying via TURN servers.

then there's the alleged idea this is all part of a webrtc "standard", which
is laughable cause no browser follows the wild collection of RFCs that
supposedly makes up the standard and the only reason any of it works is
because there's a non written down general consensus of what's required.

------
Naac
Neat, looks like a different backend and frontend implementation of the very
similiar magic-wormhole[0]

Now I wonder if anyone has made a web frontend of the original.

[0] [https://github.com/warner/magic-
wormhole](https://github.com/warner/magic-wormhole)

~~~
jimpick
I made a minimal web API for some experimental stuff I was trying:

[https://github.com/jimpick/magic-wormhole-
service](https://github.com/jimpick/magic-wormhole-service)

Not really hardened for production usage.

------
crazygringo
> _...it uses WebRTC to make the direct peer connections. This allows us to
> make use of WebRTC 's NAT traversal tricks, as well as the fact that it can
> be used in browsers._

But I'm assuming it can't break through all NAT routers, right? A good portion
of people still won't be able to use this?

A service usable by everyone would require STUN and TURN servers to be set up,
no?

Or has WebRTC made advances I'm unaware of?

~~~
Sean-Der
I don't have any hard numbers, but I have heard ~85% ICE success rate with out
TURN. But you are right, in some cases WebRTC will fail without TURN. Just no
one wants to pay to run those servers :)

I would love to see TCP hole punching in ICE, but it sounds like it is super
hard to get right.

Consumer internet does a lot better, lots of those failures come from
Government/Military/Medical I bet.

~~~
algesten
how would TCP hole punching even work? TCP has state and a handshake. UDP
doesn't.

~~~
zozbot234
UPnP can be used to setup port forwarding if the NAT gateway is configured
correctly.

~~~
algesten
sure. I think it's a bit different though. upnp is like some remote control of
your fw.

------
rmbeard
I'm curious how this compares with the DAT project
[https://docs.dat.foundation/docs/intro](https://docs.dat.foundation/docs/intro)
I've had issues using that with networks throwing NAT errors, but need a
secure P2P file solution for large data transfers. Wondering if this wil do
the trick.

~~~
rmbeard
So, I tested this but it was blocked by our firewall.

------
pkulak
Very nice! I'm assuming this is based on the wonderful "Magic Wormhole"? Is it
actually using that program under the hood?

~~~
psanford
No, its doesn't use any of the same protocols that Magic Wormhole uses.

------
jchook
Why not generate the QR code client-side?

Folks that care about P2P want to see zero HTTP requests to your server after
loading the basic resources.

~~~
saljam
The QR code is generated client side.

~~~
jchook
Why do I see a network transaction for it?

~~~
ascorbic
Chrome shows "blob:" URLs as network transactions, but they're not.

------
rpmuller
This makes me ridiculously happy. Magic wormhole is one of those tools that
works so well that you want to use it even when you don't need to. So happy to
see something like this so I don't have to install wormhole on my wife or my
son's computers to send them stuff.

------
andrewfromx
Anyone else get something like this?
[https://github.com/saljam/webwormhole/issues/27](https://github.com/saljam/webwormhole/issues/27)
I was running `ww send ~/Downloads/myfile.bin` and my friend went to recv it
from browser.

------
est
This is nice and all but is it possible to make a few kilobytes single-file
static HTML instead of 2.7MB
[https://webwormhole.io/util.wasm](https://webwormhole.io/util.wasm) ?

I want to host it on my router.

------
kevincox
It is annoying that it removes the ID from the URL. It would be nice to
bookmark my own code and I can just open it on multiple devices whenever I
want to transfer a file. However I need to do a bit of gymnastics with the QR
code to grab the URL.

~~~
saljam
Codes are intentionally single use, to limit the bruteforce vector. And only
two peers can connect any given time currently. It would be interesting to
figure out how to make it work with more than 2 peers!

------
harel
I've just used it. It's absolutely fantastic. Saved me from sending a 500MB
file through a sharing service or having to create S3 temporary buckets or
whatever other complicated method. Simple, works, perfect. Thank you!

------
gramakri
file.pizza is another similar project

~~~
grishka
I once tried sending a 3 GB file through it, then kept wondering why my entire
system became so sluggish. Turns out it loads the entire thing into RAM... The
file didn't go through either.

I hope this one isn't like that.

~~~
h-cobordism
Does HTML5 even let you read a file without loading it all into memory?

Edit: Looks like this is it. [https://developer.mozilla.org/en-
US/docs/Web/API/ReadableStr...](https://developer.mozilla.org/en-
US/docs/Web/API/ReadableStream)

Edit 2: And yes, this is using it.
[https://github.com/saljam/webwormhole/blob/master/web/main.j...](https://github.com/saljam/webwormhole/blob/master/web/main.js#L96-L105)

~~~
anderspitman
You can also do this manually (and on older browsers) by creating a FileReader
and only loading new chunks after old ones have been transferred. With async
APIs like WebSockets and WebRTC this typically requires implementing your own
backpressure to avoid blowing up browser memory. See for example how
omnistreams does it[0].

[0]: [https://github.com/omnistreams/omnistreams-filereader-
js/blo...](https://github.com/omnistreams/omnistreams-filereader-
js/blob/master/index.mjs)

------
neiman
Is there a size limit of on the files? This was the issue with all WebRTC file
sending websites I saw so far.

------
waynenilsen
We need a distributed db based on webrtc

~~~
nomel
Just curious, why do we need this?

~~~
waynenilsen
I would love to see zero barrier entry to creating a website (like twitter /
name your favorite site that is not a static site) that can run on peoples
laptops just by visiting a static javascript/html/css webpage. For this, you
would need some decentralized backend storage solution akin to a sql or nosql
database.

IPFS is not a database, perhaps one could be built on top but then who pins
the data and who runs the gateway? IPFS gateways are particularly confounding
at this juncture. Until IPFS gets native browser support for pinning and
gateways it cannot be the storage layer for a decentralized database.

This kind of technology could help people take back the internet (imo) and
webrtc goes a long way toward that goal. Even webrtc doesn't have the full
promise of what I am suggesting however, it still requires a server that knows
the IP of the other party so that you can directly connect (discovery). This
would also need to be decentralized (somehow) perhaps only the discovery of
peers would be done over a bootstrapped p2p DHT or something equivalent.

------
0xdeadbeefbabe
Who pays for the stun and turn servers?

~~~
inglor
Turn servers are expensive but there are plenty of free SatUN servers. For
example Google offers free stun servers.

~~~
0xdeadbeefbabe
Has the pandemic made ipv6 more popular somehow?

~~~
tialaramex
Of course. IPv6 is much more widely deployed to home networks, whereas
businesses tend to go out of their way to disable it. So when people are at
home all over the world, whether that's the Christmas period or this present
crisis, it bumps up IPv6 numbers slightly.

------
mgerb
Seems to work well sending images from my phone, but please let me select
multiple at one time.

------
jonplackett
How secure is this?

~~~
quickthrower2
From the github repo (original caps):

THIS PROJECT IS STILL IN EARLY DEVELOPMENT, USES EXPERIMENTAL CRYPTOGRAPHIC
LIBRARIES, AND HAS NOT HAD ANY KIND OF SECURITY OR CRYPTOGRAPHY REVIEWS. IT
MIGHT BE BROKEN AND UNSAFE.

~~~
jonplackett
I’ll rephrase my question - how secure is this attempting to be?

~~~
tialaramex
Conceptually it's the same design as Magic Wormhole though all the
technologies are different.

It's just a PAKE then you do a file transfer encrypted with the key you agreed
using the PAKE.

PAKEs are very human friendly, they leverage a relatively weak secret (like
"Monopoly Vegetable") that humans can deal with, to agree a good quality
secret (like an effectively random 128-bit AES key) in such a way that both
parties find out if the other party doesn't know the weak secret.

Because humans are bored easily you can use rather weak secrets safely - it's
a natural rate limit. An adversary who guesses almost right "Cluedo Animal?"
only gets told they're wrong, and after maybe two or three more attempts the
legitimate parties are annoyed and refuse to keep trying so their adversary is
foiled.

Machines wouldn't naturally use something like this because if a machine has a
secure channel to another machine it can just move the 128-bit AES key, not
waste time with some weaker human-memorable secret.

This technology won't hide the IP addresses of those communicating

A passive on-path adversary learns the size (perhaps not exactly but at least
close) of the file transferred.

And of course an active adversary can prevent the file transfer by spamming
the service with nonsense.

------
andred14
Come on it didn't work with a 5.5GB file :P

~~~
saljam
The command line version shouldn't have any trouble with large files. There's
[https://github.com/saljam/webwormhole/issues/4](https://github.com/saljam/webwormhole/issues/4)
to fix the web version. :)

~~~
andred14
ok will give it a try :)

------
duke360
it happily loops forever tranferring an empty file :D

------
jo32
consuming enormous cpu resources

