#include #include #include #include #include #include #include #include #include #include #include "cw/sock.h" #include "cw/log.h" #include "cw/dbg.h" #include "wtpman.h" #include "cw/connlist.h" #include "wtplist.h" #include "ac.h" struct rpcdata{ FILE *in; FILE *out; char prompt[1024]; cw_Cfg_t * update_cfg; cw_Cfg_t * global_cfg; char *history[2000]; char line[4096]; int pos; char esc[8]; int escpos; int quit; History *hist; HistEvent ev; Tokenizer *tok; EditLine *el; }; struct sockdata{ const char *name; int fd; cw_Cfg_t * global_cfg; }; int select_cmd(struct rpcdata *sd, const char *cmd); int list_cmd(struct rpcdata *sd, const char * cmd); int cfg_cmd(struct rpcdata *sd, const char * cmd); int ucfg_cmd(struct rpcdata *sd, const char * cmd); int set_cmd(struct rpcdata *sd, const char * cmd); int del_cmd(struct rpcdata *sd, const char * cmd); int send_cmd(struct rpcdata *sd, const char * cmd); int wlan0_cmd(struct rpcdata *sd, const char * cmd); int exit_cmd(struct rpcdata *sd, const char * cmd); int prompt_cmd(struct rpcdata *sd, const char * cmd); int global_cfg_cmd(struct rpcdata *sd, const char * cmd); int status_cmd(struct rpcdata *sd, const char * cmd); void print_mw(FILE *f, int w, const char * str); int clear_cmd(struct rpcdata *sd, const char *cmd); int load_cmd(struct rpcdata *sd, const char *cmd); int save_cmd(struct rpcdata *sd, const char *cmd); //void show_cfg (FILE *out, mavl_t ktv); int show_aps (FILE *out); struct cw_Conn * find_ap(const char *name); struct command{ char * cmd; int (*fun)(struct rpcdata *sd, const char *cmd); }; static struct command cmdlist[]={ {"exit",exit_cmd}, {"bumm",exit_cmd}, {"cfg", cfg_cmd }, {"del", del_cmd }, {"ucfg", ucfg_cmd}, {"list", list_cmd }, {"select", select_cmd }, {"send", send_cmd}, {"set", set_cmd }, {"wlan0",wlan0_cmd}, {"global_cfg", global_cfg_cmd}, {"status",status_cmd}, {"clear",clear_cmd}, {"load",load_cmd}, {"save",save_cmd}, {"@prompt",prompt_cmd}, {NULL,NULL} }; static void finish_cmd(FILE *f) { fprintf(f,"\n"); fflush(f); } int prompt_cmd(struct rpcdata *sd, const char *cmd) { const char *acname = cw_cfg_get(sd->global_cfg,"capwap/ac-name","actube"); fprintf(sd->out,"%s[%s]:>\n",acname,sd->prompt); finish_cmd(sd->out); return 0; } int global_cfg_cmd(struct rpcdata *sd, const char *str) { char *s; while( isspace( *str ) ) str++; s=(char*)str; while (!isspace(*s) && *s!=0) s++; *s=0; cw_cfg_fdump(sd->out,sd->global_cfg,str); finish_cmd(sd->out); return 0; } int select_cmd(struct rpcdata *sd, const char *cmd) { char ap [CAPWAP_MAX_WTP_NAME_LEN]; sscanf(cmd,"%s",ap); strcpy(sd->prompt,ap); finish_cmd(sd->out); return 0; } int list_cmd(struct rpcdata *sd, const char *cmd) { show_aps(sd->out); finish_cmd(sd->out); return 0; } int exit_cmd(struct rpcdata *sd, const char *cmd) { finish_cmd(sd->out); fflush(sd->out); return 1; } int cfg_cmd(struct rpcdata *sd, const char *str) { char *s; while( isspace( *str ) ) str++; s=(char*)str; while (!isspace(*s) && *s!=0) s++; *s=0; struct cw_Conn * conn; wtplist_lock(); conn = find_ap(sd->prompt); if (conn==NULL){ fprintf(sd->out,"WTP '%s' not found\n",sd->prompt); } else { cw_cfg_fdump(sd->out,conn->remote_cfg,str); } finish_cmd(sd->out); wtplist_unlock(); return 0; } int status_cmd(struct rpcdata *sd, const char *cmd) { struct cw_Conn * conn; int i; char key[CW_CFG_MAX_KEY_LEN]; wtplist_lock(); print_mw(sd->out,8,"Radio"); print_mw(sd->out,15,"Admin State"); print_mw(sd->out,15,"Oper State"); print_mw(sd->out,13,"Cause"); fprintf(sd->out,"\n"); conn = find_ap(sd->prompt); if (conn==NULL){ fprintf(sd->out,"WTP '%s' not found\n",sd->prompt); goto errX; } i=0; do { char tmp[128]; sprintf(key,"radio.%d",i); if (!cw_cfg_base_exists(conn->remote_cfg,key)) break; sprintf(tmp,"%d",i); print_mw(sd->out,8,tmp); sprintf(key,"radio.%d/capwap/admin-state",i); print_mw(sd->out,15, cw_cfg_get(conn->remote_cfg,key,"?")); sprintf(key,"radio.%d/capwap/operational-state/state",i); print_mw(sd->out,15, cw_cfg_get(conn->remote_cfg,key,"?")); sprintf(key,"radio.%d/capwap/operational-state/cause",i); print_mw(sd->out,13, cw_cfg_get(conn->remote_cfg,key,"?")); fprintf(sd->out,"\n"); i++; }while(1); errX: finish_cmd(sd->out); wtplist_unlock(); return 0; } int ucfg_cmd(struct rpcdata *sd, const char *str) { char *s; while( isspace( *str ) ) str++; s=(char*)str; while (!isspace(*s) && *s!=0) s++; *s=0; cw_cfg_fdump(sd->out,sd->update_cfg,str); finish_cmd(sd->out); return 0; } int clear_cmd(struct rpcdata *sd, const char *cmd) { cw_cfg_clear(sd->update_cfg); fprintf(sd->out,"ucfg cleard\n"); finish_cmd(sd->out); return 0; } int send_cmd(struct rpcdata * sd, const char *cmd) { struct wtpman * wtpman; struct cw_Conn * conn; wtplist_lock(); conn = find_ap(sd->prompt); if (conn==NULL){ fprintf(sd->out,"WTP '%s' not found\n",sd->prompt); goto errX; } else { wtpman=conn->data; cw_cfg_copy(sd->update_cfg,conn->update_cfg,0,NULL); wtpman->update=1; fprintf(sd->out, "Sending update cmd\n"); } errX: wtplist_unlock(); finish_cmd(sd->out); return 0; } int wlan0_cmd(struct rpcdata * sd, const char *cmd) { stop(); struct cw_Conn * conn; wtplist_lock(); conn = find_ap(sd->prompt); if (conn==NULL){ fprintf(sd->out,"WTP '%s' not found\n",sd->prompt); } else { FILE *f=fopen("wlan0.ktv","r"); fclose(f); } wtplist_unlock(); return 0; } int set_cmd(struct rpcdata *sd, const char *str) { cw_Cfg_t *cfg; cfg = cw_cfg_create(); cw_cfg_read_from_string(str,cfg); cw_cfg_fdump(sd->out,cfg,NULL); cw_cfg_copy(cfg,sd->update_cfg,DBG_CFG_UPDATES,"rpc ucfg"); cw_cfg_destroy(cfg); finish_cmd(sd->out); return 0; } int load_cmd(struct rpcdata *sd, const char *str) { char fn[CW_CFG_MAX_KEY_LEN]; int rc; const char * dir=cw_cfg_get(sd->global_cfg,"actube/rpc/macros-dir","./rpc-macros"); sprintf(fn,"%s/%s.ckv",dir,str); rc= cw_cfg_load(fn,sd->update_cfg); if (rc){ fprintf(sd->out,"Error loading %s: %s\n",fn,strerror(rc)); } finish_cmd(sd->out); return 0; } int save_cmd(struct rpcdata *sd, const char *str) { char fn[CW_CFG_MAX_KEY_LEN]; int rc; const char * dir=cw_cfg_get(sd->global_cfg,"actube/rpc/macros-dir","./rpc-macros"); sprintf(fn,"%s/%s.ckv",dir,str); rc= cw_cfg_save(fn,sd->update_cfg,"#\n# Managed by acTube\n#\n\n"); if (rc){ fprintf(sd->out,"Error saving %s: %s\n",fn,strerror(rc)); } finish_cmd(sd->out); return 0; } int del_cmd(struct rpcdata *sd, const char *str) { char *s; while( isspace( *str ) ) str++; s=(char*)str; while (!isspace(*s) && *s!=0) s++; *s=0; fprintf(sd->out,"DEL: '%s'\n",str); cw_cfg_del(sd->update_cfg,str); finish_cmd(sd->out); return 0; } void print_mw(FILE *f, int w, const char * str) { int n,i; fprintf(f, "%.*s",w,str); n=strlen(str); if ( n>w ){ fprintf(f,"> "); return; } n = w-n; for(i=0;i<(n+2);i++){ fprintf(f,"%c",' '); } } int show_aps (FILE *out) { struct connlist * cl; mavliter_t it; wtplist_lock(); cl = wtplist_get_connlist(); mavliter_init (&it, cl->by_addr); print_mw (out, 16, "AP Name"); print_mw (out, 16, "AP Model"); print_mw (out, 14, "Vendor"); print_mw (out, 16, "IP "); fprintf(out,"\n"); mavliter_foreach (&it) { char addr[SOCK_ADDR_BUFSIZE]; const char *vendor; struct cw_Conn * conn; conn = mavliter_get_ptr (&it); print_mw(out,16,cw_cfg_get(conn->remote_cfg, "capwap/wtp-name", "Unknown")); print_mw(out,16,cw_cfg_get(conn->remote_cfg, "capwap/wtp-board-data/model-no", "Unknown")); vendor = cw_cfg_get(conn->remote_cfg, "capwap/wtp-board-data/vendor", "0"); print_mw(out,14,vendor); sock_addr2str_p (&conn->addr, addr); print_mw(out,16,addr); fprintf(out,"\n"); } wtplist_unlock(); return 0; } struct cw_Conn * find_ap(const char *name) { struct connlist * cl; mavliter_t it; cl = wtplist_get_connlist(); mavliter_init (&it, cl->by_addr); mavliter_foreach (&it) { const char *wtpname; struct cw_Conn * conn; conn = mavliter_get_ptr (&it); wtpname = cw_cfg_get (conn->remote_cfg, "capwap/wtp-name", NULL); if (wtpname == NULL) continue; if(strcmp(wtpname,name)==0){ return conn; } } return NULL; } struct command * find_cmd(const char *cmd) { struct command * search,*result; result=NULL; search = cmdlist; while (search->cmd!=NULL){ if (strncmp(cmd,search->cmd,strlen(cmd))==0){ if (result==NULL) result = search; else return NULL; } search ++; } return result; } int execute_cmd (struct rpcdata * sd, const char *str) { char cmd[1024]; char args[1024]; int n; struct command * searchcmd; args[0]=0; n = sscanf (str, "%s", cmd); if (n<=0) return 0; searchcmd = find_cmd(cmd); if (searchcmd!=NULL){ if (searchcmd->fun != NULL){ char *args; int n; args = (char*)(str+strlen(cmd)); while( isspace( *args ) ) args++; n = strlen(args); n--; while (n>=0 && isspace(args[n])) n--; args[n+1]=0; return searchcmd->fun(sd, args); } } else{ fprintf(sd->out,"Unknown command: '%s'\n",cmd); finish_cmd(sd->out); } return 0; } void rpc_loop (FILE *file, cw_Cfg_t *global_cfg) { struct rpcdata sd; int c; c=0; char str[2048]; sd.in = file; sd.out = file; sd.global_cfg=global_cfg; sd.update_cfg=cw_cfg_create(); sprintf(sd.prompt,"%s","*"); sd.quit=0; do { str[0]=0; fgets (str, sizeof (str), file); if (execute_cmd (&sd, str)) { break; } } while (c != EOF); } void * run_rpc_server (void * arg) { char sockstr[SOCK_ADDR_BUFSIZE]; struct sockdata * sockdata; int clientsock; struct sockaddr_storage client; socklen_t client_size; sockdata = (struct sockdata *)arg; memset(&client,0,sizeof(client)); client_size=sizeof(client); cw_dbg(DBG_INFO,"Starting RPC Service, listening on: %s (sock fd: %d)",sockdata->name, sockdata->fd); while(1){ clientsock = accept (sockdata->fd, (struct sockaddr*) &client, &client_size); if (clientsock == -1){ cw_log (LOG_ERR, "Accept error '%s', %s", "addr", strerror (errno)); return NULL; } if (clientsock > 0) { sock_addr2str_p (&client, sockstr); cw_dbg (DBG_INFO, "Accepting RPC session from %s", sockstr); rpc_loop (fdopen (clientsock, "a+"),sockdata->global_cfg); close (clientsock); } } return NULL; } int create_tcp_fd(const char *name) { struct sockaddr_storage server; //, client; int rc; const char * addr = name; int sockfd; int yes; rc = sock_strtoaddr (addr, (struct sockaddr*) &server); if (! rc) { cw_log (LOG_ERR, "Can't parse address '%s', %s", addr, strerror (errno)); return -1; } sockfd = socket ( ( (struct sockaddr*) &server)->sa_family, SOCK_STREAM, 0); yes = 1; /* reuse address */ setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (yes)); /* bind address */ rc = bind (sockfd, (struct sockaddr*) &server, sizeof (struct sockaddr)); if (rc) { cw_log (LOG_ERR, "Can't bind socket address '%s', %s", addr, strerror (errno)); return -1; } return sockfd; } static int create_unix_fd(const char *name) { struct sockaddr_un addr; int rc,fd; unlink(name); fd = socket(PF_UNIX, SOCK_STREAM, 0); sock_addrinit((struct sockaddr_storage*)&addr,AF_UNIX); strncpy(addr.sun_path, name, sizeof(addr.sun_path)-1); rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); if (rc) { cw_log (LOG_ERR, "Can't bind socket 'unix:%s', %s", name, strerror (errno)); return -1; } return fd; } int start_rpc(cw_Cfg_t *global_cfg) { struct sockdata * sockdata; const char *sockname; int rc; int fd; rc = cw_cfg_get_bool(global_cfg,"actube/rpc/enable",1); if (!rc) return 1; sockdata = malloc(sizeof(struct sockdata)); if (sockdata==NULL) return 0; memset(sockdata,0,sizeof(struct sockdata)); sockdata->global_cfg = global_cfg; sockdata->fd=-1; sockname = cw_cfg_get(global_cfg,"actube/rpc/listen",NULL); if (sockname==NULL) { cw_log (LOG_ERR, "Can't get RPC listen address from global_cfg 'actube/rpc/listen"); goto errX; } if (strncmp("unix:",sockname,strlen("unix:"))==0){ fd = create_unix_fd(strchr(sockname,':')+1); if (fd==-1) goto errX; sockdata->name=cw_strdup(sockname); sockdata->fd=fd; }else if (strncmp("tcp:",sockname,strlen("tcp:"))==0){ fd = create_tcp_fd(strchr(sockname,':')+1); if (fd==-1) goto errX; sockdata->name=cw_strdup(sockname); sockdata->fd=fd; }else { fd = create_tcp_fd(sockname); if (fd==-1) goto errX; sockdata->name=cw_strdup(sockname); sockdata->fd=fd; } rc = listen (sockdata->fd, 5); if (rc) { cw_log (LOG_ERR, "Can't listen on address '%s', %s", "addr", strerror (errno)); goto errX; } pthread_t thread; pthread_create (&thread, NULL, run_rpc_server, sockdata); return 1; errX: if (sockdata->fd!=-1) close(sockdata->fd); if (sockdata->name) free((void*)sockdata->name); free(sockdata); return 0; }