1 #include "kvm/kvm-ipc.h" 2 #include "kvm/rwsem.h" 3 #include "kvm/read-write.h" 4 #include "kvm/util.h" 5 6 #include <sys/epoll.h> 7 #include <sys/un.h> 8 #include <sys/types.h> 9 #include <sys/socket.h> 10 11 #define KVM_IPC_MAX_MSGS 16 12 13 static void (*msgs[KVM_IPC_MAX_MSGS])(int fd, u32 type, u32 len, u8 *msg); 14 static DECLARE_RWSEM(msgs_rwlock); 15 static int epoll_fd, server_fd; 16 17 int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg)) 18 { 19 if (type >= KVM_IPC_MAX_MSGS) 20 return -ENOSPC; 21 22 down_write(&msgs_rwlock); 23 msgs[type] = cb; 24 up_write(&msgs_rwlock); 25 26 return 0; 27 } 28 29 int kvm_ipc__handle(int fd, struct kvm_ipc_msg *msg) 30 { 31 void (*cb)(int fd, u32 type, u32 len, u8 *msg); 32 33 if (msg->type >= KVM_IPC_MAX_MSGS) 34 return -ENOSPC; 35 36 down_read(&msgs_rwlock); 37 cb = msgs[msg->type]; 38 up_read(&msgs_rwlock); 39 40 if (cb == NULL) { 41 pr_warning("No device handles type %u\n", msg->type); 42 return -ENODEV; 43 } 44 45 cb(fd, msg->type, msg->len, msg->data); 46 47 return 0; 48 } 49 50 static int kvm_ipc__new_conn(int fd) 51 { 52 int client; 53 struct epoll_event ev; 54 55 client = accept(fd, NULL, NULL); 56 if (client < 0) 57 return -1; 58 59 ev.events = EPOLLIN | EPOLLRDHUP; 60 ev.data.fd = client; 61 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client, &ev) < 0) { 62 close(client); 63 return -1; 64 } 65 66 return client; 67 } 68 69 static void kvm_ipc__close_conn(int fd) 70 { 71 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL); 72 close(fd); 73 } 74 75 static void kvm_ipc__new_data(int fd) 76 { 77 struct kvm_ipc_msg *msg; 78 u32 n; 79 80 msg = malloc(sizeof(*msg)); 81 if (msg == NULL) 82 goto done; 83 84 n = read(fd, msg, sizeof(*msg)); 85 if (n != sizeof(*msg)) 86 goto done; 87 88 msg = realloc(msg, sizeof(*msg) + msg->len); 89 if (msg == NULL) 90 goto done; 91 92 n = read_in_full(fd, msg->data, msg->len); 93 if (n != msg->len) 94 goto done; 95 96 kvm_ipc__handle(fd, msg); 97 98 done: 99 free(msg); 100 } 101 102 static void *kvm_ipc__thread(void *param) 103 { 104 struct epoll_event event; 105 106 for (;;) { 107 int nfds; 108 109 nfds = epoll_wait(epoll_fd, &event, 1, -1); 110 if (nfds > 0) { 111 int fd = event.data.fd; 112 113 if (fd == server_fd) { 114 int client; 115 116 client = kvm_ipc__new_conn(fd); 117 kvm_ipc__new_data(client); 118 } else if (event.events && (EPOLLERR | EPOLLRDHUP | EPOLLHUP)) { 119 kvm_ipc__close_conn(fd); 120 } else { 121 kvm_ipc__new_data(fd); 122 } 123 } 124 } 125 126 return NULL; 127 } 128 129 int kvm_ipc__start(int sock) 130 { 131 pthread_t thread; 132 struct epoll_event ev; 133 134 server_fd = sock; 135 136 epoll_fd = epoll_create(KVM_IPC_MAX_MSGS); 137 138 ev.events = EPOLLIN | EPOLLOUT | EPOLLPRI; 139 ev.data.fd = sock; 140 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) < 0) 141 die("Failed starting IPC thread"); 142 143 if (pthread_create(&thread, NULL, kvm_ipc__thread, NULL) != 0) 144 die("Failed starting IPC thread"); 145 146 return 0; 147 } 148