parent
c5089878cb
commit
680f1c7025
@ -0,0 +1,193 @@ |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
#include <sys/uio.h> |
||||
|
||||
#include "connection.h" |
||||
|
||||
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) |
||||
|
||||
struct wl_buffer { |
||||
char data[4096]; |
||||
int head, tail; |
||||
}; |
||||
|
||||
struct wl_connection { |
||||
struct wl_buffer in, out; |
||||
int fd; |
||||
void *data; |
||||
wl_connection_update_func_t update; |
||||
}; |
||||
|
||||
struct wl_connection * |
||||
wl_connection_create(int fd, |
||||
wl_connection_update_func_t update, |
||||
void *data) |
||||
{ |
||||
struct wl_connection *connection; |
||||
|
||||
connection = malloc(sizeof *connection); |
||||
memset(connection, 0, sizeof *connection); |
||||
connection->fd = fd; |
||||
connection->update = update; |
||||
connection->data = data; |
||||
|
||||
connection->update(connection, |
||||
WL_CONNECTION_READABLE, |
||||
connection->data); |
||||
|
||||
return connection; |
||||
} |
||||
|
||||
void |
||||
wl_connection_destroy(struct wl_connection *connection) |
||||
{ |
||||
free(connection); |
||||
} |
||||
|
||||
void |
||||
wl_connection_copy(struct wl_connection *connection, void *data, size_t size) |
||||
{ |
||||
struct wl_buffer *b; |
||||
int tail, rest; |
||||
|
||||
b = &connection->in; |
||||
tail = b->tail; |
||||
if (tail + size <= ARRAY_LENGTH(b->data)) { |
||||
memcpy(data, b->data + tail, size); |
||||
} else {
|
||||
rest = ARRAY_LENGTH(b->data) - tail; |
||||
memcpy(data, b->data + tail, rest); |
||||
memcpy(data + rest, b->data, size - rest); |
||||
} |
||||
} |
||||
|
||||
void |
||||
wl_connection_consume(struct wl_connection *connection, size_t size) |
||||
{ |
||||
struct wl_buffer *b; |
||||
int tail, rest; |
||||
|
||||
b = &connection->in; |
||||
tail = b->tail; |
||||
if (tail + size <= ARRAY_LENGTH(b->data)) { |
||||
b->tail += size; |
||||
} else {
|
||||
rest = ARRAY_LENGTH(b->data) - tail; |
||||
b->tail = size - rest; |
||||
} |
||||
} |
||||
|
||||
int wl_connection_data(struct wl_connection *connection, uint32_t mask) |
||||
{ |
||||
struct wl_buffer *b; |
||||
struct iovec iov[2]; |
||||
int len, head, tail, count, size, available; |
||||
|
||||
if (mask & WL_CONNECTION_READABLE) { |
||||
b = &connection->in; |
||||
head = connection->in.head; |
||||
if (head < b->tail) { |
||||
iov[0].iov_base = b->data + head; |
||||
iov[0].iov_len = b->tail - head; |
||||
count = 1; |
||||
} else { |
||||
size = ARRAY_LENGTH(b->data) - head; |
||||
iov[0].iov_base = b->data + head; |
||||
iov[0].iov_len = size; |
||||
iov[1].iov_base = b->data; |
||||
iov[1].iov_len = b->tail; |
||||
count = 2; |
||||
} |
||||
len = readv(connection->fd, iov, count); |
||||
if (len < 0) { |
||||
fprintf(stderr, |
||||
"read error from connection %p: %m (%d)\n", |
||||
connection, errno); |
||||
return -1; |
||||
} else if (len == 0) { |
||||
/* FIXME: Handle this better? */ |
||||
return -1; |
||||
} else if (head + len <= ARRAY_LENGTH(b->data)) { |
||||
b->head += len; |
||||
} else { |
||||
b->head = head + len - ARRAY_LENGTH(b->data); |
||||
} |
||||
|
||||
/* We know we have data in the buffer at this point,
|
||||
* so if head equals tail, it means the buffer is |
||||
* full. */ |
||||
|
||||
available = b->head - b->tail; |
||||
if (available == 0) |
||||
available = sizeof b->data; |
||||
else if (available < 0) |
||||
available += ARRAY_LENGTH(b->data); |
||||
} else { |
||||
available = 0; |
||||
}
|
||||
|
||||
if (mask & WL_CONNECTION_WRITABLE) { |
||||
b = &connection->out; |
||||
tail = b->tail; |
||||
if (tail < b->head) { |
||||
iov[0].iov_base = b->data + tail; |
||||
iov[0].iov_len = b->head - tail; |
||||
count = 1; |
||||
} else { |
||||
size = ARRAY_LENGTH(b->data) - tail; |
||||
iov[0].iov_base = b->data + tail; |
||||
iov[0].iov_len = size; |
||||
iov[1].iov_base = b->data; |
||||
iov[1].iov_len = b->head; |
||||
count = 2; |
||||
} |
||||
len = writev(connection->fd, iov, count); |
||||
if (len < 0) { |
||||
fprintf(stderr, "write error for connection %p: %m\n", connection); |
||||
return -1; |
||||
} else if (tail + len <= ARRAY_LENGTH(b->data)) { |
||||
b->tail += len; |
||||
} else { |
||||
b->tail = tail + len - ARRAY_LENGTH(b->data); |
||||
} |
||||
|
||||
/* We just took data out of the buffer, so at this
|
||||
* point if head equals tail, the buffer is empty. */ |
||||
|
||||
if (b->tail == b->head) |
||||
connection->update(connection, |
||||
WL_CONNECTION_READABLE, |
||||
connection->data); |
||||
} |
||||
|
||||
return available; |
||||
} |
||||
|
||||
void |
||||
wl_connection_write(struct wl_connection *connection, const void *data, size_t count) |
||||
{ |
||||
struct wl_buffer *b; |
||||
size_t size; |
||||
int head; |
||||
|
||||
b = &connection->out; |
||||
head = b->head; |
||||
if (head + count <= ARRAY_LENGTH(b->data)) { |
||||
memcpy(b->data + head, data, count); |
||||
b->head += count; |
||||
} else { |
||||
size = ARRAY_LENGTH(b->data) - head; |
||||
memcpy(b->data + head, data, size); |
||||
memcpy(b->data, data + size, count - size); |
||||
b->head = count - size; |
||||
} |
||||
|
||||
if (b->tail == head) |
||||
connection->update(connection, |
||||
WL_CONNECTION_READABLE | |
||||
WL_CONNECTION_WRITABLE, |
||||
connection->data); |
||||
} |
@ -0,0 +1,21 @@ |
||||
#ifndef _CONNECTION_H_ |
||||
#define _CONNECTION_H_ |
||||
|
||||
struct wl_connection; |
||||
|
||||
#define WL_CONNECTION_READABLE 0x01 |
||||
#define WL_CONNECTION_WRITABLE 0x02 |
||||
|
||||
typedef int (*wl_connection_update_func_t)(struct wl_connection *connection, |
||||
uint32_t mask, void *data); |
||||
|
||||
struct wl_connection *wl_connection_create(int fd, |
||||
wl_connection_update_func_t update, |
||||
void *data); |
||||
void wl_connection_destroy(struct wl_connection *connection); |
||||
void wl_connection_copy(struct wl_connection *connection, void *data, size_t size); |
||||
void wl_connection_consume(struct wl_connection *connection, size_t size); |
||||
int wl_connection_data(struct wl_connection *connection, uint32_t mask); |
||||
void wl_connection_write(struct wl_connection *connection, const void *data, size_t count); |
||||
|
||||
#endif |
Loading…
Reference in new issue