#include #include #include #include #include #include #include #include #include #include enum { SERVER_FD = 0, IEEE_FD = 1, CLIENT_FD = 2, DESCRIPTORS = 3 }; static struct msg_state client_state; static raw1394handle_t ieee_handle; static struct pollfd pollfds[DESCRIPTORS] = {{0}}; static void verr(char *fmt, va_list va) { int n = 0; if (fmt) n = vfprintf(stderr, fmt, va); if (errno) fprintf(stderr, "%s%s\n", n ? ": " : "", strerror(errno)); else fprintf(stderr, "\n"); exit(1); } static void err(char *fmt, ...) { va_list va; va_start(va, fmt); verr(fmt, va); va_end(va); } static void server_accept(void) { int fd = accept(pollfds[SERVER_FD], NULL, NULL); if (pollfds[CLIENT_FD].fd >= 0) { close(fd); return; } if (fd < 0) { if (errno != ECONNABORTED) err("accept"); else return; } pollfds[CLIENT_FD].fd = fd; client_state.state = PARSE_VERSION_MESSAGE; client_state.type = MESSAGE_INVALID; if (client_state.buf) { sdsclear(client_state.buf); } else { client_state.buf = sdsempty(); } } static void iterate(void) { if (raw1394_loop_iterate(ieee_handle) < 0) err("raw1394_loop_iterate"); } /* 0b111111 = 0x3F * if tags[x] < 0, then tag is not allocated */ #define TAG_NUM 0x40 static long tag_to_handle[TAG_NUM]; static void handle_send_async(union msg *msg) { switch (msg->send_async.tcode) { case TCODE_WRITE_QUADLET_REQUEST: case TCODE_WRITE_BLOCK_REQUEST: raw1394_start_write(ieee_handle, msg->send_async.node, msg->send_async.addr, msg->send_async.len, msg->send_async.buf, msg->send_async.tlabel); break; case TCODE_READ_QUADLET_REQUEST: case TCODE_READ_BLOCK_REQUEST: raw1394_start_read(ieee_handle, msg->send_async.node, msg->send_async.addr, msg->send_async.len, msg->send_async.buf, msg->send_async.tlabel); break; case TCODE_WRITE_RESONSE: case TCODE_READ_QUADLET_RESPONSE: case TCODE_READ_BLOCK_RESPONSE: if (msg->send_async.tlabel < TAG_NUM && tags_to_handle[msg->send_async.tlabel] >= 0) { raw1394_send_rw_response(ieee_handle, msg->send_async.tcode, msg->send_async.buf, msg->send_async.len, tags_to_handle[msg->send_async.tlabel]); tags_to_handle[msg->send_async.tlabel] = 0; } break; /* FIXME: implement lock request */ } } static void handle_send_iso(union msg *msg) { /* do nothing */ } static int arm_handler(raw1394handle_t handle, raw1394_arm_allocation_t *arm, int tcode, unsigned long long offset, int source_node_id, int card, unsigned kernel_handle, size_t length, void *data) { (void)handle; uint8_t tag; /* Allocate tags. * Tags are temporarily allocated since the real tag is stored in the * kernel in the kernel_handle. * * firewire-cdev: bus is only 1023? */ for (tag = 0; tag < MAX_TAG; tag++) { if (tag_to_handle[tag] < 0) break; } if (tag == MAX_TAG) return -1; tag_to_handle[tag] = kernel_handle; if (msg_send_async(pollfds[SERVER_FD].fd, 1023, source_node_id, offset, tcode, tag, length, data) < 0) tag_to_handle[tag] = -1; /* TODO: return an error response */ return 0; } static void handle_allocation(union msg *msg) { /* may fail due to overlap: ignore */ raw1394_arm_register(ieee_handle, msg->allocate.start, msg->allocate.length, ARM_READ | ARM_WRITE | ARM_LOCK, ARM_READ | ARM_WRITE | ARM_LOCK, 0 /* ignored */); } static bool read_client(void) { char buf[512]; ssize_t len; int msgtype; len = read(pollfds[CLIENT_FD].fd, buf, sizeof(buf)); if (len <= 0) return false; client_state.buf = sdscatlen(client_state.buf, buf, len); while (!parse_packet(fdstate)); return true; } static bool client_process(void) { if (fd->revents & POLLERR) return false; if (fd->revents & POLLIN) if (!read_client(fd, fdstate)) return false; if (!(fd->revents & POLLIN) && fd->revents & POLLHUP) return false; return true; } static int open_server(const char *port) { int r; struct addrinfo *serv; int sock; if ((r = getaddrinfo(NULL, port, &(struct addrinfo){ .ai_family = AF_INET, .ai_socktype = SOCK_STREAM, .ai_flags = AI_PASSIVE }, &serv) != 0) { err("getaddrinfo: %s", gai_strerror(r)); } for (struct addrinfo *p = serv; p; p = p->ai_next) { sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (sock < 0) continue; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR) < 0) continue; if (bind(sock, p->ai_addr, p->ai_addrlen) < 0) continue; break; } if (!p) err("socket"); freeaddrinfo(serv); if (listen(p, 5) < 0) err("listen"); return sock; } static int setup_port(int port) { int num; int fd; static struct raw1394_portinfo ports[PORTSNUM] = {0}; ieee_handle = raw1394_new_handle(); if (!ieee_handle) err("raw1394_new_handle"); num = raw1394_get_port_info(ieee_handle, ports, PORTSNUM); do { for (int i = 0; i < num && i < PORTSNUM; i++) fprintf(stderr, "[%d/%d]: %s w/ %d\n", i + 1, num, ports[i].name, ports[i].nodes); errno = 0; raw1394_set_port(ieee_handle, port); } while (errno != ESTALE); if (errno) die("raw1394_set_port"); fd = raw1394_get_fd(ieee_handle); if (fd < 0) die("raw1394_get_fd"); return fd; } int main(void) { pollfds[IEEE_FD].fd = setup_port(0); pollfds[IEEE_FD].events = POLLIN | POLLPRI; pollfds[SERVER_FD].fd = open_server("1394"); pollfds[SERVER_FD].events = POLLIN | POLLPRI; pollfds[CLIENT_FD].fd = -1; for (int i = 0; i < TAG_NUM; i++) tag_to_handle[i] = -1; client_state.on_read[PARSE_SEND_ASYNC] = ieee_process; while (1) { if (poll(pollfds, DESCRIPTORS, -1) <= 0) err("poll"); if (pollfds[SERVER_FD].revents & (POLLIN | POLLPRI)) { server_accept(); } else if (pollfds[IEEE_FD].revents & (POLLIN | POLLPRI)) { ieee_process(); } if (!client_process()) { close(pollfds[CLIENT_FD].fd); pollfds[CLIENT_FD].fd = -1; // Reset Firewire raw1394_destroy_handle(ieee_handle); pollfds[IEEE_FD].fd = setup_port(0); } } }