Ftp.c

From Nutwiki
Revision as of 19:06, 2 October 2007 by Harald (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Ein FTP-Server. Sofern Ihr Netzwerk einen DHCP-Server hat, wird automatisch eine IP-Adresse bezogen. Solte kein DHCP-Server vorhanden sein, so wird die IP-Adresse 192.168.192.35 verwendet. Daten werden von der SD/MMC-Karte gelsen.

<source lang="c">

  1. include <stdio.h>
  2. include <fcntl.h>
  3. include <io.h>
  1. include <dev/board.h>
  2. include <dev/lanc111.h>
  3. include <dev/debug.h>
  4. include <dev/pnut.h>
  5. include <dev/nplmmc.h>
  6. include <dev/sbimmc.h>
  7. include <dev/spimmc_at91.h>
  8. include <dev/at91_mci.h>
  9. include <dev/x12rtc.h>
  10. include <fs/phatfs.h>
  1. include <sys/confnet.h>
  2. include <sys/version.h>
  3. include <sys/heap.h>
  4. include <sys/thread.h>
  5. include <sys/socket.h>
  1. include <arpa/inet.h>
  2. include <netinet/tcp.h>
  3. include <net/route.h>
  4. include <pro/dhcp.h>
  5. include <pro/ftpd.h>
  6. include <pro/wins.h>
  7. include <pro/sntp.h>
  8. include <pro/discover.h>

/* Determine the compiler. */

  1. if defined(__IMAGECRAFT__)
  2. if defined(__AVR__)
  3. define CC_STRING "ICCAVR"
  4. else
  5. define CC_STRING "ICC"
  6. endif
  7. elif defined(__GNUC__)
  8. if defined(__AVR__)
  9. define CC_STRING "AVRGCC"
  10. elif defined(__arm__)
  11. define CC_STRING "ARMGCC"
  12. else
  13. define CC_STRING "GCC"
  14. endif
  15. else
  16. define CC_STRING "Compiler unknown"
  17. endif

/*

* Baudrate for debug output. 
*/
  1. ifndef DBG_BAUDRATE
  2. define DBG_BAUDRATE 115200
  3. endif

/*

* Wether we should use DHCP.
*/
  1. define USE_DHCP

/*

* Wether we should run a discovery responder.
*/
  1. if defined(__arm__)
  2. define USE_DISCOVERY
  3. endif

/*

* Unique MAC address of the Ethernut Board. 
*
* Ignored if EEPROM contains a valid configuration.
*/
  1. define MY_MAC { 0x00, 0x06, 0x98, 0x30, 0x00, 0x35 }

/*

* Unique IP address of the Ethernut Board. 
*
* Ignored if DHCP is used. 
*/
  1. define MY_IPADDR "192.168.192.35"

/*

* IP network mask of the Ethernut Board.
*
* Ignored if DHCP is used. 
*/
  1. define MY_IPMASK "255.255.255.0"

/*

* Gateway IP address for the Ethernut Board.
*
* Ignored if DHCP is used. 
*/
  1. define MY_IPGATE "192.168.192.1"

/*

* NetBIOS name.
*
* Use a symbolic name with Win32 Explorer.
*/

//#define MY_WINSNAME "ETHERNUT"

/*

* FTP port number.
*/
  1. define FTP_PORTNUM 21

/*

* FTP timeout.
*
* The server will terminate the session, if no new command is received
* within the specified number of milliseconds.
*/
  1. define FTPD_TIMEOUT 600000

/*

* TCP buffer size.
*/
  1. define TCPIP_BUFSIZ 5840

/*

* Maximum segment size. 
*
* Choose 536 up to 1460. Note, that segment sizes above 536 may result 
* in fragmented packets. Remember, that Ethernut doesn't support TCP 
* fragmentation.
*/
  1. define TCPIP_MSS 1460
  1. if defined(ETHERNUT3)

/* Ethernut 3 file system. */

  1. define FSDEV devPhat0
  2. define FSDEV_NAME "PHAT0"

/* Ethernut 3 block device interface. */

  1. define BLKDEV devNplMmc0
  2. define BLKDEV_NAME "MMC0"
  1. elif defined(AT91SAM7X_EK)

/* SAM7X-EK file system. */

  1. define FSDEV devPhat0
  2. define FSDEV_NAME "PHAT0"

/* SAM7X-EK block device interface. */

  1. define BLKDEV devAt91SpiMmc0
  2. define BLKDEV_NAME "MMC0"
  1. elif defined(AT91SAM9260_EK)

/* SAM9260-EK file system. */

  1. define FSDEV devPhat0
  2. define FSDEV_NAME "PHAT0"

/* SAM9260-EK block device interface. */

  1. define BLKDEV devAt91Mci0
  2. define BLKDEV_NAME "MCI0"
  1. elif defined(ETHERNUT2)

/*

* Ethernut 2 File system
*/
  1. define FSDEV devPnut
  2. define FSDEV_NAME "PNUT"
  1. else
  1. define FSDEV_NAME "NONE"
  1. endif
  1. define MYTZ -1
  1. define MYTIMED "130.149.17.21"
  1. ifdef ETHERNUT3
  1. define X12RTC_DEV
  2. endif

/*

* FTP service.
*
* This function waits for client connect, processes the FTP request 
* and disconnects. Nut/Net doesn't support a server backlog. If one 
* client has established a connection, further connect attempts will 
* be rejected. 
*
* Some FTP clients, like the Win32 Explorer, open more than one 
* connection for background processing. So we run this routine by
* several threads.
*/

void FtpService(void) {

   TCPSOCKET *sock;
   /*
    * Create a socket.
    */
   if ((sock = NutTcpCreateSocket()) != 0) {
       /* 
        * Set specified socket options. 
        */
  1. ifdef TCPIP_MSS
       {
           u_short mss = TCPIP_MSS;
           NutTcpSetSockOpt(sock, TCP_MAXSEG, &mss, sizeof(mss));
       }
  1. endif
  2. ifdef FTPD_TIMEOUT
       {
           u_long tmo = FTPD_TIMEOUT;
           NutTcpSetSockOpt(sock, SO_RCVTIMEO, &tmo, sizeof(tmo));
       }
  1. endif
  2. ifdef TCPIP_BUFSIZ
       {
           u_short siz = TCPIP_BUFSIZ;
           NutTcpSetSockOpt(sock, SO_RCVBUF, &siz, sizeof(siz));
       }
  1. endif
       /*
        * Listen on our port. If we return, we got a client.
        */
       printf("\nWaiting for an FTP client...");
       if (NutTcpAccept(sock, FTP_PORTNUM) == 0) {
           printf("%s connected, %u bytes free\n", inet_ntoa(sock->so_remote_addr), (u_int)NutHeapAvailable());
           NutFtpServerSession(sock);
           printf("%s disconnected, %u bytes free\n", inet_ntoa(sock->so_remote_addr), (u_int)NutHeapAvailable());
       } else {
           puts("Accept failed");
       }
       /*
        * Close our socket.
        */
       NutTcpCloseSocket(sock);
   }

}

/*

* FTP service thread.
*/

THREAD(FtpThread, arg) {

   /* Loop endless for connections. */
   for (;;) {
       FtpService();
   }

}

/*

* Assign stdout to the UART device.
*/

void InitDebugDevice(void) {

   u_long baud = DBG_BAUDRATE;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);

}

/*

* Setup the ethernet device. Try DHCP first. If this is
* the first time boot with empty EEPROM and no DHCP server
* was found, use hardcoded values.
*/

int InitEthernetDevice(void) {

   u_long ip_addr = inet_addr(MY_IPADDR);
   u_long ip_mask = inet_addr(MY_IPMASK);
   u_long ip_gate = inet_addr(MY_IPGATE);
   u_char mac[6] = MY_MAC;
   if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5)) {
       puts("No Ethernet Device");
       return -1;
   }
   printf("Configure %s...", DEV_ETHER_NAME);
  1. ifdef USE_DHCP
   if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000) == 0) {
       puts("OK");
       return 0;
   }
   printf("initial boot...");
   if (NutDhcpIfConfig(DEV_ETHER_NAME, mac, 60000) == 0) {
       puts("OK");
       return 0;
   }
  1. endif
   printf("No DHCP...");
   NutNetIfConfig(DEV_ETHER_NAME, mac, ip_addr, ip_mask);
   /* Without DHCP we had to set the default gateway manually.*/
   if(ip_gate) {
       printf("hard coded gate...");
       NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER);
   }
   puts("OK");
   return 0;

}

/*

* Query a time server and optionally update the hardware clock.
*/

static int QueryTimeServer(void) {

   int rc = -1;
  1. ifdef MYTIMED
   {
       time_t now;
       u_long timeserver = inet_addr(MYTIMED);
       /* Query network time service and set the system time. */
       printf("Query time from %s...", MYTIMED);
       if(NutSNTPGetTime(&timeserver, &now) == 0) {
           puts("OK");
           rc = 0;
           stime(&now);
  1. ifdef X12RTC_DEV
           /* If RTC hardware is available, update it. */
           {
               struct _tm *gmt = gmtime(&now);
               if (X12RtcSetClock(gmt)) {
                   puts("RTC update failed");
               }
           }
  1. endif
       }
       else {
           puts("failed");
       }
   }
  1. endif
   return rc;

}

