static void be_connect(void *data, int fd) { cosocket_t *c*k = data; if(fd < 0) { connection_pool_counter_operate(c*k->pool_key, -1); lua_pushnil(c*k->L); if(se_errno == SE_DNS_QUERY_TIMEOUT) { lua_pushstring(c*k->L, "Connect error!(dns query timeout)"); } else if(se_errno == SE_CONNECT_TIMEOUT) { lua_pushstring(c*k->L, "Connect error!(timeout)"); } else { lua_pushstring(c*k->L, "Connect error!(unknow)"); } c*k->status = 0; c*k->inuse = 0; lua_f_lua_uthread_resume_in_c(c*k->L, 2); return; } int ret = _be_connect(c*k, fd, 1); if(ret == -2) { return; } lua_f_lua_uthread_resume_in_c(c*k->L, ret); }
static int cosocket_be_close(se_ptr_t *ptr) { //printf("cosocket_be_close %d\n", ptr->fd); int fd = ptr->fd; cosocket_connection_pool_t *n = ptr->data; int k = n->pool_key % 64; if(n == connect_pool_p[0][k]) { connect_pool_p[0][k] = n->next; if(n->next) { ((cosocket_connection_pool_t *) n->next)->uper = NULL; } } else if(n == connect_pool_p[1][k]) { connect_pool_p[1][k] = n->next; if(n->next) { ((cosocket_connection_pool_t *) n->next)->uper = NULL; } } else { ((cosocket_connection_pool_t *) n->uper)->next = n->next; if(n->next) { ((cosocket_connection_pool_t *) n->next)->uper = n->uper; } } se_delete(n->ptr); n->ptr = NULL; if(n->ssl) { SSL_free(n->ssl); n->ssl = NULL; SSL_CTX_free(n->ctx); n->ctx = NULL; } connection_pool_counter_operate(n->pool_key, -1); close(fd); free(n); return 1; }
static int _lua_co_close(lua_State *L, cosocket_t *c*k) { if(c*k->read_buf) { cosocket_link_buf_t *fr = c*k->read_buf; cosocket_link_buf_t *nb = NULL; while(fr) { nb = fr->next; free(fr->buf); free(fr); fr = nb; } c*k->read_buf = NULL; } if(c*k->send_buf_need_free) { free(c*k->send_buf_need_free); c*k->send_buf_need_free = NULL; } if(c*k->pool_wait) { delete_in_waiting_get_connection(c*k->pool_wait); c*k->pool_wait = NULL; } delete_timeout(c*k->timeout_ptr); c*k->timeout_ptr = NULL; c*k->status = 0; if(c*k->fd > -1) { ((se_ptr_t *) c*k->ptr)->fd = c*k->fd; if(c*k->pool_size < 1 || add_connection_to_pool(_loop_fd, c*k->pool_key, c*k->pool_size, c*k->ptr, c*k->ssl, c*k->ctx, c*k->ssl_pw) == 0) { se_delete(c*k->ptr); c*k->ptr = NULL; connection_pool_counter_operate(c*k->pool_key, -1); close(c*k->fd); if(c*k->ssl) { SSL_free(c*k->ssl); c*k->ssl = NULL; } if(c*k->ctx) { SSL_CTX_free(c*k->ctx); c*k->ctx = NULL; } if(c*k->ssl_pw) { free(c*k->ssl_pw); c*k->ssl_pw = NULL; } } c*k->ssl = NULL; c*k->ctx = NULL; c*k->ssl_pw = NULL; c*k->ptr = NULL; c*k->fd = -1; } }
static void timeout_handle(void *ptr) { cosocket_t *c*k = ptr; delete_timeout(c*k->timeout_ptr); c*k->timeout_ptr = NULL; if(c*k->pool_wait) { delete_in_waiting_get_connection(c*k->pool_wait); c*k->pool_wait = NULL; } lua_pushnil(c*k->L); if(c*k->ptr) { if(c*k->status == 3) { lua_pushstring(c*k->L, "Connect error!(wait pool timeout)"); } else if(((se_ptr_t *) c*k->ptr)->wfunc == cosocket_be_ssl_connected) { lua_pushstring(c*k->L, "SSL Connect timeout!"); } else if(((se_ptr_t *) c*k->ptr)->wfunc == cosocket_be_write) { lua_pushstring(c*k->L, "Send timeout!"); } else if(((se_ptr_t *) c*k->ptr)->rfunc == cosocket_be_read) { lua_pushstring(c*k->L, "Read timeout!"); } else { lua_pushstring(c*k->L, "Timeout!"); } } else { if(c*k->status == 3) { lua_pushstring(c*k->L, "Connect error!(wait pool timeout)"); } else { lua_pushstring(c*k->L, "Timeout!"); } } { se_delete(c*k->ptr); c*k->ptr = NULL; if(c*k->fd > -1) { connection_pool_counter_operate(c*k->pool_key, -1); close(c*k->fd); c*k->fd = -1; } c*k->status = 0; } if(c*k->ssl) { SSL_shutdown(c*k->ssl); SSL_free(c*k->ssl); c*k->ssl = NULL; SSL_CTX_free(c*k->ctx); c*k->ctx = NULL; } if(c*k->read_buf) { cosocket_link_buf_t *fr = c*k->read_buf; cosocket_link_buf_t *nb = NULL; while(fr) { nb = fr->next; free(fr->buf); free(fr); fr = nb; } c*k->read_buf = NULL; } if(c*k->send_buf_need_free) { free(c*k->send_buf_need_free); c*k->send_buf_need_free = NULL; } c*k->inuse = 0; lua_f_lua_uthread_resume_in_c(c*k->L, 2); }
int cosocket_be_read(se_ptr_t *ptr) { cosocket_t *c*k = ptr->data; int n = 0, ret = 0; init_read_buf: if(!c*k->read_buf || (c*k->last_buf->buf_len >= c*k->last_buf->buf_size)) { /// init read buf cosocket_link_buf_t *nbuf = NULL; nbuf = malloc(sizeof(cosocket_link_buf_t)); if(nbuf == NULL) { LOGF(ERR, "malloc error @%s:%d\n", __FILE__, __LINE__); exit(1); } nbuf->buf = large_malloc(4096); if(!nbuf->buf) { LOGF(ERR, "malloc error @%s:%d\n", __FILE__, __LINE__); exit(1); } nbuf->buf_size = 4096; nbuf->buf_len = 0; nbuf->next = NULL; if(c*k->read_buf) { c*k->last_buf->next = nbuf; } else { c*k->read_buf = nbuf; } c*k->last_buf = nbuf; } if(!c*k->ssl) { while((n = recv(c*k->fd, c*k->last_buf->buf + c*k->last_buf->buf_len, c*k->last_buf->buf_size - c*k->last_buf->buf_len, 0)) > 0) { c*k->last_buf->buf_len += n; c*k->total_buf_len += n; if(c*k->last_buf->buf_len >= c*k->last_buf->buf_size) { goto init_read_buf; } } } else { while((n = SSL_read(c*k->ssl, c*k->last_buf->buf + c*k->last_buf->buf_len, c*k->last_buf->buf_size - c*k->last_buf->buf_len)) > 0) { c*k->last_buf->buf_len += n; c*k->total_buf_len += n; if(c*k->last_buf->buf_len >= c*k->last_buf->buf_size) { goto init_read_buf; } } } if(n == 0 || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) { int rfd = c*k->fd; /// socket closed delete_timeout(c*k->timeout_ptr); c*k->timeout_ptr = NULL; { c*k->status = 0; se_delete(c*k->ptr); c*k->ptr = NULL; connection_pool_counter_operate(c*k->pool_key, -1); close(c*k->fd); c*k->fd = -1; c*k->status = 0; } if(c*k->in_read_action == 1) { c*k->in_read_action = 0; int rt = lua_co_read_(c*k); c*k->inuse = 0; if(rt > 0) { ret = lua_f_lua_uthread_resume_in_c(c*k->L, rt); } else if(n == 0) { lua_pushnil(c*k->L); ret = lua_f_lua_uthread_resume_in_c(c*k->L, 1); } if(ret == LUA_ERRRUN) { se_delete(c*k->ptr); c*k->ptr = NULL; connection_pool_counter_operate(c*k->pool_key, -1); close(c*k->fd); c*k->fd = -1; c*k->status = 0; } } } else { if(c*k->in_read_action == 1) { int rt = lua_co_read_(c*k); if(rt > 0) { c*k->in_read_action = 0; delete_timeout(c*k->timeout_ptr); c*k->timeout_ptr = NULL; c*k->inuse = 0; ret = lua_f_lua_uthread_resume_in_c(c*k->L, rt); if(ret == LUA_ERRRUN) { se_delete(c*k->ptr); c*k->ptr = NULL; connection_pool_counter_operate(c*k->pool_key, -1); close(c*k->fd); c*k->fd = -1; c*k->status = 0; } } } } return 0; }
int cosocket_be_write(se_ptr_t *ptr) { cosocket_t *c*k = ptr->data; int n = 0, ret = 0; c*k->in_read_action = 0; if(!c*k->ssl) { while((n = send(c*k->fd, c*k->send_buf + c*k->send_buf_ed, c*k->send_buf_len - c*k->send_buf_ed, MSG_DONTWAIT)) > 0) { c*k->send_buf_ed += n; } } else { while((n = SSL_write(c*k->ssl, c*k->send_buf + c*k->send_buf_ed, c*k->send_buf_len - c*k->send_buf_ed)) > 0) { c*k->send_buf_ed += n; } } if(c*k->send_buf_ed == c*k->send_buf_len || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) { if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { se_delete(c*k->ptr); c*k->ptr = NULL; connection_pool_counter_operate(c*k->pool_key, -1); close(c*k->fd); c*k->fd = -1; c*k->status = 0; c*k->send_buf_ed = 0; } /* else { se_be_pri(c*k->ptr, NULL); }*/ if(c*k->send_buf_need_free) { free(c*k->send_buf_need_free); c*k->send_buf_need_free = NULL; } delete_timeout(c*k->timeout_ptr); c*k->timeout_ptr = NULL; int rc = 1; if(c*k->send_buf_ed >= c*k->send_buf_len) { lua_pushnumber(c*k->L, c*k->send_buf_ed); } else if(c*k->fd == -1) { lua_pushnil(c*k->L); lua_pushstring(c*k->L, "connection closed!"); rc = 2; } else { lua_pushboolean(c*k->L, 0); } if(c*k->inuse == 1) { se_be_pri(c*k->ptr, NULL); c*k->inuse = 0; lua_f_lua_uthread_resume_in_c(c*k->L, rc); return 0; } else { return 0 - rc; } } return c*k->send_buf_len - c*k->send_buf_ed; }
static int lua_co_connect(lua_State *L) { cosocket_t *c*k = NULL; { if(!lua_isuserdata(L, 1) || !lua_isstring(L, 2)) { lua_pushnil(L); lua_pushstring(L, "Error params!"); return 2; } c*k = (cosocket_t *) lua_touserdata(L, 1); if(c*k->status > 0) { lua_pushnil(L); lua_pushstring(L, "Aleady connected!"); return 2; } if(c*k->inuse == 1) { lua_pushnil(L); lua_pushstring(L, "socket busy!"); return 2; } //printf(" 0x%p connect to %s\n", L, lua_tostring(L, 2)); size_t host_len = 0; const char *host = lua_tolstring(L, 2, &host_len); if(host_len > (host[0] == '/' ? 108 : 60)) { lua_pushnil(L); lua_pushstring(L, "hostname length must be <= 60!"); return 2; } int port = 0; int pn = 3; if(host[0] != '/') { port = lua_tonumber(L, 3); if(port < 1) { lua_pushnil(L); lua_pushstring(L, "port must be > 0"); return 2; } pn = 4; } if(lua_gettop(L) >= pn) { /// set keepalive options if(lua_isnumber(L, pn)) { c*k->pool_size = lua_tonumber(L, pn); if(c*k->pool_size < 0) { c*k->pool_size = 0; } else if(c*k->pool_size > 4096) { c*k->pool_size = 4096; } pn++; } if(c*k->pool_size > 0) { size_t len = 0; if(lua_gettop(L) == pn && lua_isstring(L, pn)) { const char *key = lua_tolstring(L, pn, &len); c*k->pool_key = fnv1a_32(key, len); } } } if(c*k->pool_key == 0) { /// create a normal key int len = snprintf(temp_buf, 4096, "%s%s:%d:%ld", port > 0 ? "tcp://" : "unix://", host, port, c*k->ssl_sign); c*k->pool_key = fnv1a_32(temp_buf, len); } c*k->status = 1; c*k->L = L; c*k->read_buf = NULL; c*k->last_buf = NULL; c*k->total_buf_len = 0; c*k->buf_read_len = 0; /// check pool count cosocket_connection_pool_counter_t *pool_counter = get_connection_pool_counter(c*k->pool_key); if(pool_counter->size > c*k->pool_size) { c*k->pool_size = pool_counter->size; } if(c*k->pool_size > 0) { c*k->ptr = get_connection_in_pool(_loop_fd, c*k->pool_key, c*k); if(c*k->ptr) { ((se_ptr_t *) c*k->ptr)->data = c*k; c*k->status = 2; c*k->reusedtimes = 1; c*k->fd = ((se_ptr_t *) c*k->ptr)->fd; //printf("reuse %d\n", c*k->fd); se_be_pri(c*k->ptr, NULL); lua_pushboolean(L, 1); return 1; } if(pool_counter->count > 0 && pool_counter->count >= c*k->pool_size / _process_count) { /// pool full if((c*k->pool_wait = add_waiting_get_connection(c*k))) { c*k->status = 3; c*k->timeout_ptr = add_timeout(c*k, c*k->timeout, timeout_handle); //printf("wait %d\n", c*k->fd); c*k->inuse = 1; return lua_yield(L, 0); } else { lua_pushnil(L); lua_pushstring(L, "pool error"); return 2; } } } int fd = se_connect(_loop_fd, host, port, c*k->timeout > 0 ? c*k->timeout : 30000, be_connect, c*k); if(fd != -2) { if(fd > -1) { connection_pool_counter_operate(c*k->pool_key, 1); int ret = _be_connect(c*k, fd, 0); if(ret == -2) { return lua_yield(L, 0); } return ret; } else { lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2; } } connection_pool_counter_operate(c*k->pool_key, 1); } return lua_yield(L, 0); }
static int _be_connect(cosocket_t *c*k, int fd, int yielded) { int flag = 1; int ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); c*k->fd = fd; c*k->ptr = se_add(_loop_fd, fd, c*k); c*k->status = 2; c*k->in_read_action = 0; if(c*k->use_ssl) { if(c*k->ctx == NULL) { c*k->ctx = SSL_CTX_new(SSLv23_client_method()); if(c*k->ctx == NULL) { connection_pool_counter_operate(c*k->pool_key, -1); se_delete(c*k->ptr); close(c*k->fd); c*k->ptr = NULL; c*k->fd = -1; c*k->status = 0; lua_pushnil(c*k->L); lua_pushstring(c*k->L, "SSL_CTX_new Error"); return 2; } } c*k->ssl = SSL_new(c*k->ctx); if(c*k->ssl == NULL) { connection_pool_counter_operate(c*k->pool_key, -1); se_delete(c*k->ptr); close(c*k->fd); c*k->ptr = NULL; c*k->fd = -1; c*k->status = 0; SSL_CTX_free(c*k->ctx); c*k->ctx = NULL; lua_pushnil(c*k->L); lua_pushstring(c*k->L, "SSL_new Error"); return 2; } SSL_set_fd(c*k->ssl, c*k->fd); se_be_read(c*k->ptr, cosocket_be_ssl_connected); if(SSL_connect(c*k->ssl) == 1) { se_be_pri(c*k->ptr, NULL); lua_pushboolean(c*k->L, 1); c*k->inuse = 0; return 1; } c*k->timeout_ptr = add_timeout(c*k, c*k->timeout, timeout_handle); return -2; } se_be_pri(c*k->ptr, NULL); lua_pushboolean(c*k->L, 1); c*k->inuse = 0; return 1; }
se_ptr_t *get_connection_in_pool(int loop_fd, unsigned long pool_key, cosocket_t *c*k) { int k = pool_key % 64; int p = (now / connect_pool_ttl) % 2; cosocket_connection_pool_t *n = NULL, *m = NULL, *nn = NULL; se_ptr_t *ptr = NULL; /// clear old caches int q = (p + 1) % 2; int i = 0; for(i = 0; i < 64; i++) { n = connect_pool_p[q][i]; while(n) { m = n; n = n->next; ptr = m->ptr; if(m->z == 0) { m->z = 1; nn = connect_pool_p[p][m->pool_key % 64]; if(nn == NULL) { connect_pool_p[p][m->pool_key % 64] = m; m->next = NULL; m->uper = NULL; } else { m->uper = NULL; m->next = nn; nn->uper = m; connect_pool_p[p][m->pool_key % 64] = m; } } else { int fd = ptr->fd; se_delete(ptr); connection_pool_counter_operate(m->pool_key, -1); close(fd); free(m); } } connect_pool_p[q][i] = NULL; } /// end if(pool_key == 0) { resume_in_waiting_get_connection(loop_fd); return NULL; /// only do clear job } regetfd: n = connect_pool_p[p][k]; while(n != NULL) { if(n->pool_key == pool_key) { break; } n = (cosocket_connection_pool_t *) n->next; } if(n) { if(n == connect_pool_p[p][k]) { /// at top m = n->next; if(m) { m->uper = NULL; connect_pool_p[p][k] = m; } else { connect_pool_p[p][k] = NULL; } } else { ((cosocket_connection_pool_t *) n->uper)->next = n->next; if(n->next) { ((cosocket_connection_pool_t *) n->next)->uper = n->uper; } } ptr = n->ptr; if(c*k) { if(c*k->ctx) { SSL_CTX_free(c*k->ctx); } if(c*k->ssl_pw) { free(c*k->ssl_pw); } c*k->ctx = n->ctx; c*k->ssl = n->ssl; c*k->ssl_pw = n->ssl_pw; } free(n); //printf ( "get fd in pool%d %d key:%d\n", p, ptr->fd, k ); return ptr; } if(p != q) { p = q; goto regetfd; } return NULL; }