Streams

STREAMS是一个framework,使用TPI(Transport Provider Interface,基于STREAMS的在传输层的接口)创建应用。

STREAMS在进程和driver(也可以是一个software driver)之间提供一个full-duplex的连接

当对STREAMS descriptor进行函数调用时(read, putmsg, ioctl),相关的实现由stream head提供。

进程可在stream head和driver之间动态插入和移除processing modules。一个module提供了一个filtering

multiplexor是一个预置的module,它可以从多个源接收数据

  1. 当一个socket被创建,sockmod被sockets library插入到stream中,sockets library和sockmod STREAMS module组合起来提供sockets API给进程
  2. 不同的服务提供不同的消息格式
    TPI定义了transport-layer provider提供的接口(TCP,UDP)
    NPI(Network Provider Interface)定义了network-layer provider提供的接口(IP)
    DLPI(Data Link Provider Interface)

stream中的所有组件:stream head,processing modules,driver都至少包含两个队列:write queue和read queue

Message Types

STREAMS消息分为high priority, priority band, normal。priority band的范围从0-255,normal消息为band 0,优先级用在消息队列和flow control中,如对high-priority消息不受flow control影响。

网络协议一般用band 1当作紧急消息,band 0用作一般消息

TCP的out-of-band用作band 0。

有3种类型的消息要关心一下:

消息分为控制和数据。

#include <stropts.h>
int getmsg(int fd, struct strbuf *ctlptr, struct strbuf *dataptr, int *flagsp) ;

返回0表示所有数据都返回了,如果control buffer太小,返回MORECTL。如果data buffer太小,返回MOREDATA。两者都太小,返回两者的OR
int putmsg(int fd, const struct strbuf *ctlptr, const struct strbuf *dataptr, int flags) ;

错误返回-1,成功返回0

可同时操作控制消息和数据。

struct strbuf
{
         int maxlen;      /* maximum size of buf */
         int len;         /* actual amount of data in buf */
         char *buf;       /* data */
};

如果不发送控制消息,ctlptr=0,或 ctlptr->len = -1

没有控制消息,类型为M_DATA,有控制消息,类型为M_PROTO(flags为0)或M_PCPROTO(flags 为RS_HIPRI)

int putpmsg(int fd, const struct strbuf *ctlptr, const struct strbuf *dataptr, int band, int flags) ;
band在0-255这间,如果flags为MSG_BAND,消息的优先级为指定的band(为0相当于调用putmsg)。flags为MSG_HIPRI,band必须为0,高优先级消息产生。

int getpmsg(int fd, struct strbuf *ctlptr, struct strbuf *dataptr, int *bandp, int *flagsp) ;

flagsp可为MSG_HIPRI(读高优先级消息),MSG_BAND(消息的优先级最少等于bandp),MSG_ANY(读所有消息)

int ioctl(int fd, int request, ... /* void *arg */ ) ;

成功返回0,错误返回-1

Transport Provider Interface (TPI)

提供传输层的接口,在STREAMS环境中sockets和XTI都使用这一接口。它由sockets library和sockmod组成,也由XTI library和timod组成。用TCP和UDP传送TPI消息。

TPI是message-based接口。它定义了进程和传输层传递消息的格式

