?? ksh_svr.c
字號:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/net.h>
#include <linux/version.h>
#include <net/sock.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/list.h>
#include "ksh_svr.h"
MODULE_AUTHOR("Dupree");
#ifdef FUNCTRACE
#define ENTERFUNCTION printk("Enter: %s, line %i\n", __func__,__LINE__)
#define LEAVEFUNCTION printk("Leave: %s, line %i\n", __func__,__LINE__)
#else
#define ENTERFUNCTION do {} while (0)
#define LEAVEFUNCTION do {} while (0)
#endif
/*macro*/
#define MAX_SESSION_NUM 8
#define MAX_SOCKET_READ_LEN 1000
#define MAX_SOCKET_WRITE_LEN 8000
struct session_info{
struct list_head list;
pid_t session_pid;
struct socket* sock;
struct completion thread_exit;
wait_queue_head_t wait_queue;
};
/*var*/
static LIST_HEAD(session_list_head);
unsigned int session_sum = 0;
char *sym = "/proc/ksyms";
MODULE_PARM(sym, "s");
struct file *sym_file = NULL;
static DECLARE_MUTEX(exec_sem);
/*func*/
static struct socket *listen_and_bind(const int port);
static struct socket *ksh_svr_accept(struct socket *sock);
void thread_init(struct session_info* psession);
static void read_data(struct socket *sock);
static int new_session(void *arg);
static void send_data(struct socket *sock, char *buffer, int len);
extern int execute_cmd(char *usr_input, char *output);
#if 1 //def DEBUG
void dump_data(char *addr, int length);
#endif
#if 1 //def DEBUG
void dump_data(char *addr, int length)
{
int i;
printk("length = %d", length);
for(i = 0; i < length; i++)
{
if((i%16)==0)
{
printk("\n%08x: ", (unsigned int)&addr[i]);
}else if((i%8)==0)
{
printk("- ");
}
printk("%2.2x ", (unsigned char)addr[i]);
}
printk("\n");
}
#endif
void thread_init(struct session_info* psession)
{
daemonize();
reparent_to_init();
spin_lock_irq(¤t->sigmask_lock);
sigfillset(¤t->blocked);
siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)|sigmask(SIGTERM));
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
init_completion(&psession->thread_exit);
init_waitqueue_head(&psession->wait_queue);
}
/*
* read data from socket, reference ip_vs_receive()
*/
static void read_data(struct socket *sock)
{
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
int len = 0, output_len = 0;
char *buffer = (char *)kmalloc(MAX_SOCKET_READ_LEN, GFP_KERNEL);
if(buffer == NULL){
printk("malloc memory failed\n");
return;
}
memset(buffer, 0, MAX_SOCKET_READ_LEN);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
msg.msg_iov->iov_base = buffer;
msg.msg_iov->iov_len = (size_t)MAX_SOCKET_READ_LEN;
oldfs = get_fs();
set_fs(KERNEL_DS);
/*len = sock_recvmsg(sock, &msg, 4000, MSG_PEEK);*/
len = sock_recvmsg(sock, &msg, MAX_SOCKET_READ_LEN, 0);
if(len >0){
//dump_data(buffer, len);
char *output = (char *)kmalloc(MAX_SOCKET_WRITE_LEN, GFP_KERNEL);
if(output == NULL){
set_fs(oldfs);
kfree(buffer);
return;
}
memset(output, 0, MAX_SOCKET_WRITE_LEN);
/*execute_cmd會訪問一些全局變量*/
down_interruptible(&exec_sem);
output_len = execute_cmd(buffer, output);
//printk("output_len = %d\n", output_len);
//printk("%s\n", output);
send_data(sock, output, output_len);
kfree(output);
up(&exec_sem);
}
set_fs(oldfs);
kfree(buffer);
}
static void send_data(struct socket *sock, char *buffer, int len)
{
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
if(buffer == NULL){
printk("buffer == NULL\n");
return;
}
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
msg.msg_iov->iov_base = buffer;
msg.msg_iov->iov_len = len;
oldfs = get_fs();
set_fs(KERNEL_DS);
len = sock_sendmsg(sock, &msg, len);
//printk("server say send msg len = %d\n", len);
set_fs(oldfs);
}
static int new_session(void *arg)
{
struct session_info *psession = (struct session_info *)arg;
struct socket *sock = psession->sock;
struct sock *sk = sock->sk;
ENTERFUNCTION;
sprintf(current->comm, "ksh_session%d", current->pid);
thread_init(psession);
while(1){
/*If this is no data, then sleep*/
if(!skb_queue_empty(&sk->receive_queue)){
read_data(psession->sock);
}
interruptible_sleep_on_timeout(&psession->wait_queue, 1*HZ);
if (sock->sk->state == TCP_CLOSE){
break;
}
if(signal_pending(current)){
break;
}
}
LEAVEFUNCTION;
session_sum--;
sock_release(sock);
list_del(&psession->list);
complete_and_exit(&psession->thread_exit, 0);
kfree(psession);
printk("%s exit\n", current->comm);
return 0;
}
static int main_daemon(void *arg)
{
struct socket *sock = NULL;
struct socket *new_sock = NULL;
struct session_info *psession = (struct session_info *)arg;
int err = 0;
sprintf(current->comm, "ksh_daemon");
thread_init(psession);
sock = listen_and_bind(KSH_SVR_PORT);
if(sock == NULL){
printk("listen on port %d failed\n", KSH_SVR_PORT);
goto failed;
}
while(1){
new_sock = ksh_svr_accept(sock);
/*go to sleep*/
if(new_sock == NULL){
interruptible_sleep_on_timeout(&psession->wait_queue, 1*HZ);
}
if(signal_pending(current)){
printk("thread %s receive a signal\n", current->comm);
break;
}
if(new_sock != NULL){
if(session_sum < MAX_SESSION_NUM){
struct session_info *psi = (struct session_info *)kmalloc(sizeof(struct session_info), GFP_KERNEL);
if(psi == NULL){
printk("[%s]kmalloc memory for session %d failed\n", __func__, session_sum);
break;
}
memset(psi, 0, sizeof(struct session_info));
psi->sock = new_sock;
list_add(&psi->list, &session_list_head);
psi->session_pid = kernel_thread(new_session, psi, CLONE_FS | CLONE_FILES);
printk("Someone connected, spawn new task[%d]\n", psi->session_pid);
session_sum++;
}else{
sock_release(new_sock);
printk("Too many connects\n");
}
}
}
/*close socket*/
err = sock->ops->shutdown(sock, 2);
if(err){
printk(KERN_ERR"Close sock failed!!\n");
}
sock_release(sock);
failed:
list_del(&psession->list);
complete_and_exit(&psession->thread_exit, 0);
kfree(psession);
return 0;
}
static struct socket *ksh_svr_accept(struct socket *sock)
{
int error = 0;
struct socket *new_sock = NULL;
#if 0 /*直接使用阻塞的accept*/
if(sock->sk->tp_pinfo.af_tcp.accept_queue == NULL){
return NULL;
}
#endif
new_sock = sock_alloc();
if (new_sock == NULL){
printk("sock_alloc failed!\n");
return NULL;
}
new_sock->type = sock->type;
new_sock->ops = sock->ops;
/* 00 - read-only
* 01 - write-only
* 10 - read-write
*/
/*確保accept會被阻塞 O_RDONLY , NOT O_NONBLOCK*/
error = sock->ops->accept(sock, new_sock, O_RDONLY); /*read only*/
if(error == 0){
return new_sock;
}else{
sock_release(new_sock);
return NULL;
}
}
static struct socket *listen_and_bind(const int port)
{
struct socket *sock;
struct sockaddr_in sin;
int error;
error = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
if (error < 0)
{
printk(KERN_ERR "create ksh svr socket error!!\n");
return NULL;
}
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons((unsigned short)port);
error = sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin));
if (error < 0)
{
printk(KERN_ERR " Error binding socket, using port %i. error = %d\n", port, -error);
return NULL;
}
sock->sk->reuse = 1;
error = sock->ops->listen(sock, MAX_SESSION_NUM);
if (error != 0)
{
printk(KERN_ERR "Error listening on socket \n");
return NULL;
}
printk("listen and bind to port %d successful\n", port);
return sock;
}
static int __init ksh_dev_init(void)
{
struct session_info *psi = NULL;
sym_file = filp_open(sym, O_RDONLY, 0);
if(IS_ERR(sym_file)){
printk("open symbol file:%s failed\n", sym);
return -1;
}
psi = (struct session_info *)kmalloc(sizeof(struct session_info), GFP_KERNEL);
if(psi == NULL){
printk("[%s]kmalloc memory failed\n", __func__);
return -1;
}
list_add(&psi->list, &session_list_head);
psi->session_pid = kernel_thread(main_daemon, psi, CLONE_FS | CLONE_FILES);
printk("symbol file = %s\n", sym);
return 0;
}
static void __exit ksh_dev_exit(void)
{
int ret;
struct list_head *p, *n;
struct session_info *psi;
/*kill all session*/
list_for_each_safe(p, n, &session_list_head){
psi = list_entry(p, struct session_info, list);
if(psi->session_pid > 0){
ret = kill_proc(psi->session_pid, SIGTERM, 1);
if(ret){
printk("unable to send signal to pid %d\n", psi->session_pid);
}else{
wait_for_completion(&psi->thread_exit);
/*printk("sesion pid[%d] exit\n", psi->session_pid);*/
}
}
}
printk("ksh module removed successful\n");
filp_close(sym_file, NULL);
return;
}
module_init(ksh_dev_init);
module_exit(ksh_dev_exit);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -