PERFORCE change 125058 for review
Alexey Tarasov
taleks at FreeBSD.org
Sat Aug 11 09:18:11 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=125058
Change 125058 by taleks at 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) <<<
More information about the p4-projects
mailing list