void extint_w2a(void *param) { int n, i, j; conn_t *conn = (conn_t *) param; u4_t ka_time = timer_sec(); // initialize extension for this connection send_msg_mc(conn->mc, false, "EXT ext_client_init"); nbuf_t *nb = NULL; while (TRUE) { int rx_chan, ext_rx_chan; ext_t *ext; if (nb) web_to_app_done(conn, nb); n = web_to_app(conn, &nb); if (n) { char *cmd = nb->buf; cmd[n] = 0; // okay to do this -- see nbuf.c:nbuf_allocq() char id[64]; ka_time = timer_sec(); // receive and send a roundtrip keepalive i = strcmp(cmd, "SET keepalive"); if (i == 0) { ext_send_msg(conn->ext_rx_chan, false, "EXT keepalive"); continue; } ext_rx_chan = conn->ext_rx_chan; //printf("extint_w2a: %s CONN%d-%p RX%d-%p %d <%s>\n", conn->ext? conn->ext->name:"?", conn->self_idx, conn, ext_rx_chan, (ext_rx_chan == -1)? 0:ext_users[ext_rx_chan].conn, strlen(cmd), cmd); // answer from client ext about who they are // match against list of known extensions and register msg handler char client[32]; int first_time; i = sscanf(cmd, "SET ext_switch_to_client=%s first_time=%d rx_chan=%d", client, &first_time, &rx_chan); if (i == 3) { for (i=0; i < n_exts; i++) { ext = ext_list[i]; if (strcmp(client, ext->name) == 0) { //printf("ext_switch_to_client: found func %p CONN%d-%p for ext %s RX%d\n", ext->receive_msgs, conn->self_idx, conn, client, rx_chan); ext_users[rx_chan].ext = ext; ext_users[rx_chan].conn = conn; conn->ext_rx_chan = rx_chan; conn->ext = ext; TaskNameS(ext->name); break; } } if (i == n_exts) panic("ext_switch_to_client: unknown ext"); // automatically let extension server-side know the connection has been established and // our stream thread is running if (first_time) ext->receive_msgs((char *) "SET ext_server_init", rx_chan); continue; } i = sscanf(cmd, "SET ext_blur=%d", &rx_chan); if (i == 1) { extint_ext_users_init(rx_chan); continue; } i = strcmp(cmd, "SET init"); if (i == 0) { continue; } i = sscanf(cmd, "SERVER DE CLIENT %s", id); if (i == 1) { continue; } ext_rx_chan = conn->ext_rx_chan; if (ext_rx_chan == -1) { printf("### extint_w2a: %s CONN%d-%p ext_rx_chan == -1?\n", conn->ext? conn->ext->name:"?", conn->self_idx, conn); continue; } ext = ext_users[ext_rx_chan].ext; if (ext == NULL) { printf("### extint_w2a: %s CONN%d-%p ext_rx_chan %d ext NULL?\n", conn->ext? conn->ext->name:"?", conn->self_idx, conn, ext_rx_chan); continue; } if (ext->receive_msgs) { //printf("extint_w2a: %s ext->receive_msgs() %p CONN%d-%p RX%d-%p %d <%s>\n", conn->ext? conn->ext->name:"?", ext->receive_msgs, conn->self_idx, conn, ext_rx_chan, (ext_rx_chan == -1)? 0:ext_users[ext_rx_chan].conn, strlen(cmd), cmd); if (ext->receive_msgs(cmd, ext_rx_chan)) continue; } else { printf("### extint_w2a: %s CONN%d-%p RX%d-%p ext->receive_msgs == NULL?\n", conn->ext? conn->ext->name:"?", conn->self_idx, conn, ext_rx_chan, (ext_rx_chan == -1)? 0:ext_users[ext_rx_chan].conn); continue; } printf("extint_w2a: %s CONN%d-%p unknown command: <%s> ======================================================\n", conn->ext? conn->ext->name:"?", conn->self_idx, conn, cmd); continue; } conn->keep_alive = timer_sec() - ka_time; bool keepalive_expired = (conn->keep_alive > KEEPALIVE_SEC); if (keepalive_expired) { ext_rx_chan = conn->ext_rx_chan; ext = ext_users[ext_rx_chan].ext; printf("EXT KEEP-ALIVE EXPIRED RX%d %s\n", ext_rx_chan, ext? ext->name : "(no ext)"); if (ext != NULL && ext->close_conn != NULL) ext->close_conn(ext_rx_chan); extint_ext_users_init(ext_rx_chan); rx_server_remove(conn); panic("shouldn't return"); } TaskSleep(250000); } }
// if this connection is new spawn new receiver channel with sound/waterfall tasks conn_t *rx_server_websocket(struct mg_connection *mc) { int i; conn_t *c; stream_t *st; assert(mc->remote_port != 0); c = (conn_t*) mc->connection_param; if (c) { // existing connection if (c->magic != CN_MAGIC) printf("for: %s:%d %s\n", mc->remote_ip, mc->remote_port, mc->uri); assert(c->magic == CN_MAGIC); assert(c->mc == mc); assert(c->remote_port == mc->remote_port); return c; } const char *uri = mc->uri; if (uri[0] == '/') uri++; //printf("#### new connection: %s:%d %s ", mc->remote_ip, mc->remote_port, uri); for (i=0; streams[i].uri; i++) { st = &streams[i]; if (strcmp(uri, st->uri) == 0) break; } if (!streams[i].uri) { lprintf("**** unknown stream type <%s>\n", uri); return NULL; } printf("LOOKING for free conn for type=%d (%s)\n", st->type, st->uri); for (c=conns; c<&conns[RX_CHANS*2]; c++) { if ((c->remote_port == 0) && (c->type == st->type)) break; printf("BUSY conn rx=%d, remote_port=%d, type=%d (%s)\n", c->rx_channel, c->remote_port, c->type, streams[c->type].uri); } if (c == &conns[RX_CHANS*2]) { printf("(too many rx channels open for %s)\n", st->uri); if (st->type == STREAM_WATERFALL) send_msg_mc(mc, "MSG too_busy=%d", RX_CHANS); return NULL; } printf("FREE conn rx=%d, remote_port=%d, type=%d (%s)\n", c->rx_channel, c->remote_port, c->type, streams[c->type].uri); if (down) { //printf("(down for devl)\n"); if (st->type == STREAM_WATERFALL) send_msg_mc(mc, "MSG down"); return NULL; } if (!do_wrx) { if (do_gps && (st->type == STREAM_WATERFALL)) { // display GPS data in waterfall send_msg_mc(mc, "MSG gps"); } else if (do_fft && (st->type == STREAM_WATERFALL)) { send_msg_mc(mc, "MSG fft"); } else if (do_fft && (st->type == STREAM_SOUND)) { ; // start sound task to process sound UI controls } else { //printf("(no wrx)\n"); return NULL; } } // NB: c->type & c->rx_channel are preset c->magic = CN_MAGIC; c->mc = mc; c->remote_port = mc->remote_port; memcpy(c->remote_ip, mc->remote_ip, NRIP); c->a2w.mc = c->w2a.mc = mc; lock_init(&c->a2w.lock); lock_init(&c->w2a.lock); mc->connection_param = c; c->ui = find_ui(mc->local_port); assert(c->ui); //printf("NEW channel %d\n", c->rx_channel); if (st->f != NULL) { int id = _CreateTaskP(st->f, st->uri, st->priority, c); c->task = id; } return c; }