void fstream::open(ACL_FILE_HANDLE fh, unsigned int oflags) { acl_assert(ACL_VSTREAM_FILE(m_pStream) == ACL_FILE_INVALID); m_pStream->fread_fn = acl_file_read; m_pStream->fwrite_fn = acl_file_write; m_pStream->fwritev_fn = acl_file_writev; m_pStream->fclose_fn = acl_file_close; m_pStream->fd.h_file = fh; m_pStream->type = ACL_VSTREAM_TYPE_FILE; m_pStream->oflags = oflags; m_bOpened = true; m_bEof = false; }
ACL_VSTREAM *local_listen() { const char *myname = "local_listen"; char lock_file[MAX_PATH], ebuf[256]; ACL_VSTREAM *sstream, *fp; ACL_FILE_HANDLE handle; get_lock_file(lock_file, sizeof(lock_file)); fp = acl_vstream_fopen(lock_file, O_RDWR | O_CREAT, 0600, 1024); if (fp == NULL) acl_msg_fatal("%s(%d): open file(%s) error(%s)", myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); handle = ACL_VSTREAM_FILE(fp); if (acl_myflock(handle, 0, ACL_MYFLOCK_OP_EXCLUSIVE | ACL_MYFLOCK_OP_NOWAIT) == -1) { acl_msg_error("%s(%d): lock file(%s) error(%s)", myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); return (NULL); } sstream = acl_vstream_listen_ex("127.0.0.1:0", 128, ACL_BLOCKING, 1024, 0); if (sstream == NULL) acl_msg_fatal("%s(%d): listen error(%s)", myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); if (acl_file_ftruncate(fp, 0) < 0) acl_msg_fatal("%s(%d): truncate file(%s) error(%s)", myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); if (acl_vstream_fseek(fp, 0, SEEK_SET) < 0) acl_msg_fatal("%s(%d): fseek file(%s) error(%s)", myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); if (acl_vstream_fprintf(fp, "%s\r\n", sstream->local_addr) == ACL_VSTREAM_EOF) acl_msg_fatal("%s(%d): fprintf to file(%s) error(%s)", myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); /* XXX: 只能采用先解排它锁,再加共享锁,微软比较弱!!! */ if (acl_myflock(handle, 0, ACL_MYFLOCK_OP_NONE) == -1) acl_msg_fatal("%s(%d): unlock file(%s) error(%s)", myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); if (acl_myflock(handle, 0, ACL_MYFLOCK_OP_SHARED | ACL_MYFLOCK_OP_NOWAIT) == -1) acl_msg_fatal("%s(%d): lock file(%s) error(%s)", myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); return (sstream); }
bool fstream::close() { if (m_bOpened == false) return (false); if (m_pStream == NULL) return (true); if (m_pStream->type != ACL_VSTREAM_TYPE_FILE) return (false); ACL_FILE_HANDLE fh = ACL_VSTREAM_FILE(m_pStream); if (fh == ACL_FILE_INVALID) return (false); m_bEof = true; m_bOpened = false; return (acl_file_close(fh) == 0 ? true : false); }
static void master_status_event(int event, void *context) { const char *myname = "master_status_event"; ACL_MASTER_SERV *serv = (ACL_MASTER_SERV *) context; ACL_MASTER_STATUS stat_buf; ACL_MASTER_PROC *proc; ACL_MASTER_PID pid; int n; if (event == 0) /* XXX Can this happen? */ return; /* * We always keep the child end of the status pipe open, so an EOF read * condition means that we're seriously confused. We use non-blocking * reads so that we don't get stuck when someone sends a partial message. * Messages are short, so a partial read means someone wrote less than a * whole status message. Hopefully the next read will be in sync again... * We use a global child process status table because when a child dies * only its pid is known - we do not know what service it came from. */ #if 1 n = read(ACL_VSTREAM_FILE(serv->status_read_stream), (char *) &stat_buf, sizeof(stat_buf)); #else n = acl_vstream_readn(serv->status_read_stream, (char *) &stat_buf, sizeof(stat_buf)); #endif switch (n) { case -1: acl_msg_warn("%s(%d)->%s: fd = %d, read: %s", __FILE__, __LINE__, myname, serv->status_fd[0], strerror(errno)); return; case 0: acl_msg_panic("%s(%d)->%s: fd = %d, read EOF status", __FILE__, __LINE__, myname, serv->status_fd[0]); /* NOTREACHED */ default: acl_msg_warn("%s(%d)->%s: service %s: child (pid %d) " "sent partial, fd = %d, status update (%d bytes)", __FILE__, __LINE__, myname, serv->name, stat_buf.pid, serv->status_fd[0], n); return; case sizeof(stat_buf): pid = stat_buf.pid; if (acl_msg_verbose) acl_msg_info("%s: pid = %d, gen = %u, avail = %d, " "fd = %d", myname, stat_buf.pid, stat_buf.gen, stat_buf.avail, serv->status_fd[0]); } /* end switch */ /* * Sanity checks. Do not freak out when the child sends garbage because * it is confused or for other reasons. However, be sure to freak out * when our own data structures are inconsistent. A process not found * condition can happen when we reap a process before receiving its * status update, so this is not an error. */ if (acl_var_master_child_table == 0) acl_msg_fatal("%s(%d): acl_var_master_child_table null", myname, __LINE__); if ((proc = (ACL_MASTER_PROC *) acl_binhash_find( acl_var_master_child_table, (char *) &pid, sizeof(pid))) == 0) { acl_msg_warn("%s(%d)->%s: process id not found: pid = %d," " status = %d, gen = %u", __FILE__, __LINE__, myname, stat_buf.pid, stat_buf.avail, stat_buf.gen); return; } if (proc->gen != stat_buf.gen) { acl_msg_warn("%s(%d)->%s: ignoring status update from child " "pid %d generation %u", __FILE__, __LINE__, myname, pid, stat_buf.gen); return; } if (proc->serv != serv) acl_msg_panic("%s(%d)->%s: pointer corruption: %p != %p", __FILE__, __LINE__, myname, (void *) proc->serv, (void *) serv); /* * Update our idea of the child process status. Allow redundant status * updates, because different types of events may be processed out of * order. Otherwise, warn about weird status updates but do not take * action. It's all gossip after all. */ if (proc->avail == stat_buf.avail) return; switch (stat_buf.avail) { case ACL_MASTER_STAT_AVAIL: proc->use_count++; acl_master_avail_more(serv, proc); break; case ACL_MASTER_STAT_TAKEN: acl_master_avail_less(serv, proc); break; default: acl_msg_warn("%s(%d)->%s: ignoring unknown status: %d " "allegedly from pid: %d", __FILE__, __LINE__, myname, stat_buf.pid, stat_buf.avail); break; } }
static int __vstream_sys_read(ACL_VSTREAM *stream) { if (stream == NULL) return (-1); if (stream->type == ACL_VSTREAM_TYPE_FILE) { if (ACL_VSTREAM_FILE(stream) == ACL_FILE_INVALID) return (-1); } else if (ACL_VSTREAM_SOCK(stream) == ACL_SOCKET_INVALID) return (-1); AGAIN: if (stream->rw_timeout > 0 && __read_wait(ACL_VSTREAM_SOCK(stream), stream->rw_timeout) < 0) { stream->errnum = acl_last_error(); if (stream->errnum != ACL_ETIMEDOUT) { (void) acl_strerror(stream->errnum, stream->errbuf, sizeof(stream->errbuf)); stream->flag |= ACL_VSTREAM_FLAG_ERR; } else { stream->flag |= ACL_VSTREAM_FLAG_TIMEOUT; ACL_SAFE_STRNCPY(stream->errbuf, "read timeout", sizeof(stream->errbuf)); } return (-1); } acl_set_error(0); if (stream->type == ACL_VSTREAM_TYPE_FILE) { stream->read_cnt = stream->fread_fn(ACL_VSTREAM_FILE(stream), stream->read_buf, (size_t) stream->read_buf_len, stream->rw_timeout, stream, stream->context); if (stream->read_cnt > 0) stream->sys_offset += stream->read_cnt; } else stream->read_cnt = stream->read_fn(ACL_VSTREAM_SOCK(stream), stream->read_buf, (size_t) stream->read_buf_len, stream->rw_timeout, stream, stream->context); if (stream->read_cnt < 0) { stream->errnum = acl_last_error(); if (stream->errnum == ACL_EINTR) { goto AGAIN; } else if (stream->errnum == ACL_ETIMEDOUT) { stream->flag |= ACL_VSTREAM_FLAG_TIMEOUT; ACL_SAFE_STRNCPY(stream->errbuf, "read timeout", sizeof(stream->errbuf)); } else if (stream->errnum != ACL_EWOULDBLOCK && stream->errnum != ACL_EAGAIN) { stream->flag |= ACL_VSTREAM_FLAG_ERR; acl_strerror(stream->errnum, stream->errbuf, sizeof(stream->errbuf)); } /* XXX: should do something where, 2009.12.25 -- zsx */ stream->read_cnt = 0; /* xxx: why? */ return (-1); } else if (stream->read_cnt == 0) { /* closed by peer */ stream->flag = ACL_VSTREAM_FLAG_EOF; stream->errnum = 0; snprintf(stream->errbuf, sizeof(stream->errbuf), "closed by peer(%s)", acl_last_serror()); return (0); } stream->read_ptr = stream->read_buf; stream->flag &= ~ACL_VSTREAM_FLAG_BAD; stream->errnum = 0; stream->errbuf[0] = 0; stream->total_read_cnt += stream->read_cnt; return ((int) stream->read_cnt); }
static int __vstream_sys_write(ACL_VSTREAM *stream, const void *vptr, int dlen) { int n, neintr = 0; acl_assert(stream && vptr && dlen > 0); if (stream->type == ACL_VSTREAM_TYPE_FILE) { if (ACL_VSTREAM_FILE(stream) == ACL_FILE_INVALID) return (ACL_VSTREAM_EOF); } else if (ACL_VSTREAM_SOCK(stream) == ACL_SOCKET_INVALID) return (ACL_VSTREAM_EOF); TAG_AGAIN: if (stream->type == ACL_VSTREAM_TYPE_FILE) { if ((stream->oflags & O_APPEND)) { #ifdef ACL_WINDOWS stream->sys_offset = acl_lseek( ACL_VSTREAM_FILE(stream), 0, SEEK_END); if (stream->sys_offset < 0) return (ACL_VSTREAM_EOF); #endif } else if ((stream->flag & ACL_VSTREAM_FLAG_CACHE_SEEK) && stream->offset != stream->sys_offset) { stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), stream->offset, SEEK_SET); if (stream->sys_offset == -1) return (ACL_VSTREAM_EOF); stream->offset = stream->sys_offset; } n = stream->fwrite_fn(ACL_VSTREAM_FILE(stream), vptr, dlen, stream->rw_timeout, stream, stream->context); if (n > 0) { stream->sys_offset += n; stream->offset = stream->sys_offset; /* 防止缓冲区内的数据与实际不一致, 仅对文件IO有效 */ stream->read_cnt = 0; } } else n = stream->write_fn(ACL_VSTREAM_SOCK(stream), vptr, dlen, stream->rw_timeout, stream, stream->context); if (n < 0) { if (acl_last_error() == ACL_EINTR) { if (++neintr >= 5) return (ACL_VSTREAM_EOF); goto TAG_AGAIN; } if (acl_last_error() == ACL_EAGAIN || acl_last_error() == ACL_EWOULDBLOCK) { acl_set_error(ACL_EAGAIN); } return (ACL_VSTREAM_EOF); } stream->total_write_cnt += n; return (n); }
static void test_fseek2(int buflen) { ACL_VSTREAM *fp; ACL_VSTRING *why = acl_vstring_alloc(100); char filename[] ="./tmp.txt"; char buf[10]; int n; int offset, off2; int ch; fp = acl_safe_open(filename, O_CREAT | O_RDWR, 0600, (struct stat *) 0, (uid_t)-1, (uid_t )-1, why); if (fp == 0) acl_msg_fatal("%s(%d)->%s: can't open %s, serr = %s", __FILE__, __LINE__, __FUNCTION__, filename, acl_vstring_str(why)); fp->read_buf_len = buflen; ch = acl_vstream_getc(fp); printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", __LINE__, ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, offset=%d, %d\n\n", __LINE__, ch, (int)fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); ch = acl_vstream_getc(fp); printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", __LINE__, ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, %s, offset=%d, %d\n\n", __LINE__, ch, (int)fp->read_cnt, offset, strerror(errno), (int) fp->offset, (int) fp->sys_offset); offset = acl_vstream_fseek2(fp, 10, SEEK_CUR); off2 = lseek(ACL_VSTREAM_FILE(fp), 0, SEEK_CUR); printf("after fseek(10)(%d) >>> off=%d, lseek = %d, read_cnt = %d, offset=%d, %d\n\n", __LINE__, offset, off2, (int)fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); n = acl_vstream_gets_nonl(fp, buf, sizeof(buf) - 1); printf("after read(getline)(%d) >>> buf = [%s], fp->read_cnt = %d, offset=%d, %d\n", __LINE__, buf, (int)fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); printf("after fseek(0)(%d) >>> buf = [%s], read_cnt = %d, off = %d, offset=%d, %d\n\n", __LINE__, buf, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); ch = acl_vstream_getc(fp); printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", __LINE__, ch, (int)fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, offset=%d, %d\n\n", __LINE__, ch, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); n = acl_vstream_readn(fp, buf, 2); buf[n] = 0; printf("after read(buf)(%d) >>> buf = [%s], fp->read_cnt = %d, offset=%d, offset=%d, %d\n", __LINE__, buf, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); offset = acl_vstream_fseek2(fp, 10, SEEK_CUR); printf("after fseek(10)(%d) >>> read_cnt = %d, off = %d, offset=%d, %d\n\n", __LINE__, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); ch = acl_vstream_getc(fp); printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", __LINE__, ch, (int)fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, %s, offset=%d, %d\n\n", __LINE__, ch, (int) fp->read_cnt, offset, strerror(errno), (int) fp->offset, (int) fp->sys_offset); acl_vstring_free(why); acl_vstream_close(fp); }
static void stream_on_close(ACL_VSTREAM *stream, void *arg) { const char *myname = "stream_on_close"; EVENT_KERNEL *ev = (EVENT_KERNEL*) arg; ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE*) stream->fdp; ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); BOOL is_completed; if (fdp == NULL) acl_msg_fatal("%s(%d): fdp null, sockfd(%d)", myname, __LINE__, sockfd); if (fdp->h_iocp != NULL) { fdp->h_iocp = NULL; fdp->flag &= ~EVENT_FDTABLE_FLAG_IOCP; } /* windows xp 环境下,必须在关闭套接字之前调用此宏判断重叠 IO * 是否处于 STATUS_PENDING 状态 */ is_completed = HasOverlappedIoCompleted(&fdp->event_read->overlapped); /* 必须在释放 fdp->event_read/fdp->event_write 前关闭套接口句柄 */ if (ACL_VSTREAM_SOCK(stream) != ACL_SOCKET_INVALID && stream->close_fn) { (void) stream->close_fn(ACL_VSTREAM_SOCK(stream)); } else if (ACL_VSTREAM_FILE(stream) != ACL_FILE_INVALID && stream->fclose_fn) { (void) stream->fclose_fn(ACL_VSTREAM_FILE(stream)); } ACL_VSTREAM_SOCK(stream) = ACL_SOCKET_INVALID; ACL_VSTREAM_FILE(stream) = ACL_FILE_INVALID; if (fdp->event_read) { /* 如果完成端口处于未决状态,则不能释放重叠结构,需在主循环的 * GetQueuedCompletionStatus 调用后来释放 */ if (is_completed) acl_myfree(fdp->event_read); else { fdp->event_read->type = IOCP_EVENT_DEAD; fdp->event_read->fdp = NULL; } fdp->event_read = NULL; } if (fdp->event_write) { /* 如果完成端口处于未决状态,则不能释放重叠结构,需在主循环的 * GetQueuedCompletionStatus 调用后来释放 */ if (HasOverlappedIoCompleted(&fdp->event_write->overlapped)) acl_myfree(fdp->event_write); else { fdp->event_write->type = IOCP_EVENT_DEAD; fdp->event_write->fdp = NULL; } fdp->event_write = NULL; } if ((fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { fdp->flag &= ~EVENT_FDTABLE_FLAG_DELAY_OPER; acl_ring_detach(&fdp->delay_entry); } if (ev->event.maxfd == ACL_VSTREAM_SOCK(fdp->stream)) ev->event.maxfd = ACL_SOCKET_INVALID; if (fdp->fdidx >= 0 && fdp->fdidx < --ev->event.fdcnt) { ev->event.fdtabs[fdp->fdidx] = ev->event.fdtabs[ev->event.fdcnt]; ev->event.fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; } fdp->fdidx = -1; if (fdp->fdidx_ready >= 0 && fdp->fdidx_ready < ev->event.fdcnt_ready && ev->event.fdtabs_ready[fdp->fdidx_ready] == fdp) { ev->event.fdtabs_ready[fdp->fdidx_ready] = NULL; } fdp->fdidx_ready = -1; event_fdtable_free(fdp); stream->fdp = NULL; }
ACL_FILE_HANDLE fstream::file_handle() const { return (ACL_VSTREAM_FILE(m_pStream)); }