lt_rs/errors.rs
1use crate::ffi::error::ffi::{self};
2
3#[derive(Debug)]
4pub enum LtrsError {
5 LibtorrentError(LibtorrentError),
6 HttpError(HttpError),
7 GzipError(GzipError),
8 I2pError(I2pError),
9 PcpError(PcpError),
10 BdecodeError(BdecodeError),
11 SocksError(SocksError),
12 UpnpError(UpnpError),
13 // If error category is not known
14 // This is enable even without safe_enums feature because we need to check
15 // libtorrent to see if we already covered all possible variants
16 Unknown(i32),
17}
18
19impl LtrsError {
20 pub fn is_ok(&self) -> bool {
21 match self {
22 LtrsError::LibtorrentError(e) => {
23 matches!(e, LibtorrentError::NoError)
24 }
25 LtrsError::HttpError(e) => {
26 matches!(e, HttpError::Ok)
27 }
28 LtrsError::GzipError(e) => {
29 matches!(e, GzipError::NoError)
30 }
31 LtrsError::I2pError(e) => {
32 matches!(e, I2pError::NoError)
33 }
34 LtrsError::PcpError(e) => {
35 matches!(e, PcpError::Success)
36 }
37 LtrsError::BdecodeError(e) => {
38 matches!(e, BdecodeError::NoError)
39 }
40 LtrsError::SocksError(e) => {
41 matches!(e, SocksError::NoError)
42 }
43 LtrsError::UpnpError(e) => {
44 matches!(e, UpnpError::NoError)
45 }
46 LtrsError::Unknown(e) => *e == 0,
47 }
48 }
49}
50
51#[derive(Debug)]
52#[cfg_attr(feature = "safe_enums", derive(num_enum::FromPrimitive))]
53#[repr(u8)]
54pub enum LibtorrentError {
55 /// Not an error
56 NoError = 0,
57 /// Two torrents has files which end up overwriting each other
58 FileCollision,
59 /// A piece did not match its piece hash
60 FailedHashCheck,
61 /// The .torrent file does not contain a bencoded dictionary at
62 /// its top level
63 TorrentIsNoDict,
64 /// The .torrent file does not have an ``info`` dictionary
65 TorrentMissingInfo,
66 /// The .torrent file's ``info`` entry is not a dictionary
67 TorrentInfoNoDict,
68 /// The .torrent file does not have a ``piece length`` entry
69 TorrentMissingPieceLength,
70 /// The .torrent file does not have a ``name`` entry
71 TorrentMissingName,
72 /// The .torrent file's name entry is invalid
73 TorrentInvalidName,
74 /// The length of a file, or of the whole .torrent file is invalid.
75 /// Either negative or not an integer
76 TorrentInvalidLength,
77 /// Failed to parse a file entry in the .torrent
78 TorrentFileParseFailed,
79 /// The ``pieces`` field is missing or invalid in the .torrent file
80 TorrentMissingPieces,
81 /// The ``pieces`` string has incorrect length
82 TorrentInvalidHashes,
83 /// The .torrent file has more pieces than is supported by libtorrent
84 TooManyPiecesInTorrent,
85 /// The metadata (.torrent file) that was received from the swarm
86 /// matched the info-hash, but failed to be parsed
87 InvalidSwarmMetadata,
88 /// The file or buffer is not correctly bencoded
89 InvalidBencoding,
90 /// The .torrent file does not contain any files
91 NoFilesInTorrent,
92 /// The string was not properly url-encoded as expected
93 InvalidEscapedString,
94 /// Operation is not permitted since the session is shutting down
95 SessionIsClosing,
96 /// There's already a torrent with that info-hash added to the
97 /// session
98 DuplicateTorrent,
99 /// The supplied torrent_handle is not referring to a valid torrent
100 InvalidTorrentHandle,
101 /// The type requested from the entry did not match its type
102 InvalidEntryType,
103 /// The specified URI does not contain a valid info-hash
104 MissingInfoHashInUri,
105 /// One of the files in the torrent was unexpectedly small. This
106 /// might be caused by files being changed by an external process
107 FileTooShort,
108 /// The URL used an unknown protocol. Currently ``http`` and
109 /// ``https`` (if built with openssl support) are recognized. For
110 /// trackers ``udp`` is recognized as well.
111 UnsupportedUrlProtocol,
112 /// The URL did not conform to URL syntax and failed to be parsed
113 UrlParseError,
114 /// The peer sent a piece message of length 0
115 PeerSentEmptyPiece,
116 /// A bencoded structure was corrupt and failed to be parsed
117 ParseFailed,
118 /// The fast resume file was missing or had an invalid file version
119 /// tag
120 InvalidFileTag,
121 /// The fast resume file was missing or had an invalid info-hash
122 MissingInfoHash,
123 /// The info-hash did not match the torrent
124 MismatchingInfoHash,
125 /// The URL contained an invalid hostname
126 InvalidHostname,
127 /// The URL had an invalid port
128 InvalidPort,
129 /// The port is blocked by the port-filter, and prevented the
130 /// connection
131 PortBlocked,
132 /// The IPv6 address was expected to end with "]"
133 ExpectedCloseBracketInAddress,
134 /// The torrent is being destructed, preventing the operation to
135 /// succeed
136 DestructingTorrent,
137 /// The connection timed out
138 TimedOut,
139 /// The peer is upload only, and we are upload only. There's no point
140 /// in keeping the connection
141 UploadUploadConnection,
142 /// The peer is upload only, and we're not interested in it. There's
143 /// no point in keeping the connection
144 UninterestingUploadPeer,
145 /// The peer sent an unknown info-hash
146 InvalidInfoHash,
147 /// The torrent is paused, preventing the operation from succeeding
148 TorrentPaused,
149 /// The peer sent an invalid have message, either wrong size or
150 /// referring to a piece that doesn't exist in the torrent
151 InvalidHave,
152 /// The bitfield message had the incorrect size
153 InvalidBitfieldSize,
154 /// The peer kept requesting pieces after it was choked, possible
155 /// abuse attempt.
156 TooManyRequestsWhenChoked,
157 /// The peer sent a piece message that does not correspond to a
158 /// piece request sent by the client
159 InvalidPiece,
160 /// memory allocation failed
161 NoMemory,
162 /// The torrent is aborted, preventing the operation to succeed
163 TorrentAborted,
164 /// The peer is a connection to ourself, no point in keeping it
165 SelfConnection,
166 /// The peer sent a piece message with invalid size, either negative
167 /// or greater than one block
168 InvalidPieceSize,
169 /// The peer has not been interesting or interested in us for too
170 /// long, no point in keeping it around
171 TimedOutNoInterest,
172 /// The peer has not said anything in a long time, possibly dead
173 TimedOutInactivity,
174 /// The peer did not send a handshake within a reasonable amount of
175 /// time, it might not be a bittorrent peer
176 TimedOutNoHandshake,
177 /// The peer has been unchoked for too long without requesting any
178 /// data. It might be lying about its interest in us
179 TimedOutNoRequest,
180 /// The peer sent an invalid choke message
181 InvalidChoke,
182 /// The peer send an invalid unchoke message
183 InvalidUnchoke,
184 /// The peer sent an invalid interested message
185 InvalidInterested,
186 /// The peer sent an invalid not-interested message
187 InvalidNotInterested,
188 /// The peer sent an invalid piece request message
189 InvalidRequest,
190 /// The peer sent an invalid hash-list message (this is part of the
191 /// merkle-torrent extension)
192 InvalidHashList,
193 /// The peer sent an invalid hash-piece message (this is part of the
194 /// merkle-torrent extension)
195 InvalidHashPiece,
196 /// The peer sent an invalid cancel message
197 InvalidCancel,
198 /// The peer sent an invalid DHT port-message
199 InvalidDhtPort,
200 /// The peer sent an invalid suggest piece-message
201 InvalidSuggest,
202 /// The peer sent an invalid have all-message
203 InvalidHaveAll,
204 /// The peer sent an invalid have none-message
205 InvalidHaveNone,
206 /// The peer sent an invalid reject message
207 InvalidReject,
208 /// The peer sent an invalid allow fast-message
209 InvalidAllowFast,
210 /// The peer sent an invalid extension message ID
211 InvalidExtended,
212 /// The peer sent an invalid message ID
213 InvalidMessage,
214 /// The synchronization hash was not found in the encrypted handshake
215 SyncHashNotFound,
216 /// The encryption constant in the handshake is invalid
217 InvalidEncryptionConstant,
218 /// The peer does not support plain text, which is the selected mode
219 NoPlaintextMode,
220 /// The peer does not support RC4, which is the selected mode
221 NoRc4Mode,
222 /// The peer does not support any of the encryption modes that the
223 /// client supports
224 UnsupportedEncryptionMode,
225 /// The peer selected an encryption mode that the client did not
226 /// advertise and does not support
227 UnsupportedEncryptionModeSelected,
228 /// The pad size used in the encryption handshake is of invalid size
229 InvalidPadSize,
230 /// The encryption handshake is invalid
231 InvalidEncryptHandshake,
232 /// The client is set to not support incoming encrypted connections
233 /// and this is an encrypted connection
234 NoIncomingEncrypted,
235 /// The client is set to not support incoming regular bittorrent
236 /// connections, and this is a regular connection
237 NoIncomingRegular,
238 /// The client is already connected to this peer-ID
239 DuplicatePeerId,
240 /// Torrent was removed
241 TorrentRemoved,
242 /// The packet size exceeded the upper sanity check-limit
243 PacketTooLarge,
244
245 Reserved,
246
247 /// The web server responded with an error
248 HttpError,
249 /// The web server response is missing a location header
250 MissingLocation,
251 /// The web seed redirected to a path that no longer matches the
252 /// .torrent directory structure
253 InvalidRedirection,
254 /// The connection was closed because it redirected to a different
255 /// URL
256 Redirecting,
257 /// The HTTP range header is invalid
258 InvalidRangeLtrsError,
259 /// The HTTP response did not have a content length
260 NoContentLength,
261 /// The IP is blocked by the IP filter
262 BannedByIpFilter,
263 /// At the connection limit
264 TooManyConnections,
265 /// The peer is marked as banned
266 PeerBanned,
267 /// The torrent is stopping, causing the operation to fail
268 StoppingTorrent,
269 /// The peer has sent too many corrupt pieces and is banned
270 TooManyCorruptPieces,
271 /// The torrent is not ready to receive peers
272 TorrentNotReady,
273 /// The peer is not completely constructed yet
274 PeerNotConstructed,
275 /// The session is closing, causing the operation to fail
276 SessionClosing,
277 /// The peer was disconnected in order to leave room for a
278 /// potentially better peer
279 OptimisticDisconnect,
280 /// The torrent is finished
281 TorrentFinished,
282 /// No UPnP router found
283 NoRouter,
284 /// The metadata message says the metadata exceeds the limit
285 MetadataTooLarge,
286 /// The peer sent an invalid metadata request message
287 InvalidMetadataRequest,
288 /// The peer advertised an invalid metadata size
289 InvalidMetadataSize,
290 /// The peer sent a message with an invalid metadata offset
291 InvalidMetadataOffset,
292 /// The peer sent an invalid metadata message
293 InvalidMetadataMessage,
294 /// The peer sent a peer exchange message that was too large
295 PexMessageTooLarge,
296 /// The peer sent an invalid peer exchange message
297 InvalidPexMessage,
298 /// The peer sent an invalid tracker exchange message
299 InvalidLtTrackerMessage,
300 /// The peer sent pex messages too often. This is a possible
301 /// attempt of and attack
302 TooFrequentPex,
303 /// The operation failed because it requires the torrent to have
304 /// the metadata (.torrent file) and it doesn't have it yet.
305 /// This happens for magnet links before they have downloaded the
306 /// metadata, and also torrents added by URL.
307 NoMetadata,
308 /// The peer sent an invalid ``dont_have`` message. The don't have
309 /// message is an extension to allow peers to advertise that the
310 /// no longer has a piece they previously had.
311 InvalidDontHave,
312 /// The peer tried to connect to an SSL torrent without connecting
313 /// over SSL.
314 RequiresSslConnection,
315 /// The peer tried to connect to a torrent with a certificate
316 /// for a different torrent.
317 InvalidSslCert,
318 /// the torrent is not an SSL torrent, and the operation requires
319 /// an SSL torrent
320 NotAnSslTorrent,
321 /// peer was banned because its listen port is within a banned port
322 /// range, as specified by the port_filter.
323 BannedByPortFilter,
324 /// The session_handle is not referring to a valid session_impl
325 InvalidSessionHandle,
326 /// the listen socket associated with this request was closed
327 InvalidListenSocket,
328 InvalidHashRequest,
329 InvalidHashes,
330 InvalidHashReject,
331
332 /// these error codes are deprecated, NAT-PMP/PCP error codes have
333 /// been moved to their own category
334
335 // /// The NAT-PMP router responded with an unsupported protocol version
336 // #[deprecated]
337 // UnsupportedProtocolVersion = 120,
338 // /// You are not authorized to map ports on this NAT-PMP router
339 // #[deprecated]
340 // NatpmpNotAuthorized,
341 // /// The NAT-PMP router failed because of a network failure
342 // #[deprecated]
343 // NetworkFailure,
344 // /// The NAT-PMP router failed because of lack of resources
345 // #[deprecated]
346 // NoResources,
347 // /// The NAT-PMP router failed because an unsupported opcode was sent
348 // #[deprecated]
349 // UnsupportedOpcode,
350
351 /// The resume data file is missing the ``file sizes`` entry
352 MissingFileSizes = 130,
353 /// The resume data file ``file sizes`` entry is empty
354 NoFilesInResumeData,
355 /// The resume data file is missing the ``pieces`` and ``slots`` entry
356 MissingPieces,
357 /// The number of files in the resume data does not match the number
358 /// of files in the torrent
359 MismatchingNumberOfFiles,
360 /// One of the files on disk has a different size than in the fast
361 /// resume file
362 MismatchingFileSize,
363 /// One of the files on disk has a different timestamp than in the
364 /// fast resume file
365 MismatchingFileTimestamp,
366 /// The resume data file is not a dictionary
367 NotADictionary,
368 /// The ``blocks per piece`` entry is invalid in the resume data file
369 InvalidBlocksPerPiece,
370 /// The resume file is missing the ``slots`` entry, which is required
371 /// for torrents with compact allocation. *DEPRECATED*
372 MissingSlots,
373 /// The resume file contains more slots than the torrent
374 TooManySlots,
375 /// The ``slot`` entry is invalid in the resume data
376 InvalidSlotList,
377 /// One index in the ``slot`` list is invalid
378 InvalidPieceIndex,
379 /// The pieces on disk needs to be re-ordered for the specified
380 /// allocation mode. This happens if you specify sparse allocation
381 /// and the files on disk are using compact storage. The pieces needs
382 /// to be moved to their right position. *DEPRECATED*
383 PiecesNeedReorder,
384 /// this error is returned when asking to save resume data and
385 /// specifying the flag to only save when there's anything new to save
386 /// (torrent_handle::only_if_modified) and there wasn't anything changed.
387 ResumeDataNotModified,
388 /// the save_path in add_torrent_params is not valid
389 InvalidSavePath,
390
391 /// The HTTP header was not correctly formatted
392 HttpParseError = 150,
393 /// The HTTP response was in the 300-399 range but lacked a location
394 /// header
395 HttpMissingLocation,
396 /// The HTTP response was encoded with gzip or deflate but
397 /// decompressing it failed
398 HttpFailedDecompress,
399
400 /// The URL specified an i2p address, but no i2p router is configured
401 NoI2pRouter = 160,
402 /// i2p acceptor is not available yet, can't announce without endpoint
403 NoI2pEndpoint,
404
405 /// The tracker URL doesn't support transforming it into a scrape
406 /// URL. i.e. it doesn't contain "announce.
407 ScrapeNotAvailable = 170,
408 /// invalid tracker response
409 InvalidTrackerResponse,
410 /// invalid peer dictionary entry. Not a dictionary
411 InvalidPeerDict,
412 /// tracker sent a failure message
413 TrackerFailure,
414 /// missing or invalid ``files`` entry
415 InvalidFilesEntry,
416 /// missing or invalid ``hash`` entry
417 InvalidHashEntry,
418 /// missing or invalid ``peers`` and ``peers6`` entry
419 InvalidPeersEntry,
420 /// UDP tracker response packet has invalid size
421 InvalidTrackerResponseLength,
422 /// invalid transaction id in UDP tracker response
423 InvalidTrackerTransactionId,
424 /// invalid action field in UDP tracker response
425 InvalidTrackerAction,
426 /// skipped announce (because it's assumed to be unreachable over the
427 /// given source network interface)
428 AnnounceSkipped,
429
430 /// expected string in bencoded string
431 // #[deprecated]
432 // ExpectedString190,
433 // /// expected colon in bencoded string
434 // #[deprecated]
435 // ExpectedColon,
436 // /// unexpected end of file in bencoded string
437 // #[deprecated]
438 // UnexpectedEof,
439 // /// expected value (list, dict, int or string) in bencoded string
440 // #[deprecated]
441 // ExpectedValue,
442 // /// bencoded recursion depth limit exceeded
443 // #[deprecated]
444 // DepthExceeded,
445 // /// bencoded item count limit exceeded
446 // #[deprecated]
447 // LimitExceeded,
448 // /// integer overflow
449 // #[deprecated]
450 // Overflow,
451
452 /// random number generation failed
453 NoEntropy = 200,
454 /// blocked by SSRF mitigation
455 SsrvMitigation,
456 /// blocked because IDNA host names are banned
457 BlockedByIdna,
458
459 /// the torrent file has an unknown meta version
460 TorrentUnknownVersion = 210,
461 /// the v2 torrent file has no file tree
462 TorrentMissingFileTree,
463 /// the torrent contains v2 keys but does not specify meta version 2
464 TorrentMissingMetaVersion,
465 /// the v1 and v2 file metadata does not match
466 TorrentInconsistentFiles,
467 /// one or more files are missing piece layer hashes
468 TorrentMissingPieceLayer,
469 /// a piece layer has the wrong size or failed hash check
470 TorrentInvalidPieceLayer,
471 /// a v2 file entry has no root hash
472 TorrentMissingPiecesRoot,
473 /// the v1 and v2 hashes do not describe the same data
474 TorrentInconsistentHashes,
475 /// a file in the v2 metadata has the pad attribute set
476 TorrentInvalidPadFile,
477 /// The value is not used by libtorrent itself, it is only used
478 /// internally to match againt C++ integers and prevent crashes
479 /// as otherwise we would need a unreachable!() in the match arms.
480 #[cfg(feature = "safe_enums")]
481 #[num_enum(default)]
482 UnknownErrorCode,
483}
484
485#[derive(Debug)]
486#[cfg_attr(feature = "safe_enums", derive(num_enum::FromPrimitive))]
487#[repr(u16)]
488pub enum HttpError {
489 Cont = 100,
490 Ok = 200,
491 Created = 201,
492 Accepted = 202,
493 NoContent = 204,
494 MultipleChoices = 300,
495 MovedPermanently = 301,
496 MovedTemporarily = 302,
497 NotModified = 304,
498 BadRequest = 400,
499 Unauthorized = 401,
500 Forbidden = 403,
501 NotFound = 404,
502 InternalServerError = 500,
503 NotImplemented = 501,
504 BadGateway = 502,
505 ServiceUnavailable = 503,
506 #[cfg(feature = "safe_enums")]
507 #[num_enum(default)]
508 UnknownErrorCode,
509}
510
511#[derive(Debug)]
512#[cfg_attr(feature = "safe_enums", derive(num_enum::FromPrimitive))]
513#[repr(u8)]
514pub enum I2pError {
515 NoError = 0,
516 ParseFailed,
517 CantReachPeer,
518 I2pError,
519 InvalidKey,
520 InvalidId,
521 Timeout,
522 KeyNotFound,
523 DuplicatedId,
524 #[cfg(feature = "safe_enums")]
525 #[num_enum(default)]
526 UnknownErrorCode,
527}
528
529#[derive(Debug)]
530#[cfg_attr(feature = "safe_enums", derive(num_enum::FromPrimitive))]
531#[repr(u8)]
532pub enum GzipError {
533 NoError = 0,
534 InvalidGzipHeader,
535 InflatedDataTooLarge,
536 DataDidNotTerminate,
537 SpaceExhausted,
538 InvalidBlockType,
539 InvalidStoredBlockLength,
540 TooManyLengthOrDistanceCodes,
541 CodeLengthsCodesIncomplete,
542 RepeatLengthsWithNoFirstLength,
543 RepeatMoreThanSpecifiedLengths,
544 InvalidLiteralLengthCodeLengths,
545 InvalidDistanceCodeLengths,
546 InvalidLiteralCodeInBlock,
547 DistanceTooFarBackInBlock,
548 UnknownGzipError,
549 #[cfg(feature = "safe_enums")]
550 #[num_enum(default)]
551 UnknownErrorCode,
552}
553
554#[derive(Debug)]
555#[cfg_attr(feature = "safe_enums", derive(num_enum::FromPrimitive))]
556#[repr(u8)]
557pub enum PcpError {
558 Success = 0,
559 UnsupportedVersion,
560 NotAuthorized,
561 MalformedRequest,
562 UnsupportedOpcode,
563 UnsupportedOption,
564 MalformedOption,
565 NetworkFailure,
566 NoResources,
567 UnsupportedProtocol,
568 UserExQuota,
569 CannotProvideExternal,
570 AddressMismatch,
571 ExcessiveRemotePeers,
572 #[cfg(feature = "safe_enums")]
573 #[num_enum(default)]
574 UnknownErrorCode,
575}
576
577#[derive(Debug)]
578#[cfg_attr(feature = "safe_enums", derive(num_enum::FromPrimitive))]
579#[repr(u8)]
580pub enum BdecodeError {
581 NoError = 0,
582 ExpectedDigit,
583 ExpectedColon,
584 UnexpectedEof,
585 ExpectedValue,
586 DepthExceeded,
587 LimitExceeded,
588 Overflow,
589 #[cfg(feature = "safe_enums")]
590 #[num_enum(default)]
591 UnknownErrorCode,
592}
593
594#[derive(Debug)]
595#[cfg_attr(feature = "safe_enums", derive(num_enum::FromPrimitive))]
596#[repr(u8)]
597pub enum SocksError {
598 NoError = 0,
599 UnsupportedVersion,
600 UnsupportedAuthenticationMethod,
601 UnsupportedAuthenticationVersion,
602 AuthenticationError,
603 UsernameRequired,
604 GeneralFailure,
605 CommandNotSupported,
606 NoIdentd,
607 IdentdError,
608 #[cfg(feature = "safe_enums")]
609 #[num_enum(default)]
610 UnknownErrorCode,
611}
612
613#[derive(Debug)]
614#[cfg_attr(feature = "safe_enums", derive(num_enum::FromPrimitive))]
615#[repr(u16)]
616pub enum UpnpError {
617 NoError = 0,
618 InvalidArgument = 402,
619 ActionFailed = 501,
620 ValueNotInArray = 714,
621 SourceIpCannotBeWildcarded = 715,
622 ExternalPortCannotBeWildcarded = 716,
623 PortMappingConflict = 718,
624 InternalPortMustMatchExternal = 724,
625 OnlyPermanentLeasesSupported = 725,
626 RemoteHostMustBeWildcarded = 726,
627 ExternalPortMustBeWildcarded = 727,
628 #[cfg(feature = "safe_enums")]
629 #[num_enum(default)]
630 UnknownErrorCode,
631}
632
633impl From<ffi::Error> for LtrsError {
634 fn from(err: ffi::Error) -> Self {
635 cfg_if::cfg_if! {
636 if #[cfg(feature = "safe_enums")] {
637 match err.category {
638 ffi::ErrorCategory::LibtorrentError => {
639 LtrsError::LibtorrentError(err.code.into())
640 }
641 ffi::ErrorCategory::HttpError => {
642 LtrsError::HttpError(err.code.into())
643 }
644 ffi::ErrorCategory::GzipError => {
645 LtrsError::GzipError(err.code.into())
646 }
647 ffi::ErrorCategory::PcpError => {
648 LtrsError::PcpError(err.code.into())
649 }
650 ffi::ErrorCategory::BdecodeError => {
651 LtrsError::BdecodeError(err.code.into())
652 }
653 ffi::ErrorCategory::SocksError => {
654 LtrsError::SocksError(err.code.into())
655 }
656 ffi::ErrorCategory::UpnpError => {
657 LtrsError::UpnpError(err.codee.into())
658 }
659 ffi::ErrorCategory::I2pError => {
660 LtrsError::I2pError(err.code.into())
661 }
662 _ => LtrsError::Unknown(err.code),
663 }
664 } else {
665 // SAFETY: We trust that libtorrent will not return invalid error codes
666 unsafe {
667 match err.category {
668 ffi::ErrorCategory::LibtorrentError => {
669 LtrsError::LibtorrentError(std::mem::transmute(err.code as u8))
670 }
671 ffi::ErrorCategory::HttpError => {
672 LtrsError::HttpError(std::mem::transmute(err.code as u16))
673 }
674 ffi::ErrorCategory::GzipError => {
675 LtrsError::GzipError(std::mem::transmute(err.code as u8))
676 }
677 ffi::ErrorCategory::PcpError => {
678 LtrsError::PcpError(std::mem::transmute(err.code as u8))
679 }
680 ffi::ErrorCategory::BdecodeError => {
681 LtrsError::BdecodeError(std::mem::transmute(err.code as u8))
682 }
683 ffi::ErrorCategory::SocksError => {
684 LtrsError::SocksError(std::mem::transmute(err.code as u8))
685 }
686 ffi::ErrorCategory::UpnpError => {
687 LtrsError::UpnpError(std::mem::transmute(err.code as u16))
688 }
689 ffi::ErrorCategory::I2pError => {
690 LtrsError::I2pError(std::mem::transmute(err.code as u8))
691 }
692 _ => LtrsError::Unknown(err.code),
693 }
694 }
695 }
696 }
697 }
698}