void acl_master_flow_init(void) { char *myname = "acl_master_flow_init"; if (pipe(acl_var_master_flow_pipe) < 0) acl_msg_fatal("%s(%d)->%s: pipe: %s", __FILE__, __LINE__, myname, strerror(errno)); acl_non_blocking(acl_var_master_flow_pipe[0], ACL_NON_BLOCKING); acl_non_blocking(acl_var_master_flow_pipe[1], ACL_NON_BLOCKING); acl_close_on_exec(acl_var_master_flow_pipe[0], ACL_CLOSE_ON_EXEC); acl_close_on_exec(acl_var_master_flow_pipe[1], ACL_CLOSE_ON_EXEC); }
bool master_service::on_accept(acl::aio_socket_stream* client) { if (0) logger("connect from %s, fd %d", client->get_peer(true), client->sock_handle()); acl_non_blocking(client->sock_handle(), ACL_BLOCKING); // 根据客户端连接服务端口号的不同来区分不同的服务应用协议 const char* local = client->get_local(true); if (acl_strrncasecmp(local, var_cfg_backend_service, strlen(var_cfg_backend_service)) == 0) { // 创建服务对象处理来自于后端服务模块的请求 IConnection* conn = new ServerConnection(client); conn->run(); return true; } else { // 创建对象处理来自于前端客户端模块的请求 IConnection* conn = new ClientConnection(client, var_cfg_conn_expired); conn->run(); return true; } return true; }
void acl_master_status_init(ACL_MASTER_SERV *serv) { const char *myname = "acl_master_status_init"; /* * Sanity checks. */ if (serv->status_fd[0] >= 0 || serv->status_fd[1] >= 0) acl_msg_panic("%s: status events already enabled", myname); if (acl_msg_verbose) acl_msg_info("%s: %s", myname, serv->name); /* * Make the read end of this service's status pipe non-blocking so that * we can detect partial writes on the child side. We use a duplex pipe * so that the child side becomes readable when the master goes away. */ if (acl_duplex_pipe(serv->status_fd) < 0) acl_msg_fatal("pipe: %s", strerror(errno)); acl_non_blocking(serv->status_fd[0], ACL_BLOCKING); acl_close_on_exec(serv->status_fd[0], ACL_CLOSE_ON_EXEC); acl_close_on_exec(serv->status_fd[1], ACL_CLOSE_ON_EXEC); serv->status_read_stream = acl_vstream_fdopen(serv->status_fd[0], O_RDWR, acl_var_master_buf_size, acl_var_master_rw_timeout, ACL_VSTREAM_TYPE_SOCK); if (acl_msg_verbose) acl_msg_info("%s(%d)->%s: call acl_event_enable_read, " "status_fd = %d", __FILE__, __LINE__, myname, serv->status_fd[0]); acl_event_enable_read(acl_var_master_global_event, serv->status_read_stream, 0, master_status_event, (void *) serv); }
static bool connect_server(acl::polarssl_conf* ssl_conf, IO_CTX* ctx, int id) { // 开始异步连接远程服务器 acl::aio_socket_stream* stream = acl::aio_socket_stream::open( ctx->handle, ctx->addr, ctx->connect_timeout); if (stream == NULL) { std::cout << "connect " << ctx->addr << " error!" << std::endl; std::cout << "stoping ..." << std::endl; if (id == 0) ctx->handle->stop(); return false; } acl_non_blocking(stream->sock_handle(), ACL_BLOCKING); // 创建连接后的回调函数类 client_io_callback* callback = new client_io_callback(stream, ssl_conf, ctx, id); // 添加连接成功的回调函数类 stream->add_open_callback(callback); // 添加连接失败后回调函数类 stream->add_close_callback(callback); // 添加连接超时的回调函数类 stream->add_timeout_callback(callback); return true; }
socket_stream& socket_stream::set_tcp_non_blocking(bool on) { ACL_SOCKET sock = sock_handle(); if (sock == ACL_SOCKET_INVALID) { logger_error("invalid socket handle"); return *this; } (void) acl_non_blocking(sock, on ? ACL_NON_BLOCKING : ACL_BLOCKING); return *this; }
int acl_stream_connect(const char *path, int block_mode, int unused_timeout) { const char *myname = "acl_stream_connect"; #ifdef ACL_FREEBSD path = path; block_mode = block_mode; unused_timeout = unused_timeout; acl_msg_fatal("%s(%d): not support!", myname, __LINE__); return -1; #else int pair[2]; int fifo; unused_timeout = unused_timeout; /* * The requested file system object must exist, otherwise we can't reach * the server. */ if ((fifo = open(path, O_WRONLY | O_NONBLOCK, 0)) < 0) return -1; /* * Create a pipe, and send one pipe end to the server. */ if (pipe(pair) < 0) acl_msg_fatal("%s: pipe: %s", myname, acl_last_serror()); if (ioctl(fifo, I_SENDFD, pair[1]) < 0) acl_msg_fatal("%s: send file descriptor: %s", myname, acl_last_serror()); close(pair[1]); /* * This is for {unix,inet}_connect() compatibility. */ if (block_mode == ACL_NON_BLOCKING) acl_non_blocking(pair[0], ACL_NON_BLOCKING); /* * Cleanup. */ close(fifo); /* * Keep the other end of the pipe. */ return pair[0]; #endif /* ACL_FREEBSD */ }
void ClientConnection::run() { // 必须先将套接置为阻塞状态,否则接收者调用读时会立刻返回 -1 acl_non_blocking(conn_->sock_handle(), ACL_BLOCKING); // 调用描述字发送过程将客户端套接字传给服务端 if (ManagerTimer::transfer(this) == false) // 如果传输描述字失败,则加入待处理队列,由定时器 // 进行处理 ClientManager::get_instance().set(this); else { // 尝试从集合中删除 ClientManager::get_instance().del(this); delete this; } }
ACL_SOCKET acl_unix_listen(const char *addr, int backlog, int block_mode) { #undef sun struct sockaddr_un sun; int len = strlen(addr); ACL_SOCKET sock; char tbuf[256]; /* * Translate address information to internal form. */ if (len >= (int) sizeof(sun.sun_path)) acl_msg_fatal("unix-domain name too long: %s", addr); memset((char *) &sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; #ifdef HAS_SUN_LEN sun.sun_len = len + 1; #endif memcpy(sun.sun_path, addr, len + 1); /* * Create a listener socket. Do whatever we can so we don't run into * trouble when this process is restarted after crash. */ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == ACL_SOCKET_INVALID) acl_msg_fatal("socket: %s", acl_last_strerror(tbuf, sizeof(tbuf))); (void) unlink(addr); if (bind(sock, (struct sockaddr *) & sun, sizeof(sun)) < 0) acl_msg_fatal("bind: %s: %s", addr, acl_last_strerror(tbuf, sizeof(tbuf))); #ifdef FCHMOD_UNIX_SOCKETS if (fchmod(sock, 0666) < 0) acl_msg_fatal("fchmod socket %s: %s", addr, acl_last_strerror(tbuf, sizeof(tbuf))); #else if (chmod(addr, 0666) < 0) acl_msg_fatal("chmod socket %s: %s", addr, acl_last_strerror(tbuf, sizeof(tbuf))); #endif acl_non_blocking(sock, block_mode); if (listen(sock, backlog) < 0) acl_msg_fatal("listen: %s", acl_last_strerror(tbuf, sizeof(tbuf))); return (sock); }
bool master_service::on_accept(acl::aio_socket_stream* client) { if (0) logger("connect from %s, fd %d", client->get_peer(true), client->sock_handle()); acl_non_blocking(client->sock_handle(), ACL_BLOCKING); IConnection* conn; // 根据客户端连接服务端口号的不同来区分不同的服务应用协议 const char* local = client->get_local(true); if (acl_strrncasecmp(local, var_cfg_backend_service, strlen(var_cfg_backend_service)) == 0) { // 创建服务对象处理来自于后端服务模块的请求 conn = new ServerConnection(client); } else if (acl_strrncasecmp(local, var_cfg_status_service, strlen(var_cfg_status_service)) == 0) { const char* ip = client->get_peer(); if (ip == NULL || *ip == 0) { logger_error("can't get peer ip"); return false; } if (allow_list::get_instance().allow_manager(ip) == false) { logger_warn("deny manager ip: %s", ip); return false; } // 创建服务对象处理状态汇报的请求 conn = new StatusConnection(client); } else // 创建对象处理来自于前端客户端模块的请求 conn = new ClientConnection(client, var_cfg_conn_expired); conn->run(); return true; }
int main(void) { const char *addr = "0.0.0.0:8089"; ACL_VSTREAM *sstream = acl_vstream_listen(addr, 128); fiber_init(); if (sstream == NULL) { printf("acl_vstream_listen error %s\r\n", acl_last_serror()); return 1; } acl_non_blocking(ACL_VSTREAM_SOCK(sstream), ACL_NON_BLOCKING); printf("%s: call fiber_creater\r\n", __FUNCTION__); fiber_create(fiber_accept, sstream, 32768); printf("call fiber_schedule\r\n"); fiber_schedule(); return 0; }
static int vstream_client(void) { const char *myname = "vstream_client"; ACL_VSTREAM *client; char ebuf[256], buf[4096]; int n, dlen = 0; printf("addr: %s, timeout: %d\n", addr, timeout); client = acl_vstream_connect(addr, ACL_NON_BLOCKING, timeout, timeout, 1024); if (client == NULL) { printf("%s(%d): connect addr %s error(%s)\n", myname, __LINE__, addr, acl_last_strerror(ebuf, sizeof(ebuf))); return (-1); } printf("%s: connect %s ok\r\n", myname, addr); acl_non_blocking(ACL_VSTREAM_SOCK(client), ACL_BLOCKING); n = acl_write_wait(ACL_VSTREAM_SOCK(client), 10); if (n < 0) { printf("connect timeout: %s\n", acl_last_serror()); goto END; } acl_vstream_fprintf(client, "hello world\n"); while (1) { n = acl_vstream_read(client, buf, sizeof(buf)); if (n == ACL_VSTREAM_EOF) { printf("read over: %s\n", acl_last_serror()); break; } dlen += n; buf[n] = 0; printf("read reply: %s\n", buf); } END: acl_vstream_close(client); printf("%s: read %d\n", myname, dlen); return (0); }
ACL_VSTREAM *acl_vstream_listen_ex(const char *addr, int qlen, int block_mode, int io_bufsize, int io_timeout) { const char *myname = "acl_vstream_listen_ex"; ACL_SOCKET listenfd; struct sockaddr_in local; ACL_VSTREAM *listen_stream; int len; if (addr == 0 || *addr == 0 || qlen <= 0) { acl_msg_error("%s: input invalid", myname); return NULL; } #ifdef ACL_UNIX /* this maybe unix addr, such as '/home/test/listen.sock' */ if (strchr(addr, '/') != NULL) { listenfd = acl_unix_listen(addr, qlen, 0); if (listenfd == ACL_SOCKET_INVALID) return NULL; acl_non_blocking(listenfd, block_mode); listen_stream = acl_vstream_fdopen(listenfd, ACL_VSTREAM_FLAG_RW, io_bufsize, io_timeout, ACL_VSTREAM_TYPE_LISTEN_UNIX); if (listen_stream == NULL) { acl_socket_close(listenfd); acl_msg_error("%s: open vstream error, addr(%s)", myname, addr); return NULL; } acl_vstream_set_local(listen_stream, addr); sprintf(listen_stream->errbuf, "+OK"); return (listen_stream); } #endif /* addr such as '192.168.0.1:80' */ listenfd = acl_inet_listen(addr, qlen, block_mode); if (listenfd == ACL_SOCKET_INVALID) { acl_msg_error("%s: listen addr(%s) error(%s)", myname, addr, acl_last_serror()); return NULL; } listen_stream = acl_vstream_fdopen(listenfd, ACL_VSTREAM_FLAG_RW, io_bufsize, io_timeout, ACL_VSTREAM_TYPE_LISTEN_INET); if (listen_stream == NULL) { acl_socket_close(listenfd); acl_msg_error("%s: open vstream error addr(%s)", myname, addr); return NULL; } memset(&local, 0, sizeof(local)); len = (int) sizeof(struct sockaddr); if (getsockname(listenfd, (struct sockaddr*) &local, (socklen_t *) &len) < 0) { acl_msg_warn("%s: getsockname error(%s) for sock(%d)", myname, acl_last_serror(), listenfd); acl_vstream_set_local(listen_stream, addr); } else { char ip[32], buf[64]; int port; acl_inet_ntoa(local.sin_addr, ip, sizeof(ip)); port = ntohs(local.sin_port); snprintf(buf, sizeof(buf), "%s:%d", ip, port); acl_vstream_set_local(listen_stream, buf); } sprintf(listen_stream->errbuf, "+OK"); return listen_stream; }
ACL_SOCKET acl_inet_listen(const char *addr, int backlog, int block_mode) { const char *myname = "acl_inet_listen"; ACL_SOCKET sock; int on, nport; char *buf, *host = NULL, *sport = NULL; const char *ptr; struct sockaddr_in sa; /* * Translate address information to internal form. */ buf = acl_mystrdup(addr); ptr = acl_host_port(buf, &host, "", &sport, (char *) 0); if (ptr) { acl_msg_error("%s(%d): %s, %s invalid", myname, __LINE__, addr, ptr); acl_myfree(buf); return ACL_SOCKET_INVALID; } if (host && *host == 0) host = 0; if (host == NULL) host = "0.0.0.0"; if (sport == NULL) { acl_msg_error("%s(%d): no port given from addr(%s)", myname, __LINE__, addr); acl_myfree(buf); return ACL_SOCKET_INVALID; } nport = atoi(sport); if (nport < 0) { acl_msg_error("%s: port(%d) < 0 invalid from addr(%s)", myname, nport, addr); acl_myfree(buf); return ACL_SOCKET_INVALID; } memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons((short) nport); sa.sin_addr.s_addr = inet_addr(host); acl_myfree(buf); /* Create a listener socket. */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == ACL_SOCKET_INVALID) { acl_msg_error("%s: socket %s", myname, acl_last_serror()); return ACL_SOCKET_INVALID; } on = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) { acl_msg_error("%s: setsockopt(SO_REUSEADDR): %s", myname, acl_last_serror()); } if (bind(sock, (struct sockaddr *) &sa, sizeof(struct sockaddr)) < 0) { acl_msg_error("%s: bind %s error %s", myname, addr, acl_last_serror()); acl_socket_close(sock); return ACL_SOCKET_INVALID; } acl_non_blocking(sock, block_mode); if (listen(sock, backlog) < 0) { acl_msg_error("%s: listen error: %s, addr(%s)", myname, acl_last_serror(), addr); acl_socket_close(sock); return ACL_SOCKET_INVALID; } return sock; }
void acl_master_sigsetup(void) { char *myname = "acl_master_sigsetup"; struct sigaction action; static int sigs[] = { SIGINT, SIGQUIT, SIGILL, SIGBUS, /* SIGSEGV, only for test */ SIGTERM, }; unsigned i; sigemptyset(&action.sa_mask); action.sa_flags = 0; /* * Prepare to kill our children * when we receive any of the above signals. */ action.sa_handler = master_sigdeath; for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++) if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0) acl_msg_fatal("%s: sigaction(%d): %s", myname, sigs[i], strerror(errno)); #ifdef USE_SIG_PIPE if (pipe(acl_master_sig_pipe)) acl_msg_fatal("pipe: %s", strerror(errno)); acl_non_blocking(ACL_SIG_PIPE_WRITE_FD, ACL_NON_BLOCKING); acl_non_blocking(ACL_SIG_PIPE_READ_FD, ACL_NON_BLOCKING); acl_close_on_exec(ACL_SIG_PIPE_WRITE_FD, ACL_CLOSE_ON_EXEC); acl_close_on_exec(ACL_SIG_PIPE_READ_FD, ACL_CLOSE_ON_EXEC); ACL_SIG_PIPE_READ_STREAM = acl_vstream_fdopen(ACL_SIG_PIPE_READ_FD, O_RDONLY, acl_var_master_buf_size, acl_var_master_rw_timeout, ACL_VSTREAM_TYPE_SOCK); if (ACL_SIG_PIPE_READ_STREAM == NULL) acl_msg_fatal("%s(%d)->%s: acl_vstream_fdopen error=%s", __FILE__, __LINE__, myname, strerror(errno)); if (acl_msg_verbose) acl_msg_info("%s(%d)->%s: call acl_event_enable_read, " "SIG_PIPE_READ_FD = %d", __FILE__, __LINE__, myname, ACL_SIG_PIPE_READ_FD); acl_event_enable_read(acl_var_master_global_event, ACL_SIG_PIPE_READ_STREAM, 0, master_sig_event, (void *) 0); #endif /* * Intercept SIGHUP (re-read config file) and SIGCHLD (child exit). */ #ifdef SA_RESTART action.sa_flags |= SA_RESTART; #endif action.sa_handler = master_sighup; if (sigaction(SIGHUP, &action, (struct sigaction *) 0) < 0) acl_msg_fatal("%s: sigaction(%d): %s", myname, SIGHUP, strerror(errno)); action.sa_flags |= SA_NOCLDSTOP; action.sa_handler = master_sigchld; if (sigaction(SIGCHLD, &action, (struct sigaction *) 0) < 0) acl_msg_fatal("%s: sigaction(%d): %s", myname, SIGCHLD, strerror(errno)); }
int acl_fifo_listen(const char *path, int permissions, int block_mode) { char *myname = "acl_fifo_listen"; char buf[BUF_LEN], tbuf[256]; static int open_mode = 0; struct stat st; int fd; int count; /* * Create a named pipe (fifo). Do whatever we can so we don't run into * trouble when this process is restarted after crash. Make sure that * we open a fifo and not something else, then change permissions to * what we wanted them to be, because mkfifo() is subject to umask * settings. Instead we could zero the umask temporarily before * creating the FIFO, but that would cost even more system calls. * Figure out if the fifo needs to be opened O_RDWR or O_RDONLY. Some * systems need one, some need the other. If we choose the wrong mode, * the fifo will stay readable, causing the program to go into a loop. */ if (unlink(path) && acl_last_error() != ENOENT) { acl_msg_error("%s: remove %s: %s", myname, path, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (mkfifo(path, permissions) < 0) { acl_msg_error("%s: create fifo %s: %s", myname, path, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } switch (open_mode) { case 0: if ((fd = open(path, O_RDWR | O_NONBLOCK, 0)) < 0) { acl_msg_error("%s: open %s: %s", myname, path, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (acl_readable(fd) == 0) { open_mode = O_RDWR | O_NONBLOCK; break; } open_mode = O_RDONLY | O_NONBLOCK; if (acl_msg_verbose) acl_msg_info("open O_RDWR makes fifo readable" " - trying O_RDONLY"); (void) close(fd); if ((fd = open(path, open_mode, 0)) < 0) { acl_msg_error("%s: open %s: %s", myname, path, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } break; default: if ((fd = open(path, open_mode, 0)) < 0) { acl_msg_error("%s: open %s: %s", myname, path, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } break; } /* * Make sure we opened a FIFO and skip any cruft that might have * accumulated before we opened it. */ if (fstat(fd, &st) < 0) { acl_msg_error("%s: fstat %s: %s", myname, path, acl_last_strerror(tbuf, sizeof(tbuf))); close(fd); return -1; } if (S_ISFIFO(st.st_mode) == 0) { acl_msg_error("%s: not a fifo: %s", myname, path); close(fd); return -1; } if (fchmod(fd, permissions) < 0) { acl_msg_error("%s: fchmod %s: %s", myname, path, acl_last_strerror(tbuf, sizeof(tbuf))); close(fd); return -1; } acl_non_blocking(fd, block_mode); while ((count = acl_peekfd(fd)) > 0 && read(fd, buf, BUF_LEN < count ? BUF_LEN : count) > 0) { } return fd; }