ftpdLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:75k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* ftpdLib.c - File Transfer Protocol (FTP) server */
  2. /* Copyright 1990 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02u,22may02,elr  Corrected closing of sockets so they do not linger (SPR #77377)
  8. 02t,05nov01,vvv  fixed compilation warnings
  9. 02s,15oct01,rae  merge from truestack ver 02w, base 02q
  10. 02r,13oct00,cn   fixed memory leak (SPR# 25954).
  11. 02q,16mar99,spm  recovered orphaned code from tor2_0_x branch (SPR #25770)
  12. 02p,01dec98,spm  changed reply code for successful DELE command (SPR #20554)
  13. 02o,27mar98,spm  corrected byte-ordering problem in PASV command (SPR #20828)
  14. 02n,27mar98,spm  merged from recovered version 02m of tor1_0_x branch
  15. 02m,10dec97,spm  upgraded server shutdown routine to terminate active 
  16.                  sessions (SPR #9906); corrected response for PASV command
  17.                  to include valid IP address (SPR #1318); modified syntax
  18.                  of PASV command (SPR #5627); corrected handling of PORT 
  19.                  command to support multiple interfaces (SPR #3500); added 
  20.                  support for maximum number of connections (SPR #2032);
  21.                  applied changes for configurable password authentication 
  22.                  from SENS branch (SPR #8602); removed incorrect note from
  23.                  man page concerning user/password verification, which was 
  24.                  actually performed (SPR #7672); general cleanup (reorganized
  25.                  code, added FTP responses for error conditions, replaced 
  26.                  "static" with LOCAL keyword in function declarations)
  27. 02l,09jul97,dgp  doc: add note on UID and password per SPR 7672
  28. 02k,06feb97,jdi  made drawing internal.
  29. 02j,30sep96,spm  partial fix for spr #7227. Added support for deleting files
  30.                  and using relative pathnames when listing directories.
  31. 02i,05aug96,sgv  fix for spr #3583 and spr #5920. Provide login security
  32.  for VxWorks login
  33. 02h,21may96,sgv  Added global variable ftpdWindowSize which can be set by
  34.  the user. the server would set the window size after the
  35.  connection is established.
  36. 02g,29mar95,kdl  changed ftpdDirListGet() to use ANSI time format in stat.
  37. 02f,11feb95,jdi  doc format tweak.
  38. 02e,20aug93,jag  Fixed memory leak by calling fclose (SPR #2194)
  39.                  Changed ftpdWorkTask Command Read Logic, Added error checking
  40.  on write calls to the network and file operations.
  41.                  Added case-conversion changes (SPR #2035)
  42. 02d,20aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  43. 02c,27feb93,kdl  Removed 01z case-conversion changes (SPR #2035).
  44. 02b,05feb93,jag  Changed call to inet_ntoa to inet_ntoa_b. SPR# 1814
  45. 02a,20jan93,jdi  documentation cleanup for 5.1.
  46. 01z,09sep92,jmm  fixed spr 1568, ftpd now recognizes lower case commands
  47.                  changed errnoGet() to errno to get rid of warning message
  48. 01y,19aug92,smb  Changed systime.h to sys/times.h.
  49. 01x,16jun92,kdl  increased slot buffer to hold null terminator; use calloc()
  50.  to allocate slot struct (SPR #1509).
  51. 01w,26may92,rrr  the tree shuffle
  52.   -changed includes to have absolute path from h/
  53. 01v,08apr92,jmm  cleaned up some ansi warnings
  54. 01u,18dec91,rrr  removed a recursive macro (killed the mips compiler)
  55. 01t,10dec91,gae  ANSI cleanup. Changed ftpdSlotSem to an Id so that internal
  56.     routine semTerminate() not used.
  57. 01s,19nov91,rrr  shut up some ansi warnings.
  58. 01r,14nov91,rrr  shut up some warnings
  59. 01q,12nov91,wmd  fixed bug in ftpdDataStreamSend() and ftpdDataStreamReceive(),
  60.                  EOF is cast to type char to prevent endless looping.
  61. 01p,04oct91,rrr  passed through the ansification filter
  62.                   -changed functions to ansi style
  63.   -changed includes to have absolute path from h/
  64.   -changed VOID to void
  65.   -changed copyright notice
  66. 01o,10jul91,gae  i960 fixes: non-varargs usage, added ntohs().  added HELP
  67.  command, changed listing to support NFS/DOS not old style.
  68. 01n,30apr91,jdi  documentation tweaks.
  69. 01m,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  70.  doc review by dnw.
  71. 01l,12feb91,jaa  documentation.
  72. 01k,08oct90,hjb  included "inetLib.h".
  73. 01j,05oct90,dnw  made ftpdWorkTask() be LOCAL.
  74.  documentation tweaks.
  75. 01i,02oct90,hjb  deleted "inet.h".  added more doc to ftpdInit().  added a call
  76.    to htons() where needed.
  77. 01h,18sep90,kdl  removed erroneous forward declaration of "ftpDataStreamRecv()".
  78. 01g,10aug90,dnw  added forward declaration of ftpdDataStreamReceive().
  79. 01f,10aug90,kdl  added forward declarations for functions returning void.
  80. 01e,26jun90,jcf  changed ftpd semaphore to static mutex.
  81. 01d,07may90,hjb  various bug fixes -- too numerous to mention.
  82. 01c,17apr90,jcf  changed ftpd work task name to tFtpd...
  83. 01b,11apr90,hjb  de-linted
  84. 01a,01mar90,hjb  written
  85. */
  86. /*
  87. DESCRIPTION
  88. This library implements the server side of the File Transfer Protocol (FTP),
  89. which provides remote access to the file systems available on a target.
  90. The protocol is defined in RFC 959. This implementation supports all commands
  91. required by that specification, as well as several additional commands.
  92. USER INTERFACE
  93. During system startup, the ftpdInit() routine creates a control connection
  94. at the predefined FTP server port which is monitored by the primary FTP
  95. task. Each FTP session established is handled by a secondary server task
  96. created as necessary. The server accepts the following commands:
  97. .TS
  98. tab(|);
  99. l1 l.
  100.     HELP | - List supported commands.
  101.     USER | - Verify user name.
  102.     PASS | - Verify password for the user.
  103.     QUIT | - Quit the session.
  104.     LIST | - List out contents of a directory.
  105.     NLST | - List directory contents using a concise format.
  106.     RETR | - Retrieve a file.
  107.     STOR | - Store a file.
  108.     CWD | - Change working directory.
  109.     TYPE | - Change the data representation type.
  110.     PORT | - Change the port number.
  111.     PWD | - Get the name of current working directory.
  112.     STRU | - Change file structure settings.
  113.     MODE | - Change file transfer mode.
  114.     ALLO | - Reserver sufficient storage.
  115.     ACCT | - Identify the user's account.
  116.     PASV | - Make the server listen on a port for data connection.
  117.     NOOP | - Do nothing.
  118.     DELE | - Delete a file
  119. .TE
  120. The ftpdDelete() routine will disable the FTP server until restarted. 
  121. It reclaims all system resources used by the server tasks and cleanly 
  122. terminates all active sessions.
  123. To use this feature, include the following component:
  124. INCLUDE_FTP_SERVER
  125. INTERNAL
  126. The ftpdInit() routine spawns the primary server task ('ftpdTask') to handle
  127. multiple FTP sessions. That task creates a separate task ('ftpdWorkTask') for
  128. each active control connection.
  129. The diagram below defines the structure chart of ftpdLib.
  130. .CS
  131.   ftpdDelete     ftpdInit
  132. |     |
  133. |      |
  134. |     ftpdTask
  135. |      /    |  ____________
  136. |              /     |      
  137. | |              ftpdSessionAdd ftpdWorkTask ftpdSessionDelete
  138. | |       ______________________/     |  
  139. | |      /    / |           |   
  140.  ftpdSlotDelete | ftpdDirListGet /  ftpdDataStreamReceive |   ftpdDataStreamSend
  141. | |         / |   |   /      /
  142.   |    __________/ |     |  /     /
  143.    |   / |         ftpdDataConnGet  /
  144.     |   | |    |   ___________/
  145.      |   | |    |  /
  146.          ftpdSockFree ftpdDataCmdSend
  147. .CE
  148. INCLUDE FILES: ftpdLib.h
  149. SEE ALSO:
  150. ftpLib, netDrv, 
  151. .I "RFC-959 File Transfer Protocol"
  152. */
  153. #include "vxWorks.h"
  154. #include "ioLib.h"
  155. #include "taskLib.h"
  156. #include "lstLib.h"
  157. #include "stdio.h"
  158. #include "sys/socket.h"
  159. #include "netinet/in.h"
  160. #include "errno.h"
  161. #include "version.h"
  162. #include "string.h"
  163. #include "stdlib.h"
  164. #include "iosLib.h"
  165. #include "inetLib.h"
  166. #include "dirent.h"
  167. #include "sys/stat.h"
  168. #include "sys/times.h"
  169. #include "sockLib.h"
  170. #include "logLib.h"
  171. #include "unistd.h"
  172. #include "pathLib.h"
  173. #include "sysLib.h"
  174. #include "ftpdLib.h"
  175. #include "ctype.h"
  176. #include "time.h"
  177. #include "loginLib.h"
  178. #include "memPartLib.h"
  179. #ifndef _WRS_VXWORKS_5_X
  180. #include "private/pdLibP.h"
  181. #endif /* _WRS_VXWORKS_5_X */
  182. /* Representation Type */
  183. #define FTPD_BINARY_TYPE 0x1
  184. #define FTPD_ASCII_TYPE 0x2
  185. #define FTPD_EBCDIC_TYPE 0x4
  186. #define FTPD_LOCAL_BYTE_TYPE 0x8
  187. /* Transfer mode */
  188. #define FTPD_STREAM_MODE 0x10
  189. #define FTPD_BLOCK_MODE 0x20
  190. #define FTPD_COMPRESSED_MODE 0x40
  191. /* File structure */
  192. #define FTPD_NO_RECORD_STRU 0x100
  193. #define FTPD_RECORD_STRU 0x200
  194. #define FTPD_PAGE_STRU 0x400
  195. /* Session Status */
  196. #define FTPD_USER_OK 0x1000
  197. #define FTPD_PASSIVE 0x2000
  198. /* Macros to obtain correct parts of the status code */
  199. #define FTPD_REPRESENTATION(slot) ( (slot)->status & 0xff)
  200. #define FTPD_TRANS_MODE(slot) (((slot)->status >> 8) & 0xff)
  201. #define FTPD_FILE_STRUCTURE(slot) (((slot)->status >> 16) & 0xff)
  202. #define FTPD_STATUS(slot) (((slot)->status >> 24) & 0xff)
  203. /* Well known port definitions -- someday we'll have getservbyname */
  204. #define FTP_DATA_PORT 20
  205. #define FTP_DAEMON_PORT 21
  206. /* Free socket indicative */
  207. #define FTPD_SOCK_FREE -1
  208. /* Arbitrary limits for the size of the FTPD work task name */
  209. #define FTPD_WORK_TASK_NAME_LEN 40
  210. /* Arbitrary limits hinted by Unix FTPD in waing for a new data connection */
  211. #define FTPD_WAIT_MAX 90
  212. #define FTPD_WAIT_INTERVAL 5
  213. /* Macro to get the byte out of an int */
  214. #define FTPD_UC(ch) (((int) (ch)) & 0xff)
  215. /* Bit set in FTP reply code to indicate multi-line reply.
  216.  * Used internally by ftpdCmdSend() where codes are less than
  217.  * 1024 but are 32-bit integers.  [Admittedly a hack, see
  218.  * ftpdCmdSend().]
  219.  */
  220. #define FTPD_MULTI_LINE 0x10000000
  221. #define FTPD_WINDOW_SIZE 10240
  222. /* globals */
  223. int ftpdDebug = FALSE; /* TRUE: debugging messages */
  224. int ftpdTaskPriority = 56;
  225. int ftpdTaskOptions  = VX_SUPERVISOR_MODE | VX_UNBREAKABLE;
  226. int ftpdWorkTaskPriority = 252;
  227. int ftpdWorkTaskOptions = VX_SUPERVISOR_MODE | VX_UNBREAKABLE; 
  228. int ftpdWorkTaskStackSize = 12000;
  229. int ftpdWindowSize              = FTPD_WINDOW_SIZE;
  230. int ftpsMaxClients = 4;  /* Default max. for simultaneous connections */
  231. int ftpsCurrentClients;
  232. FUNCPTR loginVerifyRtn;
  233. /* locals */
  234. LOCAL BOOL ftpsActive = FALSE;  /* Server started? */
  235. LOCAL BOOL ftpsShutdownFlag;  /* Server halt requested? */
  236. /*
  237.  * The FTP server keeps track of active client sessions in a linked list
  238.  * of the following FTPD_SESSION_DATA data structures. That structure
  239.  * contains all the variables which must be maintained separately
  240.  * for each client so that the code shared by every secondary
  241.  * task will function correctly.
  242.  */
  243. typedef struct
  244.     {
  245.     NODE node; /* for link-listing */
  246.     int status; /* see various status bits above */
  247.     int byteCount; /* bytes transferred */
  248.     int cmdSock; /* command socket */
  249.     STATUS cmdSockError;   /* Set to ERROR on write error */
  250.     int dataSock; /* data socket */
  251.     struct sockaddr_in peerAddr; /* address of control connection */
  252.     struct sockaddr_in  dataAddr;  /* address of data connection */
  253.     char buf [BUFSIZE]; /* multi-purpose buffer per session */
  254.     char  curDirName [MAX_FILENAME_LENGTH]; /* active directory */
  255.     char               user [MAX_LOGIN_NAME_LEN+1]; /* current user */
  256.     } FTPD_SESSION_DATA;
  257. LOCAL int ftpdTaskId  = -1;
  258. LOCAL int ftpdServerSock  = FTPD_SOCK_FREE;
  259. LOCAL LIST ftpsSessionList;
  260. LOCAL SEM_ID ftpsMutexSem;
  261. LOCAL SEM_ID  ftpsSignalSem;
  262. LOCAL char ftpdWorkTaskName [FTPD_WORK_TASK_NAME_LEN];
  263. LOCAL int ftpdNumTasks;
  264. /* Various messages to be told to the clients */
  265. LOCAL char *messages [] =
  266.     {
  267.     "Can't open passive connection",
  268.     "Parameter not accepted",
  269.     "Data connection error",
  270.     "Directory non existent or syntax error",
  271.     "Local resource failure: %s",
  272.     "VxWorks (%s) FTP server ready",
  273.     "Password required",
  274.     "User logged in",
  275.     "Bye...see you later",
  276.     "USER and PASS required",
  277.     "No files found or invalid directory or permission problem",
  278.     "Transfer complete",
  279.     "File "%s" not found or permission problem",
  280.     "Cannot create file "%s" or permission problem",
  281.     "Changed directory to "%s"",
  282.     "Type set to I, binary mode",
  283.     "Type set to A, ASCII mode",
  284.     "Port set okay",
  285.     "Current directory is "%s"",
  286.     "File structure set to NO RECORD",
  287.     "Stream mode okay",
  288.     "Allocate and Account not required",
  289.     "Entering Passive Mode (%d,%d,%d,%d,%d,%d)",
  290.     "NOOP -- did nothing as requested...hah!",
  291.     "Command not recognized",
  292.     "Error in input file",
  293.     "Unimplemented TYPE %d",
  294.     "You could at least say goodbye.",
  295.     "The following commands are recognized:",
  296.     "End of command list.",
  297.     "File deleted successfully.",
  298.     "Login failed.",
  299.     };
  300. /* Indexes to the messages [] array */
  301. #define MSG_PASSIVE_ERROR 0
  302. #define MSG_PARAM_BAD 1
  303. #define MSG_DATA_CONN_ERROR 2
  304. #define MSG_DIR_NOT_PRESENT 3
  305. #define MSG_LOCAL_RESOURCE_FAIL 4
  306. #define MSG_SERVER_READY 5
  307. #define MSG_PASSWORD_REQUIRED 6
  308. #define MSG_USER_LOGGED_IN 7
  309. #define MSG_SEE_YOU_LATER 8
  310. #define MSG_USER_PASS_REQ 9
  311. #define MSG_DIR_ERROR 10
  312. #define MSG_TRANS_COMPLETE 11
  313. #define MSG_FILE_ERROR 12
  314. #define MSG_CREATE_ERROR 13
  315. #define MSG_CHANGED_DIR 14
  316. #define MSG_TYPE_BINARY 15
  317. #define MSG_TYPE_ASCII 16
  318. #define MSG_PORT_SET 17
  319. #define MSG_CUR_DIR 18
  320. #define MSG_FILE_STRU 19
  321. #define MSG_STREAM_MODE 20
  322. #define MSG_ALLOC_ACCOUNT 21
  323. #define MSG_PASSIVE_MODE 22
  324. #define MSG_NOOP_OKAY 23
  325. #define MSG_BAD_COMMAND 24
  326. #define MSG_INPUT_FILE_ERROR 25
  327. #define MSG_TYPE_ERROR 26
  328. #define MSG_NO_GOOD_BYE 27
  329. #define MSG_COMMAND_LIST_BEGIN 28
  330. #define MSG_COMMAND_LIST_END 29
  331. #define MSG_DELE_OKAY           30
  332. #define        MSG_USER_LOGIN_FAILED   31
  333. LOCAL char *ftpdCommandList =
  334. "HELP USER PASS QUIT LIST NLSTn
  335. RETR STOR CWD TYPE PORT PWDn
  336. STRU MODE ALLO ACCT PASV NOOPn
  337. DELEn";
  338. /* forward declarations */
  339. LOCAL FTPD_SESSION_DATA *ftpdSessionAdd (void);
  340. LOCAL void ftpdSessionDelete (FTPD_SESSION_DATA *);
  341. LOCAL STATUS ftpdWorkTask (FTPD_SESSION_DATA *);
  342. LOCAL STATUS ftpdCmdSend (FTPD_SESSION_DATA *, int, int, char *,
  343.                           int, int, int, int, int, int);
  344. LOCAL STATUS ftpdDataConnGet (FTPD_SESSION_DATA *);
  345. LOCAL void ftpdDataStreamSend (FTPD_SESSION_DATA *, FILE *);
  346. LOCAL void ftpdDataStreamReceive (FTPD_SESSION_DATA *, FILE *outStream);
  347. LOCAL void ftpdSockFree (int *);
  348. LOCAL STATUS ftpdDirListGet (int, char *, BOOL);
  349. LOCAL void ftpdDebugMsg (char *, int, int, int, int);
  350. LOCAL void unImplementedType (FTPD_SESSION_DATA *pSlot);
  351. LOCAL void dataError (FTPD_SESSION_DATA *pSlot);
  352. LOCAL void fileError (FTPD_SESSION_DATA *pSlot);
  353. LOCAL void transferOkay (FTPD_SESSION_DATA *pSlot);
  354. /*******************************************************************************
  355. *
  356. * ftpdTask - FTP server daemon task
  357. *
  358. * This routine monitors the FTP control port for incoming requests from clients
  359. * and processes each request by spawning a secondary server task after 
  360. * establishing the control connection. If the maximum number of connections is
  361. * reached, it returns the appropriate error to the requesting client. The 
  362. * routine is the entry point for the primary FTP server task and should only
  363. * be called internally.
  364. *
  365. * RETURNS: N/A
  366. *
  367. * ERRNO: N/A
  368. *
  369. * INTERNAL:
  370. * The server task is deleted by the server shutdown routine. Adding a newly
  371. * created client session to the list of active clients is performed atomically
  372. * with respect to the shutdown routine. However, accepting control connections
  373. * is not a critical section, since closing the initial socket used in the
  374. * listen() call also closes any later connections which are still open.
  375. *
  376. * NOMANUAL
  377. */
  378. LOCAL void ftpdTask (void)
  379.     {
  380.     int newSock;
  381.     FAST FTPD_SESSION_DATA *pSlot;
  382.     int on = 1;
  383.     int addrLen;
  384.     struct sockaddr_in addr;
  385.     char a_ip_addr [INET_ADDR_LEN];  /* ascii ip address of client */
  386.     ftpdNumTasks = 0;
  387.     /* The following loop halts if this task is deleted. */
  388.     FOREVER
  389.         {
  390.         /* Wait for a new incoming connection. */
  391.         addrLen = sizeof (struct sockaddr);
  392.         ftpdDebugMsg ("waiting for a new client connection...n",0,0,0,0);
  393.         newSock = accept (ftpdServerSock, (struct sockaddr *) &addr, &addrLen);
  394. if (newSock < 0)
  395.             {
  396.             ftpdDebugMsg ("cannot accept a new connectionn",0,0,0,0);
  397.             break;
  398.             }
  399.         /*
  400.          * Register a new FTP client session. This process is a critical
  401.          * section with the server shutdown routine. If an error occurs,
  402.          * the reply must be sent over the control connection to the peer
  403.          * before the semaphore is released. Otherwise, this task could
  404.          * be deleted and no response would be sent, possibly causing
  405.          * the new client to hang indefinitely.
  406.          */
  407.         semTake (ftpsMutexSem, WAIT_FOREVER);
  408.         setsockopt (newSock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
  409.                     sizeof (on));
  410.         inet_ntoa_b (addr.sin_addr, a_ip_addr);
  411.         ftpdDebugMsg ("accepted a new client connection from %sn",
  412.                       (int) a_ip_addr, 0, 0, 0);
  413.         /* Create a new session entry for this connection, if possible. */
  414.         pSlot = ftpdSessionAdd ();
  415.         if (pSlot == NULL)  /* Maximum number of connections reached. */
  416.             {
  417.             /* Send transient failure report to client. */
  418.             ftpdCmdSend (pSlot, newSock, 421, 
  419.                          "Session limit reached, closing control connection", 
  420.                          0, 0, 0, 0, 0, 0);
  421.             ftpdDebugMsg ("cannot get a new connection slotn",0,0,0,0);
  422.     close (newSock);
  423.             semGive (ftpsMutexSem);
  424.             continue;
  425.             }
  426. pSlot->cmdSock = newSock;
  427.         /* Save the control address and assign the default data address. */
  428.         bcopy ( (char *)&addr, (char *)&pSlot->peerAddr, 
  429.                sizeof (struct sockaddr_in));
  430.         bcopy ( (char *)&addr, (char *)&pSlot->dataAddr, 
  431.                sizeof (struct sockaddr_in));
  432.         pSlot->dataAddr.sin_port = htons (FTP_DATA_PORT);
  433. /* Create a task name. */
  434.         sprintf (ftpdWorkTaskName, "tFtpdServ%d", ftpdNumTasks);
  435.         /* Spawn a secondary task to process FTP requests for this session. */
  436. ftpdDebugMsg ("creating a new server task %s...n", 
  437.       (int) ftpdWorkTaskName, 0, 0, 0);
  438. if (taskSpawn (ftpdWorkTaskName, ftpdWorkTaskPriority,
  439.        ftpdWorkTaskOptions, ftpdWorkTaskStackSize,
  440.        ftpdWorkTask, (int) pSlot,
  441.        0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
  442.     {
  443.             /* Send transient failure report to client. */
  444.             ftpdCmdSend (pSlot, newSock, 421, 
  445.                          "Service not available, closing control connection",
  446.                          0, 0, 0, 0, 0, 0);
  447.     ftpdSessionDelete (pSlot);
  448.     ftpdDebugMsg ("cannot create a new work taskn",0,0,0,0);
  449.             semGive (ftpsMutexSem);
  450.             continue;
  451.     }
  452. ftpdDebugMsg ("done.n",0,0,0,0);
  453.         /* Session added - end of critical section with shutdown routine. */
  454.         semGive (ftpsMutexSem);
  455. }
  456.     /* Fatal error - update state of server. */
  457.     ftpsActive = FALSE;
  458.     return;
  459.     }
  460. /*******************************************************************************
  461. *
  462. * ftpdInit - initialize the FTP server task
  463. *
  464. * This routine installs the password verification routine indicated by
  465. * <pLoginRtn> and establishes a control connection for the primary FTP
  466. * server task, which it then creates. It is called automatically during
  467. * system startup if INCLUDE_FTP_SERVER is defined. The primary server task 
  468. * supports simultaneous client sessions, up to the limit specified by the 
  469. * global variable 'ftpsMaxClients'. The default value allows a maximum of 
  470. * four simultaneous connections. The <stackSize> argument specifies the stack 
  471. * size for the primary server task. It is set to the value specified in the 
  472. * 'ftpdWorkTaskStackSize' global variable by default.
  473. *
  474. * RETURNS:
  475. * OK if server started, or ERROR otherwise.
  476. *
  477. * ERRNO: N/A
  478. */
  479. STATUS ftpdInit
  480.     (
  481.     FUNCPTR  pLoginRtn,  /* user verification routine, or NULL */
  482.     int  stackSize  /* task stack size, or 0 for default */
  483.     )
  484.     {
  485.     int  on = 1;
  486.     struct sockaddr_in  ctrlAddr;
  487.     if (ftpsActive)
  488. return (OK);
  489.     loginVerifyRtn = pLoginRtn;
  490.     ftpsShutdownFlag = FALSE;
  491.     ftpsCurrentClients = 0;
  492.     /* Create the FTP server control socket. */
  493.     ftpdServerSock = socket (AF_INET, SOCK_STREAM, 0);
  494.     if (ftpdServerSock < 0)
  495.         return (ERROR);
  496.     /* Create data structures for managing client connections. */
  497.     lstInit (&ftpsSessionList);
  498.     ftpsMutexSem = semMCreate (SEM_Q_FIFO | SEM_DELETE_SAFE);
  499.     if (ftpsMutexSem == NULL)
  500.         {
  501.         close (ftpdServerSock);
  502.         return (ERROR);
  503.         }
  504.     ftpsSignalSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY);
  505.     if (ftpsSignalSem == NULL)
  506.         {
  507.         close (ftpdServerSock);
  508.         semDelete (ftpsMutexSem);
  509.         return (ERROR);
  510.         }
  511.     /* Setup control connection for client requests. */
  512.     ctrlAddr.sin_family = AF_INET;
  513.     ctrlAddr.sin_addr.s_addr = INADDR_ANY;
  514.     ctrlAddr.sin_port = htons (FTP_DAEMON_PORT);
  515.     if (setsockopt (ftpdServerSock, SOL_SOCKET, SO_REUSEADDR,
  516.                     (char *) &on, sizeof (on)) < 0)
  517.         {
  518.         close (ftpdServerSock);
  519.         semDelete (ftpsMutexSem);
  520.         semDelete (ftpsSignalSem);
  521.         return (ERROR);
  522.         }
  523.     if (bind (ftpdServerSock, (struct sockaddr *) &ctrlAddr,
  524.               sizeof (ctrlAddr)) < 0)
  525.         {
  526.         close (ftpdServerSock);
  527.         semDelete (ftpsMutexSem);
  528.         semDelete (ftpsSignalSem);
  529.         return (ERROR);
  530.         }
  531.     if (listen (ftpdServerSock, 5) < 0)
  532.         {
  533.         close (ftpdServerSock);
  534.         semDelete (ftpsMutexSem);
  535.         semDelete (ftpsSignalSem);
  536.         return (ERROR);
  537.         }
  538.     /* Create a FTP server task to receive client requests. */
  539.     ftpdTaskId = taskSpawn ("tFtpdTask", ftpdTaskPriority - 1, ftpdTaskOptions,
  540.                             stackSize == 0 ? ftpdWorkTaskStackSize : stackSize,
  541.                             (FUNCPTR) ftpdTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  542.     if (ftpdTaskId == ERROR)
  543.         {
  544.         ftpdDebugMsg ("ERROR: ftpdTask cannot be createdn",0,0,0,0);
  545.         close (ftpdServerSock);
  546.         semDelete (ftpsMutexSem);
  547.         semDelete (ftpsSignalSem);
  548.         return (ERROR);
  549.         }
  550.     ftpsActive = TRUE;
  551.     ftpdDebugMsg ("ftpdTask createdn",0,0,0,0);
  552.     return (OK);
  553.     }
  554. /*******************************************************************************
  555. *
  556. * ftpdDelete - terminate the FTP server task
  557. *
  558. * This routine halts the FTP server and closes the control connection. All
  559. * client sessions are removed after completing any commands in progress.
  560. * When this routine executes, no further client connections will be accepted
  561. * until the server is restarted. This routine is not reentrant and must not
  562. * be called from interrupt level.
  563. *
  564. * NOTE: If any file transfer operations are in progress when this routine is
  565. * executed, the transfers will be aborted, possibly leaving incomplete files
  566. * on the destination host.
  567. *
  568. * RETURNS: OK if shutdown completed, or ERROR otherwise.
  569. *
  570. * ERRNO: N/A
  571. *
  572. * INTERNAL
  573. * This routine is synchronized with the deletion routine for a client session
  574. * so that the exit of the client tasks can be detected. It also shares a
  575. * critical section with the creation of client sessions to prevent orphaned
  576. * tasks, which would occur if a session were added after this routine had
  577. * shut down all known clients.
  578. */
  579. STATUS ftpdDelete (void)
  580.     {
  581.     BOOL serverActive = FALSE;
  582.     FTPD_SESSION_DATA *  pData;
  583.     if (! ftpsActive)    /* Automatic success if server is not running. */
  584.         return (OK);
  585.     /*
  586.      * Remove the FTP server task to prevent additional sessions from starting.
  587.      * The exclusion semaphore guarantees a stable list of active clients.
  588.      */
  589.     semTake (ftpsMutexSem, WAIT_FOREVER);
  590.     taskDelete (ftpdTaskId);
  591.     ftpdTaskId = -1;
  592.     if (ftpsCurrentClients != 0)
  593.         serverActive = TRUE;
  594.     /*
  595.      * Set the shutdown flag so that any secondary server tasks will exit
  596.      * as soon as possible. Once the FTP server has started, this routine is
  597.      * the only writer of the flag and the secondary tasks are the only
  598.      * readers. To avoid unnecessary blocking, the secondary tasks do not
  599.      * guard access to this flag when checking for a pending shutdown during
  600.      * normal processing. Those tasks do protect access to this flag during
  601.      * their cleanup routine to prevent a race condition which would result
  602.      * in incorrect use of the signalling semaphore.
  603.      */
  604.     ftpsShutdownFlag = TRUE;
  605.     /* 
  606.      * Close the command sockets of any active sessions to prevent further 
  607.      * activity. If the session is waiting for a command from a socket,
  608.      * the close will trigger the session exit.
  609.      */
  610.     pData = (FTPD_SESSION_DATA *)lstFirst (&ftpsSessionList);
  611.     while (pData != NULL)
  612.         {
  613.         ftpdSockFree (&pData->cmdSock);
  614.         pData = (FTPD_SESSION_DATA *)lstNext (&pData->node);
  615.         }
  616.     semGive (ftpsMutexSem);   
  617.     /* Wait for all secondary tasks to exit. */
  618.     if (serverActive)
  619.         {
  620.         /*
  621.          * When a shutdown is in progress, the cleanup routine of the last
  622.          * client task to exit gives the signalling semaphore.
  623.          */
  624.         semTake (ftpsSignalSem, WAIT_FOREVER);
  625.         }
  626.     /*
  627.      * Remove the original socket - this occurs after all secondary tasks
  628.      * have exited to avoid prematurely closing their control sockets.
  629.      */
  630.     ftpdSockFree (&ftpdServerSock);
  631.     /* Remove the protection and signalling semaphores and list of clients. */
  632.     lstFree (&ftpsSessionList);    /* Sanity check - should already be empty. */
  633.     semDelete (ftpsMutexSem);
  634.     semDelete (ftpsSignalSem);
  635.     ftpsActive = FALSE;
  636.     return (OK);
  637.     }
  638. /*******************************************************************************
  639. *
  640. * ftpdSessionAdd - add a new entry to the ftpd session slot list
  641. *
  642. * Each of the incoming FTP sessions is associated with an entry in the
  643. * FTP server's session list which records session-specific context for each
  644. * control connection established by the FTP clients. This routine creates and
  645. * initializes a new entry in the session list, unless the needed memory is not
  646. * available or the upper limit for simultaneous connections is reached.
  647. *
  648. * RETURNS: A pointer to the session list entry, or NULL of none available.
  649. *
  650. * ERRNO: N/A
  651. *
  652. * NOMANUAL
  653. *
  654. * INTERNAL
  655. * This routine executes within a critical section of the primary FTP server
  656. * task, so mutual exclusion is already present when adding entries to the
  657. * client list and updating the shared variables indicating the current number
  658. * of connected clients.
  659. */
  660. LOCAL FTPD_SESSION_DATA *ftpdSessionAdd (void)
  661.     {
  662.     FAST FTPD_SESSION_DATA  *pSlot;
  663.     if (ftpsCurrentClients == ftpsMaxClients)
  664.         return (NULL);
  665.     /* get memory for the new session entry */
  666.     pSlot = (FTPD_SESSION_DATA *) KHEAP_ALLOC(sizeof (FTPD_SESSION_DATA));
  667.     if (pSlot == NULL)
  668. {
  669. return (NULL);
  670. }
  671.     bzero ((char *)pSlot, sizeof(FTPD_SESSION_DATA));
  672.     /* initialize key fields in the newly acquired slot */
  673.     pSlot->dataSock = FTPD_SOCK_FREE;
  674.     pSlot->cmdSock = FTPD_SOCK_FREE;
  675.     pSlot->cmdSockError = OK;
  676.     pSlot->status = FTPD_STREAM_MODE | FTPD_ASCII_TYPE | FTPD_NO_RECORD_STRU;
  677.     pSlot->byteCount = 0;
  678.     /* assign the default directory for this guy */
  679.     ioDefPathGet (pSlot->curDirName);
  680.     /* Add new entry to the list of active sessions. */
  681.     lstAdd (&ftpsSessionList, &pSlot->node);
  682.     ftpdNumTasks++;
  683.     ftpsCurrentClients++;
  684.     return (pSlot);
  685.     }
  686. /*******************************************************************************
  687. *
  688. * ftpdSessionDelete - remove an entry from the FTP session list
  689. *
  690. * This routine removes the session-specific context from the session list
  691. * after the client exits or a fatal error occurs.
  692. *
  693. * RETURNS: N/A
  694. *
  695. * ERRNO: N/A
  696. *
  697. * NOMANUAL
  698. *
  699. * INTERNAL
  700. * Unless an error occurs, this routine is only called in response to a
  701. * pending server shutdown, indicated by the shutdown flag. Even if the
  702. * shutdown flag is not detected and this routine is called because of an
  703. * error, the appropriate signal will still be sent to any pending shutdown
  704. * routine. The shutdown routine will only return after any active client
  705. * sessions have exited.
  706. */
  707. LOCAL void ftpdSessionDelete
  708.     (
  709.     FAST FTPD_SESSION_DATA *pSlot       /* pointer to the slot to be deleted */
  710.     )
  711.     {
  712.     if (pSlot == NULL) /* null slot? don't do anything */
  713.         return;
  714.     /*
  715.      * The deletion of a session entry must be an atomic operation to support
  716.      * an upper limit on the number of simultaneous connections allowed.
  717.      * This mutual exclusion also prevents a race condition with the server
  718.      * shutdown routine. The last client session will always send an exit
  719.      * signal to the shutdown routine, whether or not the shutdown flag was
  720.      * detected during normal processing.
  721.      */
  722.     semTake (ftpsMutexSem, WAIT_FOREVER);
  723.     --ftpdNumTasks;
  724.     --ftpsCurrentClients;
  725.     lstDelete (&ftpsSessionList, &pSlot->node);
  726.     ftpdSockFree (&pSlot->cmdSock); /* release data and command sockets */
  727.     ftpdSockFree (&pSlot->dataSock);
  728.     KHEAP_FREE((char *)pSlot);
  729.     /* Send required signal if all sessions are closed. */
  730.     if (ftpsShutdownFlag)
  731.         {
  732.         if (ftpsCurrentClients == 0)
  733.             semGive (ftpsSignalSem);
  734.         }
  735.     semGive (ftpsMutexSem);
  736.     return;
  737.     }
  738. /*******************************************************************************
  739. *
  740. * ftpdWorkTask - main protocol processor for the FTP service
  741. *
  742. * This function handles all the FTP protocol requests by parsing
  743. * the request string and performing appropriate actions and returning
  744. * the result strings.  The main body of this function is a large
  745. * FOREVER loop which reads in FTP request commands from the client
  746. * located on the other side of the connection.  If the result of
  747. * parsing the request indicates a valid command, ftpdWorkTask() will
  748. * call appropriate functions to handle the request and return the
  749. * result of the request.  The parsing of the requests are done via
  750. * a list of strncmp routines for simplicity.
  751. *
  752. * RETURNS: N/A
  753. *
  754. * ERRNO: N/A
  755. *
  756. * NOMANUAL
  757. *
  758. * INTERNAL
  759. * To handle multiple simultaneous connections, this routine and all secondary
  760. * routines which process client commands must be re-entrant. If the server's
  761. * halt routine is started, the shutdown flag is set, causing this routine to
  762. * exit after completing any operation already in progress.
  763. */
  764. LOCAL STATUS ftpdWorkTask
  765.     (
  766.     FTPD_SESSION_DATA   *pSlot  /* pointer to the active slot to be handled */
  767.     )
  768.     {
  769.     FAST int sock; /* command socket descriptor */
  770.     FAST char *pBuf; /* pointer to session specific buffer */
  771.     struct sockaddr_in passiveAddr; /* socket address in passive mode */
  772.     FAST char *dirName; /* directory name place holder */
  773.     FAST int numRead;
  774.     int addrLen = sizeof (passiveAddr); /* for getpeername */
  775.     int portNum [6]; /* used for "%d,%d,%d,%d,%d,%d" */
  776.     u_long  value;
  777.     char  *pTail;
  778.     char  newPath [MAX_FILENAME_LENGTH];
  779.     char  curDirName [MAX_FILENAME_LENGTH];
  780.     char *pFileName;
  781.     FILE *inStream;
  782.     FILE  *outStream;
  783.     char                *upperCommand;    /* convert command to uppercase */
  784.     pBuf = &pSlot->buf [0]; /* use session specific buffer area */
  785.     sock = pSlot->cmdSock;
  786.     if (ftpsShutdownFlag)
  787.         {
  788.         /* Server halt in progress - send abort message to client. */
  789.         ftpdCmdSend (pSlot, sock, 421, 
  790.                      "Service not available, closing control connection",
  791.                      0, 0, 0, 0, 0, 0);
  792.         ftpdSessionDelete (pSlot);
  793.         return (OK);
  794.         }
  795.     /* tell the client we're ready to rock'n'roll */
  796. #ifdef _WRS_VXWORKS_5_X
  797.     if (ftpdCmdSend (pSlot, sock, 220, messages [MSG_SERVER_READY],
  798. (int)vxWorksVersion, 0, 0, 0, 0, 0) == ERROR)
  799. #else
  800.         if (ftpdCmdSend (pSlot, sock, 220, messages [MSG_SERVER_READY],
  801.                          (int)runtimeVersion, 0, 0, 0, 0, 0) == ERROR)
  802. #endif /* _WRS_VXWORKS_5_X */
  803. {
  804. ftpdSessionDelete (pSlot);
  805. return (ERROR);
  806. }
  807.     FOREVER
  808. {
  809. taskDelay (1); /* time share among same priority tasks */
  810. /* Check error in writting to the control socket */
  811. if (pSlot->cmdSockError == ERROR)
  812.     {
  813.     ftpdSessionDelete (pSlot);
  814.     return (ERROR);
  815.     }
  816.         /*
  817.          * Stop processing client requests if a server halt is in progress.
  818.          * These tests of the shutdown flag are not protected with the
  819.          * mutual exclusion semaphore to prevent unnecessary synchronization
  820.          * between client sessions. Because the secondary tasks execute at
  821.          * a lower priority than the primary task, the worst case delay
  822.          * before ending this session after shutdown has started would only
  823.          * allow a single additional command to be performed.
  824.          */
  825.         if (ftpsShutdownFlag)
  826.             break;
  827. /* get a request command */
  828. FOREVER
  829.     {
  830.     taskDelay (1); /* time share among same priority tasks */
  831.     if ((numRead = read (sock, pBuf, 1)) <= 0)
  832. {
  833.                 /*
  834.                  * The primary server task will close the control connection
  835.                  * when a halt is in progress, causing an error on the socket.
  836.                  * In this case, ignore the error and exit the command loop
  837.                  * to send a termination message to the connected client.
  838.                  */
  839.                 if (ftpsShutdownFlag)
  840.                     {
  841.                     *pBuf = EOS;
  842.                     break;
  843.                     }
  844.                 /* 
  845.                  * Send a final message if the control socket 
  846.                  * closed unexpectedly.
  847.                  */
  848. if (numRead == 0)
  849.     ftpdCmdSend (pSlot, sock, 221, messages [MSG_NO_GOOD_BYE],
  850.     0, 0, 0, 0, 0, 0);
  851. ftpdSessionDelete (pSlot);
  852. return ERROR;
  853. }
  854.     
  855.     /* Skip the CR in the buffer. */
  856.     if ( *pBuf == 'r' )
  857. continue;
  858.     /* End Of Command delimeter. exit loop and process command */
  859.     if ( *pBuf == 'n' )
  860.     {
  861. *pBuf = EOS;
  862. break;
  863.     }
  864.     pBuf++; /* Advance to next character to read */
  865.     }
  866. /*  Reset Buffer Pointer before we use it */
  867. pBuf = &pSlot->buf [0];
  868. /* convert the command to upper-case */
  869. for (upperCommand = pBuf; (*upperCommand != ' ') &&
  870.      (*upperCommand != EOS); upperCommand++)
  871.     *upperCommand = toupper (*upperCommand);
  872. ftpdDebugMsg ("read command %sn", (int)pBuf,0,0,0);
  873.         /*
  874.          * Send an abort message to the client if a server
  875.          * shutdown was started while reading the next command.
  876.          */
  877.         if (ftpsShutdownFlag)
  878.             {
  879.             ftpdCmdSend (pSlot, sock, 421, 
  880.                          "Service not available, closing control connection",
  881.                          0, 0, 0, 0, 0, 0);
  882.             break;
  883.             }
  884. if (strncmp (pBuf, "USER", 4) == 0)
  885.     {
  886.     /* check user name */
  887.            /* Actually copy the user name into a buffer and save it */
  888.            /* till the password comes in. Name is located one space */
  889.            /* character after USER string */
  890.            if ( *(pBuf + 4) == '' )
  891.                pSlot->user[0] = '';          /* NOP user for null user */
  892.            else
  893.                strncpy(pSlot->user, pBuf+5, MAX_LOGIN_NAME_LEN);
  894.            pSlot->status &= ~FTPD_USER_OK;
  895.     if (ftpdCmdSend (pSlot, sock, 331, messages [MSG_PASSWORD_REQUIRED],
  896.  0, 0, 0, 0, 0, 0) == ERROR)
  897. {
  898. ftpdSessionDelete (pSlot);
  899. return (ERROR);
  900. }
  901.     continue;
  902.     }
  903. else if (strncmp (pBuf, "PASS", 4) == 0)
  904.     {
  905.     /* check user passwd */
  906.            /* Actually check it against earlier supplied user name */
  907.    if ( loginVerifyRtn != (FUNCPTR)NULL )
  908.        {
  909.        if ( (FUNCPTR *)(loginVerifyRtn)(pSlot->user, pBuf+5) != OK )
  910.    {
  911.    if (ftpdCmdSend (pSlot, sock,
  912.                                     530, messages [MSG_USER_LOGIN_FAILED], 
  913.                                     0, 0, 0, 0, 0, 0) == ERROR)
  914.        {
  915.        ftpdSessionDelete (pSlot);
  916.        return (ERROR);
  917.        }
  918.    pSlot->status &= ~FTPD_USER_OK;
  919.    continue;
  920.    }
  921.         }
  922.     pSlot->status |= FTPD_USER_OK;
  923.     if (ftpdCmdSend (pSlot, sock, 230, messages [MSG_USER_LOGGED_IN],
  924.  0, 0, 0, 0, 0, 0) == ERROR)
  925. {
  926. ftpdSessionDelete (pSlot);
  927. return (ERROR);
  928. }
  929.     continue;
  930.     }
  931. else if (strncmp (pBuf, "QUIT", 4) == 0)
  932.     {
  933.     /* sayonara */
  934.     ftpdCmdSend (pSlot, sock, 221, messages [MSG_SEE_YOU_LATER],
  935.  0, 0, 0, 0, 0, 0);
  936.     ftpdSessionDelete (pSlot);
  937.     return OK;
  938.     }
  939. else if (strncmp (pBuf, "HELP", 4) == 0)
  940.     {
  941.     /* send list of supported commands with multiple line response */
  942.     if (ftpdCmdSend (pSlot, sock, FTPD_MULTI_LINE | 214,
  943. messages [MSG_COMMAND_LIST_BEGIN], 0, 0, 0, 0, 0, 0) 
  944.  == ERROR)
  945. {
  946. ftpdSessionDelete (pSlot);
  947. return (ERROR);
  948. }
  949.     if (write (pSlot->cmdSock, ftpdCommandList,
  950. strlen (ftpdCommandList)) <= 0)
  951. {
  952. ftpdSessionDelete (pSlot);
  953. return (ERROR);
  954. }
  955.     /* this signifies the end of the multiple line response */
  956.     if (ftpdCmdSend (pSlot, sock, 214, messages [MSG_COMMAND_LIST_END],
  957.  0, 0, 0, 0, 0, 0) == ERROR)
  958. {
  959. ftpdSessionDelete (pSlot);
  960. return (ERROR);
  961. }
  962.     continue; /* All is well go wait for the next command */
  963.     }
  964. else if ((pSlot->status & FTPD_USER_OK) == 0) /* validated yet? */
  965.     {
  966.     /* user is not validated yet.  tell him to log in first */
  967.     if (ftpdCmdSend (pSlot, sock, 530, messages [MSG_USER_PASS_REQ],
  968.  0, 0, 0, 0, 0, 0) == ERROR)
  969. {
  970. ftpdSessionDelete (pSlot);
  971. return (ERROR);
  972. }
  973.     /* do not proceed further until he's legit */
  974.     continue;
  975.     }
  976. if (strncmp (pBuf, "LIST", 4) == 0 ||
  977.  strncmp (pBuf, "NLST", 4) == 0)
  978.     {
  979.     STATUS retVal;
  980.     /* client wants to list out the contents of a directory */
  981.     /* if no directory specified or "." specified as a directory
  982.      * we use the currently active directory name
  983.      */
  984.     if (strlen (pBuf) < 6 || pBuf [5] == '.')
  985.         dirName = &pSlot->curDirName [0];
  986.     else if (pBuf [5] != '/')
  987. {
  988. if (pSlot->curDirName [strlen (pSlot->curDirName) - 1] == '/')
  989.     (void) sprintf (newPath,
  990.     "%s%s", pSlot->curDirName, &pBuf [5]);
  991. else
  992.     (void) sprintf (newPath,
  993.     "%s/%s", pSlot->curDirName, &pBuf [5]);
  994.         dirName = newPath;
  995.                } 
  996.             else
  997.                dirName = &pBuf [5];
  998.     ftpdDebugMsg ("LIST %sn", (int)dirName,0,0,0);
  999.     /* get a new data socket connection for the transmission of
  1000.      * the directory listing data
  1001.      */
  1002.     if (ftpdDataConnGet (pSlot) == ERROR)
  1003. {
  1004. if (ftpdCmdSend (pSlot, sock, 
  1005.                                  426, messages [MSG_DATA_CONN_ERROR],
  1006.                                  0, 0, 0, 0, 0, 0) == ERROR)
  1007.     
  1008.     {
  1009.     ftpdSessionDelete (pSlot);
  1010.     return (ERROR);
  1011.     }
  1012. continue;
  1013. }
  1014.     /* print out the directory contents over the data connection */
  1015.     retVal = ftpdDirListGet (pSlot->dataSock, dirName,
  1016.      (strncmp (pBuf, "LIST", 4) == 0));
  1017.     if (retVal == ERROR)
  1018. {
  1019. if (ftpdCmdSend (pSlot, sock, 550, messages [MSG_DIR_ERROR],
  1020.      0, 0, 0, 0, 0, 0) == ERROR)
  1021.     
  1022.     {
  1023.     ftpdSessionDelete (pSlot);
  1024.     return (ERROR);
  1025.     }
  1026. }
  1027.     else
  1028. {
  1029.                 if (ftpdCmdSend (pSlot, sock, 
  1030.                                  226, messages [MSG_TRANS_COMPLETE],
  1031.                                  0, 0, 0, 0, 0, 0) == ERROR)
  1032.     {
  1033.     ftpdSessionDelete (pSlot);
  1034.     return (ERROR);
  1035.     }
  1036. }
  1037.     /* free up the data socket */
  1038.     ftpdSockFree (&pSlot->dataSock);
  1039.     }
  1040. else if (strncmp (pBuf, "RETR", 4) == 0)
  1041.     {
  1042.     /* retrieve a file */
  1043.     /* open the file to be sent to the client */
  1044.     if (pBuf [5] != '/')
  1045. {
  1046. if (pSlot->curDirName [strlen (pSlot->curDirName) - 1] == '/')
  1047.     (void) sprintf (newPath,
  1048.     "%s%s", pSlot->curDirName, &pBuf [5]);
  1049. else
  1050.     (void) sprintf (newPath,
  1051.     "%s/%s", pSlot->curDirName, &pBuf [5]);
  1052. pFileName = newPath;
  1053. }
  1054.     else
  1055.         pFileName = &pBuf [5];
  1056.     ftpdDebugMsg ("RETR %sn", (int)pFileName,0,0,0);
  1057.     if ((inStream = fopen (pFileName, "r")) == NULL)
  1058.         {
  1059. if (ftpdCmdSend (pSlot, sock, 550, messages [MSG_FILE_ERROR],
  1060.      (int)(&pBuf[5]), 0, 0, 0, 0, 0) == ERROR)
  1061.     
  1062.     {
  1063.     ftpdSessionDelete (pSlot);
  1064.     return (ERROR);
  1065.     }
  1066. continue;
  1067. }
  1068.     /* ship it away */
  1069.     ftpdDataStreamSend (pSlot, inStream);
  1070.     (void) fclose (inStream);
  1071.     }
  1072. else if (strncmp (pBuf, "STOR", 4) == 0)
  1073.     {
  1074.     /* store a file */
  1075.     /* create a local file */
  1076.     if (pBuf [5] != '/')
  1077. {
  1078. if (pSlot->curDirName [strlen (pSlot->curDirName) - 1] == '/')
  1079.     (void) sprintf (newPath,
  1080.     "%s%s", pSlot->curDirName, &pBuf [5]);
  1081. else
  1082.     (void) sprintf (newPath,
  1083.     "%s/%s", pSlot->curDirName, &pBuf [5]);
  1084. pFileName = newPath;
  1085. }
  1086.     else
  1087.         pFileName = &pBuf [5];
  1088.     ftpdDebugMsg ("STOR %sn", (int)pFileName,0,0,0);
  1089.     if ((outStream = fopen (pFileName, "w")) == NULL)
  1090.         {
  1091. if (ftpdCmdSend (pSlot, sock, 553, messages[MSG_CREATE_ERROR],
  1092. (int)(&pBuf[5]), 0, 0, 0, 0, 0) == ERROR)
  1093.     {
  1094.     ftpdSessionDelete (pSlot);
  1095.     return (ERROR);
  1096.     }
  1097. continue;
  1098. }
  1099.     /* receive the file */
  1100.     ftpdDataStreamReceive (pSlot, outStream);
  1101.     (void) fclose (outStream);
  1102.     }
  1103. else if (strncmp (pBuf, "CWD", 3) == 0)
  1104.     {
  1105.     /* change directory */
  1106.     dirName = &pBuf [4];
  1107.     /* there is no default device for the specified directory */
  1108. #ifdef _WRS_VXWORKS_5_X
  1109.     if (iosDevFind (dirName, (char **)&pTail) == NULL)
  1110. #else
  1111.     if (iosDevFind (dirName, (const char **)&pTail) == NULL)
  1112. #endif
  1113. {
  1114.                 if (ftpdCmdSend (pSlot, sock, 
  1115.                                  501, messages [MSG_DIR_NOT_PRESENT],
  1116.                                  0, 0, 0, 0, 0, 0) == ERROR)
  1117.     
  1118.     {
  1119.     ftpdSessionDelete (pSlot);
  1120.     return (ERROR);
  1121.     }
  1122. continue;
  1123. }
  1124.     /* dirName doesn't start with a device name, prepend old path */
  1125.     if (dirName == pTail)
  1126. {
  1127. (void) strcpy (curDirName, pSlot->curDirName);
  1128. (void) pathCat (curDirName, dirName, newPath);
  1129. }
  1130.     else /* it starts with a dev name */
  1131. (void) strcpy (newPath, dirName);/* use the whole thing */
  1132.     pathCondense (newPath); /* condense ".." shit */
  1133.     /* remember where we are */
  1134.     (void) strcpy (pSlot->curDirName, newPath);
  1135.     /* notify successful chdir */
  1136.     if (ftpdCmdSend (pSlot, sock, 250, messages [MSG_CHANGED_DIR],
  1137.     (int)newPath, 0, 0, 0, 0, 0) == ERROR)
  1138. {
  1139. ftpdSessionDelete (pSlot);
  1140. return (ERROR);
  1141. }
  1142.     }
  1143. else if (strncmp (pBuf, "TYPE", 4) == 0)
  1144.     {
  1145.     /* we only support BINARY and ASCII representation types */
  1146.     if (pBuf [5] == 'I' || pBuf [5] == 'i' ||
  1147. pBuf [5] == 'L' || pBuf [5] == 'l')
  1148. {
  1149.         pSlot->status |= FTPD_BINARY_TYPE;
  1150. pSlot->status &= ~FTPD_ASCII_TYPE;
  1151. if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_TYPE_BINARY],
  1152.      0, 0, 0, 0, 0, 0) == ERROR)
  1153.     {
  1154.     ftpdSessionDelete (pSlot);
  1155.     return (ERROR);
  1156.     }
  1157. }
  1158.     else if (pBuf [5] == 'A' || pBuf [5] == 'a')
  1159. {
  1160.         pSlot->status |= FTPD_ASCII_TYPE;
  1161. pSlot->status &= ~FTPD_BINARY_TYPE;
  1162. if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_TYPE_ASCII],
  1163.      0, 0, 0, 0, 0, 0) == ERROR)
  1164.     {
  1165.     ftpdSessionDelete (pSlot);
  1166.     return (ERROR);
  1167.     }
  1168. }
  1169.     else
  1170. {
  1171. if (ftpdCmdSend (pSlot, sock, 504, messages [MSG_PARAM_BAD],
  1172.      0, 0, 0, 0, 0, 0) == ERROR)
  1173.     
  1174.     {
  1175.     ftpdSessionDelete (pSlot);
  1176.     return (ERROR);
  1177.     }
  1178. }
  1179.     }
  1180. else if (strncmp (pBuf, "PORT", 4) == 0)
  1181.     {
  1182.     /* client specifies the port to be used in setting up
  1183.      * active data connections later on (see ftpdDataConnGet ()).
  1184.      * format:  first four decimal digits separated by commas
  1185.      * indicate the internet address; the last two decimal
  1186.      * digits separated by a comma represents hi and low
  1187.      * bytes of a port number.
  1188.      */
  1189.     (void) sscanf (&pBuf [5], "%d,%d,%d,%d,%d,%d",
  1190.    &portNum [0], &portNum [1], &portNum [2],
  1191.    &portNum [3], &portNum [4], &portNum [5]);
  1192.     pSlot->dataAddr.sin_port = portNum [4] * 256 + portNum [5];
  1193.     /* convert port number to network byte order */
  1194.     pSlot->dataAddr.sin_port = htons (pSlot->dataAddr.sin_port);
  1195.             /* Set remote host to given value. */
  1196.             value = (portNum [0] << 24) | (portNum [1] << 16) |
  1197.                     (portNum [2] << 8) | portNum [3];
  1198.             pSlot->dataAddr.sin_addr.s_addr = htonl (value);
  1199.     if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_PORT_SET],
  1200.  0, 0, 0, 0, 0, 0) == ERROR)
  1201. {
  1202. ftpdSessionDelete (pSlot);
  1203. return (ERROR);
  1204. }
  1205.     }
  1206. else if (strncmp (pBuf, "PWD", 3) == 0)
  1207.     {
  1208.     /* get current working directory */
  1209.     (void) strcpy (pBuf, pSlot->curDirName);
  1210.     if (ftpdCmdSend (pSlot, sock, 257, messages [MSG_CUR_DIR],
  1211.  (int)pBuf, 0, 0, 0, 0, 0) == ERROR)
  1212. {
  1213. ftpdSessionDelete (pSlot);
  1214. return (ERROR);
  1215. }
  1216.     }
  1217. else if (strncmp (pBuf, "STRU", 4) == 0)
  1218.     {
  1219.     /* specify the file structure */
  1220.     /* we only support normal byte stream oriented files;
  1221.      * we don't support IBM-ish record block oriented files
  1222.      */
  1223.     if (pBuf [5] == 'F' || pBuf [5] == 'f')
  1224. {
  1225.         if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_FILE_STRU],
  1226.      0, 0, 0, 0, 0, 0) == ERROR)
  1227.     
  1228.     {
  1229.     ftpdSessionDelete (pSlot);
  1230.     return (ERROR);
  1231.     }
  1232. }
  1233.     else
  1234. {
  1235.         if (ftpdCmdSend (pSlot, sock, 504, messages [MSG_PARAM_BAD],
  1236.      0, 0, 0, 0, 0, 0) == ERROR)
  1237.     {
  1238.     ftpdSessionDelete (pSlot);
  1239.     return (ERROR);
  1240.     }
  1241. }
  1242.     }
  1243. else if (strncmp (pBuf, "MODE", 4) == 0)
  1244.     {
  1245.     /* specify transfer mode */
  1246.     /* we only support stream mode -- no block or compressed mode */
  1247.     if (pBuf [5] == 'S' || pBuf [5] == 's')
  1248. {
  1249.         if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_STREAM_MODE],
  1250.      0, 0, 0, 0, 0, 0) == ERROR)
  1251.     {
  1252.     ftpdSessionDelete (pSlot);
  1253.     return (ERROR);
  1254.     }
  1255. }
  1256.     else
  1257. {
  1258.         if (ftpdCmdSend (pSlot, sock, 504, messages [MSG_PARAM_BAD],
  1259.      0, 0, 0, 0, 0, 0) == ERROR)
  1260.     {
  1261.     ftpdSessionDelete (pSlot);
  1262.     return (ERROR);
  1263.     }
  1264. }
  1265.     }
  1266. else if (strncmp (pBuf, "ALLO", 4) == 0 ||
  1267.  strncmp (pBuf, "ACCT", 4) == 0)
  1268.     {
  1269.     /* allocate and account commands are not need */
  1270.     if (ftpdCmdSend (pSlot, sock, 202, messages [MSG_ALLOC_ACCOUNT],
  1271.  0, 0, 0, 0, 0, 0) == ERROR)
  1272. {
  1273. ftpdSessionDelete (pSlot);
  1274. return (ERROR);
  1275. }
  1276.     }
  1277. else if (strncmp (pBuf, "PASV", 4) == 0)
  1278.     {
  1279.     /* client wants to connect to us instead of waiting
  1280.      * for us to make a connection to its data connection
  1281.      * socket
  1282.      */
  1283.     ftpdSockFree (&pSlot->dataSock);
  1284.     /* we need to open a socket and start listening on it
  1285.      * to accommodate his request.
  1286.      */
  1287.     if ((pSlot->dataSock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
  1288. {
  1289. if (ftpdCmdSend (pSlot, sock, 425, messages [MSG_PASSIVE_ERROR],
  1290.      0, 0, 0, 0, 0, 0) == ERROR)
  1291.     {
  1292.     ftpdSessionDelete (pSlot);
  1293.     return (ERROR);
  1294.     }
  1295. }
  1296.     else
  1297. {
  1298.                 int outval1;
  1299.                 int outval2;
  1300.                 int outval3;
  1301.                 int outval4;
  1302.                 int outval5;
  1303.                 int outval6;
  1304.                 if (getsockname (pSlot->cmdSock,
  1305.                                  (struct sockaddr *) &pSlot->dataAddr,
  1306.                                  &addrLen) < 0)
  1307.                     {
  1308.                     /* Couldn't find address for local end of connection. */
  1309.                     if (ftpdCmdSend (pSlot, sock,
  1310.                                      425, messages [MSG_PASSIVE_ERROR],
  1311.                                      0, 0, 0, 0, 0, 0) == ERROR)
  1312.                         {
  1313.                         ftpdSessionDelete (pSlot);
  1314.                         return (ERROR);
  1315.                         }
  1316.                     }
  1317.                 /*
  1318.                  * Find an ephemeral port for the expected connection
  1319.                  * and initialize connection queue. 
  1320.                  */
  1321.                 pSlot->dataAddr.sin_port = htons (0);
  1322.                 addrLen = sizeof (struct sockaddr_in);
  1323. if (bind (pSlot->dataSock, (struct sockaddr *)&pSlot->dataAddr,
  1324.   sizeof (struct sockaddr_in)) < 0 ||
  1325.     getsockname (pSlot->dataSock,
  1326.  (struct sockaddr *) &pSlot->dataAddr,
  1327.  &addrLen) < 0 ||
  1328.     listen (pSlot->dataSock, 1) < 0)
  1329.     {
  1330.     ftpdSockFree (&pSlot->dataSock);
  1331.                     if (ftpdCmdSend (pSlot, sock, 
  1332.                                      425, messages [MSG_PASSIVE_ERROR],
  1333.                                      0, 0, 0, 0, 0, 0) == ERROR)
  1334. {
  1335. ftpdSessionDelete (pSlot);
  1336. return (ERROR);
  1337. }
  1338.     continue;
  1339.     }
  1340. /* we're passive, let us keep that in mind */
  1341. pSlot->status |= FTPD_PASSIVE;
  1342.                 value = pSlot->dataAddr.sin_addr.s_addr;
  1343.                 outval1 = ( (u_char *)&value)[0];
  1344.                 outval2 = ( (u_char *)&value)[1];
  1345.                 outval3 = ( (u_char *)&value)[2];
  1346.                 outval4 = ( (u_char *)&value)[3];
  1347.                  /* Separate port number into bytes. */
  1348.                 outval5 = ( (u_char *)&pSlot->dataAddr.sin_port)[0];
  1349.                 outval6 = ( (u_char *)&pSlot->dataAddr.sin_port)[1];
  1350. /* tell the client to which port to connect */
  1351.                 if (ftpdCmdSend (pSlot, pSlot->cmdSock, 
  1352.                                  227, messages [MSG_PASSIVE_MODE],
  1353.                                  outval1, outval2, outval3, outval4,
  1354.                                  outval5, outval6) == ERROR)
  1355.     {
  1356.     ftpdSessionDelete (pSlot);
  1357.     return (ERROR);
  1358.     }
  1359. }
  1360.     }
  1361. else if (strncmp (pBuf, "NOOP", 4) == 0)
  1362.     {
  1363.     /* don't do anything */
  1364.     if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_NOOP_OKAY],
  1365.  0, 0, 0, 0, 0, 0) == ERROR)
  1366. {
  1367. ftpdSessionDelete (pSlot);
  1368. return (ERROR);
  1369. }
  1370.     }
  1371.         else if (strncmp (pBuf, "DELE", 4) == 0)
  1372.             {
  1373.              if (pBuf [5] != '/')
  1374.                  {
  1375.                  if (pSlot->curDirName [strlen (pSlot->curDirName) - 1] == '/')
  1376.                      (void) sprintf (newPath,
  1377.                                      "%s%s", pSlot->curDirName, &pBuf [5]);
  1378.                  else
  1379.                      (void) sprintf (newPath,
  1380.                                      "%s/%s", pSlot->curDirName, &pBuf [5]);
  1381.                  pFileName = newPath;
  1382.                  }
  1383.              else
  1384.                  pFileName = &pBuf [5];
  1385.              ftpdDebugMsg ("DELE %sn", (int)pFileName,0,0,0);
  1386.              if (remove (pFileName) != OK)
  1387.                  {
  1388.                  if (ftpdCmdSend (pSlot, sock, 550, messages [MSG_FILE_ERROR],
  1389.                                   (int) pFileName, 0, 0, 0, 0, 0) == ERROR)
  1390.                      {
  1391.                       ftpdSessionDelete (pSlot);
  1392.                       return (ERROR);
  1393.                       }
  1394.                  continue;
  1395.                  }
  1396.              else
  1397.                  {
  1398.                   if (ftpdCmdSend (pSlot, sock, 250, messages [MSG_DELE_OKAY],
  1399.                                    0, 0, 0, 0, 0, 0) == ERROR)
  1400.                       {
  1401.                        ftpdSessionDelete (pSlot);
  1402.                        return (ERROR);
  1403.                       }
  1404.                  }
  1405.            }
  1406.        else
  1407.            {
  1408.     /* unrecognized command or command not supported */
  1409.     if (ftpdCmdSend (pSlot, sock, 500, messages [MSG_BAD_COMMAND],
  1410.  0, 0, 0, 0, 0, 0) == ERROR)
  1411. {
  1412. ftpdSessionDelete (pSlot);
  1413. return (ERROR);
  1414. }
  1415.     }
  1416. }
  1417.     /*
  1418.      * Processing halted due to pending server shutdown.
  1419.      * Remove all resources and exit.
  1420.      */
  1421.     ftpdSessionDelete (pSlot);
  1422.     return (OK);
  1423.     }
  1424. /*******************************************************************************
  1425. *
  1426. * ftpdDataConnGet - get a fresh data connection socket for FTP data transfer
  1427. *
  1428. * FTP uses upto two connections per session (as described above) at any
  1429. * time.  The command connection (cmdSock) is maintained throughout the
  1430. * FTP session to pass the request command strings and replies between
  1431. * the client and the server.  For commands that require bulk data transfer
  1432. * such as contents of a file or a list of files in a directory, FTP
  1433. * sets up dynamic data connections separate from the command connection.
  1434. * This function, ftpdDataConnGet, is responsible for creating
  1435. * such connections.
  1436. *
  1437. * Setting up the data connection is performed in two ways.  If the dataSock
  1438. * is already initialized and we're in passive mode (as indicated by the
  1439. * FTPD_PASSIVE bit of the status field in the FTPD_SESSION_SLOT) we need to
  1440. * wait for our client to make a connection to us -- so we just do an accept
  1441. * on this already initialized dataSock.  If the dataSock is already
  1442. * initialized and we're not in passive mode, we just use the already
  1443. * existing connection.  Otherwise, we need to initialize a new socket and
  1444. * make a connection to the the port where client is accepting new
  1445. * connections.  This port number is in general set by "PORT" command (see
  1446. * ftpdWorkTask()).
  1447. */
  1448. LOCAL STATUS ftpdDataConnGet
  1449.     (
  1450.     FTPD_SESSION_DATA   *pSlot          /* pointer to the work slot */
  1451.     )
  1452.     {
  1453.     FAST int newSock; /* new connection socket */
  1454.     int addrLen; /* to be used with accept */
  1455.     struct sockaddr_in addr; /* to be used with accept */
  1456.     int on = 1; /* to be used to turn things on */
  1457.     int retry = 0; /* retry counter initialized to zero */
  1458.     /* command socket is invalid, return immediately */
  1459.     if (pSlot->cmdSock == FTPD_SOCK_FREE)
  1460.         return (ERROR);
  1461.     pSlot->byteCount = 0;
  1462.     if (pSlot->dataSock != FTPD_SOCK_FREE)
  1463.         {
  1464. /* data socket is already initialized */
  1465. /* are we being passive? (should we wait for client to connect
  1466.  * to us rather than connecting to the client?)
  1467.  */
  1468. if (pSlot->status & FTPD_PASSIVE)
  1469.     {
  1470.     /* we're being passive.  wait for our client to connect to us. */
  1471.     addrLen = sizeof (struct sockaddr);
  1472.     if ((newSock = accept (pSlot->dataSock, (struct sockaddr *) &addr,
  1473.    &addrLen)) < 0)
  1474. {
  1475.                 ftpdCmdSend (pSlot, pSlot->cmdSock,
  1476.                              425, "Can't open data connection",
  1477.                              0, 0, 0, 0, 0, 0);
  1478.                 ftpdSockFree (&pSlot->dataSock);
  1479. /* we can't be passive no more */
  1480. pSlot->status &= ~FTPD_PASSIVE;
  1481. return (ERROR);
  1482. }
  1483.             /*
  1484.              * Enable the keep alive option to prevent misbehaving clients
  1485.              * from locking the server.
  1486.              */
  1487.             if (setsockopt (newSock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
  1488.                             sizeof (on)) != 0)
  1489.                 {
  1490.                 ftpdSockFree (&pSlot->dataSock);
  1491.                 return (ERROR);
  1492.                 }
  1493. /* Check for window size validity */
  1494.         if (ftpdWindowSize < 0 || ftpdWindowSize > 65536)
  1495.             ftpdWindowSize = FTPD_WINDOW_SIZE;
  1496.         /* set the window size  */
  1497.         if (setsockopt(newSock, SOL_SOCKET, SO_SNDBUF,
  1498.             (char *)&ftpdWindowSize, sizeof (ftpdWindowSize)))
  1499.                 printf("Couldn't set the Send Window to 10kn");
  1500.         if (setsockopt(newSock, SOL_SOCKET, SO_RCVBUF,
  1501.             (char *)&ftpdWindowSize, sizeof (ftpdWindowSize)))
  1502.                 printf("Couldn't set the Send Window to 10kn");
  1503.     /* replace the dataSock with our new connection */
  1504.     (void) close (pSlot->dataSock);
  1505.     pSlot->dataSock = newSock;
  1506.     /* N.B.: we stay passive */
  1507.             if (ftpdCmdSend (pSlot, pSlot->cmdSock,
  1508.                              150, "Opening %s mode data connection",
  1509.                              pSlot->status & FTPD_ASCII_TYPE ? (int) "ASCII"
  1510.                              : (int) "BINARY", 0, 0, 0, 0, 0) == ERROR)
  1511. {
  1512. (void) close (pSlot->dataSock);
  1513. return (ERROR);
  1514. }
  1515.     return (OK);
  1516.     }
  1517. else
  1518.     {
  1519.     /* reuse the old connection -- it's still useful */
  1520.             if (ftpdCmdSend (pSlot, pSlot->cmdSock, 
  1521.                              125, "Using existing data connection",
  1522.                              0, 0, 0, 0, 0, 0) == ERROR)
  1523. {
  1524.      ftpdSockFree (&pSlot->dataSock);
  1525. return (ERROR);
  1526. }
  1527.     return (OK);
  1528.     }
  1529. }
  1530.     else
  1531.         {
  1532.         /* Determine address for local end of connection. */
  1533.         addrLen = sizeof (struct sockaddr);
  1534.         if (getsockname (pSlot->cmdSock, (struct sockaddr *) &addr, &addrLen)
  1535.                 < 0)
  1536.             {
  1537.             return (ERROR);
  1538.             }
  1539.         /* Replace control port with default data port. */
  1540.         addr.sin_port = htons (FTP_DATA_PORT);
  1541. /* open a new data socket */
  1542. if ((pSlot->dataSock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
  1543.     { 
  1544.     return (ERROR);
  1545.     }
  1546. if (setsockopt (pSlot->dataSock, SOL_SOCKET,
  1547. SO_REUSEADDR, (char *) &on, sizeof (on)) < 0 ||
  1548.     bind (pSlot->dataSock, (struct sockaddr *) &addr,
  1549.   sizeof (addr)) < 0)
  1550.     {
  1551.     ftpdSockFree (&pSlot->dataSock);
  1552.     return (ERROR);
  1553.     }
  1554.         /* Set socket address to PORT command values or default. */
  1555.         bcopy ( (char *)&pSlot->dataAddr, (char *)&addr, 
  1556.                sizeof (struct sockaddr_in));
  1557. /* try until we get a connection to the client's port */
  1558. while (connect (pSlot->dataSock,
  1559. (struct sockaddr *) &addr, sizeof (addr)) < 0)
  1560.     {
  1561.     if ((errno & 0xffff) == EADDRINUSE && retry < FTPD_WAIT_MAX)
  1562.         {
  1563. taskDelay (FTPD_WAIT_INTERVAL * sysClkRateGet ());
  1564. retry += FTPD_WAIT_INTERVAL;
  1565. continue;
  1566. }
  1567.     /* timeout -- we give up */
  1568.             ftpdCmdSend (pSlot, pSlot->cmdSock,
  1569.                          425, "Can't build data connection",
  1570.                          0, 0, 0, 0, 0, 0);
  1571.     ftpdSockFree (&pSlot->dataSock);
  1572.     return (ERROR);
  1573.     }
  1574.             /*
  1575.              * Enable the keep alive option to prevent misbehaving clients
  1576.              * from locking the secondary task during file transfers.
  1577.              */
  1578.             if (setsockopt (pSlot->dataSock, SOL_SOCKET, SO_KEEPALIVE, 
  1579.                             (char *) &on, sizeof (on)) != 0)
  1580.                 {
  1581.                 ftpdSockFree (&pSlot->dataSock);
  1582.                 return (ERROR);
  1583.                 }
  1584.     /* Check for window size validity */
  1585.     if (ftpdWindowSize < 0 || ftpdWindowSize > 65536)
  1586. ftpdWindowSize = FTPD_WINDOW_SIZE;
  1587.     /* set the window size  */
  1588.     if (setsockopt(pSlot->dataSock, SOL_SOCKET, SO_SNDBUF,
  1589. (char *)&ftpdWindowSize, sizeof (ftpdWindowSize)))
  1590.     printf("Couldn't set the Send Window to 10kn");
  1591.     if (setsockopt(pSlot->dataSock, SOL_SOCKET, SO_RCVBUF,
  1592. (char *)&ftpdWindowSize, sizeof (ftpdWindowSize)))
  1593.     printf("Couldn't set the Send Window to 10kn");
  1594.             if (ftpdCmdSend (pSlot, pSlot->cmdSock, 
  1595.                              150, "Opening %s mode data connection",
  1596.                              pSlot->status & FTPD_ASCII_TYPE ? (int) "ASCII" :
  1597.                              (int) "BINARY", 0, 0, 0, 0, 0) == ERROR)
  1598. {
  1599. ftpdSockFree (&pSlot->dataSock);
  1600. return (ERROR);
  1601. }
  1602. }
  1603.     return (OK);
  1604.     }
  1605. /*******************************************************************************
  1606. *
  1607. * ftpdDataStreamSend - send FTP data over data connection
  1608. *
  1609. * When our FTP client does a "RETR" (send me a file) and we find an existing
  1610. * file, ftpdWorkTask() will call us to perform the actual shipment of the
  1611. * file in question over the data connection.
  1612. *
  1613. * We do the initialization of the new data connection ourselves here
  1614. * and make sure that everything is fine and dandy before shipping the
  1615. * contents of the file.  Special attention is given to the type of
  1616. * the file representation -- ASCII or BINARY.  If it's binary, we
  1617. * don't perform the prepending of "r" character in front of each
  1618. * "n" character.  Otherwise, we have to do this for the ASCII files.
  1619. *
  1620. * SEE ALSO:
  1621. * ftpdDataStreamReceive  which is symmetric to this function.
  1622. */
  1623. LOCAL void ftpdDataStreamSend
  1624.     (
  1625.     FTPD_SESSION_DATA   *pSlot,         /* pointer to our session slot */
  1626.     FILE                *inStream       /* pointer to the input file stream */
  1627.     )
  1628.     {
  1629.     FAST char *pBuf; /* pointer to the session buffer */
  1630.     FAST int netFd; /* output socket */
  1631.     FAST int fileFd; /* input file descriptor */
  1632.     FAST char ch; /* character holder */
  1633.     FAST int cnt; /* number of chars read/written */
  1634.     FAST FILE *outStream; /* buffered output socket stream */
  1635.     int retval = 0;
  1636.     /* get a fresh connection or reuse the old one */
  1637.     if (ftpdDataConnGet (pSlot) == ERROR)
  1638. {
  1639. dataError (pSlot);
  1640. return;
  1641. }
  1642.     pBuf = &pSlot->buf [0];
  1643.     if (pSlot->status & FTPD_ASCII_TYPE)
  1644. {
  1645. /* ASCII representation */
  1646. /* get a buffered I/O stream for this output data socket */
  1647. if ((outStream = fdopen (pSlot->dataSock, "w")) == NULL)
  1648.     {
  1649.     dataError (pSlot);
  1650.     return;
  1651.     }
  1652. /* write out the contents of the file and do the 'r' prepending */
  1653. while ((ch = getc (inStream)) != (char) EOF)
  1654.     {
  1655.     pSlot->byteCount++;
  1656.     /* if 'n' is encountered, we prepend a 'r' */
  1657.     if (ch == 'n')
  1658. {
  1659. if (ferror (outStream))
  1660.     {
  1661.     dataError (pSlot);
  1662.     fclose (outStream);
  1663.     return;
  1664.     }
  1665. if (putc ('r', outStream) == EOF)
  1666.     {
  1667.     dataError (pSlot);
  1668.     fclose (outStream);
  1669.     return;
  1670.     }
  1671. }
  1672.      if (putc (ch, outStream) == EOF)
  1673. {
  1674. dataError (pSlot);
  1675. fclose (outStream);
  1676. return;
  1677. }
  1678.             /* Abort the file transfer if a shutdown is in progress. */
  1679.             if (ch == 'n' && ftpsShutdownFlag)
  1680.                 {
  1681. dataError (pSlot);
  1682.                 fclose (outStream);
  1683.                 return;
  1684.                 }
  1685.     }
  1686. /* flush it out */
  1687. (void) fflush (outStream);
  1688. if (ferror (inStream))
  1689.     {
  1690.     /* error in reading the file */
  1691.     fileError (pSlot);
  1692.     fclose (outStream);
  1693.     return;
  1694.     }
  1695. if (ferror (outStream))
  1696.     {
  1697.     /* error in sending the file */
  1698.     dataError (pSlot);
  1699.     fclose (outStream);
  1700.     return;
  1701.     }
  1702. fclose (outStream);
  1703. /* everything is okay */
  1704. transferOkay (pSlot);
  1705. }
  1706.     else if (pSlot->status & FTPD_BINARY_TYPE)
  1707. {
  1708. /* BINARY representation */
  1709. netFd = pSlot->dataSock;
  1710. /* get a raw descriptor for this input file */
  1711. fileFd = fileno (inStream);
  1712. /* unbuffered block I/O between file and network */
  1713. while ((cnt = read (fileFd, pBuf, BUFSIZE)) > 0 &&
  1714.        (retval = write (netFd, pBuf, cnt)) == cnt)
  1715.             {
  1716.     pSlot->byteCount += cnt;
  1717.             if (ftpsShutdownFlag)
  1718.                 {
  1719.                 /* Abort the file transfer if a shutdown is in progress. */
  1720.                 cnt = 1;
  1721.                 break;
  1722.                 }
  1723.             }
  1724. /* cnt should be zero if the transfer ended normally */
  1725. if (cnt != 0)
  1726.     {
  1727.     if (cnt < 0)
  1728. {
  1729. fileError (pSlot);
  1730. return;
  1731. }
  1732.     ftpdDebugMsg ("read %d bytes, wrote %d bytesn", cnt, retval,0,0);
  1733.     dataError (pSlot);
  1734.     return;
  1735.     }
  1736. transferOkay (pSlot);
  1737. }
  1738.     else
  1739. unImplementedType (pSlot); /* invalide representation type */
  1740.     }
  1741. /*******************************************************************************
  1742. *
  1743. * ftpdDataStreamReceive - receive FTP data over data connection
  1744. *
  1745. * When our FTP client requests "STOR" command and we were able to
  1746. * create a file requested, ftpdWorkTask() will call ftpdDataStreamReceive
  1747. * to actually carry out the request -- receiving the contents of the
  1748. * named file and storing it in the new file created.
  1749. *
  1750. * We do the initialization of the new data connection ourselves here
  1751. * and make sure that everything is fine and dandy before receiving the
  1752. * contents of the file.  Special attention is given to the type of
  1753. * the file representation -- ASCII or BINARY.  If it's binary, we
  1754. * don't perform the handling of 'r' character in front of each
  1755. * 'n' character.  Otherwise, we have to do this for the ASCII files.
  1756. *
  1757. * SEE ALSO:
  1758. * ftpdDataStreamSend which is symmetric to this function.
  1759. */
  1760. LOCAL void ftpdDataStreamReceive
  1761.     (
  1762.     FTPD_SESSION_DATA   *pSlot,
  1763.     FILE                *outStream
  1764.     )
  1765.     {
  1766.     FAST char *pBuf; /* pointer to the session buffer */
  1767.     FAST char  ch; /* character holder */
  1768.     FAST FILE *inStream; /* buffered input file stream for data socket */
  1769.     FAST int fileFd; /* output file descriptor */
  1770.     FAST int netFd; /* network file descriptor */
  1771.     FAST BOOL dontPutc; /* flag to prevent bogus chars */
  1772.     FAST int cnt; /* number of chars read/written */
  1773.     /* get a fresh data connection or reuse the old one */
  1774.     if (ftpdDataConnGet (pSlot) == ERROR)
  1775. {
  1776. dataError (pSlot);
  1777. return;
  1778. }
  1779.     pBuf = &pSlot->buf [0];
  1780.     if (pSlot->status & FTPD_ASCII_TYPE)
  1781. {
  1782. /* ASCII representation */
  1783. /* get a buffer I/O stream for the input data socket connection */
  1784. if ((inStream = fdopen (pSlot->dataSock, "r")) == NULL)
  1785.     {
  1786.     dataError (pSlot);
  1787.     return;
  1788.     }
  1789. /* read in the contents of the file while doing the 'r' handling */
  1790. while ((ch = getc (inStream)) != (char) EOF)
  1791.     {
  1792.     dontPutc = FALSE;
  1793.     pSlot->byteCount++;
  1794.     /* a rather strange handling of sequences of 'r' chars */
  1795.     while (ch == 'r')
  1796. {
  1797. if (ferror (outStream))
  1798.     {
  1799.     dataError (pSlot);
  1800.     fclose (inStream);
  1801.     return;
  1802.     }
  1803. /* replace bogus chars between 'r' and 'n' chars with 'r' */
  1804. if ((ch = getc (inStream)) != 'n')
  1805.     {
  1806.     (void) putc ('r', outStream);
  1807.     if (ch == '' || ch == (char) EOF)
  1808. {
  1809. dontPutc = TRUE;
  1810. break;
  1811. }
  1812.     }
  1813. }
  1814.     if (dontPutc == FALSE)
  1815. (void) putc (ch, outStream);
  1816.             /* Abort file transfer if a shutdown is in progress. */
  1817.             if (ch == 'n' && ftpsShutdownFlag)
  1818.         {
  1819.         dataError (pSlot);
  1820.         fclose (inStream);
  1821.         return;
  1822.                 }
  1823.             }
  1824. /* flush out to the file */
  1825. (void) fflush (outStream);
  1826. if (ferror (inStream))
  1827.     {
  1828.     /* network input error */
  1829.     dataError (pSlot);
  1830.     fclose (inStream);
  1831.     return;
  1832.     }
  1833. if (ferror (outStream))
  1834.     {
  1835.     /* file output error */
  1836.     fileError (pSlot);
  1837.     fclose (inStream);
  1838.     return;
  1839.     }
  1840. /* we've succeeded! */
  1841. fclose (inStream);
  1842. transferOkay (pSlot);
  1843. }
  1844.     else if (pSlot->status & FTPD_BINARY_TYPE)
  1845. {
  1846. /* BINARY representation */
  1847. /* get a raw descriptor for output file stream */
  1848. fileFd = fileno (outStream);
  1849. netFd  = pSlot->dataSock;
  1850. /* perform non-buffered block I/O between network and file */
  1851. while ((cnt = read (netFd, pBuf, BUFSIZE)) > 0)
  1852.     {
  1853.     if (write (fileFd, pBuf, cnt) != cnt)
  1854. {
  1855. fileError (pSlot);
  1856. return;
  1857. }
  1858.     pSlot->byteCount += cnt;
  1859.             /* Abort the file transfer if a shutdown is in progress. */
  1860.             if (ftpsShutdownFlag)
  1861.                 {
  1862.                 cnt = -1;
  1863.                 break;
  1864.                 }
  1865.     }
  1866. if (cnt < 0)
  1867.     {
  1868.     dataError (pSlot);
  1869.     return;
  1870.     }
  1871. /* we've done it */
  1872. transferOkay (pSlot);
  1873. }
  1874.     else
  1875. unImplementedType (pSlot); /* invalid representation type */
  1876.     }
  1877. /*******************************************************************************
  1878. *
  1879. * ftpdSockFree - release a socket
  1880. *
  1881. * This function is used to examine whether or not the socket pointed
  1882. * by pSock is active and release it if it is.
  1883. */
  1884. LOCAL void ftpdSockFree
  1885.     (
  1886.     int *pSock
  1887.     )
  1888.     {
  1889.     if (*pSock != FTPD_SOCK_FREE)
  1890.         {
  1891.         int off = 0;
  1892.         struct linger so_linger = {1, 0};
  1893.         setsockopt (*pSock, SOL_SOCKET, SO_LINGER, (void *)&so_linger, sizeof (so_linger));
  1894.         setsockopt (*pSock, SOL_SOCKET, SO_KEEPALIVE, (char *)&off, sizeof (off));
  1895.         /* 
  1896.          * Now that we have said we do not want to keep the PCBs around for 60
  1897.          * seconds (which is what happens is SO_LINGER is enabled in vxWorks), we
  1898.          * need to call shutdown to gracefully terminate the connection without
  1899.          * loosing any data.
  1900.          */
  1901.         shutdown (*pSock, 2);
  1902.         if (ftpdDebug & 0x01)
  1903.             ftpdDebugMsg ("ftpdLib: (%d) Closing sock %dn", __LINE__, *pSock, 0, 0);
  1904.         (void) close (*pSock);
  1905.         *pSock = FTPD_SOCK_FREE;
  1906.         }
  1907.     }
  1908. /*******************************************************************************
  1909. *
  1910. * ftpdDirListGet - list files in a directory for FTP client
  1911. *
  1912. * This function performs the client's request to list out all
  1913. * the files in a given directory.  The VxWorks implementation of
  1914. * stat() does not work on RT-11 filesystem drivers, it is simply not supported.
  1915. *
  1916. * This command is similar to UNIX ls.  It lists the contents of a directory
  1917. * in one of two formats.  If <doLong> is FALSE, only the names of the files
  1918. * (or subdirectories) in the specified directory are displayed.  If <doLong>
  1919. * is TRUE, then the file name, size, date, and time are displayed.  If
  1920. * doing a long listing, any entries that describe subdirectories will also
  1921. * be flagged with a "DIR" comment.
  1922. *
  1923. * The <dirName> parameter specifies the directory to be listed.  If
  1924. * <dirName> is omitted or NULL, the current working directory will be
  1925. * listed.
  1926. *
  1927. * Empty directory entries and MS-DOS volume label entries are not
  1928. * reported.
  1929. *
  1930. * INTERNAL
  1931. * Borrowed from ls() in usrLib.c.
  1932. *
  1933. * RETURNS:  OK or ERROR.
  1934. *
  1935. * SEE ALSO: ls(), stat()
  1936. */
  1937. LOCAL STATUS ftpdDirListGet
  1938.     (
  1939.     int         sd,             /* socket descriptor to write on */
  1940.     char        *dirName,       /* name of the directory to be listed */
  1941.     BOOL        doLong          /* if TRUE, do long listing */
  1942.     )
  1943.     {
  1944.     FAST STATUS status; /* return status */
  1945.     FAST DIR *pDir; /* ptr to directory descriptor */
  1946.     FAST struct dirent *pDirEnt; /* ptr to dirent */
  1947.     struct stat fileStat; /* file status info    (long listing) */
  1948.     struct tm fileDate; /* file date/time      (long listing) */
  1949.     char *pDirComment; /* dir comment         (long listing) */
  1950.     BOOL firstFile; /* first file flag     (long listing) */
  1951.     char  fileName [MAX_FILENAME_LENGTH];
  1952. /* buffer for building file name */
  1953.     static char  *monthNames[] = {"???", "Jan", "Feb", "Mar", "Apr",
  1954.       "May", "Jun", "Jul", "Aug", "Sep",
  1955.       "Oct", "Nov", "Dec"};
  1956.     /* If no directory name specified, use "." */
  1957.     if (dirName == NULL)
  1958. dirName = ".";
  1959.     /* Open dir */
  1960.     if ((pDir = opendir (dirName)) == NULL)
  1961. {
  1962. fdprintf (sd, "Can't open "%s".n", dirName);
  1963. return (ERROR);
  1964. }
  1965.     /* List files */
  1966.     status = OK;
  1967.     firstFile = TRUE;
  1968.     do
  1969. {
  1970. errno = OK;
  1971.      pDirEnt = readdir (pDir);
  1972. if (pDirEnt != NULL)
  1973.     {
  1974.     if (doLong) /* if doing long listing */
  1975. {
  1976. if (firstFile)
  1977.     {
  1978.          if (fdprintf (sd, 
  1979. "  size          date       time       namen")==ERROR)
  1980.      return ( ERROR | closedir (pDir));
  1981.          if (fdprintf (sd,
  1982.        "--------       ------     ------    --------n")==ERROR)
  1983.      return ( ERROR | closedir (pDir));
  1984.          firstFile = FALSE;
  1985.          }
  1986. /* Construct path/filename for stat */
  1987. (void) pathCat (dirName, pDirEnt->d_name, fileName);
  1988. /* Get and print file status info */
  1989. if (stat (fileName, &fileStat) != OK)
  1990.     {
  1991.     status = ERROR;
  1992.     break;
  1993.     }
  1994. /* Break down file modified time */
  1995. localtime_r (&fileStat.st_mtime, &fileDate);
  1996. if (S_ISDIR (fileStat.st_mode)) /* if a directory */
  1997.     pDirComment = "<DIR>";
  1998. else
  1999.     pDirComment = "";
  2000. if (fdprintf (sd, 
  2001. "%8d    %s-%02d-%04d  %02d:%02d:%02d   %-16s  %sn",
  2002. fileStat.st_size,  /* size in bytes */
  2003. monthNames [fileDate.tm_mon + 1],/* month */
  2004. fileDate.tm_mday, /* day of month */
  2005. fileDate.tm_year + 1900, /* year */
  2006. fileDate.tm_hour, /* hour */
  2007. fileDate.tm_min, /* minute */
  2008. fileDate.tm_sec, /* second */
  2009. pDirEnt->d_name, /* name */
  2010. pDirComment) == ERROR) /* "<DIR>" or "" */
  2011.     return ( ERROR | closedir (pDir));
  2012. }
  2013.     else /* just listing file names */
  2014. {
  2015.      if (fdprintf (sd, "%sn", pDirEnt->d_name) == ERROR)
  2016.     return ( ERROR | closedir (pDir));
  2017. }
  2018.     }
  2019. else /* readdir returned NULL */
  2020.     {
  2021.     if (errno != OK) /* if real error, not dir end */
  2022. {
  2023. if (fdprintf (sd, "error reading entry: %xn", errno) == ERROR)
  2024.     return ( ERROR | closedir (pDir));
  2025. status = ERROR;
  2026. }
  2027.     }
  2028. } while (pDirEnt != NULL); /* until end of dir */
  2029.     fdprintf (sd, "n");
  2030.     /* Close dir */
  2031.     status |= closedir (pDir);
  2032.     return (status);
  2033.     }
  2034. /*******************************************************************************
  2035. *
  2036. * unImplementedType - send FTP invalid representation type error reply
  2037. */
  2038. LOCAL void unImplementedType
  2039.     (
  2040.     FTPD_SESSION_DATA   *pSlot
  2041.     )
  2042.     {
  2043.     ftpdCmdSend (pSlot, pSlot->cmdSock, 550, messages [MSG_TYPE_ERROR],
  2044.  FTPD_REPRESENTATION (pSlot), 0, 0, 0, 0, 0);
  2045.     ftpdSockFree (&pSlot->dataSock);
  2046.     }
  2047. /*******************************************************************************
  2048. *
  2049. * dataError - send FTP data connection error reply
  2050. *
  2051. * Send the final error message about connection error and delete the session.
  2052. */
  2053. LOCAL void dataError
  2054.     (
  2055.     FTPD_SESSION_DATA   *pSlot
  2056.     )
  2057.     {
  2058.     ftpdCmdSend (pSlot, pSlot->cmdSock, 426, messages [MSG_DATA_CONN_ERROR], 
  2059.                  0, 0, 0, 0, 0, 0);
  2060.     ftpdSockFree (&pSlot->dataSock);
  2061.     }
  2062. /*******************************************************************************
  2063. *
  2064. * fileError - send FTP file I/O error reply
  2065. *
  2066. * Send the final error message about file error and delete the session.
  2067. */
  2068. LOCAL void fileError
  2069.     (
  2070.     FTPD_SESSION_DATA  *pSlot
  2071.     )
  2072.     {
  2073.     ftpdCmdSend (pSlot, pSlot->cmdSock, 551, messages [MSG_INPUT_FILE_ERROR], 
  2074.                  0, 0, 0, 0, 0, 0);
  2075.     ftpdSockFree (&pSlot->dataSock);
  2076.     }
  2077. /*******************************************************************************
  2078. *
  2079. * transferOkay - send FTP file transfer completion reply
  2080. */
  2081. LOCAL void transferOkay
  2082.     (
  2083.     FTPD_SESSION_DATA   *pSlot
  2084.     )
  2085.     {
  2086.     ftpdSockFree (&pSlot->dataSock);
  2087.     ftpdCmdSend (pSlot, pSlot->cmdSock, 226, messages [MSG_TRANS_COMPLETE], 
  2088.                  0, 0, 0, 0, 0, 0);
  2089.     }
  2090. /*******************************************************************************
  2091. *
  2092. * ftpdCmdSend - send a FTP command reply
  2093. *
  2094. * In response to a request, we send a reply containing completion
  2095. * status, error status, and other information over a command connection.
  2096. */
  2097. LOCAL STATUS ftpdCmdSend
  2098.     (
  2099.     FTPD_SESSION_DATA  *pSlot,         /* pointer to the session slot */
  2100.     int  controlSock,  /* control socket for reply */
  2101.     int                 code,           /* FTP status code */
  2102.     char                *format,        /* printf style format string */
  2103.     int                 arg1,
  2104.     int                 arg2,
  2105.     int                 arg3,
  2106.     int                 arg4,
  2107.     int                 arg5,
  2108.     int                 arg6
  2109.     )
  2110.     {
  2111.     int                 buflen;
  2112.     char buf [BUFSIZE]; /* local buffer */
  2113.     FAST char  *pBuf = &buf [0]; /* pointer to buffer */
  2114.     BOOL  lineContinue =
  2115. (code & FTPD_MULTI_LINE) == FTPD_MULTI_LINE;
  2116.     /*
  2117.      * If this routine is called before a session is established, the
  2118.      * pointer to session-specific data is NULL. Otherwise, exit with
  2119.      * an error if an earlier attempt to send a control message failed.
  2120.      */
  2121.     if ( (pSlot != NULL) && (pSlot->cmdSockError == ERROR))
  2122.         return (ERROR);
  2123.     code &= ~FTPD_MULTI_LINE; /* strip multi-line bit from reply code */
  2124.     /* embed the code first */
  2125.     (void) sprintf (pBuf, "%d%c", code, lineContinue ? '-' : ' ');
  2126.     pBuf += strlen (pBuf);
  2127.     (void) sprintf (pBuf, format, arg1, arg2, arg3, arg4, arg5, arg6);
  2128.     pBuf += strlen (pBuf);
  2129.     /* telnet style command terminator */
  2130.     (void) sprintf (pBuf, "rn");
  2131.     /* send it over to our client */
  2132.     buflen = strlen (buf);
  2133.     if ( write (controlSock, buf, buflen) != buflen )
  2134.         {
  2135.         if (pSlot != NULL)
  2136.             pSlot->cmdSockError = ERROR;
  2137.      ftpdDebugMsg ("sent %s Failed on writen", (int)buf,0,0,0);
  2138.         return (ERROR);    /* Write Error */
  2139.         }
  2140.     ftpdDebugMsg ("sent %sn", (int)buf,0,0,0);
  2141.     return (OK); /* Command Sent Successfully */
  2142.     }
  2143. /*******************************************************************************
  2144. *
  2145. * ftpdDebugMsg - print out FTP command request and replies for debugging.
  2146. */
  2147. LOCAL void ftpdDebugMsg
  2148.     (
  2149.     char        *format,
  2150.     int         arg1,
  2151.     int         arg2,
  2152.     int         arg3,
  2153.     int         arg4
  2154.     )
  2155.     {
  2156.     if (ftpdDebug == TRUE)
  2157. logMsg (format, arg1, arg2, arg3, arg4, 0, 0);
  2158.     }