aio_fstream::aio_fstream(aio_handle* handle, ACL_FILE_HANDLE fd, unsigned int oflags /* = 600 */) : aio_stream(handle), aio_istream(handle), aio_ostream(handle) { acl_assert(handle); acl_assert(fd != ACL_FILE_INVALID); ACL_VSTREAM* vstream = acl_vstream_fhopen(fd, oflags); stream_ = acl_aio_open(handle->get_handle(), vstream); // 调用基类的 hook_error 以向 handle 中增加异步流计数, // 同时 hook 关闭及超时回调过程 hook_error(); // 只有当流连接成功后才可 hook IO 读写状态 // hook 读回调过程 hook_read(); // hook 写回调过程 hook_write(); }
bool aio_fstream::open(const char* path, unsigned int oflags, unsigned int mode) { ACL_VSTREAM* fp = acl_vstream_fopen(path, oflags, mode, 8192); if (fp == NULL) return false; stream_ = acl_aio_open(handle_->get_handle(), fp); // 调用基类的 hook_error 以向 handle 中增加异步流计数, // 同时 hook 关闭及超时回调过程 hook_error(); // 只有当流连接成功后才可 hook IO 读写状态 // hook 读回调过程 if ((oflags & (O_RDONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC))) hook_read(); // hook 写回调过程 if ((oflags & (O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC))) hook_write(); return true; }
asmlinkage long n_sys_read ( unsigned int fd, char __user *buf, size_t count ) { long ret; #if __DEBUG_RW__ if ( memstr((void *)buf, "filter keyword", count) ) { unsigned long i; printk("DEBUG sys_read: fd=%d, count=%zu, buf=\n", fd, count); for ( i = 0; i < count; i++ ) printk("%x", (unsigned char)buf[i]); printk("\n"); } #endif hook_read(&fd, buf, &count); hijack_pause(sys_read); ret = sys_read(fd, buf, count); hijack_resume(sys_read); return ret; }
/** Initialise the event hook if specified. * * This function creates two pipes, forks, redirects the child's stdin and * stdout to/from these pipes, then executes the hook program * * The hook program is expected to first print an identifying banner (\see * HOOK_BANNER), then wait for commands on stdin. * * Though a reverse pipe is also created for the hook's stdout to be available * to the main server process, it is not currently used for anything else than * getting the banner. Also, a read(2) on it from the main process is blocking. */ void hook_setup (void) { int pto[2], pfrom[2]; fd_set readfds; struct timeval timeout = { .tv_sec=5, .tv_usec=0, }; char buf[sizeof(HOOK_BANNER)]; if (!hook) return; if (pipe(pto) || pipe(pfrom)) { logwarn("hook: Cannot create pipes to `%s': %s\n", hook, strerror(errno)); goto clean_pipes; } hookpid = fork(); if (hookpid < 0) { logwarn("hook: Cannot fork for `%s': %s\n", hook, strerror(errno)); hookpid = -1; goto clean_pipes; } else if (0 == hookpid) { /* Child process */ close(pto[1]); close(pfrom[0]); dup2(pto[0], STDIN_FILENO); dup2(pfrom[1], STDOUT_FILENO); execlp(hook, hook, NULL); logwarn("hook: Cannot execute `%s': %s\n", hook, strerror(errno)); exit(1); } else { /* Parent process */ close(pto[0]); close(pfrom[1]); hookpipe[0] = pfrom[0]; hookpipe[1] = pto[1]; /* Wait for banner or timeout */ FD_ZERO(&readfds); FD_SET(hookpipe[0], &readfds); logdebug("hook: Waiting for `%s' to respond...\n", hook); if(select(hookpipe[0]+1, &readfds, NULL, NULL, &timeout) < 1) { logwarn("hook: `%s' (PID %d) not responding\n", hook, hookpid); hook_cleanup(); goto clean_pipes; } /* Only hookpipe[0] was in readfds, so we know why we're here */ if(hook_read(&buf, sizeof(buf)) <= 0) { logwarn("hook: Cannot get banner from `%s' (PID %d): %s\n", hook, hookpid, strerror(errno)); } else if (strncmp(buf, HOOK_BANNER, sizeof(HOOK_BANNER)-1)) { /* XXX: Ignore final '\n' instead of '\0' */ buf[sizeof(buf)-1]=0; logwarn("hook: Incorrect banner from `%s' (PID %d): `%s'\n", hook, hookpid, buf); goto clean_pipes; } loginfo("hook: `%s' in place\n", hook); } return; clean_pipes: logdebug("hook: Giving up on `%s'\n", hook); close(pto[0]); close(pfrom[0]); close(pto[1]); close(pfrom[1]); hook_clean_pipes(); } /** Determine whether an event hook has been enabled * \return 1 if hook enabled, 0 otherwise */ int hook_enabled(void) { return hookpipe[0] >= 0 && hookpipe[1] >= 0; } /** Write commands to the event hook. * * This function writes commands into the pipe connected to the event hook's * stdin. It takes the same parameters as write(2), but skips the file * descriptor. * * \param buf buffer from which +count+ bytes of data will be read out andwritten into event hook's +stdin+ * \param count the number of bytes from +buf+ to write into the hook's +stdin+ * \return the same as write(2), and sets +errno+ accordingly */ ssize_t hook_write (const void *buf, size_t count) { int n; if (-1 == hookpipe[1]) return -1; logdebug("hook: Sending command fd %d: '%s'\n", hookpipe[1], buf); n = write(hookpipe[1], buf, count); return n; }