From owner-p4-projects@FreeBSD.ORG Sat Aug 11 16:18:11 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id D4A3516A419; Sat, 11 Aug 2007 16:18:10 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8592516A417 for ; Sat, 11 Aug 2007 16:18:10 +0000 (UTC) (envelope-from taleks@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 6F2A813C46A for ; Sat, 11 Aug 2007 16:18:10 +0000 (UTC) (envelope-from taleks@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id l7BGIAdK056134 for ; Sat, 11 Aug 2007 16:18:10 GMT (envelope-from taleks@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l7BGIAsO056131 for perforce@freebsd.org; Sat, 11 Aug 2007 16:18:10 GMT (envelope-from taleks@FreeBSD.org) Date: Sat, 11 Aug 2007 16:18:10 GMT Message-Id: <200708111618.l7BGIAsO056131@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to taleks@FreeBSD.org using -f From: Alexey Tarasov To: Perforce Change Reviews Cc: Subject: PERFORCE change 125058 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 11 Aug 2007 16:18:11 -0000 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 ==== //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 #include +#ifdef LOADER_NFS_SUPPORT #include +#endif #include #include @@ -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 +#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) <<<