⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpsw.c

📁 ATM 网 络 协 议 实 现 源 代 码
💻 C
字号:
/* tcpsw.c - ATMTCP switch *//* Written 1998 by Werner Almesberger, EPFL ICA */#if HAVE_CONFIG_H#include <config.h>#endif#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <atm.h>#include <linux/atm_tcp.h>#include <atmd.h>#include "uni.h"#include "../fab.h"#include "../dispatch.h"#include "../swc.h"#define COMPONENT "FAB(tcp)"#define PRV(call) ((FAB *) (call)->fab)#define MAX_VCI	1024#define PORT 2812		/* @@@ should merge with atmtcp.c */#define MAX_PACKET (ATM_MAX_AAL5_PDU+sizeof(struct atmtcp_hdr))#define BUFFER_SIZE (MAX_PACKET*2)typedef struct _table {    struct _link *out;	/* output port */    uint16_t in_vpi;	/* input VPI */    int	in_vci;		/* input VCI (may be ATM_VCI_ANY) */    uint16_t out_vpi;	/* output VPI */    uint16_t out_vci;	/* output VCI */    struct _table *next;} TABLE;typedef struct _link {    enum { id_none,id_set,id_reval } state;    int id;		/* switch port ID */    int fd;    int len;		/* length of data in the buffer */    char buffer[BUFFER_SIZE];    TABLE *table;	/* switching table */    struct _link *next;} LINK;typedef struct _fab {    int active; /* non-zero if there's an entry in the fabric */    CALL *next; /* relay.c may not keep track of calls, but WE are */} FAB;static CALL *calls = NULL;static LINK *links = NULL;static void (*notify)(int number,int up);static LINK *find_link(int id){    LINK *lnk;    for (lnk = links; lnk; lnk = lnk->next)	if (lnk->state == id_set && lnk->id == id) break;    return lnk;}static LINK *route(LINK *in,struct atmtcp_hdr *hdr){    TABLE *entry;    for (entry = in->table; entry; entry = entry->next)	if (ntohs(hdr->vpi) == entry->in_vpi &&	  (entry->in_vci == ATM_VCI_UNSPEC ||	  ntohs(hdr->vci) == entry->in_vci)) {	    hdr->vpi = htons(entry->out_vpi);	    if (entry->in_vci != ATM_VCI_UNSPEC)		hdr->vci = htons(entry->out_vci);	    return entry->out;	}    return NULL;}static int add_entry(struct sockaddr_atmpvc *from,struct sockaddr_atmpvc *to){    LINK *l_from,*l_to;    TABLE *entry;    l_from = find_link(from->sap_addr.itf);    l_to = find_link(to->sap_addr.itf);    if (!l_from || !l_to) return -ENODEV;    for (entry = l_from->table; entry; entry = entry->next)	if (entry->in_vpi == from->sap_addr.vpi &&	  (entry->in_vci == ATM_VCI_UNSPEC ||	  from->sap_addr.vci == ATM_VCI_UNSPEC ||	  entry->in_vci == from->sap_addr.vci)) return -EEXIST;    entry = alloc_t(TABLE);    entry->out = l_to;    entry->in_vpi = from->sap_addr.vpi;    entry->in_vci = from->sap_addr.vci;    entry->out_vpi = to->sap_addr.vpi;    entry->out_vci = to->sap_addr.vci;    entry->next = l_from->table;    l_from->table = entry;    if (entry->in_vci == ATM_VCI_UNSPEC)	diag(COMPONENT,DIAG_INFO,"added VP %d.%d -> %d.%d",l_from->id,	  entry->in_vpi,l_to->id,entry->out_vpi);    else diag(COMPONENT,DIAG_INFO,"added VC %d.%d.%d -> %d.%d.%d",l_from->id,	  entry->in_vpi,entry->in_vci,l_to->id,entry->out_vpi,entry->out_vci);    return 0;}static int del_entry(struct sockaddr_atmpvc *from,struct sockaddr_atmpvc *to){    LINK *l_from,*l_to;    TABLE **entry,*this;    l_from = find_link(from->sap_addr.itf);    l_to = find_link(to->sap_addr.itf);    if (!l_from || !l_to) return -ENODEV;    for (entry = &l_from->table; *entry; entry = &(*entry)->next)	if ((*entry)->out == l_to && (*entry)->in_vpi == from->sap_addr.vpi &&	  (*entry)->in_vci == from->sap_addr.vci &&	  ((*entry)->in_vci == ATM_VCI_UNSPEC ||	  (*entry)->out_vci == to->sap_addr.vci))	    break;    if (!*entry) return -EHOSTUNREACH;    this = *entry;    *entry = this->next;    if (this->in_vci == ATM_VCI_UNSPEC)	diag(COMPONENT,DIAG_INFO,"deleted VP %d.%d -> %d.%d",l_from->id,	  this->in_vpi,l_to->id,this->out_vpi);    else diag(COMPONENT,DIAG_INFO,"deleted VC %d.%d.%d -> %d.%d.%d",l_from->id,	  this->in_vpi,this->in_vci,l_to->id,this->out_vpi,this->out_vci);    free(this);    return 0;}static void drop_link(LINK *lnk){    diag(COMPONENT,DIAG_INFO,"dropped link %d",lnk->id);    if (lnk->state == id_set) {	notify(lnk->id,0);	lnk->state = id_reval;    }    dsp_fd_remove(lnk->fd);#if 0    LINK **walk,**next_link,**entry,**next_entry;    /* remove link from the list and delete all references to link */    for (walk = &links; *walk; walk = next_link) {	next_link = &(*walk)->next;	if (*walk == lnk) *walk = *next_link;	else for (entry = &(*walk)->table; *entry; entry = next_entry) {		next_entry = &(*entry)->next;		if ((*entry)->out == lnk) {		    TABLE *this;		    this = *entry;		    *entry = *next_entry;		    free(this);		}	    }    }    *walk = lnk->next;    /* remove link's switching table */    while (lnk->table) {	TABLE *next;	next = lnk->table->next;	free(lnk->table);	lnk->table = next;    }    /* drop memory */    free(*lnk);#endif}static void new_data(int fd,void *user){    LINK *lnk = user;    int got;    got = read(fd,lnk->buffer+lnk->len,BUFFER_SIZE-lnk->len);    if (got < 0) perror("read");    if (got <= 0) drop_link(lnk);    lnk->len += got;    if (lnk->state != id_set) {	LINK *walk;	char *end;	int id;	if (!memchr(lnk->buffer,0,lnk->len)) return;	id = strtol(lnk->buffer,&end,0);	if (*end) {	    diag(COMPONENT,DIAG_ERROR,"invalid line id \"%s\"",lnk->buffer);	    drop_link(lnk);	    return;	}	for (walk = links; walk; walk = walk->next)	    if (walk->state != id_none && id == walk->id) break;	if (walk) {	    if (walk->state == id_set) {		diag(COMPONENT,DIAG_ERROR,"line state mismatch (id %d)",id);		drop_link(lnk);		return;	    }	    diag(COMPONENT,DIAG_INFO,"reconnected link %d",id);	    walk->state = id_set;	    walk->fd = lnk->fd;	    walk->len = lnk->len;	    memcpy(walk->buffer,lnk->buffer,lnk->len);	    drop_link(lnk);	    lnk = walk;	    dsp_fd_add(lnk->fd,new_data,walk);	}	else {	    diag(COMPONENT,DIAG_INFO,"new link %d",id);	    lnk->state = id_set;	    lnk->id = id;	}	notify(lnk->id,1);	lnk->len -= strlen(lnk->buffer)+1;	memmove(lnk->buffer,lnk->buffer-strlen(lnk->buffer)-1,lnk->len);    }    while (lnk->len >= sizeof(struct atmtcp_hdr)) {	struct atmtcp_hdr *hdr = (struct atmtcp_hdr *) lnk->buffer;	LINK *out;	int size;	size = sizeof(struct atmtcp_hdr)+ntohl(hdr->length);	if (lnk->len < size) break;	out = route(lnk,hdr);	if (out) {	    int sent;	    sent = write(out->fd,lnk->buffer,size);	    if (sent < 0) perror("write");	    else if (sent != size)		    diag(COMPONENT,DIAG_ERROR,"bad write: %d != %d",sent,size);	    if (sent != size) drop_link(out);	}	lnk->len -= size;	memmove(lnk->buffer,lnk->buffer+size,lnk->len);    }}static void new_link(int sock,void *dummy){    LINK *lnk;    int fd;    fd = accept(sock,NULL,NULL);    if (fd < 0) {	perror("accept");	return;    }    lnk = alloc_t(LINK);    lnk->state = id_none;    lnk->id = -1;    lnk->fd = fd;    lnk->len = 0;    lnk->table = NULL;    lnk->next = links;    links = lnk;    dsp_fd_add(fd,new_data,lnk);}static int vci_exists(LINK *lnk,int vpi,int vci){    TABLE *walk;    for (walk = lnk->table; walk; walk = walk->next)	if (walk->in_vpi == vpi && walk->in_vci == vci) return 1;    return 0;}static int check_ci(struct sockaddr_atmpvc *pvc){    LINK *lnk;    TABLE *walk;    int vci;    lnk = find_link(pvc->sap_addr.itf);    if (!lnk) return 0;    if (pvc->sap_addr.vpi == ATM_VPI_ANY) pvc->sap_addr.vpi = 0;	/* that was easy :-) */    for (walk = lnk->table; walk; walk = walk->next)	if (walk->in_vpi == pvc->sap_addr.vpi) break;    if (walk && walk->in_vci == ATM_VCI_UNSPEC) return 0;    if (pvc->sap_addr.vci == ATM_VCI_UNSPEC) return !walk;    if (pvc->sap_addr.vci != ATM_VCI_ANY)	return !vci_exists(lnk,pvc->sap_addr.vpi,pvc->sap_addr.vci);    for (vci = ATM_NOT_RSV_VCI; vci < MAX_VCI; vci++)	if (!vci_exists(lnk,pvc->sap_addr.vpi,vci)) {	    pvc->sap_addr.vci = vci;	    return 1;	}    return 0;}void fab_option(const char *name,const char *value){    diag(COMPONENT,DIAG_FATAL,"unrecognized fabric option \"%s\"",name);}void fab_start(void (*port_notify)(int number,int up)){    struct sockaddr_in addr;    int s_listen;    notify = port_notify;    addr.sin_family = AF_INET;    addr.sin_port = htons(PORT);    addr.sin_addr.s_addr = htonl(INADDR_ANY);    if ((s_listen = socket(PF_INET,SOCK_STREAM,0)) < 0)	diag(COMPONENT,DIAG_FATAL,"socket: %s",strerror(errno));    if (bind(s_listen,(struct sockaddr *) &addr,sizeof(addr)) < 0)	diag(COMPONENT,DIAG_FATAL,"bind: %s",strerror(errno));    if (listen(s_listen,5) < 0)	diag(COMPONENT,DIAG_FATAL,"listen: %s",strerror(errno));    dsp_fd_add(s_listen,new_link,NULL);}void fab_init(CALL *call){    PRV(call) = alloc_t(FAB);    PRV(call)->active = 0;    PRV(call)->next = calls;    calls = call;}void fab_destroy(CALL *call){    CALL **walk;    for (walk = &calls; *walk; walk = &PRV(*walk)->next)	if (*walk == call) break;    if (!*walk)	diag(COMPONENT,DIAG_FATAL,"fab_destroy: call %p not found",call);    *walk = PRV(call)->next;    free(PRV(call));    PRV(call) = NULL;}void fab_op(CALL *call,int op,const struct atm_qos *qos,  void (*callback)(CALL *call,int cause,void *more,void *user),void *user){    int error,error2;    diag(COMPONENT,DIAG_INFO,"fab_op%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",      !op ? " FREE" : "",op & RM_RSV(_RM_ANY) ? " RM_RSV:" : "",      op & RM_IN_TX ? " IN_TX" : "",op & RM_IN_RX ? " IN_RX" : "",      op & RM_OUT_TX ? " OUT_TX" : "",op & RM_OUT_RX ? " OUT_RX" : "",      op & RM_PATH_TX ? " PATH_TX" : "",op & RM_PATH_RX ? " PATH_RX" : "",      op & RM_CLAIM(_RM_ANY) ? " RM_CLAIM:" : "",      op & _RM_SHIFT(RM_IN_TX) ? " IN_TX" : "",      op & _RM_SHIFT(RM_IN_RX) ? " IN_RX" : "",      op & _RM_SHIFT(RM_OUT_TX) ? " OUT_TX" : "",      op & _RM_SHIFT(RM_OUT_RX) ? " OUT_RX" : "",      op & _RM_SHIFT(RM_PATH_TX) ? " PATH_TX" : "",      op & _RM_SHIFT(RM_PATH_RX) ? " PATH_RX" : "");    if (op & (RM_RSV(RM_IN) | RM_CLAIM(RM_IN))) {	if (!check_ci(&call->in.pvc)) {	    callback(call,ATM_CV_CI_UNAVAIL,NULL,user);	    return;	}	call->in.qos = *qos;    }    if (op & (RM_RSV(RM_OUT) | RM_CLAIM(RM_OUT))) {	if (!check_ci(&call->out.pvc)) {	    callback(call,ATM_CV_CI_UNAVAIL,NULL,user);	    return;	}	call->out.qos = *qos;    }    if (op & RM_CLAIM(RM_PATH)) {	error = 0;	if (call->in.qos.txtp.traffic_class != ATM_NONE)	    error = add_entry(&call->in.pvc,&call->out.pvc);	if (!error) {	    if (call->in.qos.rxtp.traffic_class != ATM_NONE)		error = add_entry(&call->out.pvc,&call->in.pvc);	    if (error && call->in.qos.txtp.traffic_class != ATM_NONE) {		error2 = del_entry(&call->in.pvc,&call->out.pvc);		if (error2)		    diag(COMPONENT,DIAG_ERROR,"del_entry: %s",strerror(error2));	    }	}	if (error) {	    diag(COMPONENT,DIAG_ERROR,"add_entry: %s",strerror(error));	    callback(call,ATM_CV_RES_UNAVAIL,NULL,user);	    return;	}	PRV(call)->active = 1;    }    if (!op && PRV(call)->active) {	error = error2 = 0;	if (call->in.qos.txtp.traffic_class != ATM_NONE) {	    error = del_entry(&call->in.pvc,&call->out.pvc);	    if (error)		diag(COMPONENT,DIAG_ERROR,"del_entry: %s",strerror(error));	}	if (call->in.qos.rxtp.traffic_class != ATM_NONE) {	    error2 = del_entry(&call->out.pvc,&call->in.pvc);	    if (error2)		diag(COMPONENT,DIAG_ERROR,"del_entry: %s",strerror(error2));	}	if (error || error2) {	    callback(call,ATM_CV_TEMP_FAIL,NULL,user);	    return;	}    }    callback(call,0,NULL,user);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -