void check_clients(fd_set *fds) { struct client_list **c; for (c = &clients; *c; ) { int next = 1; if (FD_ISSET((*c)->fd, fds)) { int len; const void *packet = read_sf_packet((*c)->fd, &len); if (packet) { forward_packet(packet, len); free((void *)packet); } else { rem_client(c); next = 0; } } if (next) c = &(*c)->next; } }
void dispatch_packet(const void *packet, int len) { struct client_list **c; for (c = &clients; *c; ) if (write_sf_packet((*c)->fd, packet, len) >= 0) c = &(*c)->next; else rem_client(c); }
int main(int argc, char* argv[]) { int opt, ret; int daemon = 1, lock = 0; int screen_status, aux_pressed, power_pressed, y, x; char *config; FILE *file; struct sockaddr_un addr; struct chain_socket *aux_grabber = 0, *power_grabber = 0; struct input_event input; struct iod_cmd cmd; struct chain_socket *cs; size_t size; y = x = screen_status = aux_pressed = power_pressed = 0; pwd = IOD_PWD; while((opt = getopt(argc, argv, "fd:")) != -1) { switch(opt) { case 'f': daemon = 0; break; case 'd': pwd = optarg; break; default: usage(argv[0]); return 0; } } if(optind == argc) { usage(argv[0]); return 0; } config = argv[optind]; if(mkdir(pwd, 0777) == -1 && errno != EEXIST) { perror("Failed to create working dir"); return 7; } if(daemon) { int tmp = fork(); if(tmp < 0) { perror("Failed to fork process"); return 1; } if(tmp > 0) { return 0; } setsid(); close(0); close(1); close(2); tmp = open("/dev/null", O_RDWR); dup(tmp); dup(tmp); chdir(pwd); if((tmp = open("pid", O_WRONLY|O_CREAT, 755)) < 0) { perror("Failed to open pidfile"); return 2; } pid_t pid = getpid(); char buf[10]; int count = sprintf(buf, "%i", pid); write(tmp, &buf, count*sizeof(char)); if(lockf(tmp, F_TLOCK, -count*sizeof(char)) < 0) { perror("Daemon already running"); return 3; } } if(!(file = fopen(config, "r"))) { perror("Failed to open config file"); return 4; } if((size = getline(&screen_dev, &size, file)) == -1) { fprintf(stderr, "Failed to read screen config\n"); return 5; } screen_dev[size-1] = 0; if((screen_fd = open(screen_dev, O_RDONLY)) == -1) { perror("Failed to open screen socket"); return 6; } if((size = getline(&aux_dev, &size, file)) == -1) { fprintf(stderr, "Failed to read aux config\n"); return 7; } aux_dev[size-1] = 0; if((aux_fd = open(aux_dev, O_RDONLY)) == -1) { perror("Failed to open aux socket"); return 8; } if((size = getline(&power_dev, &size, file)) == -1) { fprintf(stderr, "Failed to read power config\n"); return 9; } power_dev[size-1] = 0; fclose(file); if((power_fd = open(power_dev, O_RDONLY)) == -1) { perror("Failed to open power socket"); return 10; } DEBUG(print_info(screen_fd)); DEBUG(print_info(aux_fd)); DEBUG(print_info(power_fd)); if((ret = open_socket(&sock, &addr))) return ret; pfds_cap = 10; pfds = malloc(pfds_cap*sizeof(struct pollfd)); pfds[0].fd = screen_fd; pfds[0].events = POLLIN; pfds[1].fd = aux_fd; pfds[1].events = POLLIN; pfds[2].fd = power_fd; pfds[2].events = POLLIN; pfds[3].fd = sock; pfds[3].events = POLLIN; client_count = 0; CIRCLEQ_INIT(&client_list); signal(SIGINT, signal_handler); DEBUG(printf("Ready\n")); while(1) { poll(pfds, client_count+4, -1); if(pfds[0].revents & POLLHUP || pfds[0].revents & POLLERR) { DEBUG(printf("pollhup/err on screen socket\n")); close(screen_fd); if((screen_fd = open(screen_dev, O_RDONLY)) < 0) { perror("Failed to open screen socket"); screen_fd = 0; cleanup(); return 6; } } else if(pfds[0].revents & POLLIN) { read(screen_fd, &input, sizeof(struct input_event)); if(lock) continue; switch(input.type) { case EV_KEY: switch(input.code) { case BTN_TOUCH: switch(input.value) { case 0: screen_status = 0; break; case 1: screen_status = 1; break; } break; } break; case EV_ABS: switch(input.code) { case ABS_X: y = input.value-MIN_PIXEL; break; case ABS_Y: x = input.value-MIN_PIXEL; break; case ABS_PRESSURE: break; } break; case EV_SYN: switch(input.code) { case SYN_REPORT: switch(screen_status) { case 0: DEBUG(printf("Touchscreen released (%i,%i)\n", y, x)); send_client_cord(IOD_EVENT_RELEASED, y, x, 0); break; case 1: DEBUG(printf("Touchscreen pressed (%i,%i)\n", y, x)); send_client_cord(IOD_EVENT_PRESSED, y, x, 0); screen_status = 2; break; case 2: send_client_cord(IOD_EVENT_MOVED, y, x, 0); break; } break; } break; } } else if(pfds[1].revents & POLLHUP || pfds[1].revents & POLLERR) { DEBUG(printf("pollhup/err on aux socket\n")); close(aux_fd); if((aux_fd = open(aux_dev, O_RDONLY)) == -1) { perror("Failed to open aux socket"); aux_fd = 0; cleanup(); return 8; } } else if(pfds[1].revents & POLLIN) { read(aux_fd, &input, sizeof(struct input_event)); switch(input.type) { case EV_KEY: switch(input.code) { case KEY_PHONE: aux_pressed = input.value; break; } break; case EV_SYN: switch(input.code) { case SYN_REPORT: DEBUG(printf("AUX %s\n", aux_pressed ? "pressed" : "released")); cs = aux_grabber ? aux_grabber : 0; send_client_status(IOD_EVENT_AUX, aux_pressed, cs); break; } break; } } else if(pfds[2].revents & POLLHUP || pfds[2].revents & POLLERR) { DEBUG(printf("pollhup/err on power socket\n")); close(power_fd); if((power_fd = open(power_dev, O_RDONLY)) == -1) { perror("Failed to open power socket"); power_fd = 0; cleanup(); return 10; } } else if(pfds[2].revents & POLLIN) { read(power_fd, &input, sizeof(struct input_event)); switch(input.type) { case EV_KEY: switch(input.code) { case KEY_POWER: power_pressed = input.value; break; } break; case EV_PWR: break; case EV_SYN: switch(input.code) { case SYN_REPORT: DEBUG(printf("Power %s\n", power_pressed ? "pressed" : "released")); cs = power_grabber ? power_grabber : 0; send_client_status(IOD_EVENT_POWER, power_pressed, cs); break; } break; } } else if(pfds[3].revents & POLLHUP || pfds[3].revents & POLLERR) { DEBUG(printf("pollhup/err on socket\n")); close(sock); if((ret = open_socket(&sock, &addr))) { sock = 0; cleanup(); return ret; } } else if(pfds[3].revents & POLLIN) { int client; if((client = accept(sock, 0, 0)) == -1) { DEBUG(perror("Failed to accept client")); continue; } cs = client_list.cqh_first; add_client(client); if(cs != (void*)&client_list) send_client_status(IOD_EVENT_DEACTIVATED, 0, cs); else send_client_status(IOD_EVENT_ACTIVATED, 0, 0); } else { int x; for(x=4; x<client_count+4; x++) if(pfds[x].revents & POLLHUP || pfds[x].revents & POLLERR) { DEBUG(printf("pollhup/pollerr on client socket [%i]\n", pfds[x].fd)); cs = find_client(&x, 0); remove: if(cs == aux_grabber) { DEBUG(printf("AUX ungrabbed [%i] %i\n", cs->sock, cs->pid)); aux_grabber = 0; } if(cs == power_grabber) { DEBUG(printf("Power ungrabbed [%i] %i\n", cs->sock, cs->pid)); power_grabber = 0; } if(cs->lock) { DEBUG(printf("Screen unlocked [%i] %i\n", cs->sock, cs->pid)); lock = 0; } if(rem_client(x, cs)) send_client_status(IOD_EVENT_ACTIVATED, 0, 0); break; } else if(pfds[x].revents & POLLIN) { if(recv_client(pfds[x].fd, &cmd)) break; switch(cmd.cmd) { case IOD_CMD_REGISTER: register_client(x, cmd.pid); break; case IOD_CMD_REMOVE: if((cs = find_client(&x, cmd.pid))) { if(cs->sock == pfds[x].fd) goto remove; else { DEBUG(printf("Client remove [%i] %i\n", cs->sock, cs->pid)); send_client_status( IOD_EVENT_REMOVED, 0, cs); } } break; case IOD_CMD_SWITCH: cs = client_list.cqh_first; if(switch_client(cmd.value, x, cmd.pid)) send_client_status( IOD_EVENT_DEACTIVATED, 0, cs); break; case IOD_CMD_LOCK: cs = find_client(&x, 0); if(!lock || cs->lock) { lock = cs->lock = cmd.value; DEBUG(printf("Screen %s [%i] %i\n", lock ? "locked" : "unlocked", x, cs->pid)); send_client_status( IOD_EVENT_LOCK, IOD_SUCCESS_MASK, cs); } else send_client_status( IOD_EVENT_LOCK, 0, cs); break; case IOD_CMD_HIDE: hide_client(x, cmd.pid, cmd.value & ~IOD_HIDE_MASK, cmd.value & IOD_HIDE_MASK); break; case IOD_CMD_ACK: switch(cmd.value) { case IOD_EVENT_DEACTIVATED: cs = client_list.cqh_first; DEBUG(printf("Client switched [%i] %i -> [%i] %i\n", pfds[x].fd, find_client(&x, 0)->pid, cs->sock, cs->pid)); send_client_status( IOD_EVENT_ACTIVATED, 0, 0); break; case IOD_EVENT_REMOVED: cs = find_client(&x, 0); goto remove; default: DEBUG(printf("Client done [%i] %i\n", pfds[x].fd, find_client(&x, 0)->pid)); break; } break; case IOD_CMD_GRAB: cs = find_client(&x, 0); switch(cmd.value & ~IOD_GRAB_MASK) { case IOD_GRAB_AUX: if(!aux_grabber || cs == aux_grabber) { if(cmd.value & IOD_GRAB_MASK) { DEBUG(printf("AUX grabbed [%i] %i\n", cs->sock, cs->pid)); aux_grabber = cs; } else { DEBUG(printf("AUX ungrabbed [%i] %i\n", cs->sock, cs->pid)); aux_grabber = 0; } send_client_status(IOD_EVENT_GRAB, IOD_SUCCESS_MASK|IOD_GRAB_AUX, cs); } else send_client_status(IOD_EVENT_GRAB, IOD_GRAB_AUX, cs); break; case IOD_GRAB_POWER: if(!power_grabber || cs == power_grabber) { if(cmd.value & IOD_GRAB_MASK) { DEBUG(printf("Power grabbed [%i] %i\n", cs->sock, cs->pid)); power_grabber = cs; } else { DEBUG(printf("Power ungrabbed [%i] %i\n", cs->sock, cs->pid)); power_grabber = 0; } send_client_status(IOD_EVENT_GRAB, IOD_SUCCESS_MASK|IOD_GRAB_POWER, cs); } else send_client_status(IOD_EVENT_GRAB, IOD_GRAB_POWER, cs); break; } break; case IOD_CMD_POWERSAVE: DEBUG(printf("Powersave %s broadcast\n", cmd.value ? "on" : "off")); cs = client_list.cqh_first; while(cs != (void*)&client_list) { if(cs->sock != pfds[x].fd) send_client_status( IOD_EVENT_POWERSAVE, cmd.value, cs); cs = cs->chain.cqe_next; } break; default: DEBUG(printf("Unrecognized command 0x%02hhx [%i] %i\n", cmd.cmd, pfds[x].fd, find_client(&x, 0)->pid)); } break; } } } cleanup(); return 0; }