You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
2.9 KiB
185 lines
2.9 KiB
#include "streambuf.h"
|
|
|
|
#include <stdio.h>
|
|
#include <glib.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#include <time.h>
|
|
|
|
#include "poller.h"
|
|
#include "aux.h"
|
|
|
|
|
|
|
|
struct streambuf *streambuf_new(struct poller *p, int fd) {
|
|
struct streambuf *b;
|
|
|
|
b = malloc(sizeof(*b));
|
|
ZERO(*b);
|
|
|
|
b->buf = g_string_new("");
|
|
b->fd = fd;
|
|
b->poller = p;
|
|
b->active = poller_now;
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
void streambuf_destroy(struct streambuf *b) {
|
|
g_string_free(b->buf, TRUE);
|
|
free(b);
|
|
}
|
|
|
|
|
|
int streambuf_writeable(struct streambuf *b) {
|
|
int ret;
|
|
unsigned int out;
|
|
|
|
for (;;) {
|
|
if (!b->buf->len)
|
|
break;
|
|
|
|
out = (b->buf->len > 1024) ? 1024 : b->buf->len;
|
|
ret = write(b->fd, b->buf->str, out);
|
|
|
|
if (ret < 0) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
|
return -1;
|
|
ret = 0;
|
|
}
|
|
|
|
if (ret > 0) {
|
|
g_string_erase(b->buf, 0, ret);
|
|
b->active = poller_now;
|
|
}
|
|
|
|
if (ret != out) {
|
|
poller_blocked(b->poller, b->fd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int streambuf_readable(struct streambuf *b) {
|
|
int ret;
|
|
char buf[1024];
|
|
|
|
for (;;) {
|
|
ret = read(b->fd, buf, 1024);
|
|
|
|
if (ret == 0)
|
|
return -1;
|
|
if (ret < 0) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
|
break;
|
|
return -1;
|
|
}
|
|
|
|
g_string_append_len(b->buf, buf, ret);
|
|
b->active = poller_now;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
char *streambuf_getline(struct streambuf *b) {
|
|
char *p;
|
|
int len;
|
|
char *s = NULL;
|
|
|
|
for (;;) {
|
|
if (s)
|
|
free(s);
|
|
|
|
p = memchr(b->buf->str, '\n', b->buf->len);
|
|
if (!p)
|
|
return NULL;
|
|
|
|
len = p - b->buf->str;
|
|
if (len == 0) {
|
|
g_string_erase(b->buf, 0, 1);
|
|
continue;
|
|
}
|
|
|
|
s = malloc(len + 1);
|
|
memcpy(s, b->buf->str, len);
|
|
s[len] = '\0';
|
|
g_string_erase(b->buf, 0, len + 1);
|
|
|
|
if (s[--len] == '\r') {
|
|
if (len == 0)
|
|
continue;
|
|
s[len] = '\0';
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
unsigned int streambuf_bufsize(struct streambuf *b) {
|
|
return b->buf->len;
|
|
}
|
|
|
|
|
|
void streambuf_vprintf(struct streambuf *b, const char *f, va_list va) {
|
|
GString *gs;
|
|
|
|
gs = g_string_new("");
|
|
g_string_vprintf(gs, f, va);
|
|
|
|
streambuf_write(b, gs->str, gs->len);
|
|
g_string_free(gs, TRUE);
|
|
}
|
|
|
|
void streambuf_printf(struct streambuf *b, const char *f, ...) {
|
|
va_list va;
|
|
|
|
va_start(va, f);
|
|
streambuf_vprintf(b, f, va);
|
|
va_end(va);
|
|
}
|
|
|
|
void streambuf_write(struct streambuf *b, const char *s, unsigned int len) {
|
|
unsigned int out;
|
|
int ret;
|
|
|
|
while (len && !poller_isblocked(b->poller, b->fd)) {
|
|
out = (len > 1024) ? 1024 : len;
|
|
ret = write(b->fd, s, out);
|
|
|
|
if (ret < 0) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
|
poller_error(b->poller, b->fd);
|
|
break;
|
|
}
|
|
poller_blocked(b->poller, b->fd);
|
|
break;
|
|
}
|
|
if (ret == 0)
|
|
break;
|
|
|
|
s += ret;
|
|
len -= ret;
|
|
b->active = poller_now;
|
|
}
|
|
|
|
if (b->buf->len > 5242880)
|
|
poller_error(b->poller, b->fd);
|
|
else if (len)
|
|
g_string_append_len(b->buf, s, len);
|
|
}
|