void tpi_bind(int fd, const void *addr, size_t addrlen)
{
        struct {
            struct T_bind_req msg_hdr;
            char addr[128];
        } bind_req;
        struct {
            struct T_bind_ack msg_hdr;
            char addr[128];
        } bind_ack;
        struct strbuf ctlbuf;
        struct T_error_ack *error_ack;
        int flags;
        bind_req.msg_hdr.PRIM_type = T_BIND_REQ;
        bind_req.msg_hdr.ADDR_length = addrlen;
        bind_req.msg_hdr.ADDR_offset = sizeof(struct T_bind_req);
        bind_req.msg_hdr.CONIND_number = 0;
        memcpy(bind_req.addr, addr, addrlen); /* sockaddr_in{} */
	ctlbuf.len = sizeof(struct T_bind_req) + addrlen;
	ctlbuf.buf = (char *) &bind_req;
	Putmsg(fd, &ctlbuf, NULL, 0);
	ctlbuf.maxlen = sizeof(bind_ack);
	ctlbuf.len = 0;
	ctlbuf.buf = (char *) &bind_ack;
	flags = RS_HIPRI;
	Getmsg(fd, &ctlbuf, NULL, &flags);
	if (ctlbuf.len < (int) sizeof(long))
		err_quit("bad length from getmsg");
	switch (bind_ack.msg_hdr.PRIM_type) {
		case T_BIND_ACK:
			return;
		case T_ERROR_ACK:
			if (ctlbuf.len < (int) sizeof(struct T_error_ack))
				err_quit("bad length for T_ERROR_ACK");
			error_ack = (struct T_error_ack *) &bind_ack.msg_hdr;
			err_quit("T_ERROR_ACK from bind (%d, %d)",
					error_ack->TLI_error, error_ack->UNIX_error);
		default:
			err_quit("unexpected message type: %d", bind_ack.msg_hdr.PRIM_type);
	}
}
void tpi_connect(int fd, const void *addr, size_t addrlen)
{
	struct {
		struct T_conn_req msg_hdr;
		char addr[128];
	} conn_req;
	struct {
		struct T_conn_con msg_hdr;
		char addr[128];
	} conn_con;
	struct strbuf ctlbuf;
	union T_primitives rcvbuf;
	struct T_error_ack *error_ack;
	struct T_discon_ind *discon_ind;
	int flags;
	conn_req.msg_hdr.PRIM_type = T_CONN_REQ;
	conn_req.msg_hdr.DEST_length = addrlen;
	conn_req.msg_hdr.DEST_offset = sizeof(struct T_conn_req);
	conn_req.msg_hdr.OPT_length = 0;
	conn_req.msg_hdr.OPT_offset = 0;
	memcpy(conn_req.addr, addr, addrlen); /* sockaddr_in{} */
	ctlbuf.len = sizeof(struct T_conn_req) + addrlen;
	ctlbuf.buf = (char *) &conn_req;
	Putmsg(fd, &ctlbuf, NULL, 0);
	ctlbuf.maxlen = sizeof(union T_primitives);
	ctlbuf.len = 0;
	ctlbuf.buf = (char *) &rcvbuf;
	flags = RS_HIPRI;
        Getmsg(fd, &ctlbuf, NULL, &flags);
	if (ctlbuf.len < (int) sizeof(long))
		err_quit("tpi_connect: bad length from getmsg");
	switch (rcvbuf.type) {
		case T_OK_ACK:
			break;
		case T_ERROR_ACK:
			if (ctlbuf.len < (int) sizeof(struct T_error_ack))
				err_quit("tpi_connect: bad length for T_ERROR_ACK");
			error_ack = (struct T_error_ack *) &rcvbuf;
			err_quit("tpi_connect: T_ERROR_ACK from conn (%d, %d)",
					error_ack->TLI_error, error_ack->UNIX_error);
		default:
			err_quit("tpi_connect: unexpected message type: %d", rcvbuf.type);
	}
	ctlbuf.maxlen = sizeof(conn_con);
	ctlbuf.len = 0;
	ctlbuf.buf = (char *) &conn_con;
	flags = 0;
	Getmsg(fd, &ctlbuf, NULL, &flags);
	if (ctlbuf.len < (int) sizeof(long))
		err_quit("tpi_connect2: bad length from getmsg");
	switch (conn_con.msg_hdr.PRIM_type) {
		case T_CONN_CON:
			break;
		case T_DISCON_IND:
	if (ctlbuf.len < (int) sizeof(struct T_discon_ind))
				err_quit("tpi_connect2: bad length for T_DISCON_IND");
			discon_ind = (struct T_discon_ind *) &conn_con.msg_hdr;
			err_quit("tpi_connect2: T_DISCON_IND from conn (%d)",
					discon_ind->DISCON_reason);
		default:
			err_quit("tpi_connect2: unexpected message type: %d",
					conn_con.msg_hdr.PRIM_type);
	}
}

ssize_t tpi_read(int fd, void *buf, size_t len)
{
	struct strbuf ctlbuf;
	struct strbuf datbuf;
	union T_primitives rcvbuf;
	int flags;
	976
		Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
		ctlbuf.maxlen = sizeof(union T_primitives);
	ctlbuf.buf = (char *) &rcvbuf;
	datbuf.maxlen = len;
	datbuf.buf = buf;
	datbuf.len = 0;
	flags = 0;
	Getmsg(fd, &ctlbuf, &datbuf, &flags);
	if (ctlbuf.len >= (int) sizeof(long)) {
		if (rcvbuf.type == T_DATA_IND)
			return (datbuf.len);
		else if (rcvbuf.type == T_ORDREL_IND)
			return (0);
		else
			err_quit("tpi_read: unexpected type %d", rcvbuf.type);
	} else if (ctlbuf.len == -1)
		return (datbuf.len);
	else
		err_quit("tpi_read: bad length from getmsg");
}

void tpi_close(int fd)
{
	struct T_ordrel_req ordrel_req;
	struct strbuf ctlbuf;
	ordrel_req.PRIM_type = T_ORDREL_REQ;
	ctlbuf.len = sizeof(struct T_ordrel_req);
	ctlbuf.buf = (char *) &ordrel_req;
	Putmsg(fd, &ctlbuf, NULL, 0);
	Close(fd);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值