1 Star 1 Fork 15

lihuaib/sbalance

forked from hotmocha/sbalance 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
sbproxy.c 32.99 KB
一键复制 编辑 原始数据 按行查看 历史
hotmocha 提交于 2015-06-30 20:20 . a
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
/* TODO: add dns timer */
#include "sbalance.h"
#include "sbdns.h"
#include "sbconstant.h"
#include "sbproxy.h"
#include "sbproxy.h"
#include "sblist.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
#define SB_DNS_TIMEOUT_TIME 2500
#define SB_DNS_HASH_SLOTS 11
/* fixbug: client want to finish a keepalive, but in get request function will treat
the normal finish event an error */
int sb_proxy_send_request_to_server_event(struct sb_cycle_env *env, struct sb_event *ev);
int sb_proxy_accept_event(struct sb_cycle_env *env, struct sb_event *ev);
int sb_proxy_get_request_event(struct sb_cycle_env *env, struct sb_event *ev);
int sb_proxy_test_connect_http_server_complete_event(struct sb_cycle_env *env, struct sb_event *ev);
int sb_proxy_send_to_client_connectserverok_event(struct sb_cycle_env *env, struct sb_event *ev);
int sb_proxy_dns_request(struct sb_cycle_env *env, struct sb_session *sess, int flag);
int sb_proxy_dns_recv_resp(struct sb_cycle_env *env);
static char *CRLF = "\r\n";
static char line_buf[MAXIOBUFLEN];
/* @RETURN callback Handler */
void sb_dns_done_handler(struct sb_cycle_env *env, struct sb_session *sess)
{
int rc;
int ip_len;
int len;
if (sess->status == SB_DNS_STATUS_OK) { /* DESTORYED OR OK */
len = sizeof(sess->server.net_address.ip);
rc = sb_proxy_connect_http_server(env, sess);
if (rc == SB_ERROR) {
ErrorOutput("proxy connect failed, session finish");
(void)sb_finish_session(env, sess);
}
}
else {
if (sess->host_is_ip) {
(void)sb_finish_session(env, sess);
return;
}
/* try to update */
sb_proxy_dns_request(env, sess, 1);
ErrorOutput("proxy dns request failed, session finish");
(void)sb_finish_session(env, sess);
}
}
/* @RETURN 1. SB_OK 2. SB_ERROR 3. SB_AGAIN(dns parsing, when complete, sb_dns_done_handler be called, occur in new request)*/
int sb_parse_http_request_header(struct sb_session *sess)
{
unsigned int line_len;
char *buf = sess->cs_buf;
char *start_ptr = buf + sess->current_offset;
char *end_ptr = NULL;
int err;
char *c = NULL;
struct sb_connection *server_conn = NULL;
int i = 0, j;
int len, host_len;
int del_len = 0;
server_conn = &sess->server;
while (start_ptr < start_ptr + sess->cs_used) {
end_ptr = NULL;
for (c = start_ptr; c <= start_ptr + sess->cs_used - 2; c++) {
if (*c == '\r' && *(c + 1) == '\n' ) {
end_ptr = c;
break;
}
}
if (end_ptr == NULL) {
break;
}
line_len = end_ptr - start_ptr;
/* first line */
if (sess->current_offset == 0) {
if (! ( memcmp(start_ptr, "GET", 3) == 0 ||
memcmp(start_ptr, "POST", 4) == 0 ||
memcmp(start_ptr, "PUT", 3) == 0 ||
memcmp(start_ptr, "HEAD", 4) == 0 ||
memcmp(start_ptr, "TRACE", 5) == 0 ||
memcmp(start_ptr, "CONNECT", 7) == 0 ||
memcmp(start_ptr, "DELETE", 6) == 0 )
) {
ErrorOutput("http request method error");
return SB_ERROR;
}
}
if (start_ptr == end_ptr) {
sess->crlf = 1;
}
else if (line_len >= 7 && memcmp(start_ptr, "CONNECT", 7) == 0) {
sess->http_connect_method = 1;
}
else if (line_len >= 15 && memcmp(start_ptr, "Content-Length:", 15) == 0) {
char *tmp_start = NULL;
char *tmp_end = NULL;
char tmp_buf[32];
for (tmp_start = start_ptr + 15; tmp_start < end_ptr && (*tmp_start == ' ' || *tmp_start== '\t'); tmp_start++ ){}
for (tmp_end = end_ptr - 1; tmp_end >= tmp_start && (*tmp_end == ' ' || *tmp_end== '\t'); tmp_end--) {}
if (tmp_start <= tmp_end) {
memcpy(tmp_buf, tmp_start, tmp_end - tmp_start + 1);
tmp_buf[tmp_end - tmp_start + 1] = '\0';
sess->content_length = (unsigned int)atoi(tmp_buf);
}
}
else if (line_len >= 6 && memcmp(start_ptr, "Proxy-", 6) == 0) {
/* 6: strlen("Proxy-") */
del_len = 6;
memmove(start_ptr, start_ptr + 6, sess->cs_used - sess->current_offset - del_len);
}
else if (line_len >= 5 && memcmp(start_ptr, "Host:", 5) == 0) {
char *tmp_start = NULL;
char *tmp_end = NULL;
char tmp_buf[256];
int colon = 0;
int is_origin_ip = 1;
for (tmp_start = start_ptr + 5; tmp_start < end_ptr && (*tmp_start == ' ' || *tmp_start== '\t'); tmp_start++ ){}
for (tmp_end = end_ptr - 1; tmp_end >= tmp_start && ( *tmp_end == ' ' || *tmp_end== '\t'); tmp_end--) {}
/* already dns the host ip */
if (server_conn->net_address.ip[0] == '\0') {
if (tmp_start < tmp_end) {
host_len = tmp_end - tmp_start + 1;
sess->host_is_ip = 0;
j = host_len;
for (i = 0; i < host_len; i++) {
if (tmp_start[i] != '.' && !(tmp_start[i] >= '0' && tmp_start[i] <= '9') && tmp_start[i] != ':') {
is_origin_ip = 0;
break;
} else if (tmp_start[i] == ':') {
colon++;
j = i;
}
}
if (colon >= 2) {
ErrorOutput("request header not correct");
return SB_ERROR;
}
if (is_origin_ip == 1) { /* origin ip */
if (colon == 1) {
/* ip address */
memcpy(server_conn->net_address.ip, tmp_start, j);
server_conn->net_address.ip[j] = '\0';
*(tmp_end + 1) = '\0';
/* port */
server_conn->net_address.port = atoi(tmp_start + j + 1);
}
else { /* colon = 0 */
memcpy(server_conn->net_address.ip, tmp_start, host_len);
server_conn->net_address.ip[host_len] = '\0';
server_conn->net_address.port = sess->http_connect_method ? 443 : 80;
}
sess->host_is_ip = 1;
} else {
sess->host[0] = '\0';
if (colon == 1) {
memcpy(sess->host, tmp_start, j);
sess->host[j] = '\0';
*(tmp_end + 1) = '\0';
server_conn->net_address.port = atoi(tmp_start + j + 1);
} else {
memcpy(sess->host, tmp_start, host_len);
sess->host[host_len] = '\0';
server_conn->net_address.port = sess->http_connect_method ? 443 : 80;
}
}
}
else {
return SB_ERROR;
}
} else {
/* do nothing */
}
}
sess->current_offset += (line_len + 2 - del_len);
sess->cs_used -= del_len;
del_len = 0;
start_ptr = sess->cs_buf + sess->current_offset;
if (sess->crlf == 1)
break;
}
return SB_OK;
}
/* start with no event handler both in server and client */
int sb_proxy_connect_http_server_ok(struct sb_cycle_env *env, struct sb_session *sess)
{
struct sb_connection *ser_c;
struct sb_connection *cli_c;
const static char CONNECTMETHOD_CONNECTSEREROK[] = "HTTP/1.1 200 Connection Established\r\n\r\n";
const static char CONNECTMETHOD_CONNECTSEREROK_LEN = sizeof(CONNECTMETHOD_CONNECTSEREROK) - 1;
ser_c = &sess->server;
cli_c = &sess->client;
if (sb_event_is_active(&ser_c->write)) {
if (sb_del_write_event(&ser_c->write)) {
ErrorOutput("connect server ok, but delete write event failed\n");
return SB_ERROR;
}
}
/* client use connect medhod want to build tcp tunnel */
if (sess->http_connect_method) {
/*
if (sess->request_times || sess->sc_used) {
FatalOutput("http connect method request can't use previous tcp channel");
//return SB_ERROR;
}
*/
memcpy(sess->sc_buf + sess->sc_used, CONNECTMETHOD_CONNECTSEREROK, CONNECTMETHOD_CONNECTSEREROK_LEN);
sess->sc_used += CONNECTMETHOD_CONNECTSEREROK_LEN;
if (!sb_event_is_active(&cli_c->write)) {
sb_add_write_event(&cli_c->write, sb_proxy_send_to_client_connectserverok_event);
}
}
else {
/* server's read handler always sb_transfer_read_event */
/* client's write handler always sb_transfer_write_event, but add when has sending data */
sb_add_read_event(&ser_c->read, sb_transfer_read_event );
(void)sb_proxy_start_request(env, sess);
}
sess->request_times++;
return SB_OK;
}
/* EVENT HANDLER: send the request to http server
if send done, add client's write handler sb_transfer_write_event and server's read handler sb_transfer_read_event
and delete server write handler
*/
int sb_proxy_send_request_to_server_event(struct sb_cycle_env *env, struct sb_event *ev)
{
int err;
struct sb_connection *ser_c = NULL;
struct sb_connection *cli_c = NULL;
struct sb_session *sess = NULL;
ser_c = (struct sb_connection*)ev->data;
sess= ser_c->session;
cli_c = &sess->client;
err = sb_send(ser_c);
if (err == SB_OK) { /* Send done, change handler */
if (cli_c->read.shutdown) {
InfoOutput("client[%s]:[%d]--server[%s]:[%d] finish", sess->client.net_address.ip,
sess->client.net_address.port, sess->server.net_address.ip, sess->server.net_address.port);
(void)sb_finish_session(env, sess);
return SB_OK;
}
/* now we should, recv server's data and send to client */
/* write will delete auto */
//sb_del_write_event(&ser_c->write);
/* copy next request's data to cs_buf */
memmove(sess->cs_buf, sess->cs_buf + sess->current_offset, sess->cs_used_remain);
sess->current_offset = 0;
sess->content_length = 0;
sess->cs_used_remain = 0;
sess->crlf = 0;
/* get client request */
sb_add_read_event(&cli_c->read, sb_proxy_get_request_event);
/***
sb_del_write_event(&ser_c->write);
if (!sb_event_is_active(&cli_c->write)) {
sb_add_write_event(&cli_c->write, sb_transfer_write_event );
}
***/
return SB_OK;
}
else if (err == SB_AGAIN) {
return SB_OK;
}
else {
ErrorOutput("client[%s]:[%d]--server[%s]:[%d] send error", sess->client.net_address.ip,
sess->client.net_address.port, sess->server.net_address.ip, sess->server.net_address.port);
(void)sb_finish_session(env, sess);
return SB_ERROR;
}
}
/* EVENT HANDLER: proxy send client "Established" response after connect server ok(when request use connect method) */
/* notice: because this event handler call another event handler, so in the event handler will not finish session
and when send all data, new ssl session */
int sb_proxy_send_to_client_connectserverok_event(struct sb_cycle_env *env, struct sb_event *ev)
{
int rc = 0;
struct sb_connection *cli_c;
struct sb_connection *ser_c;
struct sb_session *sess;
cli_c = (struct sb_connection*)ev->data;
sess = cli_c->session;
ser_c = &sess->server;
/* manually call another event handler */
rc = sb_transfer_write_event(env, ev);
if (rc == SB_OK) {
/* when data send done */
sess->cs_used = 0;
sb_add_read_event(&ser_c->read, sb_transfer_read_event );
sb_add_read_event(&cli_c->read, sb_transfer_read_event );
/** delete write auto in sb_transfer_write_event
if (sb_event_is_active(&cli_c->write)) {
sb_del_write_event(&cli_c->write);
}
**/
}
return rc;
}
/* EVENT HANDLER: server write handler*/
int sb_proxy_test_connect_http_server_complete_event(struct sb_cycle_env *env, struct sb_event *ev)
{
int err = 0, len = sizeof(int);
int r;
struct sb_connection *c;
struct sb_session *sess;
c = (struct sb_connection*)ev->data;
sess = c->session;
r = getsockopt(c->sockfd, SOL_SOCKET, SO_ERROR, (void *) &err, &len);
if (r || err) {
(void)sb_finish_session(env, sess);
ErrorOutput("cli[%s]-ser[%s] make transfer link failed, r[%d] errno[%d] err[%d]", sess->client.net_address.ip, sess->server.net_address.ip, r, errno, err);
return SB_ERROR;
}
else {
/* ok, finally success */
err = sb_proxy_connect_http_server_ok(env, sess);
if (err) {
(void)sb_finish_session(env, sess);
ErrorOutput("client[%s]-server[%s] connect ok,but init env failed", sess->client.net_address.ip, sess->server.net_address.ip);
return SB_ERROR;
}
else {
DebugOutput("client[%s]-server[%s]:[%d] make transfer link success", sess->client.net_address.ip, sess->server.net_address.ip, sess->server.net_address.port);
return SB_OK;
}
}
}
int sb_proxy_start_request(struct sb_cycle_env *env, struct sb_session *sess)
{
/* 1. stop recv browser's data (delte client's read event)
2. try connect http server
3. copy cs_buf_tmp to cs_buf(completely request) and clear completely request from cs_buf
*/
struct sb_connection *in;
struct sb_connection *out;
struct sockaddr_in addr;
struct sb_event *we;
in = &sess->client;
out = &sess->server;
/* activate server's write, because keepalive allow one tcp channel can exchange mutiple request and response */
if (sb_event_is_active(&out->write))
sb_del_write_event(&out->write);
sb_add_write_event(&out->write, sb_proxy_send_request_to_server_event );
return SB_OK;
}
/* init socket, try connect server */
int sb_proxy_connect_http_server(struct sb_cycle_env *env, struct sb_session *sess)
{
int err, n, fd;
struct sb_connection *in;
struct sb_connection *out;
struct sockaddr_in addr;
struct sb_event *we;
int addr_len;
in = &sess->client;
out = &sess->server;
we = &out->write;
/* let's connect server */
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
if (errno == EMFILE || errno == ENFILE) {
/* delay accept */
ErrorOutput("too many fd, access system limit, ip[%s]'s request is cut", sess->client.net_address.ip);
}
else {
ErrorOutput("connect server, get socket fd failed, ip[%s]'s request is cut", sess->client.net_address.ip);
}
return SB_ERROR;
}
out->sockfd = fd;
memset(&addr, 0x00, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(out->net_address.port);
if (inet_pton(AF_INET, out->net_address.ip, &addr.sin_addr.s_addr) != 1) {
ErrorOutput("inet_pton failed ip[%s],errno[%d]", out->net_address.ip, errno);
sess->why_finish = FINISH_REASON_SYSTEMCALLERR;
return SB_ERROR;
}
addr_len = sizeof(struct sockaddr_in);
memcpy(&out->net_address.sockaddr, &addr, addr_len);
sb_set_nonblocking(out->sockfd);
sb_set_reuseaddr(out->sockfd, 1);
sb_set_tcpkeepalive(out->sockfd);
if (connect(out->sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
if (errno != EINPROGRESS) {
ErrorOutput("connect server[%s] failed, errno[%d]", sess->server.net_address.ip, errno);
sess->why_finish = FINISH_REASON_CONNECTSERVERERR;
return SB_CONNECTERR;
}
/* can't know the connect result
so register the server's read event and set handler */
else if (errno == EINPROGRESS) {
err = sb_add_write_event(we, sb_proxy_test_connect_http_server_complete_event );
if (err) {
ErrorOutput("connect ip[%s]:port[%d] add write event failed, errno[%d]", out->net_address.ip, out->net_address.port, errno);
sess->why_finish = FINISH_REASON_PROCESSEVENTERR;
return SB_ERROR;
}
return SB_AGAIN;
}
} else { /* connect success */
err = sb_proxy_connect_http_server_ok(env, sess);
if (err) {
ErrorOutput("client[%s]-server[%s] connect ok,but init env failed", sess->client.net_address.ip, sess->server.net_address.ip);
return SB_ERROR;
}
else {
InfoOutput("client[%s]:[%d]--[%d]local[%d]--server[%s]:[%d] link success", sess->client.net_address.ip,
sess->client.net_address.port, sess->client.sockfd,sess->server.sockfd,
sess->server.net_address.ip, sess->server.net_address.port);
return SB_OK;
}
}
}
struct sb_session* sb_proxy_fork_session(struct sb_cycle_env *env, struct sb_session *sess)
{
InfoOutput("client[%s]:[%d]--[%d]local[%d]--server[%s]:[%d] fork session", sess->client.net_address.ip,
sess->client.net_address.port, sess->client.sockfd,sess->server.sockfd,
sess->server.net_address.ip, sess->server.net_address.port);
struct sb_session *new_session;
struct sb_connection *cli_c;
struct sb_connection *ser_c;
struct sb_event *cli_re;
struct sb_event *cli_we;
struct sb_event *ser_re;
struct sb_event *ser_we;
/* try two times */
new_session = sb_get_session(env);
if (new_session == NULL) {
new_session = sb_get_session(env);
}
if (new_session == NULL) {
return NULL;
}
memcpy(new_session, sess, sizeof(struct sb_session));
cli_c = &new_session->client;
ser_c = &new_session->server;
cli_c->session = new_session;
ser_c->session = new_session;
cli_re = &cli_c->read;
cli_re->data = cli_c;
cli_we = &cli_c->write;
cli_we->data = cli_c;
ser_re = &ser_c->read;
ser_re->data = ser_c;
ser_we = &ser_c->write;
ser_we->data = ser_c;
/** not need event and timer
if (sb_event_is_active(&sess->client.read)) {
sb_add_read_event(cli_re, sess->client.read.handler);
}
if (sb_event_is_active(&sess->server.read)) {
sb_add_read_event(ser_re, sess->server.read.handler);
}
if (sb_event_is_active(&sess->client.write)) {
sb_add_write_event(cli_we, sess->client.write.handler);
}
if (sb_event_is_active(&sess->server.write)) {
sb_add_write_event(ser_we, sess->server.write.handler);
}
if (sess->client.read.in_timer_set) {
sb_timer_push_event(cli_re);
}
if (sess->client.write.in_timer_set) {
sb_timer_push_event(cli_we);
}
if (sess->server.read.in_timer_set) {
sb_timer_push_event(ser_re);
}
if (sess->server.write.in_timer_set) {
sb_timer_push_event(ser_we);
}
**/
return new_session;
}
/* special use for http proxy's CONNECT method, just finish server side
client side will be held by new forked session */
int sb_finish_session_with_opening_client(struct sb_cycle_env *env, struct sb_session *sess)
{
struct sb_connection *ser_c;
struct sb_connection *cli_c;
if (sess->had_finish){
return SB_OK;
}
sess->had_finish = 1;
cli_c = &sess->client;
ser_c = &sess->server;
/* unregister event */
if (sb_event_is_active(&cli_c->read)) {
sb_del_read_event(&cli_c->read);
}
if (sb_event_is_active(&cli_c->write)) {
sb_del_write_event(&cli_c->write);
}
if (sb_event_is_active(&ser_c->read)) {
sb_del_read_event(&ser_c->read);
}
if (sb_event_is_active(&ser_c->write)) {
sb_del_write_event(&ser_c->write);
}
/* can't close client's sockfd!!! */
if (sess->server.sockfd > 0) {
close(sess->server.sockfd);
sess->server.sockfd = 0;
}
/* delete timer */
if (cli_c->read.in_timer_set) {
sb_timer_pop_event(&cli_c->read);
}
if (cli_c->write.in_timer_set) {
sb_timer_pop_event(&cli_c->write);
}
if (ser_c->read.in_timer_set) {
sb_timer_pop_event(&ser_c->read);
}
if (ser_c->write.in_timer_set) {
sb_timer_pop_event(&ser_c->write);
}
/* mv session from active list to reuse list */
sb_list_delete_session(&env->active_session_list, sess);
env->active_session_num--;
sb_list_push_session(&env->new_reuse_session_list, sess);
env->reuse_sessoion_num++;
return SB_OK;
}
/* EVENT HANDLER: client read */
int sb_proxy_get_request_event(struct sb_cycle_env *env, struct sb_event *ev)
{
int err;
struct sb_connection *in;
struct sb_connection *out;
struct sb_session *sess;
struct sb_session *new_sess;
int r, rc;
int content_len;
in = ev->data;
sess = in->session;
out = &sess->server;
/* @RETURN: 1. SB_BUFNOTENOUGH 2. SB_AGAIN 3. SB_ERROR(errno) 4. SB_DONE */
rc = sb_recv(in);
if (rc == SB_DONE) {
/* finish the session */
/* fixbug: when client use shutdown(SHUT_WR), client will not send data,
but want to recv data from server, so we can't finish whole session. Try send data to client */
/* (void)sb_finish_session(env, sess); */
in->read.shutdown = 1;
InfoOutput("[%s] request want to finish", in->net_address.ip);
}
if(rc == SB_BUFNOTENOUGH) {
/* buffer not enough */
(void)sb_finish_session(env, sess);
ErrorOutput("[%s] request too long", in->net_address.ip);
return SB_ERROR;
}
else if (rc == SB_ERROR) {
(void)sb_finish_session(env, sess);
ErrorOutput("[%s] request error!", in->net_address.ip);
return SB_ERROR;
}
else { /* SB_AGAIN or SB_DONE */
if (sess->cs_used - sess->current_offset >= 2 && sess->crlf == 0) {
if ((rc = sb_parse_http_request_header(sess)) == SB_ERROR) { /* maybe SB_AGAIN */
ErrorOutput("sessionid[%lu] sb_parse_http_request_header failed", sess->sessionid);
(void)sb_finish_session(env, sess);
return SB_ERROR;
}
}
if (sess->crlf == 1) {
//memcpy(sess->cs_buf+sess->cs_used, "Connection:Close", sizeof("Connection:Close") -1);
//sess->cs_used += sizeof("Connection:Close") -1;
/* delete client's read, and start server request */
sb_del_read_event(&in->read);
if (sess->http_connect_method) {
FatalOutput("http connect method request can't use previous tcp channel");
(void)sb_finish_session(env, sess);
ErrorOutput("[%s] request [%s] error!", in->net_address.ip, out->net_address.ip);
return SB_ERROR;
/* 1. fork session
2. discard origin http connection with server's side
*/
new_sess = sb_proxy_fork_session(env, sess);
if (new_sess == NULL) {
(void)sb_finish_session(env, sess);
ErrorOutput("get session failed!");
return SB_ERROR;
}
(void)sb_finish_session_with_opening_client(env, sess);
/* wow!!! now we are in new session, say bye bye with old http session */
rc = sb_proxy_connect_http_server(env, new_sess);
if (rc == SB_ERROR) {
(void)sb_finish_session(env, new_sess);
return SB_ERROR;
}
}
if (sess->http_connect_method && sess->content_length) {
ErrorOutput("connect method can't use contect length");
(void)sb_finish_session(env, new_sess);
return SB_ERROR;
}
if (sess->content_length) {
content_len = sess->cs_used - sess->current_offset;
if (content_len < sess->content_length) {
return SB_AGAIN;
} else {
sess->cs_used_remain = content_len - sess->content_length;
sess->cs_used -= sess->cs_used_remain;
}
}
if (sb_proxy_start_request(env, sess)) {
(void)sb_finish_session(env, sess);
return SB_ERROR;
}
sess->request_times++;
}
else {
if (in->read.shutdown) {
if (sess->cs_used == 0) {
ErrorOutput("[%s] request finish!", in->net_address.ip);
rc = SB_OK;
}
else {
ErrorOutput("[%s] request finish before connect return and http request not correct", in->net_address.ip);
rc = SB_ERROR;
}
(void)sb_finish_session(env, sess);
return rc;
}
return SB_AGAIN;
}
}
return SB_OK;
}
/* EVENT HANDLER(client read) */
int sb_proxy_get_new_request_event(struct sb_cycle_env *env, struct sb_event *ev)
{
int err;
struct sb_connection *in;
struct sb_connection *out;
struct sb_session *sess;
int r, rc, rc2 = 0;
int content_len;
in = ev->data;
sess = in->session;
out = &sess->server;
/* @RETURN: 1. SB_BUFNOTENOUGH 2. SB_AGAIN 3. SB_ERROR(errno) 4. SB_DONE */
rc = sb_recv(in);
if (rc == SB_DONE) {
/* finish the session */
/* fixbug: when client use shutdown(SHUT_WR), client will not send data,
but want to recv data from server, so we can't finish whole session. Try send data to client */
/* (void)sb_finish_session(env, sess); */
in->read.shutdown = 1;
InfoOutput("[%s] request finish before connect return", in->net_address.ip);
}
if(rc == SB_BUFNOTENOUGH) {
/* buffer not enough */
(void)sb_finish_session(env, sess);
ErrorOutput("[%s] request too long", in->net_address.ip);
return SB_ERROR;
}
else if (rc == SB_ERROR) {
(void)sb_finish_session(env, sess);
ErrorOutput("[%s] request error!", in->net_address.ip);
return SB_ERROR;
}
else { /* SB_DONE or SB_AGAIN */
/* parse request */
if (sess->cs_used - sess->current_offset >=2 && sess->crlf == 0) {
if ((rc = sb_parse_http_request_header(sess)) == SB_ERROR) { /* maybe SB_AGAIN */
ErrorOutput("sessionid[%lu] sb_parse_http_request_header failed", sess->sessionid);
(void)sb_finish_session(env, sess);
return SB_ERROR;
}
}
if (sess->crlf == 1) {
//memcpy(sess->cs_buf+sess->cs_used, "Connection:Close", sizeof("Connection:Close") -1);
//sess->cs_used += sizeof("Connection:Close") -1;
/* delete client's read, and start server request */
sb_del_read_event(&in->read);
if (sess->http_connect_method && sess->content_length) {
ErrorOutput("connect method can't use content length");
(void)sb_finish_session(env, sess);
return SB_ERROR;
}
if (sess->content_length) {
content_len = sess->cs_used - sess->current_offset;
if (content_len < sess->content_length) {
return SB_AGAIN;
} else if (content_len >= sess->content_length) {
sess->cs_used_remain = content_len - sess->content_length;
sess->cs_used -= sess->cs_used_remain;
}
}
/* has server ip in host filed */
if (sess->host_is_ip) {
rc = sb_proxy_connect_http_server(env, sess);
if (rc == SB_ERROR) {
(void)sb_finish_session(env, sess);
ErrorOutput("sessionid[%lu] sb_proxy_connect_http_server error", sess->sessionid);
return SB_ERROR;
}
}
else {
/* need use dns */
rc = sb_proxy_dns_request(env, sess, 0);
if (rc == SB_ERROR) {
ErrorOutput("sessionid[%lu] sb_proxy_dns_request error", sess->sessionid);
(void)sb_finish_session(env, sess);
return SB_ERROR;
}
}
}
else {
if (in->read.shutdown) {
ErrorOutput("[%s] request finish before connect return and http request not correct", in->net_address.ip);
(void)sb_finish_session(env, sess);
return SB_ERROR;
}
}
}
return SB_OK;
}
int sb_proxy_accept_event(struct sb_cycle_env *env, struct sb_event *ev)
{
int err;
int new_fd;
struct sockaddr_in new_addr;
int new_addr_len;
struct sb_session *new_session;
struct sb_listen *li;
li = ev->data;
while(1) {
/* eat too many resource need wait */
/**
if (env->accept_dalay_flag == 1)
break;
**/
new_addr_len = sizeof(struct sockaddr_in);
new_fd = accept(li->listen_fd, (struct sockaddr*)&new_addr, &new_addr_len);
if (new_fd == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
DebugOutput("accept EAGAIN");
}
else if (errno == EMFILE || errno == ENFILE) {
/* need wait for a moment */
/* delay accept */
if (env->accept_delay_timeout > 0) {
sb_push_accept_delay_timer(env);
}
ErrorOutput("too many fd, access the system limit");
}
else {
ErrorOutput("listen ip[%s]-port[%d]-listen_fd[%d] accept failed",
li->listen_address.ip,
li->listen_address.port,
li->listen_fd );
}
break;
}
else {
struct sb_connection *cli_c;
struct sb_connection *ser_c;
struct sb_event *cli_re;
struct sb_event *cli_we;
struct sb_event *ser_re;
struct sb_event *ser_we;
/* try two times */
new_session = sb_get_session(env);
if (new_session == NULL) {
new_session = sb_get_session(env);
}
if (new_session == NULL) {
ErrorOutput("get session failed");
/* close the new socket */
/* can't get session, need wait for a moment */
close(new_fd);
break;
}
cli_c = &new_session->client;
cli_c->connect_type = CONNECT_TYPE_CLIENT;
ser_c = &new_session->server;
ser_c->connect_type = CONNECT_TYPE_SERVER;
cli_c->session = new_session;
ser_c->session = new_session;
cli_re = &cli_c->read;
cli_re->data = cli_c;
cli_we = &cli_c->write;
cli_we->data = cli_c;
ser_re = &ser_c->read;
ser_re->data = ser_c;
ser_we = &ser_c->write;
ser_we->data = ser_c;
/* set cli sockpt */
sb_set_nonblocking(new_fd);
sb_set_reuseaddr(new_fd, 1);
sb_set_tcpkeepalive(new_fd);
/* get client address info */
cli_c->sockfd = new_fd;
memcpy(&cli_c->net_address.sockaddr, &new_addr, new_addr_len);
strcpy(cli_c->net_address.ip, inet_ntoa(new_addr.sin_addr));
cli_c->net_address.port = ntohs(new_addr.sin_port );
InfoOutput("listen ip[%s]-port[%d] accept connect ip[%s]-port[%d]", li->listen_address.ip, li->listen_address.port,
cli_c->net_address.ip, cli_c->net_address.port);
sb_add_read_event(cli_re, sb_proxy_get_new_request_event );
}
}
return SB_OK;
}
#define SB_DNS_WAITING_HASH_SLOTS 11
static struct hlist_head hash_slots[SB_DNS_WAITING_HASH_SLOTS];
static struct list_head wait_parse_list_head;
static struct list_head parsing_list_head;
static struct ares_options options;
static unsigned long RSHash(const char *str)
{
unsigned long a = 63689;
unsigned long b = 378551;
unsigned long hash = 0;
while(*str) {
hash = hash * a + (*str++);
a *= b;
}
return hash;
}
int sb_proxy_dns_init()
{
int i;
for (i = 0; i < SB_DNS_HASH_SLOTS; i++) {
INIT_HLIST_HEAD(&hash_slots[i]);
}
INIT_LIST_HEAD(&parsing_list_head);
options.timeout = SB_DNS_TIMEOUT_TIME;
options.tries = 2;
return SB_OK;
}
/* flag == 1: force dns server update host */
int sb_proxy_dns_request(struct sb_cycle_env *env, struct sb_session *sess, int force_update)
{
struct dns_msg msg;
int host_len;
int rc = 0;
char *host;
struct sb_dns_request *new_request;
unsigned long hash_val;
int slot_index;
struct hlist_head *hash_head;
host = sess->host;
slot_index = RSHash(host) % SB_DNS_HASH_SLOTS;
hash_head = &hash_slots[slot_index];
if (hash_head->first == NULL) {
new_request = (struct sb_dns_request*)calloc(1, sizeof(struct sb_dns_request));
if (new_request == NULL) {
ErrorOutput("malloc new sb_dns_request failed\n");
return SB_ERROR;
}
strcpy(new_request->host, host);
INIT_LIST_HEAD(&new_request->sess_list_head);
hlist_add_head(&new_request->hash_node, hash_head);
list_add(&sess->dns_list_node, &new_request->sess_list_head);
} else {
struct hlist_node *pos = NULL;
struct hlist_node *pre_pos = NULL;
struct sb_dns_request *type;
int cmp;
int ip_len;
int add_last = 1;
hlist_for_each_entry(type, pos, hash_head, hash_node) {
if ((cmp = strcmp(type->host, host)) == 0) {
list_add(&sess->dns_list_node, &type->sess_list_head);
add_last = 0;
break;
} else if (cmp > 0) {
new_request = (struct sb_dns_request*)calloc(1, sizeof(struct sb_dns_request));
if (new_request == NULL) {
ErrorOutput("malloc new sb_dns_request failed\n");
return SB_ERROR;
}
strcpy(new_request->host, host);
hlist_add_before(&new_request->hash_node, pos);
INIT_LIST_HEAD(&new_request->sess_list_head);
list_add(&sess->dns_list_node, &new_request->sess_list_head);
add_last = 0;
break;
} else {
pre_pos = pos;
}
}
if (add_last) {
new_request = (struct sb_dns_request*)calloc(1, sizeof(struct sb_dns_request));
if (new_request == NULL) {
ErrorOutput("malloc new sb_dns_request failed\n");
return SB_ERROR;
}
strcpy(new_request->host, host);
INIT_LIST_HEAD(&new_request->sess_list_head);
list_add(&sess->dns_list_node, &new_request->sess_list_head);
hlist_add_after(pre_pos, &new_request->hash_node);
}
}
msg.m.mtype = env->workerno;
host_len = strlen(host);
memcpy(msg.m.mtext, host, host_len);
msg.mtext_len = host_len;
if (force_update == 1) { /* force flag */
memcpy(msg.m.mtext, "#1", 2);
msg.mtext_len = 2;
}
rc = msg_send (env->msgqueueid, &msg, SB_NO_WAIT);
msg.m.mtext[msg.mtext_len] = '\0';
ErrorOutput("msgqueueid[%d], msg.m.mtext[%s], type[%ld], len[%d]", env->msgqueueid, msg.m.mtext, msg.m.mtype, msg.mtext_len);
if (rc)
{
ErrorOutput ("send dns_msg failed, info[%s], errno[%d]-error[%s]", msg.m.mtext, errno, strerror(errno));
list_del_init(&sess->dns_list_node);
return SB_ERROR;
}
msg.m.mtext[msg.mtext_len] = '\0';
DebugOutput("dns_msg[%s]", msg.m.mtext);
return SB_OK;
}
int sb_proxy_dns_recv_resp(struct sb_cycle_env *env)
{
int rc;
struct dns_msg msg;
int ip_len;
struct sb_session *sess, *next_sess;
char *host, *ip, status;
char *resp_text;
int slot_index;
struct hlist_head *hash_head;
while (1) {
memset(&msg, 0x00, sizeof(struct dns_msg));
rc = msg_recv(env->msgqueueid , env->workerno + SB_REQREPMSG_TYPESPLIT, &msg, IPC_NOWAIT);
if (rc) {
if (errno != EAGAIN && errno != ENOMSG) {
ErrorOutput ("recv dns_msg errno[%d]-error[%s] [%d]", errno, strerror(errno), env->msgqueueid);
return SB_ERROR;
} else {
//DebugOutput("no recv dns_msg");
break;
}
}
resp_text = msg.m.mtext;
resp_text[msg.mtext_len] = '\0';
DebugOutput("RECV dns_msg[%s]-len[%d]", resp_text, msg.mtext_len);
host = index(resp_text, '#');
if (host == NULL) {
status = SB_DNS_STATUS_ERROR;
ip_len = 0;
}
else {
*host = '\0';
status = *(host + 1);
ip = host + 3;
ip_len = resp_text + msg.mtext_len - ip + 1;
}
host = resp_text;
slot_index = RSHash(host) % SB_DNS_HASH_SLOTS;
hash_head = &hash_slots[slot_index];
if (hash_head->first == NULL) {
/* no hash value */
return;
} else {
struct hlist_node *pos = NULL;
struct hlist_node *pre_pos = NULL;
struct sb_dns_request *type;
int cmp;
/* can't find do nothing */
hlist_for_each_entry(type, pos, hash_head, hash_node) {
if ((cmp = strcmp(type->host, host)) == 0) {
list_for_each_entry_safe (sess, next_sess, &type->sess_list_head, dns_list_node) {
if (status == SB_DNS_STATUS_CHAR_OK) {
memcpy(sess->server.net_address.ip, ip, ip_len);
sess->status = SB_DNS_STATUS_OK;
} else if (status == SB_DNS_STATUS_CHAR_FAIL || status == SB_DNS_STATUS_CHAR_TIMEOUT) {
sess->status = SB_DNS_STATUS_ERROR;
} else {
ErrorOutput("host[%s] dns request get unknown status [%c]", host, status);
sess->status = SB_DNS_STATUS_ERROR;
}
sb_dns_done_handler(env, sess);
list_del_init(&sess->dns_list_node);
}
} else if (cmp > 0) {
break;
}
}
}
}
return SB_OK;
}
int sb_proxy_discard_resp(struct sb_cycle_env *env, int msgtype)
{
struct dns_msg msg;
int rc;
while (1) {
memset(&msg, 0x00, sizeof(struct dns_msg));
rc = msg_recv(env->msgqueueid , msgtype + SB_REQREPMSG_TYPESPLIT, &msg, IPC_NOWAIT);
if (rc) {
if (errno != EAGAIN && errno != ENOMSG) {
ErrorOutput ("recv dns_msg errno[%d]-error[%s] [%d]", errno, strerror(errno), env->msgqueueid);
return SB_ERROR;
}
} else {
break;
}
}
return SB_OK;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/lihuaib/sbalance.git
git@gitee.com:lihuaib/sbalance.git
lihuaib
sbalance
sbalance
master

搜索帮助