Пример #1
0
	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;
	}
Пример #2
0
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);
}
Пример #3
0
	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);
	}
Пример #4
0
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;
	}
}
Пример #5
0
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);
}
Пример #6
0
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);
}
Пример #7
0
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);
}
Пример #8
0
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;
}
Пример #9
0
	ACL_FILE_HANDLE fstream::file_handle() const
	{
		return (ACL_VSTREAM_FILE(m_pStream));
	}