{"id":13624460,"url":"https://github.com/gagle/node-tftp","last_synced_at":"2025-04-10T01:07:46.397Z","repository":{"id":12073495,"uuid":"14660745","full_name":"gagle/node-tftp","owner":"gagle","description":"Streaming TFTP client and server.","archived":false,"fork":false,"pushed_at":"2023-02-27T12:40:23.000Z","size":304,"stargazers_count":90,"open_issues_count":17,"forks_count":30,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-10T01:07:42.031Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gagle.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2013-11-24T12:22:52.000Z","updated_at":"2024-12-22T17:18:27.000Z","dependencies_parsed_at":"2024-01-14T07:02:48.607Z","dependency_job_id":"9fb0eb64-37cc-4c91-b206-5bd57a4249c9","html_url":"https://github.com/gagle/node-tftp","commit_stats":{"total_commits":205,"total_committers":4,"mean_commits":51.25,"dds":"0.014634146341463428","last_synced_commit":"bb27e0aae7acf057c6d9f98e9d5dd48d3a366e1c"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gagle%2Fnode-tftp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gagle%2Fnode-tftp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gagle%2Fnode-tftp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gagle%2Fnode-tftp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gagle","download_url":"https://codeload.github.com/gagle/node-tftp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248137888,"owners_count":21053775,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T21:01:42.816Z","updated_at":"2025-04-10T01:07:46.372Z","avatar_url":"https://github.com/gagle.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"tftp\r\n====\r\n\r\n#### Streaming TFTP client and server ####\r\n\r\n[![NPM version](https://badge.fury.io/js/tftp.png)](http://badge.fury.io/js/tftp \"Fury Version Badge\")\r\n[![Dependency Status](https://david-dm.org/gagle/node-tftp.png)](https://david-dm.org/gagle/node-tftp \"David Dependency Manager Badge\")\r\n\r\n[![NPM installation](https://nodei.co/npm/tftp.png?mini=true)](https://nodei.co/npm/tftp \"NodeICO Badge\")\r\n\r\nFull-featured streaming TFTP client and server. It supports most of the RFCs:\r\n\r\n- [1350 - The TFTP protocol](http://www.ietf.org/rfc/rfc1350.txt) ✓\r\n- [2347 - Option extension](http://www.ietf.org/rfc/rfc2347.txt) ✓\r\n- [2348 - Blocksize option](http://www.ietf.org/rfc/rfc2348.txt) ✓\r\n- [2349 - Timeout Interval and Transfer Size Options](http://www.ietf.org/rfc/rfc2349.txt) ✓\r\n- [2090 - Multicast option](http://www.ietf.org/rfc/rfc2090.txt) ✗\r\n- [3617 - Uniform Resource Identifier (URI)](http://www.ietf.org/rfc/rfc3617.txt) ✓\r\n- [7440 - Windowsize option](https://tools.ietf.org/rfc/rfc7440.txt) ✓\r\n- [De facto - Rollover option](http://www.compuphase.com/tftp.htm) ✓\r\n- `mail` and `netascii` transfer modes ✗\r\n\r\n[CLIENT](#client) | [SERVER](#server) | [Error codes](#error_codes)\r\n\r\nPer se, the TFTP is a lock-step protocol built on top of UDP for transferring files between two machines. It was useful in the past but nowadays it's practically an obsolete legacy protocol useful in a very few scenarios. Without the extensions support, the RFC says that a file bigger than 32MB cannot be transferred. This limit can be incremented to 91.74MB if both machines agree to use a block size of 1468 bytes, the MTU size before IP fragmentation in Ethernet networks. Also, the transfer speed is pretty slow due to the lock-step mechanism, one acknowledgement for each packet.\r\n\r\nHowever, there are two de facto extensions that can boost the transfer speed and remove the size limit: the rollover and the window.\r\n\r\nThis module it's perfectly integrated with Node.js, providing an streaming interface for GETting and PUTing files very easily. No configuration is needed. By default the client tries to negotiate with the server the best possible configuration. If that's not possible it simply fallbacks to the original lock-step TFTP implementation. The server also supports both the enhanced features and the classic lock-step RFCs.\r\n\r\nIt can be installed locally and used programmatically, but it can be also installed globally and used directly from the console as a CLI utility.\r\n\r\n#### Special thanks ####\r\n\r\nPatrick Masotta (author of the [Serva](http://www.vercot.com/~serva/) application and the internet draft about the `windowsize` option).\r\n\r\n#### Local environment vs Internet ####\r\n\r\nTFTP runs over UDP, this means that the network packets could be lost before reaching the other side. In local controlled scenarios, the TFTP can be used in a very few cases, but don't pretend to use it over the Internet, use FTP instead. It simply doesn't work because the packets are lost with an amazing ease.\r\n\r\nTFTP is a bad protocol for transferring files because it adds some of features that TCP offers (ack's, retransmission, error detection, reordering, etc.) to the UDP but at the applicaction layer (slower!). Think why you need to use TFTP instead of FTP. In most of the cases you can use FTP and obtain better results.\r\n\r\n\u003ca name=\"udploss\"\u003e\u003c/a\u003e\r\n#### Warning! UDP packet loss in Windows ####\r\n\r\nCurrently, in Windows there is a problem concerning the buffering of the received network packets ([#6696](https://github.com/joyent/node/issues/6696)). Basically, when the buffer is full, all the subsequent incoming packets are dropped, so they are never consumed by Node.js. This scenario can be reproduced by configuring a window bigger than 6 blocks with the default block size. So the advice is: do NOT increment the default window size (4) in the Windows platform until this bug is solved.\r\n\r\n---\r\n\r\n### CLIENT ###\r\n\r\n[_module_.createClient([options]) : Client](#createclient)\r\n\r\n#### Documentation ####\r\n\r\n- [Streams](#client_streams)\r\n- [Global installation](#client_global)\r\n\r\n#### Objects ####\r\n\r\n- [Client](#client_object)\r\n- [GetStream and PutStream](#client_getstream_putstream)\r\n\r\n---\r\n\r\n\u003ca name=\"client_streams\"\u003e\u003c/a\u003e\r\n__Streams__\r\n\r\nFor the sake of simplicity the following examples omit the error handling. See the [streams.js](https://github.com/gagle/node-tftp/blob/master/examples/client/streams.js) example or the [source code](https://github.com/gagle/node-tftp/blob/master/lib/client.js) of the [get()](#client-get) and [put()](#client-put) functions for more information.\r\n\r\n__GET remote \u003e local__\r\n\r\n```javascript\r\nvar get = client.createGetStream (\"remote-file\");\r\nvar write = fs.createWriteStream (\"local-file\");\r\n\r\nget.pipe (write);\r\n```\r\n\r\n__PUT local \u003e remote__\r\n\r\n```javascript\r\nvar read = fs.createReadStream (\"local-file\");\r\nvar put = client.createPutStream (\"remote-file\", { size: totalSize });\r\n\r\nread.pipe (put);\r\n```\r\n\r\n---\r\n\r\n\u003ca name=\"client_global\"\u003e\u003c/a\u003e\r\n__Global installation__\r\n\r\n```\r\nnpm install tftp -g\r\n```\r\n\r\nThen you can access to the `ntftp` binary.\r\n\r\nThere are basically two ways to use it: with or without a shell.\r\n\r\n__Without a shell__\r\n\r\nBest for individual transfers.\r\n\r\n```\r\n$ ntftp get [options] \u003crfc3617_uri\u003e [\u003clocal\u003e]\r\n$ ntftp put [options] [\u003clocal\u003e] \u003crfc3617_uri\u003e\r\n```\r\n\r\nFor example:\r\n\r\n```\r\n$ ntftp get tftp://localhost/remote-file\r\nremote-file             42.2 MiB   32.6M/s 00:12 [###·····················]  13%\r\n```\r\n\r\n```\r\n$ ntftp put my/local-file tftp://localhost/remote-file\r\nmy/local-file          148.8 MiB   30.9M/s 00:07 [###########·············]  45%\r\n```\r\n\r\nFor more information type `ntftp get|put -h`.\r\n\r\n__With a shell__\r\n\r\nBest for multiple transfers, basically because the same server address and options are reused.\r\n\r\n```\r\n$ ntftp [options] \u003chost\u003e[:\u003cport\u003e]\r\n```\r\n\r\nFor example:\r\n\r\n```\r\n$ ntftp localhost\r\n\u003e get remote-file\r\nremote-file             42.2 MiB   32.6M/s 00:12 [###·····················]  13%\r\n\u003e put my/local-file remote-file\r\nmy/local-file          148.8 MiB   30.9M/s 00:07 [###########·············]  45%\r\n```\r\n\r\nFor more information type `ntftp -h` and `get|put -h`.\r\n\r\n---\r\n\r\n\u003ca name=\"createclient\"\u003e\u003c/a\u003e\r\n___module_.createClient([options]) : Client__\r\n\r\nReturns a new [Client](#client_object) instance.\r\n\r\n```javascript\r\nvar client = tftp.createClient ({\r\n  host: \"10.10.10.10\",\r\n  port: 1234\r\n});\r\n```\r\n\r\nOptions:\r\n\r\n- __host__ - _String_\r\n  The address. Both IPv4 and IPv6 are allowed as well as a domain name. Default is `localhost` (`127.0.0.1`).\r\n- __port__ - _Number_\r\n  The port. Default is 69.\r\n- __blockSize__ - _Number_\r\n  The size of the DATA blocks. Valid range: [8, 65464]. Default is 1468, the MTU size before IP fragmentation in Ethernet networks.\r\n- __windowSize__ - _Number_\r\n  The size of each window. The window size means the number of blocks that can be sent/received without waiting an acknowledgement. Valid range: [1, 65535]. Default is 4.\r\n\r\n  Comparison of transfer times:\r\n\r\n  \u003ctable\u003e\r\n    \u003ctr\u003e\u003cth\u003eWindow size\u003c/th\u003e\u003cth\u003eImprovement\u003c/th\u003e\u003c/tr\u003e\r\n    \u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003ctd\u003e-0%\u003c/td\u003e\u003c/tr\u003e\r\n    \u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003ctd\u003e-49%\u003c/td\u003e\u003c/tr\u003e\r\n    \u003ctr\u003e\u003ctd\u003e3\u003c/td\u003e\u003ctd\u003e-64%\u003c/td\u003e\u003c/tr\u003e\r\n    \u003ctr\u003e\u003ctd\u003e4\u003c/td\u003e\u003ctd\u003e-70%\u003c/td\u003e\u003c/tr\u003e\r\n    \u003ctr\u003e\u003ctd\u003e5\u003c/td\u003e\u003ctd\u003e-73%\u003c/td\u003e\u003c/tr\u003e\r\n    \u003ctr\u003e\u003ctd\u003e6\u003c/td\u003e\u003ctd\u003e-76%\u003c/td\u003e\u003c/tr\u003e\r\n  \u003c/table\u003e\r\n\r\n  Take into account that with a bigger window more elements must be reordered (remember that UDP doesn't reorder the incoming packets). This doesn't slow down the transfer speed very much but it requires more CPU. A window size of 4 is a good trade between transfer speed and CPU usage.\r\n\r\n  Right now a window size of 6 is the maximum in Windows due to the [packet loss](#udploss) issue. With a window size of 7 or greater a lot of timeouts and retransmissions begin to occur, so the recommendation is to use a window size of 4, the default value.\r\n- __retries__ - _Number_\r\n  How many retries must be done before emitting an error. Default is 3.\r\n- __timeout__ - _Number_\r\n  Milliseconds to wait before a retry. Default is 3000.\r\n\r\n---\r\n\r\n\u003ca name=\"client_object\"\u003e\u003c/a\u003e\r\n__Client__\r\n\r\nEach of the following methods take an `options` parameter. One option available is `userExtensions`, an object with properties that can be sent with a GET or PUT operation. For example:\r\n\r\n```javascript\r\nvar options = {\r\n  userExtensions: {\r\n    foo: \"bar\",\r\n    num: 2\r\n  }\r\n};\r\n\r\nclient.get (\"file\", options, function (){ ... });\r\nclient.put (\"file\", options, function (){ ... });\r\nclient.createGetStream (\"file\", options);\r\nclient.createPutStream (\"file\", options);\r\n```\r\n\r\nThe server may ignore or not these extensions. This feature is server-dependent. Please note that the TFTP algorithm cannot be modified. For example, you can implement a basic authentication; the client could send the extensions `user` and `password` and the server could validate the user and accept or deny the request. The extensions are transmitted in plain text.\r\n\r\nThe extensions `timeout`, `tsize`, `blksize`, `windowsize` and `rollover` are reserved and cannot be used.\r\n\r\n__Methods__\r\n\r\n- [Client#createGetStream(remoteFile[, options]) : GetStream](#client_creategetstream)\r\n- [Client#createPutStream(remoteFile, options) : PutStream](#client_createputstream)\r\n- [Client#get(remoteFile[, localFile][, options], callback) : undefined](#client_get)\r\n- [Client#put(localFile[, remoteFile][, options], callback) : undefined](#client_put)\r\n\r\n\u003ca name=\"client_creategetstream\"\u003e\u003c/a\u003e\r\n__Client#createGetStream(remoteFile[, options]) : GetStream__\r\n\r\nReturns a new [GetStream](#client_getstream_putstream) instance.\r\n\r\nOptions:\r\n\r\n- __md5__ - _String_\r\n  MD5 sum for validating the integrity of the file.\r\n- __sha1__ - _String_\r\n  SHA1 sum for validating the integrity of the file.\r\n- __userExtensions__ - _Object_\r\n  Custom extensions to send with the request. [More information](#client_object).\r\n\r\n```javascript\r\nvar get = client.createGetStream (\"file\");\r\n```\r\n\r\n\u003ca name=\"client_createputstream\"\u003e\u003c/a\u003e\r\n__Client#createPutStream(remoteFile, options) : PutStream__\r\n\r\nReturns a new [PutStream](#client_getstream_putstream) instance.\r\n\r\nOptions:\r\n\r\n- __size__ - _String_\r\n  Total size of the file to upload. This option is required.\r\n- __userExtensions__ - _Object_\r\n  Custom extensions to send with the request. [More information](#client).\r\n\r\n```javascript\r\nvar put = client.createPutStream (\"file\", { size: 1234 });\r\n```\r\n\r\n\u003ca name=\"client_get\"\u003e\u003c/a\u003e\r\n__Client#get(remoteFile[, localFile][, options], callback) : undefined__\r\n\r\nDownloads a file from the server. If the local filename is missing, the basename of the remote file is used.\r\n\r\nOptions:\r\n\r\n- __md5__ - _String_\r\n  MD5 sum for validating the integrity of the file.\r\n- __sha1__ - _String_\r\n  SHA1 sum for validating the integrity of the file.\r\n- __userExtensions__ - _Object_\r\n  Custom extensions to send with the request. [More information](#client).\r\n\r\n```javascript\r\n//tftp://\u003chost\u003e/dir/to/remote-file -\u003e ./file\r\nclient.get (\"dir/to/remote-file\", function (error){\r\n  if (error) return console.error (error);\r\n  ...\r\n});\r\n```\r\n\r\n\u003ca name=\"client_put\"\u003e\u003c/a\u003e\r\n__Client#put(localFile[, remoteFile][, options], callback) : undefined__\r\n\r\nUploads a file to the server. If the remote filename is missing the basename of the local file is used.\r\n\r\nOptions:\r\n\r\n- __userExtensions__ - _Object_\r\n  Custom extensions to send with the request. [More information](#client).\r\n\r\n```javascript\r\n//./dir/to/local-file -\u003e tftp://\u003chost\u003e/file\r\nclient.put (\"dir/to/local-file\", function (error){\r\n  if (error) return console.error (error);\r\n  ...\r\n});\r\n```\r\n\r\n---\r\n\r\n\u003ca name=\"client_getstream_putstream\"\u003e\u003c/a\u003e\r\n__GetStream and PutStream__\r\n\r\nThe GetStream inherits from a Readable stream and the PutStream from a Writable stream.\r\n\r\n__Events__\r\n\r\n- [abort](#client_event_abort)\r\n- [close](#client_event_close)\r\n- [end](#client_event_end)\r\n- [error](#client_event_error)\r\n- [finish](#client_event_finish)\r\n- [stats](#client_event_stats)\r\n\r\n__Methods__\r\n\r\n- [abort([error]) : undefined](#client_getstream_putstream_abort)\r\n- [close() : undefined](#client_getstream_putstream_close)\r\n\r\n---\r\n\r\n\u003ca name=\"client_event_abort\"\u003e\u003c/a\u003e\r\n__abort__\r\n\r\nArguments: none.\r\n\r\nEmitted when the transfer has been aborted after calling to [abort()](#client_getstream_putstream_abort).\r\n\r\n\u003ca name=\"client_event_close\"\u003e\u003c/a\u003e\r\n__close__\r\n\r\nArguments: none.\r\n\r\nEmitted when the underlying socket has been closed. It is emitted __always__ and before any other event (`error`, `abort`, `end` and `finish`).\r\n\r\n\u003ca name=\"client_event_end\"\u003e\u003c/a\u003e\r\n__end__\r\n\r\nArguments: none.\r\n\r\nEmitted by the GetStream when the file download finishes.\r\n\r\n\u003ca name=\"client_event_error\"\u003e\u003c/a\u003e\r\n__error__\r\n\r\nArguments: `error`.\r\n\r\nEmitted when an error occurs. The stream is closed automatically.\r\n\r\n\u003ca name=\"client_event_finish\"\u003e\u003c/a\u003e\r\n__finish__\r\n\r\nArguments: none.\r\n\r\nEmitted by the PutStream when the file upload finishes.\r\n\r\n\u003ca name=\"client_event_stats\"\u003e\u003c/a\u003e\r\n__stats__\r\n\r\nArguments: `stats`.\r\n\r\nEmitted after the client has negotiated the best possible configuration. When it is emitted, the file transfer still hasn't begun.\r\n\r\n`stats` is an object similar to this:\r\n\r\n```\r\n{\r\n  blockSize: 1468,\r\n  windowSize: 4,\r\n  size: 105757295,\r\n  userExtensions: {},\r\n  retries: 3,\r\n  timeout: 3000,\r\n  localAddress: \"0.0.0.0\",\r\n  localPort: 55146,\r\n  remoteAddress: \"127.0.0.1\",\r\n  remotePort: 55147\r\n}\r\n```\r\n\r\nWhen the GetStream emits a `stats` event, the `size` property is not guaranteed to be a Number because the server may not implement the RFC related with file size. The size of the file is obtained during the negotiation but not all the servers are able to negotiate. In these cases the `size` is null.\r\n\r\nThe `userExtensions` property holds an object with the custom extensions sent by the server in response to the custom extensions sent with the request. Most of the TFTP servers don't let you respond with custom extensions when in fact this is a feature commented in the RFCs, so unless the TFTP server allows you to respond with custom extensions, this property will be always an empty object. Of course, the server provided by this module supports the user extensions.\r\n\r\n---\r\n\r\n\u003ca name=\"client_getstream_putstream_abort\"\u003e\u003c/a\u003e\r\n__abort([error]) : undefined__\r\n\r\nAborts the current transfer. The optional `error` can be an Error instance or any type (it is stringified). If no error message is given, it sends an [EABORT](#error_codes) error. The message is sent to the server but it is not guaranteed that it will reach the other side because TFTP is built on top of UDP and the error messages are not retransmitted, so the packet could be lost. If the message reaches the server, then the transfer is aborted immediately.\r\n\r\n---\r\n\r\n\u003ca name=\"client_getstream_putstream_close\"\u003e\u003c/a\u003e\r\n__close() : undefined__\r\n\r\nCloses the current transfer. It's the same as the [abort()](#client_getstream_putstream_abort) function but it doesn't send to the server any message, it just closes the local socket. Note that this will cause the server to start the timeout. The recommended way to interrupt a transfer is using [abort()](#client_getstream_putstream_abort).\r\n\r\n---\r\n\r\n### SERVER ###\r\n\r\n[_module_.createServer([options][, requestListener]) : Server](#createserver)\r\n\r\n#### Documentation ####\r\n\r\n- [Error handling](#error_handling)\r\n- [Graceful shutdown](#graceful_shutdown)\r\n- [Global installation](#server_global)\r\n\r\n#### Objects ####\r\n\r\n- [Server](#server_object)\r\n- [GetStream and PutStream](#server_getstream_putstream)\r\n\r\n---\r\n\r\n\u003ca name=\"error_handling\"\u003e\u003c/a\u003e\r\n__Error handling__\r\n\r\nIt's very simple. You need to attach two `error` listeners: one for the server and one for the request. If you don't attach an `error` listener, Node.js throws the error and the server just crashes.\r\n\r\n```javascript\r\nvar server = tftp.createServer (...);\r\n\r\nserver.on (\"error\", function (error){\r\n  //Errors from the main socket\r\n  //The current transfers are not aborted\r\n  console.error (error);\r\n});\r\n\r\nserver.on (\"request\", function (req, res){\r\n  req.on (\"error\", function (error){\r\n    //Error from the request\r\n    //The connection is already closed\r\n    console.error (\"[\" + req.stats.remoteAddress + \":\" + req.stats.remotePort +\r\n        \"] (\" + req.file + \") \" + error.message);\r\n  });\r\n});\r\n```\r\n\r\n\u003ca name=\"graceful_shutdown\"\u003e\u003c/a\u003e\r\n__Graceful shutdown__\r\n\r\nWhen the server closes the current transfers are not aborted to allow them to finish. If you need to shutdown the server completely, you must abort all the current transfers manually. Look at [this](https://github.com/gagle/node-tftp/blob/master/examples/server/graceful-shutdown.js) example to know how to do it.\r\n\r\n---\r\n\r\n\u003ca name=\"server_global\"\u003e\u003c/a\u003e\r\n__Global installation__\r\n\r\n\r\n```\r\nnpm install tftp -g\r\n```\r\n\r\nThen you can access to the `ntftp` binary.\r\n\r\nUse the `-l|--listen[=ROOT]` option to start the server. By default the root directory is `.`.\r\n\r\n```\r\n$ ntftp [options] \u003chost\u003e[:\u003cport\u003e] -l|--listen=ROOT\r\n```\r\n\r\nFor example:\r\n\r\n```\r\n$ ntftp localhost -l .\r\n```\r\n\r\nThis command starts a server listening on `localhost:69` and root `.`.\r\n\r\n---\r\n\r\n\u003ca name=\"createserver\"\u003e\u003c/a\u003e\r\n___module_.createServer([options][, requestListener]) : Server__\r\n\r\nReturns a new [Server](#server_object) instance.\r\n\r\n```javascript\r\nvar server = tftp.createServer ({\r\n  host: \"10.10.10.10\",\r\n  port: 1234,\r\n  root: \"path/to/root/dir\",\r\n  denyPUT: true\r\n});\r\n```\r\n\r\nThe `requestListener` is a function which is automatically attached to the [request](#server_event_request) event.\r\n\r\nOptions:\r\n\r\nIt has the same options as the [createClient()](#createclient) function with the addition of:\r\n\r\n- __root__ - _String_\r\n  The root directory. Default is `.`.\r\n- __denyGET__ - _Boolean_\r\n  Denies all the GET operations. Default is false.\r\n- __denyPUT__ - _Boolean_\r\n  Denies all the PUT operations. Default is false.\r\n\r\nSetting the options `denyGET` or `denyPUT` is more efficient than aborting the request from inside the request listener.\r\n\r\n---\r\n\r\n\u003ca name=\"server_object\"\u003e\u003c/a\u003e\r\n__Server__\r\n\r\n__Events__\r\n\r\n- [close](#server_event_close)\r\n- [error](#server_event_error)\r\n- [listening](#server_event_listening)\r\n- [request](#server_event_request)\r\n\r\n__Methods__\r\n\r\n- [close() : undefined](#server_close)\r\n- [listen() : undefined](#server_listen)\r\n- [requestListener(req, res) : undefined](#server_requestlistener)\r\n\r\n__Properties__\r\n\r\n- [host](#server_host)\r\n- [port](#server_port)\r\n- [root](#server_root)\r\n\r\n[__Error codes__](#server_errors)\r\n\r\n---\r\n\r\n\u003ca name=\"server_event_close\"\u003e\u003c/a\u003e\r\n__close__\r\n\r\nArguments: none.\r\n\r\nEmitted when the server closes. New requests are not accepted. Note that the current transfers are not aborted. If you need to abort them gracefully, look at [this](https://github.com/gagle/node-tftp/blob/master/examples/server/graceful-shutdown.js) example.\r\n\r\n\u003ca name=\"server_event_error\"\u003e\u003c/a\u003e\r\n__error__\r\n\r\nArguments: `error`.\r\n\r\nEmitted when an error occurs. The error is mostly caused by a bad packet reception, so almost always, if the server emits an error, it is still alive accepting new requests.\r\n\r\n\u003ca name=\"server_event_listening\"\u003e\u003c/a\u003e\r\n__listening__\r\n\r\nArguments: none.\r\n\r\nEmitted when the server has been bound to the socket after calling to [listen()](#server_listen).\r\n\r\n\u003ca name=\"server_event_request\"\u003e\u003c/a\u003e\r\n__request__\r\n\r\nArguments: `req`, `res`.\r\n\r\nEmitted when a new request has been received. All the connection objects that are emitted by this event can be aborted at any time.\r\n\r\n`req` is an instance of a [GetStream](#server_getstream_putstream) and `res` is an instance of a [PutStream](#server_getstream_putstream).\r\n\r\nRequests trying to access a path outside the root directory (eg.: `../file`) are automatically denied.\r\n\r\nNote: If you don't need do anything with the `req` or `res` arguments, that is, if by any reason you don't want to _consume_ the current request, then you __must__ [abort()](#client_getstream_putstream_abort) or [close()](#client_getstream_putstream_close) the connection, otherwise you'll have an open socket for the rest of the server's lifetime. The client will timeout because it won't receive any packet, that's for sure, but the connection in the server will remain open and won't timeout. The timeout retransmissions at the server-side begin when the transfer starts but if you don't read/write/close, the connection won't timeout because it is simply waiting to the user to do something with it.\r\n\r\n---\r\n\r\n\u003ca name=\"server_close\"\u003e\u003c/a\u003e\r\n__close() : undefined__\r\n\r\nCloses the server and stops accepting new connections.\r\n\r\n---\r\n\r\n\u003ca name=\"server_listen\"\u003e\u003c/a\u003e\r\n__listen() : undefined__\r\n\r\nStarts accepting new connections.\r\n\r\n---\r\n\r\n\u003ca name=\"server_requestlistener\"\u003e\u003c/a\u003e\r\n__requestListener(req, res) : undefined__\r\n\r\nThis function must NOT be called from outside a `request` listener. This function is the default request listener, it automatically handles the GET and PUT requests.\r\n\r\n---\r\n\r\n\u003ca name=\"server_host\"\u003e\u003c/a\u003e\r\n__host__\r\n\r\nThe address that the server is listening to.\r\n\r\n---\r\n\r\n\u003ca name=\"server_port\"\u003e\u003c/a\u003e\r\n__port__\r\n\r\nThe port that the server is listening to.\r\n\r\n---\r\n\r\n\u003ca name=\"server_root\"\u003e\u003c/a\u003e\r\n__root__\r\n\r\nThe root path.\r\n\r\n---\r\n\r\n\u003ca name=\"server_getstream_putstream\"\u003e\u003c/a\u003e\r\n__GetStream and PutStream__\r\n\r\nWhen the `request` event is emitted, a new GetStream and PutStream instances are created. These streams are similar to the [streams](#client_getstream_putstream) used in the client but with one difference, the GetStream (`req`) acts like a \"connection\" object. All the events from the PutStream (`res`) are forwarded to the `req` object, so you don't need to attach any event listener to the `res` object.\r\n\r\nThe GetStream has two additional properties:\r\n\r\n- __file__ - _String_\r\n  The path of the file. The directories are not created recursively if they don't exist.\r\n- __method__ - _String_\r\n  The transfer's method: `GET` or `PUT`.\r\n- __stats__ - _Object_\r\n  An object holding some stats from the current request. [More information](#client_event_stats).\r\n\r\nThe PutStream has two additional methods:\r\n\r\n\u003ca name=\"server_getstream_putstream_setsize\"\u003e\u003c/a\u003e\r\n- __setSize(size) : undefined__\r\n\r\n  Sets the size of the file to send. You need to call to this method only with GET requests when you're using a custom request listener, otherwise the request will just wait. Look at the examples [no-pipe.js](https://github.com/gagle/node-tftp/blob/master/examples/server/no-pipe.js) and [user-extensions-resume.js](https://github.com/gagle/node-tftp/blob/master/examples/user-extensions-resume.js) for more details.\r\n\r\n- __setUserExtensions(userExtensions) : undefined__\r\n\r\n  Sets the user extensions to send back to the client in response to the received ones. You cannot send extensions different from the ones that are sent by the client. This method must be called before [setSize()](#server_getstream_putstream_setsize).\r\n\r\n  As said previously, the TFTP protocol doesn't have any built-in authentication mechanism but thanks to the user extensions you can implement a simple authentication as showed [here](https://github.com/gagle/node-tftp/blob/master/examples/user-extensions-authentication.js).\r\n\r\n  Look at the [examples](https://github.com/gagle/node-tftp/tree/master/examples) for more details.\r\n\r\n---\r\n\r\n\u003ca name=\"error_codes\"\u003e\u003c/a\u003e\r\n### Error codes ###\r\n\r\nThe following errors are used internally but they are exposed in case you need to use any of them.\r\n\r\nThe errors emitted by any `error` event of this module can contain a property named `code`. It contains the name of the error, which is one of the following:\r\n\r\n* _module_.ENOENT - File not found\r\n* _module_.EACCESS - Access violation\r\n* _module_.ENOSPC - Disk full or allocation exceeded\r\n* _module_.EBADOP - Illegal TFTP operation\r\n* _module_.ETID - Unknown transfer ID\r\n* _module_.EEXIST - File already exists\r\n* _module_.ENOUSER - No such user\r\n* _module_.EDENY - The request has been denied\r\n* _module_.ESOCKET - Invalid remote socket\r\n* _module_.EBADMSG - Malformed TFTP message\r\n* _module_.EABORT - Aborted\r\n* _module_.EFBIG - File too big\r\n* _module_.ETIME - Timed out\r\n* _module_.EBADMODE - Invalid transfer mode\r\n* _module_.EBADNAME - Invalid filename\r\n* _module_.EIO - I/O error\r\n* _module_.ENOGET - Cannot GET files\r\n* _module_.ENOPUT - Cannot PUT files\r\n* _module_.ERBIG - Request bigger than 512 bytes\r\n* _module_.ECONPUT - Concurrent PUT request over the same file\r\n* _module_.ECURPUT - The requested file is being written by another request\r\n* _module_.ECURGET - The requested file is being read by another request\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgagle%2Fnode-tftp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgagle%2Fnode-tftp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgagle%2Fnode-tftp/lists"}