From: Jiaxin Wu <Jiaxin.wu@intel.com>
To: edk2-devel@lists.01.org
Cc: Ye Ting <ting.ye@intel.com>, Fu Siyuan <siyuan.fu@intel.com>,
Shao Ming <ming.shao@intel.com>, Wu Jiaxin <jiaxin.wu@intel.com>
Subject: [Patch 2/5] NetworkPkg/Mtftp6Dxe: Support windowsize in read request operation.
Date: Mon, 17 Sep 2018 13:43:45 +0800 [thread overview]
Message-ID: <20180917054348.19228-3-Jiaxin.wu@intel.com> (raw)
In-Reply-To: <20180917054348.19228-1-Jiaxin.wu@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=886
This patch is to support the TFTP windowsize option described in RFC 7440.
The feature allows the client and server to negotiate a window size of
consecutive blocks to send as an alternative for replacing the single-block
lockstep schema.
Currently, the windowsize for write request operation is not supported since
there is no real use cases.
Cc: Ye Ting <ting.ye@intel.com>
Cc: Fu Siyuan <siyuan.fu@intel.com>
Cc: Shao Ming <ming.shao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Wu Jiaxin <jiaxin.wu@intel.com>
---
NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h | 13 ++++++-
NetworkPkg/Mtftp6Dxe/Mtftp6Option.c | 22 +++++++++++-
NetworkPkg/Mtftp6Dxe/Mtftp6Option.h | 14 +++++---
NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c | 53 +++++++++++++++++++---------
NetworkPkg/Mtftp6Dxe/Mtftp6Support.c | 10 ++++++
NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c | 2 +-
6 files changed, 90 insertions(+), 24 deletions(-)
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h b/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h
index 6b1ce7f853..cf1b6abacc 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h
@@ -1,9 +1,9 @@
/** @file
Mtftp6 internal data structure and definition declaration.
- Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved. <BR>
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. <BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
@@ -44,10 +44,11 @@ typedef struct _MTFTP6_INSTANCE MTFTP6_INSTANCE;
#define MTFTP6_DEFAULT_SERVER_CMD_PORT 69
#define MTFTP6_DEFAULT_TIMEOUT 3
#define MTFTP6_GET_MAPPING_TIMEOUT 3
#define MTFTP6_DEFAULT_MAX_RETRY 5
#define MTFTP6_DEFAULT_BLK_SIZE 512
+#define MTFTP6_DEFAULT_WINDOWSIZE 1
#define MTFTP6_TICK_PER_SECOND 10000000U
#define MTFTP6_SERVICE_FROM_THIS(a) CR (a, MTFTP6_SERVICE, ServiceBinding, MTFTP6_SERVICE_SIGNATURE)
#define MTFTP6_INSTANCE_FROM_THIS(a) CR (a, MTFTP6_INSTANCE, Mtftp6, MTFTP6_INSTANCE_SIGNATURE)
@@ -75,10 +76,20 @@ struct _MTFTP6_INSTANCE {
UINT16 BlkSize;
UINT16 LastBlk;
LIST_ENTRY BlkList;
+ UINT16 Operation;
+
+ UINT16 WindowSize;
+
+ //
+ // Record the total received block number and the already acked block number.
+ //
+ UINT64 TotalBlock;
+ UINT64 AckedBlock;
+
EFI_IPv6_ADDRESS ServerIp;
UINT16 ServerCmdPort;
UINT16 ServerDataPort;
UDP_IO *UdpIo;
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c
index 0dcf546fa8..94790e3ad6 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c
@@ -1,9 +1,9 @@
/** @file
Mtftp6 option parse functions implementation.
- Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
@@ -15,10 +15,11 @@
#include "Mtftp6Impl.h"
CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM] = {
"blksize",
+ "windowsize",
"timeout",
"tsize",
"multicast"
};
@@ -144,10 +145,11 @@ Mtftp6ParseMcastOption (
@param[in] Options The pointer to the extension options list.
@param[in] Count The num of the extension options.
@param[in] IsRequest If FALSE, the extension options is included
by a request packet.
+ @param[in] Operation The current performed operation.
@param[in] ExtInfo The pointer to the option information to be filled.
@retval EFI_SUCCESS Parse the multicast option successfully.
@retval EFI_INVALID_PARAMETER There is one option is malformatted at least.
@retval EFI_UNSUPPORTED There is one option is not supported at least.
@@ -156,10 +158,11 @@ Mtftp6ParseMcastOption (
EFI_STATUS
Mtftp6ParseExtensionOption (
IN EFI_MTFTP6_OPTION *Options,
IN UINT32 Count,
IN BOOLEAN IsRequest,
+ IN UINT16 Operation,
IN MTFTP6_EXT_OPTION_INFO *ExtInfo
)
{
EFI_STATUS Status;
EFI_MTFTP6_OPTION *Opt;
@@ -226,10 +229,27 @@ Mtftp6ParseExtensionOption (
return EFI_INVALID_PARAMETER;
}
ExtInfo->BitMap |= MTFTP6_OPT_MCAST_BIT;
+ } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "windowsize") == 0) {
+ if (Operation == EFI_MTFTP6_OPCODE_WRQ) {
+ //
+ // Currently, windowsize is not supported in the write operation.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
+
+ if ((Value < 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ExtInfo->WindowSize = (UINT16) Value;
+ ExtInfo->BitMap |= MTFTP6_OPT_WINDOWSIZE_BIT;
+
} else if (IsRequest) {
//
// If it's a request, unsupported; else if it's a reply, ignore.
//
return EFI_UNSUPPORTED;
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h
index 8e2671fa21..08aa45ff63 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h
@@ -1,9 +1,9 @@
/** @file
Mtftp6 option parse functions declaration.
- Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
@@ -24,11 +24,11 @@
#include <Library/UdpIoLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
-#define MTFTP6_SUPPORTED_OPTIONS_NUM 4
+#define MTFTP6_SUPPORTED_OPTIONS_NUM 5
#define MTFTP6_OPCODE_LEN 2
#define MTFTP6_ERRCODE_LEN 2
#define MTFTP6_BLKNO_LEN 2
#define MTFTP6_DATA_HEAD_LEN 4
@@ -37,15 +37,17 @@
//
#define MTFTP6_OPT_BLKSIZE_BIT 0x01
#define MTFTP6_OPT_TIMEOUT_BIT 0x02
#define MTFTP6_OPT_TSIZE_BIT 0x04
#define MTFTP6_OPT_MCAST_BIT 0x08
+#define MTFTP6_OPT_WINDOWSIZE_BIT 0X10
extern CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM];
typedef struct {
UINT16 BlkSize;
+ UINT16 WindowSize;
UINT8 Timeout;
UINT32 Tsize;
EFI_IPv6_ADDRESS McastIp;
UINT16 McastPort;
BOOLEAN IsMaster;
@@ -74,22 +76,24 @@ Mtftp6ParseMcastOption (
@param[in] Options The pointer to the extension options list.
@param[in] Count The num of the extension options.
@param[in] IsRequest If FALSE, the extension options is included
by a request packet.
+ @param[in] Operation The current performed operation.
@param[in] ExtInfo The pointer to the option information to be filled.
- @retval EFI_SUCCESS Parse the multi-cast option successfully.
- @retval EFI_INVALID_PARAMETER An option is malformatted.
- @retval EFI_UNSUPPORTED An option is not supported.
+ @retval EFI_SUCCESS Parse the multicast option successfully.
+ @retval EFI_INVALID_PARAMETER There is one option is malformatted at least.
+ @retval EFI_UNSUPPORTED There is one option is not supported at least.
**/
EFI_STATUS
Mtftp6ParseExtensionOption (
IN EFI_MTFTP6_OPTION *Options,
IN UINT32 Count,
IN BOOLEAN IsRequest,
+ IN UINT16 Operation,
IN MTFTP6_EXT_OPTION_INFO *ExtInfo
);
/**
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
index 2aadef076c..1f685b2bfe 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
@@ -1,9 +1,9 @@
/** @file
Mtftp6 Rrq process functions implementation.
- Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
@@ -33,10 +33,13 @@ Mtftp6RrqSendAck (
IN UINT16 BlockNum
)
{
EFI_MTFTP6_PACKET *Ack;
NET_BUF *Packet;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
//
// Allocate net buffer to create ack packet.
//
Packet = NetbufAlloc (sizeof (EFI_MTFTP6_ACK_HEADER));
@@ -59,11 +62,16 @@ Mtftp6RrqSendAck (
// Reset current retry count of the instance.
//
Instance->CurRetry = 0;
Instance->LastPacket = Packet;
- return Mtftp6TransmitPacket (Instance, Packet);
+ Status = Mtftp6TransmitPacket (Instance, Packet);
+ if (!EFI_ERROR (Status)) {
+ Instance->AckedBlock = Instance->TotalBlock;
+ }
+
+ return Status;
}
/**
Deliver the received data block to the user, which can be saved
@@ -92,11 +100,10 @@ Mtftp6RrqSaveBlock (
EFI_MTFTP6_TOKEN *Token;
EFI_STATUS Status;
UINT16 Block;
UINT64 Start;
UINT32 DataLen;
- UINT64 TotalBlock;
BOOLEAN Completed;
Completed = FALSE;
Token = Instance->Token;
Block = NTOHS (Packet->Data.Block);
@@ -116,11 +123,11 @@ Mtftp6RrqSaveBlock (
// returns EFI_NOT_FOUND, the block has been saved, don't save it again.
// Note that : For bigger files, allowing the block counter to roll over
// to accept transfers of unlimited size. So TotalBlock is memorised as
// continuous block counter.
//
- Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &TotalBlock);
+ Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &Instance->TotalBlock);
if (Status == EFI_NOT_FOUND) {
return EFI_SUCCESS;
} else if (EFI_ERROR (Status)) {
return Status;
@@ -152,11 +159,11 @@ Mtftp6RrqSaveBlock (
}
}
if (Token->Buffer != NULL) {
- Start = MultU64x32 (TotalBlock - 1, Instance->BlkSize);
+ Start = MultU64x32 (Instance->TotalBlock - 1, Instance->BlkSize);
if (Start + DataLen <= Token->BufferSize) {
CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
//
// Update the file size when received the last block
//
@@ -222,30 +229,33 @@ Mtftp6RrqHandleData (
EFI_STATUS Status;
UINT16 BlockNum;
INTN Expected;
*IsCompleted = FALSE;
+ Status = EFI_SUCCESS;
BlockNum = NTOHS (Packet->Data.Block);
Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
ASSERT (Expected >= 0);
//
- // If we are active and received an unexpected packet, retransmit
- // the last ACK then restart receiving. If we are passive, save
- // the block.
+ // If we are active and received an unexpected packet, transmit
+ // the ACK for the block we received, then restart receiving the
+ // expected one. If we are passive, save the block.
//
if (Instance->IsMaster && (Expected != BlockNum)) {
//
// Free the received packet before send new packet in ReceiveNotify,
// since the udpio might need to be reconfigured.
//
NetbufFree (*UdpPacket);
*UdpPacket = NULL;
- Mtftp6TransmitPacket (Instance, Instance->LastPacket);
- return EFI_SUCCESS;
+ //
+ // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).
+ //
+ return Mtftp6RrqSendAck (Instance, (UINT16) (Expected - 1));
}
Status = Mtftp6RrqSaveBlock (Instance, Packet, Len, UdpPacket);
if (EFI_ERROR (Status)) {
@@ -286,14 +296,16 @@ Mtftp6RrqHandleData (
// since the udpio might need to be reconfigured.
//
NetbufFree (*UdpPacket);
*UdpPacket = NULL;
- Mtftp6RrqSendAck (Instance, BlockNum);
+ if (Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock) || Expected < 0) {
+ Status = Mtftp6RrqSendAck (Instance, BlockNum);
+ }
}
- return EFI_SUCCESS;
+ return Status;
}
/**
Validate whether the options received in the server's OACK packet is valid.
@@ -324,16 +336,17 @@ Mtftp6RrqOackValid (
if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
return FALSE;
}
//
- // Server can only specify a smaller block size to be used and
+ // Server can only specify a smaller block size and windowsize to be used and
// return the timeout matches that requested.
//
if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
+ (((ReplyInfo->BitMap & MTFTP6_OPT_WINDOWSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
(((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
- ) {
+ ) {
return FALSE;
}
//
// The server can send ",,master" to client to change its master
@@ -483,11 +496,11 @@ Mtftp6RrqHandleOack (
ASSERT (Options != NULL);
//
// Parse the extensive options in the packet.
//
- Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo);
+ Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);
if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) {
//
// Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
//
@@ -513,11 +526,11 @@ Mtftp6RrqHandleOack (
if ((ExtInfo.BitMap & MTFTP6_OPT_MCAST_BIT) != 0) {
//
// Save the multicast info. Always update the Master, only update the
- // multicast IP address, block size, timeoute at the first time. If IP
+ // multicast IP address, block size, window size, timeoute at the first time. If IP
// address is updated, create a UDP child to receive the multicast.
//
Instance->IsMaster = ExtInfo.IsMaster;
if (NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
@@ -610,10 +623,14 @@ Mtftp6RrqHandleOack (
//
if (ExtInfo.BlkSize != 0) {
Instance->BlkSize = ExtInfo.BlkSize;
}
+ if (ExtInfo.WindowSize != 0) {
+ Instance->WindowSize = ExtInfo.WindowSize;
+ }
+
if (ExtInfo.Timeout != 0) {
Instance->Timeout = ExtInfo.Timeout;
}
}
@@ -623,10 +640,14 @@ Mtftp6RrqHandleOack (
if (ExtInfo.BlkSize != 0) {
Instance->BlkSize = ExtInfo.BlkSize;
}
+ if (ExtInfo.WindowSize != 0) {
+ Instance->WindowSize = ExtInfo.WindowSize;
+ }
+
if (ExtInfo.Timeout != 0) {
Instance->Timeout = ExtInfo.Timeout;
}
}
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
index 282a9c8e49..275272b89e 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
@@ -977,10 +977,14 @@ Mtftp6OperationClean (
Instance->ServerCmdPort = 0;
Instance->ServerDataPort = 0;
Instance->McastPort = 0;
Instance->BlkSize = 0;
+ Instance->Operation = 0;
+ Instance->WindowSize = 1;
+ Instance->TotalBlock = 0;
+ Instance->AckedBlock = 0;
Instance->LastBlk = 0;
Instance->PacketToLive = 0;
Instance->MaxRetry = 0;
Instance->CurRetry = 0;
Instance->Timeout = 0;
@@ -1049,19 +1053,22 @@ Mtftp6OperationStart (
}
Status = EFI_SUCCESS;
Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Instance->Operation = OpCode;
+
//
// Parse the extension options in the request packet.
//
if (Token->OptionCount != 0) {
Status = Mtftp6ParseExtensionOption (
Token->OptionList,
Token->OptionCount,
TRUE,
+ Instance->Operation,
&Instance->ExtInfo
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
@@ -1103,10 +1110,13 @@ Mtftp6OperationStart (
Instance->ServerCmdPort = MTFTP6_DEFAULT_SERVER_CMD_PORT;
}
if (Instance->BlkSize == 0) {
Instance->BlkSize = MTFTP6_DEFAULT_BLK_SIZE;
}
+ if (Instance->WindowSize == 0) {
+ Instance->WindowSize = MTFTP6_DEFAULT_WINDOWSIZE;
+ }
if (Instance->MaxRetry == 0) {
Instance->MaxRetry = MTFTP6_DEFAULT_MAX_RETRY;
}
if (Instance->Timeout == 0) {
Instance->Timeout = MTFTP6_DEFAULT_TIMEOUT;
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c
index 254b757f7e..055fbe6d1b 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c
@@ -316,11 +316,11 @@ Mtftp6WrqHandleOack (
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (Options != NULL);
- Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo);
+ Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);
if (EFI_ERROR(Status) || !Mtftp6WrqOackValid (&ExtInfo, &Instance->ExtInfo)) {
//
// Don't send a MTFTP error packet when out of resource, it can
// only make it worse.
--
2.17.1.windows.2
next prev parent reply other threads:[~2018-09-17 5:43 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-09-17 5:43 [Patch 0/5] Support windowsize to benefit tftp/pxe download performance Jiaxin Wu
2018-09-17 5:43 ` [Patch 1/5] MdeModulePke/Mtftp4Dxe: Support windowsize in read request operation Jiaxin Wu
2018-09-17 5:43 ` Jiaxin Wu [this message]
2018-09-17 5:43 ` [Patch 3/5] ShellPkg/TftpDynamicCommand: Add one option for tftp command to specify windowsize Jiaxin Wu
2018-09-17 22:18 ` Carsey, Jaben
2018-09-17 5:43 ` [Patch 4/5] MdeModulePkg/MdeModulePkg.dec: Define one PCD for PXE to specify MTFTP windowsize Jiaxin Wu
2018-09-18 11:04 ` Laszlo Ersek
2018-09-19 1:55 ` Wu, Jiaxin
2018-09-19 0:38 ` Fu, Siyuan
2018-09-19 2:21 ` Wu, Jiaxin
2018-09-17 5:43 ` [Patch 5/5] NetworkPkg/UefiPxeBcDxe: Use the specified " Jiaxin Wu
2018-09-18 11:23 ` [Patch 0/5] Support windowsize to benefit tftp/pxe download performance Laszlo Ersek
2018-09-19 2:20 ` Wu, Jiaxin
2018-09-19 11:24 ` Laszlo Ersek
2018-09-20 5:54 ` Wu, Jiaxin
[not found] ` <845df55b-b9ba-20f9-25fd-22778253c198@redhat.com>
2018-09-21 6:33 ` Wu, Jiaxin
2018-09-21 9:37 ` Laszlo Ersek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180917054348.19228-3-Jiaxin.wu@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox