Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 11 Aug 2007 16:18:10 GMT
From:      Alexey Tarasov <taleks@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 125058 for review
Message-ID:  <200708111618.l7BGIAsO056131@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=125058

Change 125058 by taleks@taleks_th on 2007/08/11 16:18:03

	pxe.c: added getting server name from root-path, instead of ip.
	httpfs: added simple caching mechanism  able to speed up connections at least twice by reducing http-requests count and thus recoonect situations.
	README: added first part of documentation.

Affected files ...

.. //depot/projects/soc2007/taleks-pxe_http/Makefile#14 edit
.. //depot/projects/soc2007/taleks-pxe_http/README#2 edit
.. //depot/projects/soc2007/taleks-pxe_http/httpfs.c#7 edit
.. //depot/projects/soc2007/taleks-pxe_http/libi386_mod/pxe.c#4 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_http.c#11 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_http.h#8 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_sock.c#19 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_sock.h#17 edit

Differences ...

==== //depot/projects/soc2007/taleks-pxe_http/Makefile#14 (text+ko) ====

@@ -35,6 +35,9 @@
 #CFLAGS+=	-DPXE_HTTP_DEBUG_HELL
 
 # define to get more PXE related code and testing functions
-CFLAGS+=	-DPXE_MORE
+# CFLAGS+=	-DPXE_MORE
+
+# define to get some speed up by bigger requests
+CFLAGS+=	-DPXE_HTTPFS_CACHING
 
 .include <bsd.lib.mk>

==== //depot/projects/soc2007/taleks-pxe_http/README#2 (text+ko) ====

@@ -1,46 +1,632 @@
-project name: http support for PXE
-
-Now, it's just test file to test is perforce setuped on my side correctly.
 
 1. Introduction
+1.2. Setting up
+1.2.1. DHCP configuration
+1.2.2. TFTP configuration
+1.2.3. Web-server configuration
+1.2.4. loader.rc configuratuion
 2. Project organisation
+2.1. Code modules
+2.2. Naming conventions
+2.3. Understanding logical structure of code
 3. API usage
+3.1. Base information
+3.2. PXE sockets API overview
+3.2.1. PXE API socket details
+3.3. Quick Reference to API, available for user code
+3.3.1. pxe_arp module
+3.3.2. pxe_await module
+3.3.3 pxe_buffer module
+3.3.4. pxe_connection module
+3.3.5. pxe_core module
 
 1. Introduction 
 ----------------
 
-   This project goal is to downlload kernel image via http protocol in preboot 
-environment. So, main task to do: implement simple tcp/ip stack using UNDI API.
+		pxe_http library is user space implementation of simplified
+	TCP/IP4 stack with support of sockets.
+
+1.1. Requirements
+------------------
+
+			To use pxeboot with extensions from pxe_http library
+		you need:
+		* DHCP server
+			- any DHCP server with support of some options
+			  (see below).  In example of configuration files
+			  ISC DHCP v.3.0.5 was used.
+		* TFTP server
+		* Web server - I've used Apache 1.3.34
+
+
+1.2. Setting it up
+-------------------
+
+		In most cases, it's the same as for usual pxeboot. Main
+	difference is in configuration file of DHCP server and in usage of
+	Web-server.
+
+
+1.2.1. DHCP configuration
+-------------------------
+
+		Here is example of configuration:
+
+		# /etc/dhcpd.conf example
+		#
+		ddns-update-style none;
+		server-name "DHCPserver";
+		server-identifier 192.168.0.4;
+		default-lease-time 7200;
+		max-lease-time 7200;
+	
+		#
+		# significant options for correct working of pxeboot
+		#
+
+		# your LAN subnet mask
+		option subnet-mask 255.255.255.0;
+
+		# default gateway to use
+		option routers 192.168.0.1;
+
+		# name of file to download via TFTP
+		filename "pxeboot";
+
+		# name server, used for resolving of domain names
+		option domain-name-servers 192.168.0.1;
+
+		# ip address of web server
+		option www-server 192.168.0.2;
+
+		# path, where nessesary files are stored on web server
+		option root-path "th.lan:/path/to/root";
+
+		subnet 192.168.0.0 netmask 255.255.255.0 {
+        		next-server 192.168.0.4;
+	        	range 192.168.0.10 192.168.0.20;
+		}
+        	
+		/*  end of example */
+
+	NOTES:
+		1. www-server option is used only if root-path is absent in
+		   DHCP reply. In that case assumed, that /boot directory is
+		   placed in DocumentRoot of web-server.
+		2. format of root-path has such format: "server:/path". It's
+		   possible use both IP's and domain names for server. /path is
+		   relative to DocumentRoot of web-server. In example above
+		   files are stored at /usr/local/www/data/path/to/root,
+		   assuming that /usr/local/www/data - is DocumentRoot.
+		3. DHCP options are not greater then 255 bytes. So, root-path
+		   must satisfy this requirement.
+
+
+1.2.2. TFTP configuration
+--------------------------
+
+		Same as usually. pxe_http doesn't directly use this protocol.
+
+
+1.2.3. Web-server configuration
+--------------------------------
+
+		Just copy all from "/boot" directory to
+	/DocumentRoot/path/to/root.
+	
+	NOTES:
+		1. Need to be sure, that partial downloading and keep-alive
+		   connections are supported by server. e.g. for Apache 1.x,
+		   check this options:
+
+			KeepAlive On
+			MaxKeepAliveRequests 10		# well, choose best for
+							# server
+			KeepAliveTimeout 15		# more then 2 seconds
+							# is good enough
+
+		2. loader checks gzipped versions of files first, it's good
+		   idea to compress every needed file. e.g.
+				beastie.4th.gz
+				device.hints
+				frames.4th.gz
+				loader.4th.gz
+				loader.conf
+				loader.help.gz
+				loader.rc
+				mfsroot.gz
+				screen.4th.gz
+				support.4th.gz
+				/kernel/kernel.gz
+
+1.2.4. loader.rc configuratuion
+--------------------------------
+
+		HTTP downloading of kernel is not all need to startup system
+	correctly. The main question is where will be root filesystem after
+	booting of kernel. The simpliest way - is to use RAM drive with
+	installation tools or ready to work system.
+		Here is example of changes to loader.rc, that instructs loader
+	to download RAM-drive image (in this example, common mfsroot.gz found
+	in boot.flp floppy image file)
+
+
+	\ Includes additional commands
+	include /boot/loader.4th
+
+	\ Reads and processes loader.conf variables
+	start
+
+	\ Tests for password -- executes autoboot first if a password was defined
+	check-password
+
+	\ Load in the boot menu
+	include /boot/beastie.4th
+
+	\ pxe_http changes:
+	echo "loading RAM-drive image"
+	load -t mfs_root /boot/mfsroot
+	set vfs.root.mountfrom="ufs:/dev/md0c"
+	\
+
+	\ Start the boot menu
+	beastie-start
 
+	/* end of example */
 
+		Of course, it's possible to set any other filesystem to work
+	as root, e,g, NFS.
+		
 2. Project organisation
 ------------------------
 
-   Code is divided in modules:
-      pxe_core - provides calls to UNDI, packet handling and etc.
-      pxe_icmp - handler of icmp protocol
-      pxe_mem  - memory work routines
-      pxe_sock - simple sockets
-      pxe_tcp  - handler of tcp protocol
+2.1. Code modules
+------------------
+
+	All project code is divided into following modules:
+		pxe_arp        - ARP protocol				(3.3.1)
+		pxe_await      - provides functions for awaiting	(3.3.2)
+		pxe_buffer     - implements cyclic buffers		(3.3.3)
+		pxe_connection - TCP connection related functions	(3.3.4)
+		pxe_core       - provides calls to PXE API		(3.3.5)
+		pxe_dhcp       - DHCP client
+		pxe_dns        - DNS client
+		pxe_filter     - incoming packet filters
+		pxe_http       - HTTP related functions
+		pxe_icmp       - ICMP protocol
+		pxe_ip         - IP protocol
+		pxe_isr        - assembler side support for PXE API calling
+		pxe_mem        - memory work routines
+		pxe_sock       - simple sockets
+		pxe_segment    - TCP segments
+		pxe_tcp        - TCP protocol
+		pxe_udp        - UDP protocol
+
+2.2. Naming conventions
+------------------------
+
+		Most of functions, that may be called directly by user API uses
+	pxe_ prefix.
+		Functions related to some module have subprefix of this module,
+	e.g. pxe_dhcp_query() - function related to DHCP module.
+		All structures, that are used have typedef equivalent with
+	naming in upper case. e.g. struct pxe_ipaddr has equivalent PXE_IPADDR.
+	This is done to have similar to existing pxe.h declarations from libi386.
+
+
+2.3. Understanding logical structure of code
+---------------------------------------------
+
+		Logicallly all modules may be divided to parts.
+
+	        Part 1: PXE API related modules (pxe_isr, pxe_core)
+		Part 2: base protocols related (pxe_ip, pxe_udp)
+		Part 3: sockets related (pxe_sock)
+		Part 4: other protocols (pxe_dns, pxe_dhcp)
+		Part 5: utility (pxe_mem, pxe_buffer)
+
+		Some modules may be used independently, other depend on some
+	lower level modules.
+
+		In run-time, many calls to sockets functions start packet
+	recieving or packet sending functions. Sending is more simplier and may
+	be assumed in many cases just as wrappers to PXE API. But receiving is
+	a little bit more complicated. Receiving functions start
+	pxe_core_recv_packets()	function in cycle to get packets.
+		After receiving of packet, it's handling depends on it's type:
+	ARP, IP or other. ARP packets directly provided to handler
+	pxe_arp_protocol(), IP packets are provided to registered handler of IP
+	stack protocol, other packets are ignored.
+		Registration of handler (except ARP) is performed during
+	initialisation time of module with usage of pxe_core_register() function,
+	which register handler for IP stack protocol
+	number.
+		So, packet is provided to handler, but it may be fragmented,
+	thus before processing it must be recieved completely. But in some cases
+	packet may be not interesting for protocol (unexpected packet, dublicated
+	or something else) and it's possible to determiny if this packet useful
+	just by examining of packet header.
+		If packet is fragmented - it firstly provided to handler with
+	flag PXE_CORE_FRAG. Handler returns appropriate value if is interested in
+	whole packet, packet is read completely from input queue of fragments and
+	provided again with flag PXE_CORE_HANDLE. Otherwise packet is dropped
+	in core by reading of all it's fragments from incoming queue.
+		Packet structure provides just buffer with received packet and
+	size of packet. All pxe_core module send/recieve functions work with
+	PXE_PACKET structure.
+		TCP and UDP protocols are checking filters in theirs handlers.
+	This helps to filter out packets that are not interesting for protocol
+	(e.g. to port that is not listening)
+		Socket and filter structures are separated. Socket provides
+	buffers for incoming and outcoming data. Filters may be used without
+	sockets, e.g. for TCP connections in TIME_WAIT state. For active
+	connection filter is used to determiny in which receiving buffer (in
+	which socket) must be placed incoming data.
+
 
 3. API usage
 -------------
 
-  3.1 Initialisation.
- 
-      pxe_core_init() - main initialisation routine
-      pxe_icmp_init() - init of icmp, registers icmp protocol in pxe_core
-      pxe_tcp_init()  - init of tcp  
-  
-  3.2 Communications
+3.1. Base information
+-----------------------
+
+		User code must perform initialisation of pxe_core module (which
+	is performed currently in loader during pxe_enable() call). After this
+	sockets related functions become available.
+
+	pxe_core_init() performs initialisation of pxe_core module and starts
+	initialisation routines of other modules. It inits TCP, UDP, ARP and
+	etc modules, however in most of cases it's possible skip theirs
+	initialisation if module's functions are unused.
+		Work is finished by pxe_core_shutdown() function.
+
+
+3.2. PXE sockets API overview
+-------------------------------
+
+		PXE sockets API differs from common sockets. It's more simplier
+	and has some limitations due user space implementations. All socket
+	related functions are declared in pxe_sock.h header
+
+		Socket is created by pxe_socket() call. After usage socket must
+	be closed by pxe_close() call. Result of pxe_call() is integer
+	descriptor associated with socket. After creating socket is unbinded
+	and not connected.
+		pxe_sendto(), pxe_connect(), pxe_bind() functions performs
+	binding and connecting. After successful calling of one of them - socket
+	is in active state. It's possible to perform reading and sending from/to
+	socket. Cause socket API may use buffers to optimize packet sending
+	process, user code must call pxe_flush() functions to be sure, that
+	data is really processed to sending module.
+		While receiving need to keep in memory, that if UDP datagram is
+	not readed completely by one call of pxe_recv() in this implementation
+	rest of datagram is omited and lost for user code.
+		All incoming and outcoming data is written to socket buffers,
+	that have default sizes 16Kb and 4Kb. If buffers are full, next calls
+	related to writing or reading data will fail.
+
+3.2.1. PXE API socket details
+------------------------------
+
+	/* Here is simple example of API usage. */
+
+	int socket = pxe_socket();
+	/* if result is not -1, then socket variable contains value,
+	 * assosiated with socket structure. Call differs from common sockets,
+	 * there are no domain, type and protocol parameters.
+	 * Cause domain is always AF_INET now. others are use in pxe_connect()
+	 * call.
+	 */
+	
+	int result = pxe_connect(socket, &hh->addr, 80, PXE_TCP_PROTOCOL);
+	/*  This call creates filter, associates it with socket and establishes
+	 * communication if needed.
+	 * Parameters are socket, remote ip address (PXE_IPADDR)m remote port
+	 * and one of PXE_UDP_PROTOCOL and PXE_TCP_PROTOCOL protocols.
+	 */
+	
+	if (result == -1) {
+		pxe_close(socket);
+		/* any socket must be closed, even if it was not really used
+		 * or conencted. pxe_close() call releases used internal
+		 * structures. After this call any other operations with
+		 * 'socket' descriptor are invalid. 
+		 */
+		return (0);
+	}
+
+	/* pxe_send() function sends data to socket. As usual, there is no
+	 * guarantee, that whole buffer is transmited. And actually for TCP
+	 * protocol, this call just places data to buffer. User code have no
+	 * knowledge if data is really sent to network. if current segment is
+	 * not fullly used, data may stay in buffer infinitely.
+	 */	
+	if (len != pxe_send(socket, hh->buf, len)) {
+		/* failed to send data, at least whole buffer */
+		pxe_close(socket);
+		return (0);
+	}
+
+	/* if user code need guarantee, that data is sent to remote host, it
+	 * must call pxe_flush(). It forces sending of any data, that must be
+	 * sent.
+	 */
+	if (pxe_flush(socket) == -1) {
+		/* failed to flush socket */
+		pxe_close(socket);
+		return (0);
+	}
+
+	/* perform reading cycle */
+
+	while (count < maxsize) {
+		/* pxe_recv() is similar to recv() call for common sockets,
+		 * but have no flags parameter
+		 */
+		result = pxe_recv(socket, &data[count], maxsize - count);
+		
+		if (result == -1) {	/* failed to recv */
+			break;
+		}
+		
+		if (result == 0)	/* nothing received yet */
+			continue;       
+
+		count += result;
+	}
+
+	pxe_close(socket);
+
+
+	/* End of example */
+
+
+3.3 Quick Reference to API, available for user code
+----------------------------------------------------
+
+3.3.1 pxe_arp module
+---------------------
+
+		This module is used mainly by internal code while sending IP
+	packets.
+
+macro definitions:
+
+MAX_ARP_ENTRIES	- how much may be ARP table in size. If ARP table full and new
+	MAC must be placed, then one of older entry is replaced by new. Default
+	number is 4.
+
+PXE_MAX_ARP_TRY	- how much trys will be peformed when sending ARP requests,
+	before say MAC search failed. Default: 3
+
+PXE_TIME_TO_DIE	- how much time to wait ARP reply in milliseconds.
+	Default: 5000 ms.
+
+PXE_ARP_SNIFF	- sometimes it's usefull to get MACs from incoming requests
+	(this may save time, MAC may be found in table without requesting it by
+	ARP module itself). But	if network is big enough - ARP table will be
+	updated too often. By default this option is defined.
+
+
+functions:
+
+void pxe_arp_init()
+	- inits pxe_arp module. Usually this call is performed from
+	pxe_core_init()
+
+const MAC_ADDR *pxe_arp_ip4mac(const PXE_IPADDR *addr)
+	- returns MAC address for requested IP address
+
+void pxe_arp_stats()
+	- shows ARP table. Available if defined PXE_MORE macro.
+
+
+3.3.2 pxe_await module
+-----------------------
+
+		Implements awaiting mechanism. Many operations are performed
+	similar	in protocol implementations. Usually, packet is sended and
+	application awaits for reply. pxe_await() function helps to simplify
+	code in such case.
+		It starts await callback function with some flags and counts
+	timeouts, try count. 
+
+		Here is example of awaiting:
+
+	/* we start awaiting, with dns_await() calllback function, maximum 4
+	 * trys, each try 20 seconds and waiting data static_wait_data.
+	 * Waiting data - is some data associated with current awaiting, it's
+	 * used by await callback function.
+	 */
+	if (!pxe_await(dns_await, 4, 20000, &static_wait_data))
+		return (NULL);
+
+	/*  pxe_await() returns 1 if awaiting was successfull (await function
+	 * returned PXE_AWAIT_COMPLETED flag)
+	 */
+
+	/* it's an awaiting function. pxe_await() provides current function,
+	 * current try number, time exceeded from start of try, pointer to
+	 * associated wait data.
+	 */
+	int
+	dns_await(uint8_t function, uint16_t try_number, uint32_t timeout,
+		  void *data)
+	{
+		/* cast to our type of wait data */
+		PXE_DNS_WAIT_DATA	*wait_data = (PXE_DNS_WAIT_DATA *)data;
+
+		switch(function) {
+
+		case PXE_AWAIT_STARTTRY:
+			/* is called at start of each try 
+			 * Here must be performed any await initialisation
+			 * (e.g. request packet sending )
+			 */
+			if (!dns_request(wait_data)) {
+				/* if initialisation of try failed, try more */
+				return (PXE_AWAIT_NEXTTRY); 
+			}
+			/* otherwise return success result of await function */
+			break;
+		
+		case PXE_AWAIT_FINISHTRY: 
+			/* this function is called at the end of any try (even
+			 * if try was successful). Here cleanup must be
+			 * performed.
+			 */
+			if (wait_data->socket != -1)
+				pxe_close(wait_data->socket);
+			
+			wait_data->id += 1;
+			break;
+
+		case PXE_AWAIT_NEWPACKETS:
+			/* while waiting this function called if new packets
+			 * were received by pxe_core_recv_packets(). Actually
+			 * it may be not packets we are waiting for, may be
+			 * even not packets with out protocol. Here we must
+			 * check for new usefull for us packets, receive 
+			 * new data if any.
+			 */
+			size = pxe_recv(wait_data->socket, wait_data->data,
+				    wait_data->size);
+
+			parse_dns_reply(wait_data);
+			
+			if (wait_data->result.ip != 0) {
+				/* return success of awaiting. This may be
+				 * returned from any function
+				 */
+			        return (PXE_AWAIT_COMPLETED);
+			}
+			
+			/* if await was not completed, continue waiting */
+			return (PXE_AWAIT_CONTINUE);
+			break;
+	
+			case PXE_AWAIT_END:
+			/* this called if await is ended without any result */
+			default:
+				break;
+		}
+	
+		return (PXE_AWAIT_OK);
+	}
+
+	/* end of example */
+
+		So, wait data used for providing and receiving data while
+	awaiting. pxe_await() performs unified working with code, needed for
+	waiting of incoming packets.
+
+macro definitions:
+
+TIME_DELTA_MS	- delay between iterations during awaitng. At each iteration
+		are checked:
+		* receiving of new packet. If received - awaiting function with
+		  PXE_AWAIT_NEWPACKETS function is called.
+		* try timeout. if timeout exceeds maximum timeout - awaiting
+		  function with PXE_AWAIT_FINISHTRY and PXE_AWAIT_STARTTRY
+		  flags sequentially are called.
+		* try count. if try count exceeds maximum - awaiting function
+		  with PXE_AWAIT_ENDED flag is called. This means that await
+		  failed.
+
+
+3.3.3 pxe_buffer module
+------------------------
+	
+		This module provides reading and writing of cyclic buffers.
+	It's not used directly by user code.
+
+macro definitions:
+
+PXE_POOL_SLOTS - if defined, then statical allocation of buffers is used.
+	Otherwise buffers are allocated at run-time from heap with pxe_alloc()
+	function. Current statical allocation algorithm is simple and square,
+	there are two big buffers data storages divided in slots (by default 2).
+	Each slot has size equal to PXE_DEFAULT_RECV_BUFSIZE or
+	PXE_DEFAULT_SEND_BUFSIZE. Depending on requested size in
+	pxe_buffer_alloc() function data allocated from one of stoarge and
+	related	slot marked busy. When pxe_buffer_free() called, slot marked
+	as free.
+		Default: undefined
+
+PXE_DEFAULT_RECV_BUFSIZE	- size of receiving buffer. Default: 16392
+PXE_DEFAULT_SEND_BUFSIZE        - size of sending buffer. Default: 4096
+
+
+3.3.4 pxe_connection module
+----------------------------
+
+		This module is one of TCP related modules. It implements
+	connection entity. TCP connection is logical structure, that have
+	needed by TCP protocol counters and states.
+		User code is not directly works with this module.
+
+macro definitions:
+
+PXE_MAX_TCP_CONNECTIONS		- how much simultaneous connections may be.
+
+
+functions:
+
+void pxe_connection_stats()
+	- returns connections statistics. Available if defined PXE_MORE macro.
+
+
+3.3.5 pxe_core module
+----------------------
+
+		This module performs lowlevel work with PXE API: initialisation,
+	receiving/sending of packets, provides information functions.
+		In most cases, user code doesn't uses this module directly.
+
+macro definitions:
+
+PXE_BUFFER_SIZE 	- size of core buffers, used in PXE API calling,
+			  Default: 4096
+PXE_CORE_STATIC_BUFFERS - if defined, core buffers are allocated statically.
+		Otherwise they are allocated in heap. Default: defined
+
+functions:
+
+int pxe_core_recv_packets()
+	- recieves all packets waiting in incoming queue of NIC, and calls
+	appropriate protocols if needed
+
+
+void pxe_core_register(uint8_t ip_proto, pxe_protocol_call proc)
+	- registers IP stack protocol, associates protocol number and handler.
+
+const MAC_ADDR *pxe_get_mymac()
+	- returns MAC of NIC, for which PXE API is used.
+
+const PXE_IPADDR *pxe_get_ip(uint8_t id)
+	- returns of stored IP, for provided id.
+	id may be:
+		PXE_IP_MY		- NIC IP address
+		PXE_IP_NET		- network adrress
+		PXE_IP_NETMASK		- network mask
+		PXE_IP_NAMESERVER	- nameserver to use in name resolving
+		PXE_IP_GATEWAY		- default gateway
+		PXE_IP_BROADCAST	- broadcast address
+		PXE_IP_SERVER		- server from which loading of pxeboot
+					  was performed
+		PXE_IP_WWW		- IP address of http-server
+		PXE_IP_ROOT		- IP adddress of server, where root
+					  file system is situated. Currently
+					  it's synonym for PXE_IP_WWW
+
+void pxe_set_ip(uint8_t id, const PXE_IPADDR *ip)
+	- sets value by it's id.
 
-      pxe_tcp_socket() - creates tcp socket
-      pxe_connect()    - connects socket to remote host 
-      pxe_send()       - send data to socket
-      pxe_recv()       - recieve data from socket
-      pxe_close()      - closes socket 
+structures and types:
 
-  3.3 Cleanup
+typedef int (*pxe_protocol_call)(PXE_PACKET *pack, uint8_t function)
+	- protocol callback function type
 
-      pxe_core_shutdown() - cleanup core structures
+time_t	pxe_get_secs()
+	- returns time in seconds. Used in timeout and resend checking.
 

==== //depot/projects/soc2007/taleks-pxe_http/httpfs.c#7 (text+ko) ====

@@ -41,7 +41,7 @@
 static off_t	http_seek(struct open_file *f, off_t offset, int where);
 static int	http_stat(struct open_file *f, struct stat *sb);
 
-struct fs_ops http_fsops = {
+struct fs_ops	http_fsops = {
 	"httpfs",
 	http_open,
 	http_close,
@@ -52,6 +52,9 @@
 	null_readdir
 };
 
+/* http server name. It is set if rootpath option was in DHCP reply */
+char		servername[256] = {0};
+
 void
 handle_cleanup(PXE_HTTP_HANDLE *httpfile)
 {
@@ -64,7 +67,8 @@
 	if (httpfile->filename != NULL)
 		free(httpfile->filename);
 
-	if (httpfile->servername != NULL)
+	if ( (httpfile->servername != NULL) &&
+	     (!servername[0]) )
 		free(httpfile->servername);
 
 	if (httpfile->socket != -1)
@@ -98,9 +102,12 @@
                 return (ENOMEM);
         }
 	
-	/* TODO: may be implement getting name by PTR resource records */
 
-	httpfile->servername = strdup(inet_ntoa(httpfile->addr.ip));
+	if (servername[0]) {
+		httpfile->servername = servername;
+	} else {
+		httpfile->servername = strdup(inet_ntoa(httpfile->addr.ip));	
+	}
 	
 	if (httpfile->servername == NULL) {
 		handle_cleanup(httpfile);
@@ -132,7 +139,8 @@
 http_read(struct open_file *f, void *addr, size_t size, size_t *resid)
 {
 	PXE_HTTP_HANDLE *httpfile = (PXE_HTTP_HANDLE *) f->f_fsdata;
-	
+	int		result = -1;
+		
 	if (httpfile == NULL) {
 		printf("http_read(): NULL file descriptor.\n");
 		return (EINVAL);
@@ -156,9 +164,66 @@
 	
 	size_t to_read = (httpfile->offset + size < httpfile->size) ?
 			    size: httpfile->size - (size_t)httpfile->offset;
+
+#ifndef PXE_HTTPFS_CACHING
+	result = pxe_get(httpfile, to_read, addr);
+#else
+	void	*addr2 = addr;
+	int	part1 = -1;
 	
-	int result = pxe_get(httpfile, to_read, addr);
+	if (httpfile->cache_size < to_read) {
+
+		/* read all we have in buffer */
+		if (httpfile->cache_size != 0) {
+			part1 = pxe_recv(httpfile->socket, addr2,
+				    httpfile->cache_size);
+#ifdef PXE_HTTP_DEBUG_HELL			
+			printf("http_read(): cache > %ld/%lu/%lu/%u bytes\n",
+			    part1, to_read, size, httpfile->cache_size);
+#endif
+		}
+
+		if (part1 != -1) {
+			to_read -= part1;
+			addr2 += part1;
+			httpfile->cache_size -= part1;
+		}
+		
+		/* update cache */
+		if (httpfile->socket != -1) {
+			PXE_BUFFER *buf =
+				    pxe_sock_recv_buffer(httpfile->socket);
+			
+			size_t to_get = httpfile->size - httpfile->offset -
+					((part1 != -1) ? part1 : 0 );
+			
+			if (to_get > buf->bufsize / 2)
+				 to_get = buf->bufsize / 2;
+#ifdef PXE_HTTP_DEBUG_HELL
+			printf("http_read(): cache < %lu bytes\n", to_get);
+#endif				
+			pxe_get(httpfile, to_get, NULL);
+		}
+	}
+	
+	/* try reading of cache */
+	if (httpfile->cache_size < to_read) {
+		printf("http_read(): read of cache failed\n");
+		return (EINVAL);
+	}
+	
+	result = pxe_recv(httpfile->socket, addr2, to_read);
+#ifdef PXE_HTTP_DEBUG_HELL
+	printf("http_read(): cache > %ld/%lu/%lu/%u bytes\n",
+	    result, to_read, size, httpfile->cache_size);
+#endif	
+	if (result != -1) {
+		httpfile->cache_size -= to_read;
+		result += (part1 != -1) ? part1 : 0;
+	} else 
+		result = part1;
 
+#endif
 	if (result == -1) {
 		printf("http_read(): failed to read\n");
 		return (EINVAL);
@@ -244,6 +309,10 @@
 		errno = EOFFSET;
 		return (-1);
 	}
-
+#ifdef PXE_HTTPFS_CACHING
+	/* if we seeked somewhere, cache failed, need clean it */
+	pxe_recv(httpfile->socket, httpfile->cache_size, NULL);
+	httpfile->cache_size = 0;
+#endif
 	return (httpfile->offset);
 }

==== //depot/projects/soc2007/taleks-pxe_http/libi386_mod/pxe.c#4 (text+ko) ====

@@ -39,7 +39,9 @@
 
 #include <net.h>
 #include <netif.h>
+#ifdef LOADER_NFS_SUPPORT
 #include <nfsv2.h>
+#endif
 #include <iodesc.h>
 
 #include <bootp.h>
@@ -59,6 +61,7 @@
 extern uint8_t *data_buffer;
 #endif
 
+extern char	servername[256];
 static pxenv_t	*pxenv_p = NULL;        /* PXENV+ */
 static pxe_t	*pxe_p   = NULL;	/* !PXE */
 
@@ -182,7 +185,8 @@
 {
 	va_list	args;
 	char	*devname = NULL;
-	char	temp[FNAME_SIZE];
+	char	temp[20];
+/*	char	temp[FNAME_SIZE]; */
 	int	i = 0;
 	
         va_start(args, f);
@@ -231,11 +235,13 @@
 					pxe_set_ip(PXE_IP_ROOT, &root_addr);
 				}
 				    
-            			pxe_memcpy(&rootpath[i], &temp[0],
+/*            			pxe_memcpy(&rootpath[i], &temp[0],
 				    strlen(&rootpath[i])+1);
+ */
+             			pxe_memcpy(&rootpath[0], &servername[0], i);
 				    
-            			pxe_memcpy(&temp[0], &rootpath[0],
-				    strlen(&rootpath[i])+1);
+            			pxe_memcpy(&rootpath[i], &rootpath[0],
+				    strlen(&rootpath[i]) + 1);
 			}
 
 			struct in_addr tmp_in;
@@ -375,7 +381,7 @@
 #ifdef PXE_DEBUG
 	printf("pxe_netif_init(): called.\n");
 #endif
-	uint8_t *mac = pxe_get_mymac();
+	uint8_t *mac = (uint8_t *)pxe_get_mymac();
 	
 	int i;
 	for (i = 0; i < 6; ++i)

==== //depot/projects/soc2007/taleks-pxe_http/pxe_http.c#11 (text+ko) ====

@@ -24,17 +24,23 @@
  * SUCH DAMAGE.
  *
  */
- 
+
 #include <stand.h>
 
+#include "pxe_await.h"
 #include "pxe_core.h"
 #include "pxe_dns.h"
 #include "pxe_http.h"
 #include "pxe_ip.h"
 #include "pxe_tcp.h"
 
+#ifndef FNAME_SIZE
+#define FNAME_SIZE	128
+#endif
+
 /* for testing purposes, used by pxe_fetch() */
 static char http_data[PXE_MAX_HTTP_HDRLEN];
+extern char rootpath[FNAME_SIZE];
 
 /* parse_size_t() - converts zero ended string to size_t value
  * in:
@@ -161,7 +167,7 @@
 	return (result);
 }
 
-#ifdef PXE_MORE
+#ifdef PXE_HTTPFS_CACHING
 /* http_get_header2() - gets from socket data related to http header
  *			byte by byte.
  * in:
@@ -196,17 +202,20 @@
 		if (result == 0)	/* nothing received yet */
 			continue;
 
+		count += 1;
+
+		if (count < 4)	/* wait at least 4 bytes */
+			continue;
+		
 		/* make string ended with '\0' */
-		ch = data[count + result];
-		data[count + result] = '\0';
+		ch = data[count];
+		data[count] = '\0';
 		
 		/* searching end of reply */
-		found = strstr(&data[count], "\r\n\r\n");
+		found = strstr(&data[count - 4], "\r\n\r\n");
 
 		/* restore char replaced by zero */
-		data[count + result] = ch;
-		
-		count += 1;
+		data[count] = ch;
 		
 		if (found != NULL)
 			break;
@@ -221,6 +230,47 @@
 	return (result);
 }
 
+/* http_await() - await callback function for filling buffer
+ * in:
+ *      function        - await function
+ *      try_number      - current number of try
+ *      timeout         - current timeout from start of try
+ *      data            - pointer to PXE_DNS_WAIT_DATA
+ * out:
+ *      PXE_AWAIT_ constants
+ */
+int
+http_await(uint8_t function, uint16_t try_number, uint32_t timeout, void *data)
+{
+	PXE_HTTP_WAIT_DATA	*wait_data = (PXE_HTTP_WAIT_DATA *)data;
+	uint16_t		space = 0;
+	
+	switch(function) {
+     
+		case PXE_AWAIT_NEWPACKETS:
+			space = pxe_buffer_space(wait_data->buf);
+			
+			/* check, have we got enough? */
+			if (wait_data->start_size - space >=
+			    wait_data->wait_size)
+				return (PXE_AWAIT_COMPLETED);
+
+			/* check, is socket still working? */
+			if (pxe_sock_state(wait_data->socket) !=
+			    PXE_SOCKET_ESTABLISHED)
+				return (PXE_AWAIT_BREAK);
+
+			return (PXE_AWAIT_CONTINUE);
+		default:
+			break;
+	}
+
+	return (PXE_AWAIT_OK);
+}
+	
+#endif /* PXE_HTTPFS_CACHING */
+
+#ifdef PXE_MORE
 /* pxe_fetch() - testing function, if size = from = 0, retrieve full file,
  *		otherwise partial 
  * in:
@@ -372,7 +422,7 @@

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200708111618.l7BGIAsO056131>