/*

* Try to get initial date and time from the hardware clock or a time server.
*/

static int InitTimeAndDate(void) {

   int rc = -1;
   /* Set the local time zone. */
   _timezone = MYTZ * 60L * 60L;
  1. ifdef X12RTC_DEV
   /* Query RTC hardware if available. */
   {
       u_long rs;
       /* Query the status. If it fails, we do not have an RTC. */
       if (X12RtcGetStatus(&rs)) {
           puts("No hardware RTC");
           rc = QueryTimeServer();
       }
       else {
           /* RTC hardware seems to be available. Check for power failure. */
           //rs = RTC_STATUS_PF;
           if ((rs & RTC_STATUS_PF) == RTC_STATUS_PF) {
               puts("RTC power fail detected");
               rc = QueryTimeServer();
           }
           /* RTC hardware status is fine, update our system clock. */
           else {
               struct _tm gmt;
               /* Assume that RTC is running at GMT. */
               if (X12RtcGetClock(&gmt) == 0) {
                   time_t now = _mkgmtime(&gmt);
                   if (now != -1) {
                       stime(&now);
                       rc = 0;
                   }
               }
           }
       }
   }
  1. else
   /* No hardware RTC, query the time server if available. */
   rc = QueryTimeServer();
  1. endif
   return rc;

}

/*

* Main application routine. 
*
* Nut/OS automatically calls this entry after initialization.
*/

int main(void) {

   int volid;
   u_long ipgate;
   /* Initialize a debug output device and print a banner. */
   InitDebugDevice();
   printf("\n\nFTP Server Sample - Nut/OS %s - " CC_STRING "\n", NutVersionString());
   /* Initialize the Ethernet device and print our IP address. */
   if (InitEthernetDevice()) {
       for(;;);
   }
   printf("IP Addr: %s\n", inet_ntoa(confnet.cdn_ip_addr));
   printf("IP Mask: %s\n", inet_ntoa(confnet.cdn_ip_mask));
   NutIpRouteQuery(0, &ipgate);
   printf("IP Gate: %s\n", inet_ntoa(ipgate));
  1. ifdef USE_DISCOVERY
   /* Register a discovery responder. */
   printf("Start Responder...");
   if (NutRegisterDiscovery((u_long)-1, 0, DISF_INITAL_ANN)) {
       puts("failed");
   }
   else {
       puts("OK");
   }
  1. endif
   /* Initialize system clock and calendar. */
   if (InitTimeAndDate() == 0) {
       time_t now = time(0);
       struct _tm *lot = localtime(&now);
       printf("Date: %02u.%02u.%u\n", lot->tm_mday, lot->tm_mon + 1, 1900 + lot->tm_year);
       printf("Time: %02u:%02u:%02u\n", lot->tm_hour, lot->tm_min, lot->tm_sec);
   }
  1. ifdef FSDEV
   /* Initialize the file system. */
   printf("Register file system...");
   if (NutRegisterDevice(&FSDEV, 0, 0)) {
       puts("failed");
       for (;;);
   }
   puts("OK");
  1. endif
  1. ifdef BLKDEV
   /* Register block device. */
   printf("Register block device...");
   if (NutRegisterDevice(&BLKDEV, 0, 0)) {
       puts("failed");
       for (;;);
   }
   puts("OK");
   /* Mount partition. */
   printf("Mounting partition...");
   if ((volid = _open(BLKDEV_NAME ":1/" FSDEV_NAME, _O_RDWR | _O_BINARY)) == -1) {
       puts("failed");
       for (;;);
   }
   puts("OK");
  1. else
   volid = 0;
  1. endif
   /* Register root path. */
   printf("Register FTP root...");
   if (NutRegisterFtpRoot(FSDEV_NAME ":")) {
       puts("failed");
       for (;;);
   }
   puts("OK");
   /* Start two additional server threads. */
   NutThreadCreate("ftpd0", FtpThread, 0, 1640);
   NutThreadCreate("ftpd1", FtpThread, 0, 1640);
   /* Main server thread. */
   for (;;) {
  1. ifdef MY_WINSNAME
       NutWinsNameQuery(MY_WINSNAME, confnet.cdn_ip_addr);
  1. endif
       FtpService();
   }

}

</source> ftp.c Copyright by egnite Software GmbH