linux_echo_内核态服务器

来源:互联网 发布:做淘宝运营对数据分析 编辑:程序博客网 时间:2024/06/17 19:33

kserver.h

/* * Copyright(C) 2016 Ruijie Network. All rights reserved. *//* * kserver.c * Original Author: suntianyu@ruijie.com.cn,  2016-8-7 * * echo Kernel server * * History * */  #ifndef _SERVER_H_ #define _SERVER_H_#include <linux/init.h>  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/skbuff.h>  #include <linux/ip.h>  #include <linux/types.h>  #include <linux/sched.h>  #include <linux/netlink.h>  #include <net/sock.h>  #include <linux/proc_fs.h>   #include <linux/mutex.h>#include <linux/sched.h>   #include <linux/kthread.h> #define USER_NETLINK_CMD    25  #define MAXMSGLEN           1024  #define MODULE_NAME         "/proc"    #define DATA_LEN            30 #define NETLINK_ECHO        31#define KTHREAD_NUM         4#define NORMAL_LEN          512#define MAX_USERS           2#define ERROR               -1#define NORMAL_MODE         3#define UPPER_MODE          2#define LOWER_MODE          1#define NATIVE              0#define TABLE_SIZE          3#define PIDTABLE_SIZE       2#define TEN                 10#define READ_NOW            1#define TOASCI              32#define MODE_SIZE           4#define UPPER_SIZE          5#define LOWER_SIZE          5#define NORMAL_SIZE         6struct db_data_t {      char mode[DATA_LEN + 1];      char characters[DATA_LEN + 1];      char clients[DATA_LEN + 1]; }; struct nksend_msg{    int mode;    int pid;    char *data;    struct nksend_msg * next;};struct queue_t{    struct nksend_msg * head;    struct nksend_msg * tail;};static DEFINE_MUTEX(mutex);#endif /* _SERVER_H_ */ 

kserver.c

