168 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* control.c - User control command processing */
 | |
| 
 | |
| /* Written 1998 by Werner Almesberger, EPFL ICA */
 | |
| 
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| #include <atm.h>
 | |
| #include <atmd.h>
 | |
| 
 | |
| #include "fab.h"
 | |
| #include "dispatch.h"
 | |
| #include "swc.h"
 | |
| 
 | |
| 
 | |
| #define COMPONENT "COMMAND"
 | |
| 
 | |
| 
 | |
| typedef struct _user_call {
 | |
|     CALL call;
 | |
|     struct _user_call *next;
 | |
| } USER_CALL;
 | |
| 
 | |
| typedef struct {
 | |
|     USER_CALL *u_call;
 | |
|     UN_CTX un_ctx;
 | |
| } CONTEXT;
 | |
| 
 | |
| 
 | |
| static int s_control = -1;
 | |
| static USER_CALL *calls = NULL;
 | |
| 
 | |
| 
 | |
| static USER_CALL *find_call(const struct sockaddr_atmpvc *in,
 | |
|   const struct sockaddr_atmpvc *out)
 | |
| {
 | |
|     USER_CALL *u_call;
 | |
| 
 | |
|     for (u_call = calls; u_call; u_call = u_call->next)
 | |
| 	if (atm_equal((struct sockaddr *) in,
 | |
| 	  (struct sockaddr *) &u_call->call.in.pvc,0,0) &&
 | |
| 	  atm_equal((struct sockaddr *) out,
 | |
| 	  (struct sockaddr *) &u_call->call.out.pvc,0,0)) break;
 | |
|     return u_call;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void add_cb(CALL *call,int cause,void *more,void *user)
 | |
| {
 | |
|     CONTEXT *context = user;
 | |
|     SWC_MSG msg;
 | |
|     USER_CALL **walk;
 | |
| 
 | |
|     memset(&msg,0,sizeof(msg));
 | |
|     msg.type = smt_add;
 | |
|     msg.n = cause ? -EIO : 0; /* @@@ */
 | |
|     if (cause) free(context->u_call);
 | |
|     else {
 | |
| 	for (walk = &calls; *walk && *walk; walk = &(*walk)->next);
 | |
| 	*walk = context->u_call;
 | |
|     }
 | |
|     if (un_send(&context->un_ctx,&msg,sizeof(msg)) < 0)
 | |
| 	diag(COMPONENT,DIAG_ERROR,"control_msg: un_send: %s",strerror(errno));
 | |
| }
 | |
| 
 | |
| 
 | |
| static void del_cb(CALL *call,int cause,void *more,void *user)
 | |
| {
 | |
|     CONTEXT *context = user;
 | |
|     SWC_MSG msg;
 | |
|     USER_CALL **walk;
 | |
| 
 | |
|     memset(&msg,0,sizeof(msg));
 | |
|     msg.type = smt_del;
 | |
|     msg.n = cause ? -EIO : 0; /* @@@ */
 | |
|     if (!cause) {
 | |
| 	for (walk = &calls; *walk && *walk != context->u_call;
 | |
| 	  walk = &(*walk)->next);
 | |
| 	if (!*walk)
 | |
| 	    diag(COMPONENT,DIAG_FATAL,"del_cb: call %p not found",
 | |
| 	      context->u_call);
 | |
| 	*walk = (*walk)->next;
 | |
| 	free(context->u_call);
 | |
|     }
 | |
|     if (un_send(&context->un_ctx,&msg,sizeof(msg)) < 0)
 | |
| 	diag(COMPONENT,DIAG_ERROR,"control_msg: un_send: %s",strerror(errno));
 | |
| }
 | |
| 
 | |
| 
 | |
| static void control_msg(int sock,void *dummy)
 | |
| {
 | |
|     CONTEXT context;
 | |
|     SWC_MSG msg;
 | |
|     USER_CALL *u_call;
 | |
|     int len,i;
 | |
| 
 | |
|     len = un_recv(&context.un_ctx,s_control,&msg,sizeof(msg));
 | |
|     if (len < 0) {
 | |
| 	diag(COMPONENT,DIAG_ERROR,"control_msg: un_recv: %s",strerror(errno));
 | |
| 	return;
 | |
|     }
 | |
|     if (len != sizeof(SWC_MSG))
 | |
| 	diag(COMPONENT,DIAG_FATAL,"control_msg: bad length (%d != %d)",len,
 | |
| 	  sizeof(SWC_MSG));
 | |
|     switch (msg.type) {
 | |
| 	case smt_get:
 | |
| 	    /*
 | |
| 	     * This code only shows VCs set up using the manual configuration
 | |
| 	     * interface. Any VCs set up by signaling are invisible. To fix
 | |
| 	     * this we'll need a "list fabric" function in the fabric-specific
 | |
| 	     * part. (The relay doesn't maintain a list of active connections,
 | |
| 	     * nor should it.)
 | |
| 	     */
 | |
| 	    i = msg.n;
 | |
| 	    for (u_call = calls; i && u_call; u_call = u_call->next) i--;
 | |
| 	    if (!u_call) {
 | |
| 		msg.n = -ENOENT;
 | |
| 		break;
 | |
| 	    }
 | |
| 	    msg.in = u_call->call.in.pvc;
 | |
| 	    msg.out = u_call->call.out.pvc;
 | |
| 	    msg.qos = u_call->call.out.qos;
 | |
| 	    break;
 | |
| 	case smt_add:
 | |
| 	    u_call = find_call(&msg.in,&msg.out);
 | |
| 	    if (u_call) {
 | |
| 		msg.n = -EEXIST;
 | |
| 		break;
 | |
| 	    }
 | |
| 	    u_call = alloc_t(USER_CALL);
 | |
| 	    memset(u_call,0,sizeof(USER_CALL));
 | |
| 	    u_call->call.in.pvc = msg.in;
 | |
| 	    u_call->call.out.pvc = msg.out;
 | |
| 	    fab_init(&u_call->call);
 | |
| 	    context.u_call = u_call;
 | |
| 	    fab_op(&u_call->call,RM_CLAIM(_RM_ANY) | RM_RSV(_RM_ANY),&msg.qos,
 | |
| 	      add_cb,&context);
 | |
| 	    return;
 | |
| 	case smt_del:
 | |
| 	    u_call = find_call(&msg.in,&msg.out);
 | |
| 	    if (!u_call) {
 | |
| 		msg.n = -ENOENT;
 | |
| 		break;
 | |
| 	    }
 | |
| 	    context.u_call = u_call;
 | |
| 	    fab_op(&u_call->call,RM_FREE,NULL,del_cb,&context);
 | |
| 	    return;
 | |
| 	default:
 | |
| 	    diag(COMPONENT,DIAG_FATAL,"control_msg: unknown message type %d",
 | |
| 	      msg.type);
 | |
|     }
 | |
|     if (un_send(&context.un_ctx,&msg,sizeof(msg)) < 0)
 | |
| 	diag(COMPONENT,DIAG_ERROR,"control_msg: un_send: %s",strerror(errno));
 | |
| }
 | |
| 
 | |
| 
 | |
| void control_init(const char *path)
 | |
| {
 | |
|     if (s_control != -1)
 | |
| 	diag(COMPONENT,DIAG_FATAL,"control channel is already set");
 | |
|     s_control = un_create(path,0600);
 | |
|     if (s_control < 0)
 | |
| 	diag(COMPONENT,DIAG_FATAL,"un_create: %s",strerror(errno));
 | |
|     dsp_fd_add(s_control,control_msg,NULL);
 | |
| }
 |