diff options
author | H. Peter Anvin <hpa@zytor.com> | 2010-02-07 15:14:21 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-02-07 15:14:21 -0800 |
commit | 88f5f9b480f036ef9da9cf9deb41935c9ad9743c (patch) | |
tree | d4aae48e5a3f2b8d618ca5675c87f852d744ac46 /com32/sysdump/be_tftp.c | |
parent | 257adb86a34db443100d9e18891ce98f2518333f (diff) | |
download | syslinux.git-88f5f9b480f036ef9da9cf9deb41935c9ad9743c.tar.gz syslinux.git-88f5f9b480f036ef9da9cf9deb41935c9ad9743c.tar.xz syslinux.git-88f5f9b480f036ef9da9cf9deb41935c9ad9743c.zip |
sysdump: change to a two-phase generate/output model, buffer in memory
Instead of outputting data as it is generated, buffer it all in memory
and then output it all at once. This not only gives us exact size and
so on before we start, but turns out to be faster at least for TFTP.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'com32/sysdump/be_tftp.c')
-rw-r--r-- | com32/sysdump/be_tftp.c | 82 |
1 files changed, 46 insertions, 36 deletions
diff --git a/com32/sysdump/be_tftp.c b/com32/sysdump/be_tftp.c index e9a98873..79642385 100644 --- a/com32/sysdump/be_tftp.c +++ b/com32/sysdump/be_tftp.c @@ -18,9 +18,16 @@ enum tftp_opcode { TFTP_ERROR = 5, }; -static uint16_t local_port = 0x4000; +struct tftp_state { + uint32_t my_ip; + uint32_t srv_ip; + uint16_t my_port; + uint16_t srv_port; + uint16_t seq; +}; -static int send_ack_packet(struct backend *be, const void *pkt, size_t len) +static int send_ack_packet(struct tftp_state *tftp, + const void *pkt, size_t len) { com32sys_t ireg, oreg; t_PXENV_UDP_WRITE *uw = __com32.cs_bounce; @@ -38,9 +45,9 @@ static int send_ack_packet(struct backend *be, const void *pkt, size_t len) for (timeout = timeouts ; *timeout ; timeout++) { memset(uw, 0, sizeof uw); memcpy(uw+1, pkt, len); - uw->ip = be->tftp.srv_ip; - uw->src_port = be->tftp.my_port; - uw->dst_port = be->tftp.srv_port ? be->tftp.srv_port : htons(69); + uw->ip = tftp->srv_ip; + uw->src_port = tftp->my_port; + uw->dst_port = tftp->srv_port ? tftp->srv_port : htons(69); uw->buffer_size = len; uw->buffer = FAR_PTR(uw+1); @@ -54,10 +61,10 @@ static int send_ack_packet(struct backend *be, const void *pkt, size_t len) do { memset(ur, 0, sizeof ur); - ur->src_ip = be->tftp.srv_ip; - ur->dest_ip = be->tftp.my_ip; - ur->s_port = be->tftp.srv_port; - ur->d_port = be->tftp.my_port; + ur->src_ip = tftp->srv_ip; + ur->dest_ip = tftp->my_ip; + ur->s_port = tftp->srv_port; + ur->d_port = tftp->my_port; ur->buffer_size = __com32.cs_bounce_size - sizeof *ur; ur->buffer = FAR_PTR(ur+1); @@ -68,13 +75,13 @@ static int send_ack_packet(struct backend *be, const void *pkt, size_t len) if (!(oreg.eflags.l & EFLAGS_CF) && ur->status == PXENV_STATUS_SUCCESS && - be->tftp.srv_ip == ur->src_ip && - (be->tftp.srv_port == 0 || - be->tftp.srv_port == ur->s_port)) { + tftp->srv_ip == ur->src_ip && + (tftp->srv_port == 0 || + tftp->srv_port == ur->s_port)) { uint16_t *xb = (uint16_t *)(ur+1); if (ntohs(xb[0]) == TFTP_ACK && - ntohs(xb[1]) == be->tftp.seq) { - be->tftp.srv_port = ur->s_port; + ntohs(xb[1]) == tftp->seq) { + tftp->srv_port = ur->s_port; return 0; /* All good! */ } else if (ntohs(xb[1]) == TFTP_ERROR) { return -1; /* All bad! */ @@ -86,47 +93,50 @@ static int send_ack_packet(struct backend *be, const void *pkt, size_t len) return -1; /* No success... */ } -static int be_tftp_open(struct backend *be, const char *argv[], size_t len) +static int be_tftp_write(struct backend *be) { + static uint16_t local_port = 0x4000; + struct tftp_state tftp; char buffer[512+4+6]; int nlen; const union syslinux_derivative_info *sdi = syslinux_derivative_info(); + const char *data = be->outbuf; + size_t len = be->zbytes; + size_t chunk; - (void)len; - - be->tftp.my_ip = sdi->pxe.myip; - be->tftp.my_port = htons(local_port++); - be->tftp.srv_ip = pxe_dns(argv[1]); - be->tftp.srv_port = 0; - be->tftp.seq = 0; + tftp.my_ip = sdi->pxe.myip; + tftp.my_port = htons(local_port++); + tftp.srv_ip = pxe_dns(be->argv[1]); + tftp.srv_port = 0; + tftp.seq = 0; buffer[0] = 0; buffer[1] = TFTP_WRQ; - nlen = strlcpy(buffer+2, argv[0], 512); + nlen = strlcpy(buffer+2, be->argv[0], 512); memcpy(buffer+3+nlen, "octet", 6); - return send_ack_packet(be, buffer, 2+nlen+1+6); -} + if (send_ack_packet(&tftp, buffer, 2+nlen+1+6)) + return -1; -static int be_tftp_write(struct backend *be, const char *buf, size_t len) -{ - char buffer[512+4]; + do { + chunk = len >= 512 ? 512 : len; - buffer[0] = 0; - buffer[1] = TFTP_DATA; - *((uint16_t *)(buffer+2)) = htons(++be->tftp.seq); - memcpy(buffer+4, buf, len); + buffer[1] = TFTP_DATA; + *((uint16_t *)(buffer+2)) = htons(++tftp.seq); + memcpy(buffer+4, data, chunk); + data += chunk; + + if (send_ack_packet(&tftp, buffer, chunk+4)) + return -1; + } while (chunk == 512); - return send_ack_packet(be, buffer, len+4); + return 0; } struct backend be_tftp = { .name = "tftp", .helpmsg = "filename tftp_server", .minargs = 2, - .blocksize = 512, - .flags = 0, - .open = be_tftp_open, .write = be_tftp_write, }; |