/* * Copyright(C) 2016 Ruijie Network. All rights reserved. *//* * kserver.c * Original Author: suntianyu@ruijie.com.cn,  2016-8-7 * * echo Kernel server * * History * */  #include "kserver.h"static struct task_struct *tsk_consumes[KTHREAD_NUM];static struct proc_dir_entry *proc_file; static struct proc_dir_entry *echo_dir ;struct db_data_t proc_data;  struct sock *netlink_fd;   struct nlmsghdr *nlhdr; struct queue_t queue;char buff[NORMAL_LEN];char echo_database[TABLE_SIZE][DATA_LEN] = {"Global mode: normal   ","characters:  0    ","clients:  0    "};    int pid = READ_NOW ;int native_mode = NORMAL_MODE;int characters = NATIVE, clients = NATIVE;int output_config[TABLE_SIZE] = {NATIVE,NATIVE,NORMAL_MODE};int pid_outmode[PIDTABLE_SIZE][MAX_USERS]; /* queue */ int init_queue(void){    queue.tail = (struct nksend_msg *)kmalloc(sizeof(struct nksend_msg), 0);    if (queue.tail == NULL ) {        return ERROR;    }    queue.head = queue.tail;    queue.tail->next = NULL;    return 0;}/* queue */bool is_queue_empty(void){    return queue.head == queue.tail;}/* queue */void queue_insert(struct nksend_msg * pnk_msg){    if (pnk_msg == NULL ) {        return;    }    pnk_msg->next = NULL;    queue.head->next = pnk_msg;    queue.head = pnk_msg;}/* queue */struct nksend_msg * queue_mv_tail(void){    struct nksend_msg * ret;    ret = queue.tail->next;    queue.tail->next = queue.tail->next->next;    if ( ret == queue.head ) {        queue.head = queue.tail;    }    return ret;}/* queue */void clear_queue(struct queue_t * hq)  {      struct nksend_msg * p;    if ( !is_queue_empty()) {        p = hq->tail;          while(p != NULL) {              hq->tail = hq->tail->next;              kfree(p);              p = hq->tail;          }     }      hq->head = NULL;      hq->tail = NULL;      return;  }  /* pid  table */void init_pid_table(int native_mode){    int i;    for ( i=0; i < MAX_USERS; i++ ) {        pid_outmode[0][i] = 0;      }       for ( i=0; i < MAX_USERS; i++ ) {        pid_outmode[1][i] = native_mode;      }        }/* pid  table */int insert_pid(int pid){    int i;    for ( i=0; i < MAX_USERS; i++ ) {        if (pid_outmode[0][i] == pid) {            return ERROR;        }    }    for ( i=0; i < MAX_USERS; i++ ) {        if ( pid_outmode[0][i] == 0 ) {            clients++;            pid_outmode[0][i] = pid;             pid_outmode[1][i] = native_mode;                            return i;        }    }    if ( clients > MAX_USERS) {        clients--;        return ERROR;    }    return ERROR;}/* pid  table */int delete_pid(int pid){    int i;    for ( i=0; i < MAX_USERS; i++ ) {        if ( pid_outmode[0][i] == pid ) {            clients--;            pid_outmode[1][i] = native_mode;            pid_outmode[0][i] = 0;            return i;        }    }    return 0;}/* pid  table */int find_outmode(int pid){    int i;    for ( i=0; i < MAX_USERS; i++ ) {        if ( pid_outmode[0][i] == pid ) {                    return pid_outmode[1][i];        }    }    return native_mode;}/* pid  table */int set_outmode(int pid,int mode){    int i;    for ( i=0; i < MAX_USERS; i++ ) {        if ( pid_outmode[0][i] == pid ) {                    pid_outmode[1][i] = mode;        }    }    return 0;}  /* string processing */int kstrlen(const char *str){    int len;    len = 0;    if ( str == NULL ) {        return 0;    }    while ( *str++ ) {        len++;    }    return len;}/* string processing */int atoi(char *str){    int i,value;    value = 0;    if ( str == NULL ) {        return 0;    }    for ( i = 0; i < DATA_LEN; i++ ) {            if ( *str >= '0' && *str <= '9' ) {            value *= TEN;            value += *str - '0';        }        str++;    }    return value;}/* string processing */void itoa(int n,char *s){    int sign,i;    char temp;    char *p,*q;    if ( s == NULL ) {        return;    }    sign = n;    i = 0;    p = s;    q = s;    if (sign < 0) {        n = -n;    }    do {        s[i++] = n % TEN + '0';        n = n / TEN;    }   while (n > 0);    if ( sign < 0 ) {        s[i++] = '-';    }    s[i] = '\0';    /* rev */    while ('\0' != *(++q + 1)) {    }    while (p < q) {        if ( *p != *q ) {            temp = *p;            *p = *q;            *q = temp;        }        ++p;        --q;    }}/* input judge */   int judge_input(char *input_buf){    int i,j;       char mode[MODE_SIZE] = "mode";    char char_lower[LOWER_SIZE ] = "lower";    char char_upper[UPPER_SIZE] = "upper" ;    char char_normal[NORMAL_SIZE] = "normal";    if ( input_buf == NULL ) {        return 0;    }    /* mode */    for ( i = 0; i < MODE_SIZE; i++ ) {        if ((*(input_buf + i)) != mode[i]) {            return ERROR;        }    }    output_config[1] = atoi(input_buf);    /* lower */    for ( i = MODE_SIZE,j=0; i < DATA_LEN; i++ ) {        if ( (*(input_buf + i) >= 'a'&&*(input_buf + i) <= 'z') || (*(input_buf + i) >= 'A'&&*(input_buf + i) <= 'Z') ){            if ((*(input_buf + i)) != char_lower[j]) {                break;            } else {                         j++;            }                         }        if ( j == LOWER_SIZE  ) {            output_config[0] = READ_NOW ;                           output_config[2] = LOWER_MODE ;            if ( output_config[1] == 0 ) {                memcpy(&echo_database[0][13],char_lower,LOWER_SIZE );                echo_database[0][18] = '\0';            }            return 1;        }    }    /* upper */    for ( i = MODE_SIZE,j=0; i < DATA_LEN; i++ ) {        if ( (*(input_buf + i) >= 'a' && *(input_buf + i) <= 'z') || (*(input_buf + i) >= 'A'&&*(input_buf + i) <= 'Z') ) {            if ( (*(input_buf + i)) != char_upper[j] ) {                break;            } else {                j++;            }        }        if ( j == UPPER_SIZE ) {            output_config[0] = READ_NOW ;             output_config[2] = UPPER_MODE ;            if ( output_config[1] == 0 ) {                memcpy(&echo_database[0][13],char_upper,UPPER_SIZE);                     echo_database[0][18] = '\0';            }            return 1;        }    }    /* normal */    for ( i = MODE_SIZE,j=0; i < DATA_LEN; i++ ) {        if ( (*(input_buf + i) >= 'a'&&*(input_buf + i) <= 'z') || (*(input_buf + i) >= 'A'&&*(input_buf + i) <= 'Z') ) {            if ((*(input_buf + i)) != char_normal[j]) {                break;            } else {                 j++;            }        }        if (j == NORMAL_SIZE) {            output_config[0] = READ_NOW ;             output_config[2] = NORMAL_MODE ;            if (output_config[1] == 0) {                memcpy(&echo_database[0][13],char_normal,NORMAL_SIZE);            }            return 1;        }    }    return 0;}/* */int connection_check(char *data, char *id, int num){    int i;    if ( data == NULL ) {        return 0;    }    if ( id == NULL ) {        return 0;    }    for ( i=0; i < num; i++ ) {        if ( *(data + i) != *(id + i) ) {            return 0;        }    }    return 1;}/* proc */  static int proc_read_foobar(char *page, char **start,  off_t off, int count,  int *eof, void *data) {      int len;    len = 0;      if ( characters < TEN ) {        echo_database[1][12] = '0' + characters;        echo_database[1][13] = ' ';    }   else {        itoa(characters,&echo_database[1][12]);        }    if ( clients < TEN) {        echo_database[2][9] = '0' + clients;        echo_database[2][10] = ' ';    }   else {        itoa(clients,&echo_database[2][9]);    }    mutex_lock(&mutex);    len = sprintf(page, "%s\n%s\n%s\n",echo_database[0], echo_database[1], echo_database[2]);     mutex_unlock(&mutex);    return len;  }  /* proc */  static int proc_write_foobar(struct file *file, const char *buffer, unsigned long count, void *data) {      int len,i;    char input_data[DATA_LEN];      memset(input_data,0,DATA_LEN);    if ( count > DATA_LEN) {        len = DATA_LEN;     }   else {          len = count;      }    if ( copy_from_user(input_data, buffer, len)) {        return -EFAULT;      }    judge_input(input_data);    if ( output_config[0] == READ_NOW ) {        output_config[0] = 0;        if ( output_config[1] == 0) {            native_mode = output_config[2];            for ( i=0; i < MAX_USERS; i++) {                pid_outmode[1][i] = native_mode;            }        }   else {            set_outmode(output_config[1],output_config[2]);        }    }    return len;  }  /****************************/  /*         netlink         */  /**************************/  /* netlink 发送数据给用户空间 */static void netlink_to_user(int dest, void *buf, int len){      struct nlmsghdr *nl;      struct sk_buff *skb;      int size;    size = NLMSG_SPACE(len);      skb = alloc_skb(size, GFP_ATOMIC);      if ( !skb || !buf) {          printk(KERN_ALERT "netlink_to_user skb of buf null!\n");          return;      }      nl = nlmsg_put(skb, 0, 0, 0,NLMSG_SPACE(len) - sizeof(struct nlmsghdr), 0);     if(!nl) {        return;    }    NETLINK_CB(skb).pid = 0;      NETLINK_CB(skb).dst_group = 0;      memcpy(NLMSG_DATA(nl), buf, len);      netlink_unicast(netlink_fd, skb, dest, MSG_DONTWAIT);  }/* netlink 回调函数 */static void netlink_recv_msg(struct sk_buff *p__skb){      struct sk_buff *skb;     char login[] = "suntianyu";    char logout[] = "quit";    struct nksend_msg * pnk_msg;    skb = skb_get(p__skb);      if (skb->len >= NLMSG_SPACE(0)) {          characters++;         nlhdr = nlmsg_hdr(skb);        pid = nlhdr->nlmsg_pid;        memcpy(buff, NLMSG_DATA(nlhdr), sizeof(buff));        kfree_skb(skb);        if (connection_check(buff,login,sizeof(login))) {            if (insert_pid(pid) == ERROR) {                netlink_to_user(pid, logout, sizeof(logout));                return;            }   else {                netlink_to_user(pid, login, sizeof(login));            }        }   else if (connection_check(buff,logout,sizeof(logout))) {            delete_pid(pid);            netlink_to_user(pid, logout, sizeof(logout));        }   else {                   pnk_msg = (struct nksend_msg * )kmalloc(sizeof(struct nksend_msg), 0);            if (pnk_msg == NULL) {                return;            }            pnk_msg->data = (char * )kmalloc(kstrlen(buff) + 1, 0);            if (pnk_msg->data == NULL) {                kfree(pnk_msg);                return;            }            memcpy(pnk_msg->data, buff, kstrlen(buff) + 1);            pnk_msg->mode = find_outmode(pid);            pnk_msg->pid = pid;            pnk_msg->data[kstrlen(buff)] = '\0';            mutex_lock(&mutex);            queue_insert(pnk_msg);            mutex_unlock(&mutex);        }        return;     }   else {  /* End of if */        printk("netlink received error!\n");      }    return; }  /*********************************/  /*      kthread线程处理函数     */  /*******************************/  static int kthread_consume(void *data){    bool flag;    int k,i;    char buf[NORMAL_LEN];    struct nksend_msg * pnk_msg;    k = (int)data;    do{        flag = 0;        mutex_lock(&mutex);        if ( !is_queue_empty()) {            pnk_msg = queue_mv_tail();            flag = 1;        }        mutex_unlock(&mutex);        if (flag) {            msleep_interruptible(200*(kstrlen(pnk_msg->data)-1));            memcpy(buf,pnk_msg->data,kstrlen(pnk_msg->data));            if ( pnk_msg->mode == LOWER_MODE) {                for ( i = 0; ((i < NORMAL_LEN) && (buf[i] != '\0')); i++ ) {                    if ( buf[i] >= 'A' && buf[i] <= 'Z') {                        buf[i] = buf[i] + TOASCI;                    }                }            }   else if (pnk_msg->mode == UPPER_MODE){                for ( i = 0; ((i < NORMAL_LEN) && (buf[i] != '\0')); i++ ) {                    if ( buf[i] >= 'a' && buf[i] <= 'z') {                        buf[i] = buf[i] - TOASCI;                    }                }            }            memcpy(pnk_msg->data, buf, kstrlen(pnk_msg->data));             netlink_to_user(pnk_msg->pid,pnk_msg->data,NORMAL_LEN);            kfree(pnk_msg->data);            kfree(pnk_msg);        }    }   while (!kthread_should_stop());    return 0;}/************************/  /*        初始化       */  /**********************/static int init_kthreads(void){    int i;    for ( i=0; i < KTHREAD_NUM; i++) {        tsk_consumes[i] = kthread_run(kthread_consume, (void*)i, "kthread_consume%d", i);        if (IS_ERR(tsk_consumes[i])) {            return ERROR;        }    }    return 0;}/* init proc */int init_proc(void){    echo_dir = proc_mkdir("ruijie", NULL);      proc_file = create_proc_entry("echo_db", 0666, echo_dir);    if ( !proc_file) {        printk(KERN_ERR "can't create /proc/echo_db \n");        return ERROR;    }      proc_file->data = echo_database;     proc_file->read_proc = proc_read_foobar;      proc_file->write_proc = proc_write_foobar;         return 0;}/* netlink init*/static int __init netlink_init(void){     mutex_init(&mutex);    /* init queue */    if ( init_queue() == ERROR ) {        printk(KERN_ALERT "Init queue faill!\n");           return ERROR;         }    /* init pid_table */    init_pid_table(native_mode);    /* create proc */      if ( init_proc() == ERROR ) {        printk(KERN_ALERT "Init proc faill!\n");          return ERROR;         }    /* init netlink */        netlink_fd = netlink_kernel_create(&init_net, NETLINK_ECHO, 1, netlink_recv_msg, NULL, THIS_MODULE);      if ( netlink_fd == NULL) {          printk(KERN_ALERT "Init netlink faill!\n");         return ERROR;      }      /* create kthread */     if ( init_kthreads() == ERROR ) {        printk(KERN_ALERT "Init thread faill!\n");           return ERROR;         }    printk(KERN_ALERT "Init proc,netlink,pthread,queue, success!\n");      printk("\nRui Jie ECHO Server,Init!!! Author:Sun tian yu\n");    return 0;  }  /* exit */  static void __exit netlink_exit(void){      int i;    /* clear queue */    clear_queue(&queue);    /* proc */    remove_proc_entry("echo_db", echo_dir);        remove_proc_entry("ruijie", NULL);    /* clear kthread */    for ( i=0; i < KTHREAD_NUM; i++) {           if (!IS_ERR(tsk_consumes[i])) {            kthread_stop(tsk_consumes[i]);        }      }    /* clear netlink */    netlink_kernel_release(netlink_fd);      printk(KERN_ALERT "Exit netlink!\n");  }    MODULE_LICENSE("Dual BSD/GPL");  MODULE_AUTHOR("SunTianYu"); module_init(netlink_init);  module_exit(netlink_exit);  



0 0
原创粉丝点击