mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-25 04:33:05 +00:00
redesign connection module
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
all : test
|
||||
|
||||
test : connection.c test.c
|
||||
gcc -g -Wall -o $@ $^
|
||||
|
||||
clean :
|
||||
rm test
|
||||
|
||||
|
||||
|
||||
@@ -2,259 +2,55 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define EPOLLQUEUE 32
|
||||
#define SEPLEN 8
|
||||
#define DEFAULT_LINE 64
|
||||
|
||||
struct connection {
|
||||
int handle;
|
||||
int fd;
|
||||
short in_epoll;
|
||||
short read_complete;
|
||||
int readbuffer_cap;
|
||||
int read_request;
|
||||
int read_sz;
|
||||
int yield_sz;
|
||||
char sep[SEPLEN];
|
||||
char * readbuffer;
|
||||
};
|
||||
|
||||
struct connection_pool {
|
||||
int size;
|
||||
struct connection * conn;
|
||||
int epoll_fd;
|
||||
int handle_index;
|
||||
int queue_len;
|
||||
int queue_head;
|
||||
struct epoll_event ev[EPOLLQUEUE];
|
||||
};
|
||||
|
||||
struct connection_pool *
|
||||
struct connection_pool *
|
||||
connection_newpool(int max) {
|
||||
int epoll_fd = epoll_create(max);
|
||||
if (epoll_fd == -1) {
|
||||
return NULL;
|
||||
}
|
||||
struct connection_pool * pool = malloc(sizeof(*pool));
|
||||
pool->size = max;
|
||||
pool->conn = malloc(max * sizeof(struct connection));
|
||||
memset(pool->conn, 0, max * sizeof(struct connection));
|
||||
pool->epoll_fd = epoll_fd;
|
||||
pool->handle_index =0;
|
||||
pool->queue_len = 0;
|
||||
pool->queue_head = 0;
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
void
|
||||
connection_deletepool(struct connection_pool *pool) {
|
||||
int i;
|
||||
for (i=0;i<pool->size;i++) {
|
||||
struct connection * c = &pool->conn[i];
|
||||
if (c->handle) {
|
||||
close(c->fd);
|
||||
}
|
||||
if (c->readbuffer) {
|
||||
free(c->readbuffer);
|
||||
}
|
||||
}
|
||||
void
|
||||
connection_deletepool(struct connection_pool * pool) {
|
||||
close(pool->epoll_fd);
|
||||
free(pool->conn);
|
||||
free(pool);
|
||||
}
|
||||
|
||||
static struct connection *
|
||||
_new_connection(struct connection_pool *pool) {
|
||||
int i;
|
||||
for (i=1;i<=pool->size;i++) {
|
||||
int handle = pool->handle_index + i;
|
||||
struct connection *c = &pool->conn[handle % pool->size];
|
||||
if (c->handle == 0) {
|
||||
c->handle = handle;
|
||||
c->in_epoll = 0;
|
||||
c->read_complete = 0;
|
||||
pool->handle_index = handle;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
connection_open(struct connection_pool *pool, const char * address) {
|
||||
char * sep = strchr(address,':');
|
||||
if (sep == NULL)
|
||||
return 0;
|
||||
int len = sep-address;
|
||||
char tmp[len+1];
|
||||
memcpy(tmp, address, len);
|
||||
tmp[len] = '\0';
|
||||
int port = strtol(sep+1, NULL, 10);
|
||||
connection_add(struct connection_pool * pool, int fd, void *ud) {
|
||||
struct epoll_event ev;
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.ptr = ud;
|
||||
|
||||
struct sockaddr_in my_addr;
|
||||
memset(&my_addr, 0, sizeof(struct sockaddr_in));
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(port);
|
||||
my_addr.sin_addr.s_addr=inet_addr(tmp);
|
||||
|
||||
int fd = socket(AF_INET,SOCK_STREAM,0);
|
||||
int r = connect(fd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr_in));
|
||||
|
||||
if (r == -1) {
|
||||
return 0;
|
||||
if (epoll_ctl(pool->epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct connection * c = _new_connection(pool);
|
||||
if (c == NULL) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
c->fd = fd;
|
||||
return c->handle;
|
||||
}
|
||||
|
||||
static void
|
||||
_remove_connection(struct connection_pool * pool, struct connection *c) {
|
||||
c->handle = 0;
|
||||
if (c->in_epoll) {
|
||||
epoll_ctl(pool->epoll_fd, EPOLL_CTL_DEL, c->fd , NULL);
|
||||
}
|
||||
close(c->fd);
|
||||
}
|
||||
|
||||
struct connection *
|
||||
_get_connection(struct connection_pool *pool, int handle) {
|
||||
assert(handle != 0);
|
||||
struct connection * c = &pool->conn[handle % pool->size];
|
||||
if (c->handle != handle)
|
||||
return NULL;
|
||||
return c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
connection_close(struct connection_pool * pool, int handle) {
|
||||
struct connection * c = _get_connection(pool, handle);
|
||||
if (c) {
|
||||
_remove_connection(pool, c);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_add_epoll(struct connection_pool * pool, struct connection *c) {
|
||||
if (!c->in_epoll) {
|
||||
struct epoll_event ev;
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.ptr = c;
|
||||
if (epoll_ctl(pool->epoll_fd, EPOLL_CTL_ADD, c->fd, &ev) == -1) {
|
||||
close(c->fd);
|
||||
c->handle = 0;
|
||||
return;
|
||||
}
|
||||
c->in_epoll = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_yield(struct connection *c) {
|
||||
c->read_complete = 0;
|
||||
int len = c->read_sz - c->yield_sz;
|
||||
if (len == 0) {
|
||||
c->read_sz = 0;
|
||||
return;
|
||||
}
|
||||
assert(len > 0);
|
||||
memmove(c->readbuffer, c->readbuffer + c->yield_sz, len);
|
||||
c->read_sz = len;
|
||||
}
|
||||
|
||||
void *
|
||||
connection_read(struct connection_pool * pool, int handle, size_t sz) {
|
||||
struct connection * c = _get_connection(pool, handle);
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
if (c->read_complete) {
|
||||
_yield(c);
|
||||
}
|
||||
if (c->readbuffer_cap < sz) {
|
||||
int cap = DEFAULT_LINE;
|
||||
while (cap <= sz) {
|
||||
cap *=2;
|
||||
}
|
||||
c->readbuffer = realloc(c->readbuffer, cap);
|
||||
c->readbuffer_cap = cap;
|
||||
}
|
||||
|
||||
if (c->read_sz >= sz) {
|
||||
c->yield_sz = sz;
|
||||
c->read_complete = 1;
|
||||
c->read_request = 0;
|
||||
return c->readbuffer;
|
||||
}
|
||||
|
||||
c->read_request = sz;
|
||||
_add_epoll(pool,c);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
_try_readline(struct connection_pool * pool, struct connection *c) {
|
||||
int seplen = strlen(c->sep);
|
||||
int i;
|
||||
for (i=0;i<= c->read_sz - seplen;i++) {
|
||||
if (memcmp(c->readbuffer+i,c->sep,seplen) == 0) {
|
||||
c->readbuffer[i] = '\0';
|
||||
c->read_request = i;
|
||||
c->yield_sz = i + seplen;
|
||||
c->read_complete = 1;
|
||||
return c->readbuffer;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
connection_readline(struct connection_pool * pool, int handle, const char * sep, size_t *sz) {
|
||||
struct connection * c = _get_connection(pool, handle);
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
if (c->read_complete) {
|
||||
_yield(c);
|
||||
}
|
||||
int i;
|
||||
for (i=0;i<SEPLEN;i++) {
|
||||
c->sep[i] = sep[i];
|
||||
if (sep[i] == '\0')
|
||||
break;
|
||||
}
|
||||
assert(i < SEPLEN);
|
||||
|
||||
const char * line = _try_readline(pool,c);
|
||||
if (line) {
|
||||
if (sz) {
|
||||
*sz = c->read_request;
|
||||
}
|
||||
c->read_request = 0;
|
||||
return c->readbuffer;
|
||||
}
|
||||
|
||||
c->read_request = -1;
|
||||
_add_epoll(pool,c);
|
||||
|
||||
return NULL;
|
||||
connection_del(struct connection_pool * pool, int fd) {
|
||||
epoll_ctl(pool->epoll_fd, EPOLL_CTL_DEL, fd , NULL);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -269,155 +65,13 @@ _read_queue(struct connection_pool * pool, int timeout) {
|
||||
return n;
|
||||
}
|
||||
|
||||
inline static struct connection *
|
||||
_read_one(struct connection_pool * pool) {
|
||||
if (pool->queue_head >= pool->queue_len) {
|
||||
return NULL;
|
||||
}
|
||||
return pool->ev[pool->queue_head ++].data.ptr;
|
||||
}
|
||||
|
||||
static int
|
||||
_read_buffer(struct connection_pool * pool, struct connection *c) {
|
||||
int bytes = recv(c->fd, c->readbuffer + c->read_sz, c->readbuffer_cap - c->read_sz, MSG_DONTWAIT);
|
||||
if (bytes > 0) {
|
||||
c->read_sz += bytes;
|
||||
}
|
||||
if (bytes == 0) {
|
||||
// closed
|
||||
_remove_connection(pool, c);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static int
|
||||
_read_block(struct connection_pool * pool, struct connection *c, size_t * id) {
|
||||
assert(c->read_complete == 0);
|
||||
int need_read = c->read_request - c->read_sz;
|
||||
if (need_read <= 0) {
|
||||
c->yield_sz = c->read_request;
|
||||
c->read_complete = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int handle = c->handle;
|
||||
int bytes = _read_buffer(pool,c);
|
||||
if (bytes > 0) {
|
||||
if (c->read_request - c->read_sz <= 0) {
|
||||
c->yield_sz = c->read_request;
|
||||
c->read_complete = 1;
|
||||
return 1;
|
||||
}
|
||||
} else if (bytes == 0) {
|
||||
if (id) {
|
||||
*id = c - pool->conn;
|
||||
}
|
||||
return -handle;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_read_line(struct connection_pool * pool, struct connection *c, size_t * id) {
|
||||
assert(c->read_complete == 0);
|
||||
if (c->readbuffer_cap == c->read_sz) {
|
||||
int cap = DEFAULT_LINE;
|
||||
while (cap <= c->read_sz) {
|
||||
cap *=2;
|
||||
}
|
||||
c->readbuffer = realloc(c->readbuffer, cap);
|
||||
c->readbuffer_cap = cap;
|
||||
}
|
||||
int handle = c->handle;
|
||||
int bytes = _read_buffer(pool,c);
|
||||
if (bytes == 0) {
|
||||
if (id) {
|
||||
*id = c - pool->conn;
|
||||
}
|
||||
return -handle; // close
|
||||
}
|
||||
const char * line = _try_readline(pool,c);
|
||||
if (line)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_read_request(struct connection_pool * pool, struct connection *c, size_t * id) {
|
||||
if (c->read_request < 0) {
|
||||
return _read_line(pool, c, id);
|
||||
} else {
|
||||
return _read_block(pool, c, id);
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
connection_poll(struct connection_pool * pool, int timeout, int *phandle, size_t * id) {
|
||||
connection_poll(struct connection_pool * pool, int timeout) {
|
||||
if (pool->queue_head >= pool->queue_len) {
|
||||
if (_read_queue(pool, timeout) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
struct connection * c = _read_one(pool);
|
||||
if (c == NULL) {
|
||||
*phandle = 0;
|
||||
return NULL;
|
||||
}
|
||||
if (c->read_complete) {
|
||||
assert(c->in_epoll);
|
||||
epoll_ctl(pool->epoll_fd, EPOLL_CTL_DEL, c->fd , NULL);
|
||||
c->in_epoll = 0;
|
||||
continue;
|
||||
}
|
||||
int result = _read_request(pool, c, id);
|
||||
switch (result) {
|
||||
case 0:
|
||||
// block
|
||||
*phandle = 0;
|
||||
break;
|
||||
case 1:
|
||||
*phandle = c->handle;
|
||||
if (id) {
|
||||
*id = c->read_request;
|
||||
}
|
||||
c->read_request = 0;
|
||||
return c->readbuffer;
|
||||
default:
|
||||
// nagetive close
|
||||
*phandle = -result;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return pool->ev[pool->queue_head ++].data.ptr;
|
||||
}
|
||||
|
||||
void
|
||||
connection_write(struct connection_pool * pool, int handle, const void * buffer, size_t sz) {
|
||||
struct connection * c = _get_connection(pool, handle);
|
||||
if (c) {
|
||||
for (;;) {
|
||||
int err = send(c->fd, buffer, sz, 0);
|
||||
if (err < 0) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
assert(err == sz);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
connection_id(struct connection_pool * pool, int handle) {
|
||||
struct connection * c = _get_connection(pool, handle);
|
||||
if (c == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return c - pool->conn + 1;
|
||||
}
|
||||
|
||||
@@ -8,16 +8,9 @@ struct connection_pool;
|
||||
struct connection_pool * connection_newpool(int max);
|
||||
void connection_deletepool(struct connection_pool *);
|
||||
|
||||
int connection_open(struct connection_pool *, const char * ipaddr);
|
||||
void connection_close(struct connection_pool *, int handle);
|
||||
int connection_add(struct connection_pool *, int fd, void *ud);
|
||||
void connection_del(struct connection_pool *, int fd);
|
||||
|
||||
void * connection_read(struct connection_pool *, int handle, size_t sz);
|
||||
void * connection_readline(struct connection_pool *, int handle, const char * sep, size_t *sz);
|
||||
|
||||
void * connection_poll(struct connection_pool *, int timeout, int *handle, size_t *sz);
|
||||
int connection_closed(struct connection_pool *, int handle);
|
||||
|
||||
void connection_write(struct connection_pool *, int handle, const void * buffer, size_t sz);
|
||||
int connection_id(struct connection_pool *, int handle);
|
||||
void * connection_poll(struct connection_pool *, int timeout);
|
||||
|
||||
#endif
|
||||
|
||||
186
connection/lua-socket.c
Normal file
186
connection/lua-socket.c
Normal file
@@ -0,0 +1,186 @@
|
||||
#include "skynet.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
static int
|
||||
_open(lua_State *L) {
|
||||
const char * ip = luaL_checkstring(L,1);
|
||||
int port = luaL_checkinteger(L,2);
|
||||
|
||||
struct sockaddr_in my_addr;
|
||||
memset(&my_addr, 0, sizeof(struct sockaddr_in));
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(port);
|
||||
my_addr.sin_addr.s_addr=inet_addr(ip);
|
||||
|
||||
int fd = socket(AF_INET,SOCK_STREAM,0);
|
||||
int r = connect(fd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr_in));
|
||||
|
||||
if (r == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushinteger(L,fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_write(lua_State *L) {
|
||||
int fd = luaL_checkinteger(L,1);
|
||||
int type = lua_type(L,2);
|
||||
const char * buffer;
|
||||
size_t sz;
|
||||
if (type == LUA_TSTRING) {
|
||||
buffer = lua_tolstring(L,2,&sz);
|
||||
} else if (type == LUA_TLIGHTUSERDATA) {
|
||||
buffer = lua_touserdata(L,2);
|
||||
sz = luaL_checkinteger(L,3);
|
||||
}
|
||||
for (;;) {
|
||||
int err = send(fd, buffer, sz, 0);
|
||||
if (err < 0) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
assert(err == sz);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct buffer {
|
||||
int cap;
|
||||
int size;
|
||||
char * buffer;
|
||||
int read;
|
||||
};
|
||||
|
||||
static int
|
||||
_new(lua_State *L) {
|
||||
struct buffer * buffer = lua_newuserdata(L, sizeof(struct buffer));
|
||||
buffer->cap = 0;
|
||||
buffer->size = 0;
|
||||
buffer->buffer = NULL;
|
||||
buffer->read = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_delete(lua_State *L) {
|
||||
struct buffer * buffer = lua_touserdata(L,1);
|
||||
free(buffer->buffer);
|
||||
buffer->buffer = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_push(lua_State *L) {
|
||||
luaL_checktype(L,1,LUA_TUSERDATA);
|
||||
struct buffer * buffer = lua_touserdata(L,1);
|
||||
int type = lua_type(L,2);
|
||||
const char * buf;
|
||||
size_t size;
|
||||
if (type == LUA_TSTRING) {
|
||||
buf = lua_tolstring(L,2,&size);
|
||||
} else {
|
||||
luaL_checktype(L,2,LUA_TLIGHTUSERDATA);
|
||||
buf = lua_touserdata(L,2);
|
||||
size = luaL_checkinteger(L,3);
|
||||
}
|
||||
buffer->read = 0;
|
||||
if (size + buffer->size > buffer->cap) {
|
||||
if (buffer->cap == 0) {
|
||||
lua_rawgetp(L, LUA_REGISTRYINDEX, _delete);
|
||||
lua_setmetatable(L, 1);
|
||||
}
|
||||
|
||||
buffer->buffer = realloc(buffer->buffer, buffer->size + size);
|
||||
memcpy(buffer->buffer + buffer->size, buf, size);
|
||||
buffer->size += size;
|
||||
buffer->cap = buffer->size;
|
||||
return 0;
|
||||
}
|
||||
memcpy(buffer->buffer+buffer->size, buf, size);
|
||||
buffer->size += size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_read(lua_State *L) {
|
||||
luaL_checktype(L,1,LUA_TUSERDATA);
|
||||
struct buffer * buffer = lua_touserdata(L,1);
|
||||
int need = luaL_checkinteger(L,2);
|
||||
int size = buffer->size - buffer->read;
|
||||
if (need <= size) {
|
||||
lua_pushlstring(L, buffer->buffer + buffer->read, need);
|
||||
buffer->read += need;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_readline(lua_State *L) {
|
||||
luaL_checktype(L,1,LUA_TUSERDATA);
|
||||
struct buffer * buffer = lua_touserdata(L,1);
|
||||
size_t sz;
|
||||
const char * sep = luaL_checklstring(L,2,&sz);
|
||||
int i;
|
||||
for (i=buffer->read;i<=buffer->size - (int)sz;i++) {
|
||||
if (memcmp(buffer->buffer+i,sep,sz) == 0) {
|
||||
lua_pushlstring(L, buffer->buffer + buffer->read, i-buffer->read);
|
||||
buffer->read = i+sz;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_yield(lua_State *L) {
|
||||
luaL_checktype(L,1,LUA_TUSERDATA);
|
||||
struct buffer * buffer = lua_touserdata(L,1);
|
||||
if (buffer->read) {
|
||||
int size = buffer->size - buffer->read;
|
||||
memmove(buffer->buffer, buffer->buffer + buffer->read, size);
|
||||
buffer->size -= buffer->read;
|
||||
buffer->read = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
luaopen_socket_c(lua_State *L) {
|
||||
luaL_Reg l[] = {
|
||||
{ "open", _open },
|
||||
{ "write", _write },
|
||||
{ "new", _new },
|
||||
{ "push", _push },
|
||||
{ "read", _read },
|
||||
{ "readline", _readline },
|
||||
{ "yield", _yield },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
luaL_checkversion(L);
|
||||
luaL_newlib(L,l);
|
||||
lua_createtable(L,0,1);
|
||||
lua_pushcfunction(L, _delete);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
lua_rawsetp(L, LUA_REGISTRYINDEX, _delete);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
#include "connection.h"
|
||||
#include "skynet.h"
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
struct reply {
|
||||
int session;
|
||||
uint32_t dest;
|
||||
#define DEFAULT_BUFFER_SIZE 1024
|
||||
#define DEFAULT_CONNECTION 16
|
||||
|
||||
struct connection {
|
||||
int fd;
|
||||
char * addr;
|
||||
};
|
||||
|
||||
struct connection_server {
|
||||
int poll;
|
||||
int max_connection;
|
||||
int current_connection;
|
||||
struct connection_pool *pool;
|
||||
struct skynet_context *ctx;
|
||||
struct reply * reply;
|
||||
};
|
||||
|
||||
typedef void (*command_func)(struct connection_server *server, const char * param, size_t sz, int session, const char * reply);
|
||||
|
||||
struct command {
|
||||
const char * name;
|
||||
command_func func;
|
||||
struct connection * conn;
|
||||
};
|
||||
|
||||
struct connection_server *
|
||||
@@ -39,183 +39,86 @@ connection_release(struct connection_server * server) {
|
||||
if (server->pool) {
|
||||
connection_deletepool(server->pool);
|
||||
}
|
||||
free(server->reply);
|
||||
int i;
|
||||
for (i=0;i<server->max_connection;i++) {
|
||||
free(server->conn[i].addr);
|
||||
}
|
||||
free(server->conn);
|
||||
free(server);
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
_command(const char * cmd, const char * msg, size_t sz) {
|
||||
static void
|
||||
_expand(struct connection_server * server) {
|
||||
connection_deletepool(server->pool);
|
||||
server->pool = connection_newpool(server->max_connection * 2);
|
||||
int i;
|
||||
for (i=0;i<sz;i++) {
|
||||
if (cmd[i] == '\0') {
|
||||
if (msg[i] != ' ')
|
||||
return NULL;
|
||||
return msg+i+1;
|
||||
}
|
||||
if (cmd[i] != msg[i])
|
||||
return NULL;
|
||||
for (i=0;i<server->max_connection;i++) {
|
||||
struct connection * c = &server->conn[i];
|
||||
connection_add(server->pool, c->fd , c);
|
||||
}
|
||||
return NULL;
|
||||
server->max_connection *= 2;
|
||||
}
|
||||
|
||||
static void
|
||||
_connect(struct connection_server *server, const char * ipaddr, size_t sz, int session, const char * reply) {
|
||||
char tmp[sz+1];
|
||||
memcpy(tmp, ipaddr, sz);
|
||||
tmp[sz] = '\0';
|
||||
int id = connection_open(server->pool, ipaddr);
|
||||
if (id == 0) {
|
||||
skynet_send(server->ctx, NULL, reply, session, NULL, 0, 0);
|
||||
return;
|
||||
_add(struct connection_server * server, int fd , char * addr) {
|
||||
++server->current_connection;
|
||||
if (server->current_connection > server->max_connection) {
|
||||
_expand(server);
|
||||
}
|
||||
char idstring[20];
|
||||
int n = sprintf(idstring, "%d", id);
|
||||
skynet_send(server->ctx, NULL, reply, session, idstring, n, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
_close(struct connection_server *server, const char * param, size_t sz, int session, const char * reply) {
|
||||
int handle = strtol(param, NULL, 10);
|
||||
if (handle <= 0) {
|
||||
skynet_error(server->ctx, "[connection] Close invalid handle from %s", reply);
|
||||
return;
|
||||
}
|
||||
connection_close(server->pool, handle);
|
||||
}
|
||||
|
||||
static void
|
||||
_write(struct connection_server *server, const char * param, size_t sz, int session, const char * reply) {
|
||||
char * endptr = NULL;
|
||||
int handle = strtol(param, &endptr, 10);
|
||||
if (handle <= 0 || endptr == NULL || *endptr !=' ') {
|
||||
skynet_error(server->ctx, "[connection] Write invalid handle from %s", reply);
|
||||
return;
|
||||
}
|
||||
++endptr;
|
||||
sz -= endptr - param;
|
||||
connection_write(server->pool, handle, endptr, sz);
|
||||
}
|
||||
|
||||
static void
|
||||
_read(struct connection_server *server, const char * param, size_t sz, int session, const char * reply) {
|
||||
char * endptr = NULL;
|
||||
int handle = strtol(param, &endptr, 10);
|
||||
if (handle <= 0 || endptr == NULL || *endptr !=' ') {
|
||||
skynet_error(server->ctx, "[connection] Read invalid handle from %s", reply);
|
||||
return;
|
||||
}
|
||||
int size = strtol(endptr+1, &endptr, 10);
|
||||
|
||||
if (size <= 0 || endptr == NULL) {
|
||||
skynet_error(server->ctx, "[connection] Read invalid size (%d) from %s", size, reply);
|
||||
return;
|
||||
}
|
||||
void * buffer = connection_read(server->pool, handle, size);
|
||||
if (buffer == NULL) {
|
||||
int id = connection_id(server->pool, handle);
|
||||
if (id == 0) {
|
||||
skynet_send(server->ctx, NULL, reply, session, NULL, 0, 0);
|
||||
return;
|
||||
}
|
||||
--id;
|
||||
assert(id < server->max_connection);
|
||||
assert(reply[0] == ':');
|
||||
server->reply[id].session = session;
|
||||
server->reply[id].dest = strtoul(reply+1, NULL, 16);
|
||||
++server->poll;
|
||||
if (server->poll == 1) {
|
||||
skynet_command(server->ctx, "TIMEOUT","0");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
skynet_send(server->ctx, NULL, reply, session, buffer, size, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_readline(struct connection_server *server, const char * param, size_t sz, int session, const char * reply) {
|
||||
char * endptr = NULL;
|
||||
int handle = strtol(param, &endptr, 10);
|
||||
if (handle <= 0 || endptr == NULL || *endptr !=' ') {
|
||||
skynet_error(server->ctx, "[connection] Readline invalid handle from %s", reply);
|
||||
return;
|
||||
}
|
||||
|
||||
sz -= endptr - param + 1;
|
||||
if (sz < 1 || sz > 7) {
|
||||
skynet_error(server->ctx, "[connection] Readline invalid sep (size = %d) from %s", sz, reply);
|
||||
return;
|
||||
}
|
||||
|
||||
char sep[sz+1];
|
||||
memcpy(sep, endptr+1, sz);
|
||||
sep[sz] = '\0';
|
||||
|
||||
void * buffer = connection_readline(server->pool, handle, sep, &sz);
|
||||
if (buffer == NULL) {
|
||||
int id = connection_id(server->pool, handle);
|
||||
if (id == 0) {
|
||||
skynet_send(server->ctx, NULL, reply, session, NULL, 0, 0);
|
||||
return;
|
||||
}
|
||||
--id;
|
||||
assert(id < server->max_connection);
|
||||
assert(reply[0] == ':');
|
||||
server->reply[id].session = session;
|
||||
server->reply[id].dest = strtoul(reply+1, NULL, 16);
|
||||
++server->poll;
|
||||
if (server->poll == 1) {
|
||||
skynet_command(server->ctx, "TIMEOUT","0");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
skynet_send(server->ctx, NULL, reply, session, buffer, sz, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_id_to_hex(char * str, uint32_t id) {
|
||||
int i;
|
||||
static char hex[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
|
||||
for (i=0;i<8;i++) {
|
||||
str[i] = hex[(id >> ((7-i) * 4))&0xf];
|
||||
for (i=0;i<server->max_connection;i++) {
|
||||
struct connection * c = &server->conn[i];
|
||||
if (c->addr == NULL) {
|
||||
c->fd = fd;
|
||||
c->addr = addr;
|
||||
int err = connection_add(server->pool, fd , c);
|
||||
assert(err == 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
str[8] = '\0';
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void
|
||||
_poll(struct connection_server *server) {
|
||||
int handle = 0;
|
||||
size_t sz = 0;
|
||||
_del(struct connection_server * server, int fd) {
|
||||
int i;
|
||||
for (i=0;i<server->max_connection;i++) {
|
||||
struct connection * c = &server->conn[i];
|
||||
if (c->fd == fd) {
|
||||
free(c->addr);
|
||||
c->addr = NULL;
|
||||
c->fd = 0;
|
||||
connection_del(server->pool, fd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
skynet_error(server->ctx, "[connection] Delete invalid handle %d", fd);
|
||||
}
|
||||
|
||||
static void
|
||||
_poll(struct connection_server * server) {
|
||||
int timeout = 100;
|
||||
char addr[10];
|
||||
for (;;) {
|
||||
void * buffer = connection_poll(server->pool, timeout, &handle, &sz);
|
||||
struct connection * c = connection_poll(server->pool, timeout);
|
||||
if (c==NULL) {
|
||||
skynet_command(server->ctx,"TIMEOUT","1");
|
||||
return;
|
||||
}
|
||||
timeout = 0;
|
||||
if (buffer == NULL) {
|
||||
if (handle) {
|
||||
--server->poll;
|
||||
int id = sz;
|
||||
struct reply * r = &server->reply[id];
|
||||
addr[0] = ':';
|
||||
_id_to_hex(addr+1, id);
|
||||
skynet_send(server->ctx, NULL, addr , r->session, NULL, 0, 0);
|
||||
} else {
|
||||
assert(server->poll >= 0);
|
||||
if (server->poll > 0) {
|
||||
skynet_command(server->ctx, "TIMEOUT","1");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void * buffer = malloc(DEFAULT_BUFFER_SIZE);
|
||||
|
||||
int size = recv(c->fd, buffer, DEFAULT_BUFFER_SIZE, MSG_DONTWAIT);
|
||||
if (size < 0) {
|
||||
continue;
|
||||
}
|
||||
if (size == 0) {
|
||||
printf("disconnect\n");
|
||||
free(buffer);
|
||||
skynet_send(server->ctx, NULL, c->addr, 0x7fffffff, NULL, 0, DONTCOPY);
|
||||
} else {
|
||||
--server->poll;
|
||||
int id = connection_id(server->pool, handle);
|
||||
assert(id > 0);
|
||||
--id;
|
||||
struct reply * r = &server->reply[id];
|
||||
addr[0] = ':';
|
||||
_id_to_hex(addr+1, r->dest);
|
||||
skynet_send(server->ctx, NULL, addr, r->session, buffer, sz, 0);
|
||||
skynet_send(server->ctx, NULL, c->addr, 0x7fffffff, buffer, size, DONTCOPY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,52 +126,49 @@ _poll(struct connection_server *server) {
|
||||
static void
|
||||
_main(struct skynet_context * ctx, void * ud, int session, const char * uid, const void * msg, size_t sz) {
|
||||
if (msg == NULL) {
|
||||
assert(session >= 0);
|
||||
_poll(ud);
|
||||
return;
|
||||
}
|
||||
if (session > 0) {
|
||||
skynet_error(ctx, "[connection] Invalid response (session = %d) from %s", session, uid);
|
||||
return;
|
||||
}
|
||||
struct command cmd[] = {
|
||||
{ "CONNECT", _connect },
|
||||
{ "CLOSE" , _close },
|
||||
{ "READ" , _read },
|
||||
{ "READLINE", _readline },
|
||||
{ "WRITE", _write },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
struct command * p = cmd;
|
||||
while (p->name) {
|
||||
const char * param = _command(p->name, msg, sz);
|
||||
if (param) {
|
||||
p->func(ud, param, sz - (param-(const char *)msg), -session, uid);
|
||||
const char * param = (const char *)msg + 4;
|
||||
if (memcmp(msg, "ADD ", 4)==0) {
|
||||
char * endptr;
|
||||
int fd = strtol(param, &endptr, 10);
|
||||
if (endptr == NULL) {
|
||||
skynet_error(ctx, "[connection] Invalid ADD command from %s (session = %d)", uid, session);
|
||||
return;
|
||||
}
|
||||
++p;
|
||||
int addr_sz = sz - (endptr - (char *)msg);
|
||||
char * addr = malloc(addr_sz);
|
||||
memcpy(addr, endptr+1, addr_sz-1);
|
||||
addr[addr_sz] = '\0';
|
||||
_add(ud, fd, addr);
|
||||
} else if (memcmp(msg, "DEL ", 4)==0) {
|
||||
char * endptr;
|
||||
int fd = strtol(param, &endptr, 10);
|
||||
if (endptr == NULL) {
|
||||
skynet_error(ctx, "[connection] Invalid DEL command from %s (session = %d)", uid, session);
|
||||
return;
|
||||
}
|
||||
_del(ud, fd);
|
||||
} else {
|
||||
skynet_error(ctx, "[connection] Invalid command from %s (session = %d)", uid, session);
|
||||
}
|
||||
|
||||
skynet_error(ctx, "[connection] Invalid command from %s (session = %d)", uid, -session);
|
||||
}
|
||||
|
||||
int
|
||||
connection_init(struct connection_server * server, struct skynet_context * ctx, char * param) {
|
||||
int max = strtol(param, NULL, 10);
|
||||
if (max <=0) {
|
||||
return 1;
|
||||
}
|
||||
server->pool = connection_newpool(max);
|
||||
server->pool = connection_newpool(DEFAULT_CONNECTION);
|
||||
if (server->pool == NULL)
|
||||
return 1;
|
||||
server->max_connection = max;
|
||||
server->reply = malloc(sizeof(struct reply) * max);
|
||||
memset(server->reply, 0, sizeof(struct reply) * max);
|
||||
server->max_connection = DEFAULT_CONNECTION;
|
||||
server->current_connection = 0;
|
||||
server->ctx = ctx;
|
||||
server->poll = 0;
|
||||
server->conn = malloc(server->max_connection * sizeof(struct connection));
|
||||
memset(server->conn, 0, server->max_connection * sizeof(struct connection));
|
||||
|
||||
skynet_callback(ctx, server, _main);
|
||||
skynet_command(ctx,"REG",".connection");
|
||||
skynet_command(ctx,"TIMEOUT","0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
#include "connection.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static void
|
||||
test(struct connection_pool *p, int id) {
|
||||
int i=0;
|
||||
while (i<5) {
|
||||
int handle = id;
|
||||
const char * line = connection_readline(p, handle, "\n", NULL);
|
||||
if (line == NULL) {
|
||||
line = connection_poll(p,1000,&handle,NULL);
|
||||
}
|
||||
if (line) {
|
||||
printf("%d %d: %s\n",i,handle, line);
|
||||
connection_write(p,handle,"readline\n",9);
|
||||
++i;
|
||||
} else {
|
||||
if (handle) {
|
||||
printf("Close %d\n",handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
i=0;
|
||||
while (i<5) {
|
||||
int handle = id;
|
||||
uint8_t * buffer = connection_read(p, handle, 8);
|
||||
if (buffer == NULL) {
|
||||
buffer = connection_poll(p,1000,&handle,NULL);
|
||||
}
|
||||
if (buffer) {
|
||||
int j;
|
||||
printf("%d %d: ",i,handle);
|
||||
for (j=0;j<8;j++) {
|
||||
printf("%02x ",buffer[j]);
|
||||
}
|
||||
printf("\n");
|
||||
connection_write(p,handle,"readblock\n",10);
|
||||
++i;
|
||||
} else {
|
||||
if (handle) {
|
||||
printf("Close %d\n", handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main() {
|
||||
struct connection_pool * p = connection_newpool(16);
|
||||
|
||||
int handle = connection_open(p, "127.0.0.1:8888");
|
||||
|
||||
test(p,handle);
|
||||
|
||||
connection_deletepool(p);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user