提交 c7be7fc5c5bc73b90fb90168d6369a6250eeaa3c

作者 LJH 李佳桓
1 个父辈 27ccc688

add

正在显示 1 个修改的文件 包含 431 行增加0 行删除
  1 +/*
  2 + * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
  3 + * All rights reserved.
  4 + *
  5 + * Redistribution and use in source and binary forms, with or without
  6 + * modification, are permitted provided that the following conditions
  7 + * are met:
  8 + * 1. Redistributions of source code must retain the above copyright
  9 + * notice, this list of conditions and the following disclaimer.
  10 + * 2. Redistributions in binary form must reproduce the above copyright
  11 + * notice, this list of conditions and the following disclaimer in the
  12 + * documentation and/or other materials provided with the distribution.
  13 + * 3. The name of the author may not be used to endorse or promote products
  14 + * derived from this software without specific prior written permission.
  15 + *
  16 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26 + */
  27 +
  28 +#ifdef WIN32
  29 +#include <winsock2.h>
  30 +#pragma warning(disable: 4996)
  31 +#else
  32 +#include <unistd.h>
  33 +#endif
  34 +
  35 +#include <stdlib.h>
  36 +#include <assert.h>
  37 +#include <stdio.h>
  38 +#include <string.h>
  39 +
  40 +#include "spwin32buffer.hpp"
  41 +
  42 +struct spwin32buffer *
  43 +spwin32buffer_new(void)
  44 +{
  45 + struct spwin32buffer *buffer;
  46 +
  47 + buffer = (struct spwin32buffer*)calloc(1, sizeof(struct spwin32buffer));
  48 +
  49 + return (buffer);
  50 +}
  51 +
  52 +void
  53 +spwin32buffer_free(struct spwin32buffer *buffer)
  54 +{
  55 + if (buffer->orig_buffer != NULL)
  56 + free(buffer->orig_buffer);
  57 + free(buffer);
  58 +}
  59 +
  60 +/*
  61 + * This is a destructive add. The data from one buffer moves into
  62 + * the other buffer.
  63 + */
  64 +
  65 +#define SWAP(x,y) do { \
  66 + (x)->buffer = (y)->buffer; \
  67 + (x)->orig_buffer = (y)->orig_buffer; \
  68 + (x)->misalign = (y)->misalign; \
  69 + (x)->totallen = (y)->totallen; \
  70 + (x)->off = (y)->off; \
  71 +} while (0)
  72 +
  73 +int
  74 +spwin32buffer_add_buffer(struct spwin32buffer *outbuf, struct spwin32buffer *inbuf)
  75 +{
  76 + int res;
  77 +
  78 + /* Short cut for better performance */
  79 + if (outbuf->off == 0) {
  80 + struct spwin32buffer tmp;
  81 + size_t oldoff = inbuf->off;
  82 +
  83 + /* Swap them directly */
  84 + SWAP(&tmp, outbuf);
  85 + SWAP(outbuf, inbuf);
  86 + SWAP(inbuf, &tmp);
  87 +
  88 + /*
  89 + * Optimization comes with a price; we need to notify the
  90 + * buffer if necessary of the changes. oldoff is the amount
  91 + * of data that we transfered from inbuf to outbuf
  92 + */
  93 + if (inbuf->off != oldoff && inbuf->cb != NULL)
  94 + (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
  95 + if (oldoff && outbuf->cb != NULL)
  96 + (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
  97 +
  98 + return (0);
  99 + }
  100 +
  101 + res = spwin32buffer_add(outbuf, inbuf->buffer, inbuf->off);
  102 + if (res == 0) {
  103 + /* We drain the input buffer on success */
  104 + spwin32buffer_drain(inbuf, inbuf->off);
  105 + }
  106 +
  107 + return (res);
  108 +}
  109 +
  110 +int
  111 +spwin32buffer_add_vprintf(struct spwin32buffer *buf, const char *fmt, va_list ap)
  112 +{
  113 + char *buffer;
  114 + size_t space;
  115 + size_t oldoff = buf->off;
  116 + int sz;
  117 + va_list aq;
  118 +
  119 + /* make sure that at least some space is available */
  120 + spwin32buffer_expand(buf, 64);
  121 + for (;;) {
  122 + size_t used = buf->misalign + buf->off;
  123 + buffer = (char *)buf->buffer + buf->off;
  124 + assert(buf->totallen >= used);
  125 + space = buf->totallen - used;
  126 +
  127 +#ifndef va_copy
  128 +#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
  129 +#endif
  130 + va_copy(aq, ap);
  131 +
  132 +#ifdef WIN32
  133 + sz = _vsnprintf(buffer, space - 1, fmt, aq);
  134 + buffer[space - 1] = '\0';
  135 +#else
  136 + sz = vsnprintf(buffer, space, fmt, aq);
  137 +#endif
  138 +
  139 + va_end(aq);
  140 +
  141 + if (sz < 0)
  142 + return (-1);
  143 + if (sz < (int)space) {
  144 + buf->off += sz;
  145 + if (buf->cb != NULL)
  146 + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
  147 + return (sz);
  148 + }
  149 + if (spwin32buffer_expand(buf, sz + 1) == -1)
  150 + return (-1);
  151 +
  152 + }
  153 + /* NOTREACHED */
  154 +}
  155 +
  156 +int
  157 +spwin32buffer_add_printf(struct spwin32buffer *buf, const char *fmt, ...)
  158 +{
  159 + int res = -1;
  160 + va_list ap;
  161 +
  162 + va_start(ap, fmt);
  163 + res = spwin32buffer_add_vprintf(buf, fmt, ap);
  164 + va_end(ap);
  165 +
  166 + return (res);
  167 +}
  168 +
  169 +/* Reads data from an event buffer and drains the bytes read */
  170 +
  171 +int
  172 +spwin32buffer_remove(struct spwin32buffer *buf, void *data, size_t datlen)
  173 +{
  174 + size_t nread = datlen;
  175 + if (nread >= buf->off)
  176 + nread = buf->off;
  177 +
  178 + memcpy(data, buf->buffer, nread);
  179 + spwin32buffer_drain(buf, nread);
  180 +
  181 + return (nread);
  182 +}
  183 +
  184 +/*
  185 + * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
  186 + * The returned buffer needs to be freed by the called.
  187 + */
  188 +
  189 +char *
  190 +spwin32buffer_readline(struct spwin32buffer *buffer)
  191 +{
  192 + u_char *data = EVBUFFER_DATA(buffer);
  193 + size_t len = EVBUFFER_LENGTH(buffer);
  194 + char *line;
  195 + unsigned int i;
  196 +
  197 + for (i = 0; i < len; i++) {
  198 + if (data[i] == '\r' || data[i] == '\n')
  199 + break;
  200 + }
  201 +
  202 + if (i == len)
  203 + return (NULL);
  204 +
  205 + if ((line = (char*)malloc(i + 1)) == NULL) {
  206 + //fprintf(stderr, "%s: out of memory\n", __func__);
  207 + spwin32buffer_drain(buffer, i);
  208 + return (NULL);
  209 + }
  210 +
  211 + memcpy(line, data, i);
  212 + line[i] = '\0';
  213 +
  214 + /*
  215 + * Some protocols terminate a line with '\r\n', so check for
  216 + * that, too.
  217 + */
  218 + if ( i < len - 1 ) {
  219 + char fch = data[i], sch = data[i+1];
  220 +
  221 + /* Drain one more character if needed */
  222 + if ( (sch == '\r' || sch == '\n') && sch != fch )
  223 + i += 1;
  224 + }
  225 +
  226 + spwin32buffer_drain(buffer, i + 1);
  227 +
  228 + return (line);
  229 +}
  230 +
  231 +/* Adds data to an event buffer */
  232 +
  233 +static void
  234 +spwin32buffer_align(struct spwin32buffer *buf)
  235 +{
  236 + memmove(buf->orig_buffer, buf->buffer, buf->off);
  237 + buf->buffer = buf->orig_buffer;
  238 + buf->misalign = 0;
  239 +}
  240 +
  241 +/* Expands the available space in the event buffer to at least datlen */
  242 +
  243 +int
  244 +spwin32buffer_expand(struct spwin32buffer *buf, size_t datlen)
  245 +{
  246 + size_t need = buf->misalign + buf->off + datlen;
  247 +
  248 + /* If we can fit all the data, then we don't have to do anything */
  249 + if (buf->totallen >= need)
  250 + return (0);
  251 +
  252 + /*
  253 + * If the misalignment fulfills our data needs, we just force an
  254 + * alignment to happen. Afterwards, we have enough space.
  255 + */
  256 + if (buf->misalign >= datlen) {
  257 + spwin32buffer_align(buf);
  258 + } else {
  259 + void *newbuf;
  260 + size_t length = buf->totallen;
  261 +
  262 + if (length < 256)
  263 + length = 256;
  264 + while (length < need)
  265 + length <<= 1;
  266 +
  267 + if (buf->orig_buffer != buf->buffer)
  268 + spwin32buffer_align(buf);
  269 + if ((newbuf = realloc(buf->buffer, length)) == NULL)
  270 + return (-1);
  271 +
  272 + buf->orig_buffer = buf->buffer = (u_char*)newbuf;
  273 + buf->totallen = length;
  274 + }
  275 +
  276 + return (0);
  277 +}
  278 +
  279 +int
  280 +spwin32buffer_add(struct spwin32buffer *buf, const void *data, size_t datlen)
  281 +{
  282 + size_t need = buf->misalign + buf->off + datlen;
  283 + size_t oldoff = buf->off;
  284 +
  285 + if (buf->totallen < need) {
  286 + if (spwin32buffer_expand(buf, datlen) == -1)
  287 + return (-1);
  288 + }
  289 +
  290 + memcpy(buf->buffer + buf->off, data, datlen);
  291 + buf->off += datlen;
  292 +
  293 + if (datlen && buf->cb != NULL)
  294 + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
  295 +
  296 + return (0);
  297 +}
  298 +
  299 +void
  300 +spwin32buffer_drain(struct spwin32buffer *buf, size_t len)
  301 +{
  302 + size_t oldoff = buf->off;
  303 +
  304 + if (len >= buf->off) {
  305 + buf->off = 0;
  306 + buf->buffer = buf->orig_buffer;
  307 + buf->misalign = 0;
  308 + goto done;
  309 + }
  310 +
  311 + buf->buffer += len;
  312 + buf->misalign += len;
  313 +
  314 + buf->off -= len;
  315 +
  316 + done:
  317 + /* Tell someone about changes in this buffer */
  318 + if (buf->off != oldoff && buf->cb != NULL)
  319 + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
  320 +
  321 +}
  322 +
  323 +/*
  324 + * Reads data from a file descriptor into a buffer.
  325 + */
  326 +
  327 +#define EVBUFFER_MAX_READ 4096
  328 +
  329 +int
  330 +spwin32buffer_read(struct spwin32buffer *buf, int fd, int howmuch)
  331 +{
  332 + u_char *p;
  333 + size_t oldoff = buf->off;
  334 + int n = EVBUFFER_MAX_READ;
  335 +
  336 +#if defined(FIONREAD)
  337 +#ifdef WIN32
  338 + long lng = n;
  339 + if (ioctlsocket(fd, FIONREAD, (unsigned long*)&lng) == -1 || (n=lng) == 0) {
  340 +#else
  341 + if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
  342 +#endif
  343 + n = EVBUFFER_MAX_READ;
  344 + } else if (n > EVBUFFER_MAX_READ && n > howmuch) {
  345 + /*
  346 + * It's possible that a lot of data is available for
  347 + * reading. We do not want to exhaust resources
  348 + * before the reader has a chance to do something
  349 + * about it. If the reader does not tell us how much
  350 + * data we should read, we artifically limit it.
  351 + */
  352 + if (n > (int)buf->totallen << 2)
  353 + n = buf->totallen << 2;
  354 + if (n < EVBUFFER_MAX_READ)
  355 + n = EVBUFFER_MAX_READ;
  356 + }
  357 +#endif
  358 + if (howmuch < 0 || howmuch > n)
  359 + howmuch = n;
  360 +
  361 + /* If we don't have FIONREAD, we might waste some space here */
  362 + if (spwin32buffer_expand(buf, howmuch) == -1)
  363 + return (-1);
  364 +
  365 + /* We can append new data at this point */
  366 + p = buf->buffer + buf->off;
  367 +
  368 +#ifndef WIN32
  369 + n = read(fd, p, howmuch);
  370 +#else
  371 + n = recv(fd, (char*)p, howmuch, 0);
  372 +#endif
  373 + if (n == -1)
  374 + return (-1);
  375 + if (n == 0)
  376 + return (0);
  377 +
  378 + buf->off += n;
  379 +
  380 + /* Tell someone about changes in this buffer */
  381 + if (buf->off != oldoff && buf->cb != NULL)
  382 + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
  383 +
  384 + return (n);
  385 +}
  386 +
  387 +int
  388 +spwin32buffer_write(struct spwin32buffer *buffer, int fd)
  389 +{
  390 + int n;
  391 +
  392 +#ifndef WIN32
  393 + n = write(fd, buffer->buffer, buffer->off);
  394 +#else
  395 + n = send(fd, (char*)buffer->buffer, buffer->off, 0);
  396 +#endif
  397 + if (n == -1)
  398 + return (-1);
  399 + if (n == 0)
  400 + return (0);
  401 + spwin32buffer_drain(buffer, n);
  402 +
  403 + return (n);
  404 +}
  405 +
  406 +u_char *
  407 +spwin32buffer_find(struct spwin32buffer *buffer, const u_char *what, size_t len)
  408 +{
  409 + u_char *search = buffer->buffer, *end = search + buffer->off;
  410 + u_char *p;
  411 +
  412 + while (search < end &&
  413 + (p = (u_char*)memchr(search, *what, end - search)) != NULL) {
  414 + if (p + len > end)
  415 + break;
  416 + if (memcmp(p, what, len) == 0)
  417 + return (p);
  418 + search = p + 1;
  419 + }
  420 +
  421 + return (NULL);
  422 +}
  423 +
  424 +void spwin32buffer_setcb(struct spwin32buffer *buffer,
  425 + void (*cb)(struct spwin32buffer *, size_t, size_t, void *),
  426 + void *cbarg)
  427 +{
  428 + buffer->cb = cb;
  429 + buffer->cbarg = cbarg;
  430 +}
  431 +
... ...
注册登录 后发表评论