⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tftp_server.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
    memset(&hints,0,sizeof(hints));    hints.ai_family = from_addr->sa_family;    hints.ai_flags = AI_PASSIVE;    error = getaddrinfo(NULL,"tftp",&hints, &res);    if (0 != error) {      diag_printf("TFTPD: can't get a suitable local address: %s\n",		  gai_strerror(error));      return;    }    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);    if (s < 0) {        diag_printf("TFTPD: can't open socket for 'write_file'\n");	freeaddrinfo(res);        return;    }    // We want the stack to pick a free local port number    set_port(res->ai_addr,0);    if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {        // Problem setting up my end        diag_printf("TFTPD: can't bind to reply port for 'write_file'\n");        close(s);	freeaddrinfo(res);        return;    }    if ((fd = (server->ops->open)(hdr->th_stuff, O_RDONLY)) < 0) {        tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len);        close(s);	freeaddrinfo(res);        return;    }    block = 0;    ok = true;    while (ok) {        // Read next chunk of file        len = (server->ops->read)(fd, reply->th_data, SEGSIZE);        reply->th_block = htons(++block); // preincrement        reply->th_opcode = htons(DATA);        for (tries = 0;  tries < TFTP_RETRIES_MAX;  tries++) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT            tftp_server_instrument.data.send++;#endif            if (sendto(s, reply, 4+len, 0,                       from_addr, from_len) < 0) {                // Something went wrong with the network!                ok = false;                break;            }        repeat_select:            timeout.tv_sec = TFTP_TIMEOUT_PERIOD;            timeout.tv_usec = 0;            FD_ZERO(&fds);            FD_SET(s, &fds);            if (select(s+1, &fds, 0, 0, &timeout) <= 0) {                if (++total_timeouts > TFTP_TIMEOUT_MAX) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                    tftp_server_instrument.err_send++;#endif 		    tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);                    ok = false;                    break;                }#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                tftp_server_instrument.data.resend++;#endif                continue; // retry the send, using up one retry.            }            data_len = sizeof(data_in);            client_len = sizeof(client_addr);            if ((data_len = recvfrom(s, data_in, data_len, 0,                                      &client_addr,                                     &client_len)) < 0) {                // What happened?  Maybe someone lied to us...#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                tftp_server_instrument.data.resend++;#endif                continue; // retry the send, using up one retry.            }            if ((ntohs(response->th_opcode) == ACK) &&                (ntohs(response->th_block) < block)) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                tftp_server_instrument.ack.rx_repeat++;#endif                // Then it is a repeat ACK for an old block; listen again,                // but do not repeat sending the current block, and do not                // use up a retry count.  (we do re-send the data if                // subsequently we time out)                goto repeat_select;            }            if ((ntohs(response->th_opcode) == ACK) &&                (ntohs(response->th_block) == block)) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT                tftp_server_instrument.ack.rx++;#endif                // Happy!  Break out of the retries loop.                break;            }            // Otherwise, we got something we do not understand!  So repeat            // sending the current block, and use up a retry count.#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT            if ( (ntohs(response->th_opcode) == ACK) )                tftp_server_instrument.ack.rx_skip++;            tftp_server_instrument.data.resend++;#endif        } // End of the retries loop.        if (TFTP_RETRIES_MAX <= tries) {#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT            tftp_server_instrument.err_send++;#endif            tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);            ok = false;        }        if (len < SEGSIZE) {            break; // That's end of file then.        }    }    close(s);    freeaddrinfo(res);    (server->ops->close)(fd);}//// Actual TFTP server//static voidtftpd_server(cyg_addrword_t p){    struct tftp_server *server = (struct tftp_server *)p;    int max_s = 0;    int data_len, recv_len, from_len;    struct sockaddr from_addr;    char data[SEGSIZE+sizeof(struct tftphdr)];    struct tftphdr *hdr = (struct tftphdr *)data;    struct addrinfo hints;    struct addrinfo *ai;    fd_set readfds;    char name[64];    int error;    int i;#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT    struct info o = tftp_server_instrument;#endif    #ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS    // Otherwise routine printfs fail the test - interrupts disabled too long.    diag_printf("TFTPD [%x]: port %d\n", p, server->port);#endif    memset(&hints,0,sizeof(hints));    hints.ai_family = PF_UNSPEC;    hints.ai_flags = AI_PASSIVE;    error = getaddrinfo(NULL,"tftp",&hints, &server->res);    if (0 != error) {      diag_printf("TFTPD [%p] : can't get a local server address to bind to: %s\n",		  p, gai_strerror(error));      return;    }     // If the port is 0, we need to use the default TFTP port. Extrace    // the port number from one of the addresses returned by    // getaddrinfo.    if (server->port == 0) {      switch (server->res->ai_family) {      case AF_INET: 	{	  struct sockaddr_in *addr = (struct sockaddr_in *)server->res->ai_addr;	  server->port = ntohs(addr->sin_port);	  break;	}#ifdef CYGPKG_NET_INET6      case AF_INET6:	{	  struct sockaddr_in6 *addr = (struct sockaddr_in6 *)server->res->ai_addr;	  server->port = ntohs(addr->sin6_port);	  break;	}#endif      default:	break;      }    }#ifdef CYGSEM_NET_TFTPD_MULTITHREADED       sem_alloc(server->port);    while (true) {#endif      // Iterate over the addresses and create a local port to listen for requests       ai = server->res;      memset(server->s,0,sizeof(server->s));      server->num_s = 0;#ifdef CYGSEM_NET_TFTPD_MULTITHREADED         sem_wait(server->port);#endif      while (ai && (server->num_s < CYGNUM_NET_MAX_INET_PROTOS)) {	server->s[server->num_s] = socket(ai->ai_family, 					  ai->ai_socktype, 					  ai->ai_protocol);	if (server->s[server->num_s] < 0 ) {	  diag_printf("TFTPD [%x]: can't open socket\n", p);	  freeaddrinfo(server->res);	  server->res = NULL;	  return;	}		set_port(ai->ai_addr, server->port);		if (bind(server->s[server->num_s],ai->ai_addr, ai->ai_addrlen) < 0) {	  // Problem setting up my end	  diag_printf("TFTPD [%x]: can't bind to server port\n",p);	  close(server->s[server->num_s]);	  server->s[server->num_s] = 0;	  ai = ai->ai_next;	  continue;	}	// We need to know the highest socket number for select.	if (server->s[server->num_s] > max_s)	  max_s = server->s[server->num_s];	server->num_s++;	ai = ai->ai_next;      }      #ifndef CYGSEM_NET_TFTPD_MULTITHREADED         while (true) {#endif	FD_ZERO(&readfds);	for (i=0; i < CYGNUM_NET_MAX_INET_PROTOS; i++) {	  if (server->s[i]) {	    FD_SET(server->s[i],&readfds);	  }	}	error = select(max_s+1,&readfds,NULL,NULL,NULL);	if ( -1 == error) {	  diag_printf("TFTPD [%x]: error in select\n",p);	}	for (i=0; i < CYGNUM_NET_MAX_INET_PROTOS; i++) {	  if (server->s[i] && FD_ISSET(server->s[i],&readfds)) {	    recv_len = sizeof(data);	    from_len = sizeof(from_addr);	    data_len = recvfrom(server->s[i], hdr, recv_len, 0,				&from_addr, &from_len);	    if ( data_len < 0) {	      diag_printf("TFTPD [%x]: can't read request\n", p);	    } else {#ifdef CYGSEM_NET_TFTPD_MULTITHREADED   	      // Close the socket and post on the semaphore some	      // another thread can start listening for requests. This	      // is not quite right. select could of returned with more than	      // one socket with data to read. Here we only deal with one of them 	      for (i=0; i < CYGNUM_NET_MAX_INET_PROTOS; i++) {		if (server->s[i]) {		  close (server->s[i]);		  server->s[i] = 0;		}	      }	      sem_post(server->port);#endif#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS	      getnameinfo(&from_addr,sizeof(from_addr), name, sizeof(name),0,0,0);	      diag_printf("TFTPD [%x]: received %x from %s\n", p,			  ntohs(hdr->th_opcode), name);#endif	      switch (ntohs(hdr->th_opcode)) {	      case WRQ:		tftpd_write_file(server, hdr, &from_addr, from_len);		break;	      case RRQ:		tftpd_read_file(server, hdr, &from_addr, from_len);		break;	      case ACK:	      case DATA:	      case ERROR:		// Ignore		break;	      default:		getnameinfo(&from_addr,sizeof(from_addr), name, sizeof(name),0,0,0);		diag_printf("TFTPD [%x]: bogus request %x from %s\n", p,			    ntohs(hdr->th_opcode),			    name);		tftpd_send_error(server->s[i],hdr,TFTP_EBADOP,&from_addr,from_len);	      }	      #ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT	      tftp_server_instrument.total_transactions++;	      	      o.data.rx        -= tftp_server_instrument.data.rx       ;	      o.data.rx_repeat -= tftp_server_instrument.data.rx_repeat;	      o.data.rx_skip   -= tftp_server_instrument.data.rx_skip  ;	      o.data.send      -= tftp_server_instrument.data.send     ;	      o.data.resend    -= tftp_server_instrument.data.resend   ;	      	      o.ack.rx         -= tftp_server_instrument.ack.rx        ;	      o.ack.rx_repeat  -= tftp_server_instrument.ack.rx_repeat ;	      o.ack.rx_skip    -= tftp_server_instrument.ack.rx_skip   ;	      o.ack.send       -= tftp_server_instrument.ack.send      ;	      o.ack.resend     -= tftp_server_instrument.ack.resend    ;	      	      o.err_send       -= tftp_server_instrument.err_send      ;	      #ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS	      if ( o.data.rx        ) diag_printf( "data rx       %4d\n", -o.data.rx        );	      if ( o.data.rx_repeat ) diag_printf( "data rx_repeat%4d\n", -o.data.rx_repeat );	      if ( o.data.rx_skip   ) diag_printf( "data rx_skip  %4d\n", -o.data.rx_skip   );	      if ( o.data.send      ) diag_printf( "data send     %4d\n", -o.data.send      );	      if ( o.data.resend    ) diag_printf( "data resend   %4d\n", -o.data.resend    );	      	      if ( o.ack.rx         ) diag_printf( " ack rx       %4d\n", -o.ack.rx         );	      if ( o.ack.rx_repeat )  diag_printf( " ack rx_repeat%4d\n", -o.ack.rx_repeat  );	      if ( o.ack.rx_skip   )  diag_printf( " ack rx_skip  %4d\n", -o.ack.rx_skip    );	      if ( o.ack.send      )  diag_printf( " ack send     %4d\n", -o.ack.send       );	      if ( o.ack.resend    )  diag_printf( " ack resend   %4d\n", -o.ack.resend     );	      	      if ( o.err_send      )  diag_printf( "*error sends  %4d\n", -o.err_send      );#endif // CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS#endif // CYGOPT_NET_TFTP_SERVER_INSTRUMENT#ifdef CYGSEM_NET_TFTPD_MULTITHREADED	      break;#endif	    }	  }	}	// The following looks a little strange, but it keeps emacs's	// auto indention happy.#ifndef CYGSEM_NET_TFTPD_MULTITHREADED         }#endif#ifdef CYGSEM_NET_TFTPD_MULTITHREADED       }#endif}//// This function is used to create a new server [thread] which supports// the TFTP protocol on the given port.  A server 'id' will be returned// which can later be used to destroy the server.  //// Note: all [memory] resources for the server thread will be allocated// dynamically.  If there are insufficient resources, an error will be// returned.//int tftpd_start(int port, struct tftpd_fileops *ops){    struct tftp_server *server;#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED    static char init = 0;    if ( 0 == init ) {        init++;        cyg_semaphore_init( &tftp_server_sem, 0 );    }#endif    if ((server = malloc(sizeof(struct tftp_server)))) {        server->tag = TFTP_tag;        server->port = port;        server->ops = ops;        cyg_thread_create(CYGPKG_NET_TFTPD_THREAD_PRIORITY, // Priority                          tftpd_server,              // entry                          (cyg_addrword_t)server,    // entry parameter                          "TFTP server",             // Name                          &server->stack[0],         // Stack                          STACK_SIZE,                // Size                          &server->thread_handle,    // Handle                          &server->thread_data       // Thread data structure            );        cyg_thread_resume(server->thread_handle);  // Start it    }    return (int)server;}//// Destroy a TFTP server, using a previously created server 'id'.//int tftpd_stop(int p){    struct tftp_server *server = (struct tftp_server *)p;    // Simple sanity check    if (server->tag == TFTP_tag) {        cyg_thread_kill(server->thread_handle);        cyg_thread_set_priority(server->thread_handle, 0);        cyg_thread_delay(1);  // Make sure it gets to die...        if (cyg_thread_delete(server->thread_handle)) {            // Success shutting down the thread. Close all its sockets.	    int i;	    for (i = 0 ; i < CYGNUM_NET_MAX_INET_PROTOS; i++) {	      if (server->s[i]) {		close (server->s[i]);	      }	    }	    freeaddrinfo(server->res);            free(server);  // Give up memory            return 1;        }    }    return 0;}// EOF tftp_server.c

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -