static int http_server(void) { int server_fd = 0; int ctrl_fd = 0, ctrl_fd2 = 0; int ret, delay; struct pollfd *poll_table, *poll_entry; HTTPContext *c, *c_next; if(!(poll_table = av_mallocz_array(nb_max_http_connections + 1, sizeof(*poll_table)))) { http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections); return -1; } #if defined(PLUGIN_DVB) ctrl_fd = ff_ctl_open(1234); if (ctrl_fd < 0) { av_free(poll_table); return -1; } #endif if (my_http_addr.sin_port) { server_fd = socket_open_listen(&my_http_addr); if (server_fd < 0) { av_free(poll_table); return -1; } } if ( !server_fd) { http_log("HTTP disabled.\n"); av_free(poll_table); return -1; } #if defined(PLUGIN_SSDP) ssdp_fd = mcast_open(ssdp_ip, ssdp_port); if(ssdp_fd <= 0){ http_log("ssdp disabled\n"); } ssdp_notify(ssdp_fd, ssdp_ip, ssdp_port, "ssdp:alive"); #endif http_log("FFserver started.\n"); for(;;) { poll_entry = poll_table; #if defined(PLUGIN_DVB) if(ctrl_fd){ poll_entry->fd = ctrl_fd; poll_entry->events = POLLIN; poll_entry++; } if(ctrl_fd2){ poll_entry->fd = ctrl_fd2; poll_entry->events = POLLIN; if(ctl_msg_pending() > 0){ poll_entry->events |= POLLOUT; } poll_entry++; } #endif if (server_fd) { poll_entry->fd = server_fd; poll_entry->events = POLLIN; poll_entry++; } #if defined(PLUGIN_SSDP) if(ssdp_fd){ poll_entry->fd = ssdp_fd; poll_entry->events = POLLIN; poll_entry++; } #endif /* wait for events on each HTTP handle */ c = first_http_ctx; delay = 1500; while (c != NULL) { int fd; fd = c->fd; switch(c->state) { case HTTPSTATE_SEND_HEADER: c->poll_entry = poll_entry; poll_entry->fd = fd; poll_entry->events = POLLOUT; poll_entry++; break; case HTTPSTATE_SEND_DATA_HEADER: case HTTPSTATE_SEND_DATA: case HTTPSTATE_SEND_DATA_TRAILER: /*for TCP, we output as much as we can*/ c->poll_entry = poll_entry; poll_entry->fd = fd; poll_entry->events = POLLOUT; poll_entry++; break; case HTTPSTATE_WAIT_REQUEST: case HTTPSTATE_RECEIVE_DATA: case HTTPSTATE_WAIT_FEED: /* need to catch errors */ c->poll_entry = poll_entry; poll_entry->fd = fd; poll_entry->events = POLLIN;/* Maybe this will work */ poll_entry++; break; default: c->poll_entry = NULL; break; } c = c->next; } /* wait for an event on one connection. We poll at least every second to handle timeouts */ do { ret = poll(poll_table, poll_entry - poll_table, delay); if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) && ff_neterrno() != AVERROR(EINTR)) { av_free(poll_table); return -1; } } while (ret < 0); cur_time = av_gettime() / 1000; /* now handle the events */ for(c = first_http_ctx; c != NULL; c = c_next) { c_next = c->next; if (handle_connection(c) < 0) { log_connection(c); close_connection(c); } } poll_entry = poll_table; #if defined(PLUGIN_DVB) if(ctrl_fd){ if(poll_entry->revents & POLLIN){ ctrl_fd2 = ctl_msg_open(ctrl_fd); } poll_entry++; } if(ctrl_fd2 && poll_entry->fd == ctrl_fd2){ if(poll_entry->revents & POLLIN){ ctl_msg_recv(); ff_ctl_recv(ctl_msg_cb); }else if(poll_entry->revents & POLLOUT){ ctl_msg_send(); } poll_entry++; } #endif if(poll_entry->fd != server_fd){ printf("bad entry\n"); } if (server_fd) { if (poll_entry->revents & POLLIN) new_connection(server_fd, 0); poll_entry++; } #if defined(PLUGIN_SSDP) if (ssdp_fd) { if (poll_entry->revents & POLLIN) ssdp_response(ssdp_fd); poll_entry++; } #endif } }
/** * mc is set if packet arrived on our multicast listening socket */ static void ssdp_input(int fd, int mc) { char buf[2000]; int r, cmd, self; struct http_header_list args; uint32_t myaddr; const char *usn; struct sockaddr_in si; #if defined(IP_RECVDSTADDR) struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; char ctrl[500]; iov.iov_base = buf; iov.iov_len = sizeof(buf); msg.msg_name = (struct sockaddr *)&si; msg.msg_namelen = sizeof(struct sockaddr_in); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ctrl; msg.msg_controllen = sizeof(ctrl); r = recvmsg(fd, &msg, 0); if(r < 1) return; buf[r] = 0; myaddr = 0; for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg,cmsg)) { if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { struct in_addr *ia = (struct in_addr *)CMSG_DATA(cmsg); myaddr = ntohl(ia->s_addr); break; } } #else socklen_t slen = sizeof(struct sockaddr_in); netif_t *ni; r = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&si, &slen); if(r < 1) return; buf[r] = 0; ni = net_get_interfaces(); myaddr = ni ? ni[0].ipv4 : 0; free(ni); #endif if(!myaddr) return; LIST_INIT(&args); cmd = ssdp_parse(buf, &args); usn = http_header_get(&args, "usn"); self = usn != NULL && !strncmp(usn, "uuid:", 5) && !strncmp(usn + 5, ssdp_uuid, strlen(ssdp_uuid)); if(!self) { if(cmd == SSDP_NOTIFY && mc) ssdp_recv_notify(&args); if(cmd == SSDP_RESPONSE && !mc) ssdp_response(&args); if(cmd == SSDP_SEARCH && mc) ssdp_send_all(ssdp_fdu, myaddr, &si, NULL); } http_headers_free(&args); }