📄 ftp_task.c
字号:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004-2006
Part of BlueLab 3.6.2-release
FILE NAME
ftp_task.c
DESCRIPTION
Source file for an OBEX Server application FTP Task.
*/
#include "ftps.h"
#include <message.h>
#include <vm.h>
#include <connection.h>
#include <pio.h>
#include <file.h>
#include <panic.h>
#include <stdlib.h>
#include <ps.h>
#include "ObexServer.h"
static void sendFolderListing(tFTPState *state, bool first);
static void sendGetObject(tFTPState *state, bool first);
static void setPathSubFolder(tFTPState *state, FTPS_SETPATH_SUBFOLDER_IND_T *msg);
static void ftp_handler(Task task, MessageId id, Message message)
{
/* Get task control block */
tFTPState *state = (tFTPState*)task;
switch(id)
{
case FTPS_INIT_CFM:
{
FTPS_INIT_CFM_T *msg = (FTPS_INIT_CFM_T*)message;
FTP_SVR_DEBUG(("FTPS_INIT_CFM :- "));
if (msg->status == ftps_success)
{
GEN_DEBUG(("success\n"));
state->session = msg->ftps;
}
#ifdef FTPS_SVR_DEBUG
else
{
if (msg->status == ftps_invalid_sdp)
{
GEN_DEBUG(("failure : Invalid SDP Record\n"));
}
else
{
GEN_DEBUG(("failure : %d\n", msg->status));
}
}
#endif
break;
}
case FTPS_CONNECT_IND:
{ /* Remote client has requested a connection */
uint16 sz=0;
#ifdef FTPS_SVR_DEBUG
FTPS_CONNECT_IND_T *msg = (FTPS_CONNECT_IND_T*)message;
FTP_SVR_DEBUG(("FTPS_CONNECT_IND :-\n"));
FTP_SVR_DEBUG((" BD Addr : 0x%X 0x%X 0x%X%X\n", msg->bd_addr.nap, msg->bd_addr.uap, (uint16)(msg->bd_addr.lap>>16), (uint16)(msg->bd_addr.lap&0xFFFF)));
FTP_SVR_DEBUG((" Max. Packet Len : 0x%X (%d)\n", msg->maxPacketLen, msg->maxPacketLen));
#endif
/* Get the maximum packet size from the PS and use it if it is bigger than the default (255) */
PsRetrieve(PSKEY_FTPS_MAX_PACKET, &sz, sizeof(sz));
sz = sz<FTPS_MAX_PACKET_SIZE ? FTPS_MAX_PACKET_SIZE:sz;
FtpsConnectResponse(state->session, TRUE, sz, ftps_serv_readonly);
break;
}
case FTPS_CONNECT_CFM:
{ /* Connection process complete */
FTPS_CONNECT_CFM_T *msg = (FTPS_CONNECT_CFM_T*)message;
FTP_SVR_DEBUG(("FTPS_CONNECT_CFM :- "));
if (msg->status == ftps_success)
{
GEN_DEBUG(("success\n"));
FTP_SVR_DEBUG((" Max. Packet Len : 0x%X (%d)\n", msg->maxPacketLen, msg->maxPacketLen));
/* The actual max. packet size being used. ( minimum of client size and server size) */
state->pktSize = msg->maxPacketLen;
state->fileSrc = 0;
state->currentDir = FILE_ROOT;
}
else
{
FTP_SVR_DEBUG(("failure : %d\n", msg->status));
}
break;
}
case FTPS_DISCONNECT_IND:
{ /* Remote client has disconnected */
FTP_SVR_DEBUG(("FTPS_DISCONNECT_IND\n"));
break;
}
case FTPS_GETFOLDER_START_IND:
{ /* Start to download the folder listing */
FILE_INDEX file;
FTP_SVR_DEBUG(("FTPS_GETFOLDER_START_IND\n"));
file = FileFind(state->currentDir, folderFile, sizeof(folderFile)-1);
if (file != FILE_NONE)
{
FTP_SVR_DEBUG((" Sending Packet\n"));
state->fileSrc = StreamFileSource(file);
/* Send first packet to the client */
sendFolderListing(state, TRUE);
}
else
{ /* Not sure what to do here */
FTP_SVR_DEBUG((" Error Packet\n"));
}
break;
}
case FTPS_GETFOLDER_DATA_IND:
{ /* Send the next packet of the folder listing to the remote client */
FTP_SVR_DEBUG(("FTPS_GETFOLDER_DATA_IND\n"));
if (state->fileSrc != 0)
{
sendFolderListing(state, FALSE);
}
else
FtpsGetObjectReject(state->session, ftps_transfer_BadRequest);
break;
}
case FTPS_GETOBJECT_COMPLETE_IND:
case FTPS_GETFOLDER_COMPLETE_IND:
{
FTP_SVR_DEBUG(("FTPS_GETFOLDER_COMPLETE_IND or FTPS_GETOBJECT_COMPLETE_IND\n"));
/* Object has been transfered, dispose of the source */
StreamConnectDispose(state->fileSrc);
state->fileSrc = 0;
break;
}
case FTPS_SETPATH_SUBFOLDER_IND:
{
setPathSubFolder(state, (FTPS_SETPATH_SUBFOLDER_IND_T*)message);
break;
}
case FTPS_SETPATH_ROOT_IND:
{
FTP_SVR_DEBUG(("FTPS_SETPATH_ROOT_IND\n"));
if (state->currentDir == FILE_ROOT)
{
/* Should return ftps_setpath_AtRoot, but some stacks get confused, so just say 'OK' */
FtpsSetPathRootResponse(state->session, ftps_setpath_OK);
}
else
{
state->currentDir = FILE_ROOT;
FtpsSetPathRootResponse(state->session, ftps_setpath_OK);
}
break;
}
case FTPS_SETPATH_PARENT_IND:
{
FTP_SVR_DEBUG(("FTPS_SETPATH_PARENT_IND\n"));
if (state->currentDir == FILE_ROOT)
{
FtpsSetPathParentResponse(state->session, ftps_setpath_AtRoot);
}
else
{
FILE_INDEX parent = FileParent(state->currentDir);
if (parent == FILE_NONE)
{ /* We are potentially in trouble if this happens, but it should
just be a case of 'belt and braces' */
FtpsSetPathParentResponse(state->session, ftps_setpath_NotFound);
}
else
{
state->currentDir = parent;
FtpsSetPathParentResponse(state->session, ftps_setpath_OK);
}
}
break;
}
case FTPS_GETOBJECT_START_IND:
{
FTPS_GETOBJECT_START_IND_T *msg = (FTPS_GETOBJECT_START_IND_T*)message;
const uint8* s=SourceMap(msg->src);
uint16 cnt,end;
char *name=NULL;
uint16 pos = 0;
FTP_SVR_DEBUG(("FTPS_GETOBJECT_START_IND\n"));
if (msg->nameLen>0)
{
name = (char*)PanicUnlessMalloc(( msg->nameLen/2) );
end=msg->nameOffset+msg->nameLen-2; /* UTF-16 Null */
#ifdef FTPS_SVR_DEBUG
FTP_SVR_DEBUG((" Filename : "));
cnt=msg->nameOffset+1;
while (cnt<end)
{
GEN_DEBUG(("%c",s[cnt]));
cnt+=2;
}
GEN_DEBUG((" - "));
cnt=msg->nameOffset;
while (cnt<end)
{
GEN_DEBUG(("%X, ",s[cnt]));
cnt+=1;
}
GEN_DEBUG(("\n"));
#endif
/* Convert name to a narrow string. Assume name is Latin-1 codepage UCS-16 */
cnt=msg->nameOffset+1;
while (cnt<end)
{
name[pos]=s[cnt];
pos++;
cnt+=2;
}
}
#ifdef FTPS_SVR_DEBUG
if (msg->typeLen>0)
{
end=msg->typeOffset+msg->typeLen;
FTP_SVR_DEBUG((" Type : "));
for (cnt=msg->typeOffset; cnt<end; cnt++)
GEN_DEBUG(("%c, ",s[cnt]));
GEN_DEBUG(("\n"));
}
#endif
/* We don't need the data in the source anymore, release it as soon as possible */
FtpsPacketComplete(state->session);
if (name == NULL)
/* Server only supports get by name, not by type */
FtpsGetObjectReject(state->session, ftps_transfer_NotFound);
else
{
FILE_INDEX file;
file = FileFind(state->currentDir, name, pos);
/* Don't need the name anymore so free it */
free(name);
if ((file == FILE_NONE) || (FileType(file) == FILE_TYPE_DIRECTORY))
{ /* Don't support getting a directory */
FtpsGetObjectReject(state->session, ftps_transfer_NotFound);
}
else
{
FTP_SVR_DEBUG((" Sending Packet\n"));
state->fileSrc = StreamFileSource(file);
/* Send first packet of the object */
sendGetObject(state, TRUE);
}
}
break;
}
case FTPS_GETOBJECT_DATA_IND:
{
FTP_SVR_DEBUG(("FTPS_GETOBJECT_DATA_IND\n"));
if (state->fileSrc != 0)
{
/* Drop the packet we have just sent from the source */
SourceDrop(state->fileSrc, state->pktSize);
/* Send next packet */
sendGetObject(state, FALSE);
}
else
FtpsGetObjectReject(state->session, ftps_transfer_BadRequest);
break;
}
default:
FTP_SVR_DEBUG(("Unhandled Message : %d , 0x%0X\n",id,id));
break;
}
}
void ftp_initTask(tFTPState *state)
{
state->FtpTask.handler = ftp_handler;
state->session = 0;
state->connected = FALSE;
state->shutdown = FALSE;
}
static void sendFolderListing(tFTPState *state, bool first)
{
uint16 len = SourceSize(state->fileSrc);
if (len <= state->pktSize)
{ /* send last packet */
FTP_SVR_DEBUG((" Sending last packet\n"));
if (first)
FtpsGetFolderFirstPacketSource(state->session, len, state->fileSrc, len, TRUE);
else
FtpsGetFolderNextPacketSource(state->session,
len, state->fileSrc, TRUE);
}
else
{ /* send next packet */
FTP_SVR_DEBUG((" Sending interim packet\n"));
if (first)
FtpsGetFolderFirstPacketSource(state->session, state->pktSize, state->fileSrc, 0, FALSE);
else
FtpsGetFolderNextPacketSource(state->session,
state->pktSize, state->fileSrc, FALSE);
}
}
static void sendGetObject(tFTPState *state, bool first)
{
uint16 len = SourceSize(state->fileSrc);
if (len <= state->pktSize)
{ /* Last Packet */
FTP_SVR_DEBUG((" Sending last packet\n"));
if (first)
FtpsGetObjectFirstPacketSource(state->session,
0, NULL, /* Client should already know this */
0, NULL, len, state->fileSrc, len, TRUE);
else
FtpsGetObjectNextPacketSource(state->session, len, state->fileSrc, TRUE);
}
else
{ /* Not last packet */
FTP_SVR_DEBUG((" Sending interim packet\n"));
if (first)
FtpsGetObjectFirstPacketSource(state->session,
0, NULL, /* Client should already know this */
0, NULL, state->pktSize, state->fileSrc, 0, FALSE);
else
FtpsGetObjectNextPacketSource(state->session, state->pktSize, state->fileSrc, FALSE);
}
}
static void setPathSubFolder(tFTPState *state, FTPS_SETPATH_SUBFOLDER_IND_T *msg)
{
const uint8* s=SourceMap(msg->src);
char *name;
uint16 cnt,end;
uint16 pos = 0;
FILE_INDEX file;
FTP_SVR_DEBUG(("FTPS_SETPATH_SUBFOLDER\n"));
name = (char*)PanicUnlessMalloc(( msg->nameLength/2) );
if (msg->nameLength>0)
{
end=msg->nameOffset+msg->nameLength-2; /* UTF-16 Null */
#ifdef FTPS_SVR_DEBUG
FTP_SVR_DEBUG((" Folder name : "));
cnt=msg->nameOffset+1;
while (cnt<end)
{
GEN_DEBUG(("%c",s[cnt]));
cnt+=2;
}
GEN_DEBUG(("\n"));
#endif /* FTPS_SVR_DEBUG */
/* Convert name to a narrow string. Assume name is Latin-1 codepage UCS-16 */
cnt=msg->nameOffset+1;
while (cnt<end)
{
name[pos]=s[cnt];
pos++;
cnt+=2;
}
}
/* We don't need the data in the source anymore, release it as soon as possible */
FtpsPacketComplete(state->session);
file = FileFind(state->currentDir, name, pos);
/* Don't need the name anymore so free it */
free(name);
if ((file == FILE_NONE) && (msg->create))
{ /* Can't create folder since this is a read only file system */
FTP_SVR_DEBUG((" Rejecting create due to being read only\n"));
FtpsSetPathSubFolderResponse(state->session, ftps_setpath_ReadOnly);
}
else
{ /* Changing Directory */
bool ok = FALSE;
if ((file != FILE_NONE) && (FileType(file) == FILE_TYPE_DIRECTORY))
ok = TRUE;
if (ok)
{
FTP_SVR_DEBUG((" Changing folder\n"));
state->currentDir = file;
FtpsSetPathSubFolderResponse(state->session, ftps_setpath_OK);
}
else
{
FTP_SVR_DEBUG((" Can't find folder\n"));
FtpsSetPathSubFolderResponse(state->session, ftps_setpath_NotFound);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -