/* tsiproxy data functions */ #include #include #include #include #include #include #include #include #include #include #include #include "libfuncs/libfuncs.h" #include "conf.h" #include "data.h" extern int clean_on_exit; extern LIST *clients; extern STATS allstats; extern CONFIG *config; channel_source get_sproto(char *url) { return strncmp(url, "http", 4)==0 ? tcp_sock : udp_sock; } CHANSRC *init_chansrc(char *url) { regex_t re; regmatch_t res[5]; regcomp(&re, "^([a-z]+)://([^:/?]+):?([0-9]*)/?(.*)", REG_EXTENDED); if (regexec(&re,url,5,res,0)==0) { char *data = strdup(url); char *proto, *host, *port, *path; int iport; proto= data+res[1].rm_so; data[res[1].rm_eo]=0; host = data+res[2].rm_so; data[res[2].rm_eo]=0; port = data+res[3].rm_so; data[res[3].rm_eo]=0; path = data+res[4].rm_so; data[res[4].rm_eo]=0; iport = atoi(port); /* Setup */ CHANSRC *src = calloc(1, sizeof(CHANSRC)); src->proto = strdup(proto); src->sproto= get_sproto(url); src->host = strdup(host); src->port = iport ? iport : 80; src->path = strdup(path); FREE(data); regfree(&re); return src; } regfree(&re); return NULL; } void free_chansrc(CHANSRC *url) { if (url) { FREE(url->proto); FREE(url->host); FREE(url->path); FREE(url); } }; int is_valid_url(char *url) { regex_t re; regmatch_t res[5]; int ret; regcomp(&re, "^([a-z]+)://([^:/?]+):?([0-9]*)/?(.*)", REG_EXTENDED); ret = regexec(&re,url,5,res,0); regfree(&re); return ret == 0; } void add_channel_source(CHANNEL *c, char *src) { if (c->num_src >= MAX_CHANNEL_SOURCES-1) return; c->sources[c->num_src] = strdup(src); if (c->num_src == 0) /* Set default source to first one */ c->source = c->sources[c->num_src]; c->num_src++; } void next_channel_source(CHANNEL *c) { if (c->num_src <= 1) return; // uint8_t old_src = c->curr_src; c->curr_src++; if (c->curr_src >= MAX_CHANNEL_SOURCES-1 || c->sources[c->curr_src] == NULL) c->curr_src = 0; c->source = c->sources[c->curr_src]; // LOGf("CHAN : Switch source | Channel: %s OldSrc: %d %s NewSrc: %d %s\n", c->name, old_src, c->sources[old_src], c->curr_src, c->source); } void set_channel_source(CHANNEL *c, uint8_t src_id) { if (src_id >= MAX_CHANNEL_SOURCES-1 || c->sources[src_id] == NULL) return; // uint8_t old_src = c->curr_src; c->curr_src = src_id; c->source = c->sources[c->curr_src]; // LOGf("CHAN : Set source | Channel: %s OldSrc: %d %s NewSrc: %d %s\n", c->name, old_src, c->sources[old_src], c->curr_src, c->source); } CHANNEL * new_channel(char *name, char *source) { CHANNEL *c = calloc(1, sizeof(CHANNEL)); c->name = strdup(name); add_channel_source(c, source); return c; } void free_channel(CHANNEL *c) { int i; for (i=c->num_src-1; i>=0; i--) { FREE(c->sources[i]); } FREE(c->name); c->source = NULL; FREE(c); } int channel_search(LIST *channels_list, char *name, CHANNEL **found_channel) { int found = 0; LNODE *l, *tmp; list_for_each(channels_list, l, tmp) { CHANNEL *c = l->data; if (strcmp(c->name, name) == 0) { *found_channel = c; found = 1; break; } } return found; } NETWORK * new_network(uint32_t net, uint32_t mask, acl_t acl) { NETWORK *n = calloc(1, sizeof(NETWORK)); n->net = net; n->mask = mask; n->acl = acl; return n; } void free_network(NETWORK *n) { FREE(n); } int acl_search(LIST *acl_list, uint32_t search_ip, acl_t *found_acl) { int found = 0; LNODE *l, *tmp; list_lock(acl_list); list_for_each(acl_list, l, tmp) { NETWORK *n = l->data; if ((search_ip & n->mask) == n->net) { *found_acl = n->acl; found = 1; break; } } list_unlock(acl_list); return found; } RESTREAMER * new_restreamer(const char *name, CHANNEL *channel) { RESTREAMER *r = calloc(1, sizeof(RESTREAMER)); r->started = time(NULL); r->name = strdup(name); r->sock = -1; r->queue = queue_new(); r->clients = list_new("r->clients"); r->channel = channel; return r; } void free_restreamer(RESTREAMER *r) { if (r->sock > -1) shutdown_fd(&(r->sock)); if (r->freechannel) free_channel(r->channel); queue_free(&r->queue); list_free(&r->clients, (void (*)(void *))stop_client_shutdown, NULL); FREE(r->name); FREE(r); } int restreamer_stop(LIST *proxys, char *channel) { int matched = 0; LNODE *l, *tmp; list_lock(proxys); list_for_each(proxys, l, tmp) { RESTREAMER *r = l->data; int doit = !channel || strcmp(channel, r->channel->name) == 0; if (doit) { matched++; r->dienow = 1; } } list_unlock(proxys); return matched; } int restreamer_reconnect(LIST *proxys, char *channel) { int matched = 0; LNODE *l, *tmp; list_lock(proxys); list_for_each(proxys, l, tmp) { RESTREAMER *r = l->data; int doit = !channel || strcmp(channel, r->channel->name) == 0; if (doit) { matched++; r->reconnect = 1; } } list_unlock(proxys); return matched; } void restreamer_stop_all(LIST *proxys) { if (restreamer_stop(proxys, NULL)) { int max_loops = 30; // 3 seconds while (proxys->items > 0 && max_loops-- > 0) usleep(100000); if (proxys->items) clean_on_exit = 0; } } /* CLIENT FUNCTIONS */ int is_child_server(char *user_agent, unsigned int client_id) { if (!user_agent) return 0; return client_id == 0 && strcasestr(user_agent,"iptvd") == user_agent; } int is_ext(char *path, char *ext) { return strncmp(ext, (path+strlen(path)-strlen(ext)), strlen(ext)) == 0; } CLIENT * new_client(int fd, time_t expire, char *chan, char *IP, char *agent, unsigned long clientid, acl_t acl, uint16_t client_port, int smart_client) { CLIENT *nc = calloc(sizeof(CLIENT),1); nc->fno = fd; nc->start = time(NULL); nc->ts = nc->start; nc->expire = expire; nc->chan = strdup(chan); nc->IP = strdup(IP); inet_pton(AF_INET, IP, &(nc->ip)); nc->acl = acl; nc->clientid = clientid; nc->client_port = client_port; if (agent) { nc->agent = strdup(agent); nc->is_child_server = is_child_server(agent, clientid); } if (nc->is_child_server || smart_client) nc->smart_client = 1; list_add(clients, nc); set_sock_nonblock(fd); allstats.clients_all++; return nc; } static void __client_log_connect(CLIENT *c) { c->logged = 1; if (c->client_port == 0) { LOGf("NEW : fd: %i Valid: %li | Client: %lu IP: %s Channel: %s Agent: %s\n", c->fno, (c->expire < 0 ? c->expire : -(c->start - c->expire)), c->clientid, c->IP, c->chan, c->agent); } else { LOGf("NEW : fd: %i Valid: %li Port: %u | Client: %lu IP: %s Channel: %s Agent: %s\n", c->fno, (c->expire < 0 ? c->expire : -(c->start - c->expire)), c->client_port, c->clientid, c->IP, c->chan, c->agent); } allstats.clients_current++; if (c->is_child_server) allstats.child_servers++; else allstats.clients++; } void client_log_connect(CLIENT *c) { if (c->logged) return; __client_log_connect(c); } void client_log_disconnect(CLIENT *c, char mark) { if (!c->logged) return; allstats.clients_current--; allstats.clients_gone++; LOGf("STOP%c: fd: %i Bytes: %llu Seconds: %li | Client: %lu IP: %s Channel: %s Agent: %s\n", mark, c->fno, c->traffic_out, time(NULL)-c->start, c->clientid, c->IP, c->chan, c->agent); time_t now = time(NULL); if (now - c->start > NO_LOG_END_SECONDS) { if (c->traffic_out > 0) { char date[256]; struct tm tmres; strftime(date,sizeof(date),"%d/%b/%Y:%H:%M:%S %z",localtime_r(&c->start, &tmres)); LOGf("LOG{%s %li - [%s] \"%s %lu %s\" 200 %llu \"%lu\" \"%s\"}\n",c->IP,now-c->start,date, "-", c->clientid, c->chan, c->traffic_out, c->start, c->agent); } } } void free_client(CLIENT *c) { FREE(c->chan); FREE(c->IP); FREE(c->agent); FREE(c); } void stop_client(CLIENT *c, int socket_shutdown, char mark) { if (!c || c->stopping) return; c->stopping = 1; int client_socket = c->fno; client_log_disconnect(c, mark); list_del_entry(clients, c); free_client(c); if (socket_shutdown) shutdown_fd(&client_socket); } void stop_client_noshutdown(CLIENT *c) { stop_client(c, 0, ' '); } void stop_client_shutdown(CLIENT *c) { stop_client(c, 1, ' '); } void stop_client_shutdown_mark(CLIENT *c, char mark) { stop_client(c, 1, mark); } int control_client_stop(long clientid) { int found = 0; LNODE *l, *tmp; list_lock(clients); list_for_each(clients, l, tmp) { CLIENT *c = l->data; if (clientid == -1 || clientid == (long)c->clientid) { c->dienow = 1; found++; } } list_unlock(clients); return found; } int control_client_extend(unsigned long clientid, char *chan, time_t expire) { int found = 0; LNODE *l, *tmp; list_lock(clients); list_for_each(clients, l, tmp) { CLIENT *c = l->data; if (c->clientid == clientid && strcmp(chan, c->chan)==0) { c->expire = expire; found++; } } list_unlock(clients); return found; } int netmsg_send(long client_id, char *channel, char *netmsg) { int found = 0; LNODE *l, *tmp; list_lock(clients); list_for_each(clients, l, tmp) { CLIENT *c = l->data; int nsend = (client_id == -1 && !channel) || // Send to all clients (client_id == -1 && channel && strcmp(channel, c->chan)==0) || // Send to all clients on the channel X (client_id == (long)c->clientid && !channel) || // Send to client X (client_id == (long)c->clientid && channel && strcmp(channel, c->chan)==0); // Send to client X on the channel X if (nsend) { strncpy(c->netmsg, netmsg, sizeof(c->netmsg)-1); c->netmsg[sizeof(c->netmsg)-1] = 0; found++; } } list_unlock(clients); return found; } extern char TS_NULL_FRAME[FRAME_PACKET_SIZE]; char *get_netmsg_packet(const char *msg) { if (!strlen(msg) || strlen(msg) > 60) return NULL; char *ret = (char *)calloc(1, FRAME_PACKET_SIZE); memcpy(ret, TS_NULL_FRAME, FRAME_PACKET_SIZE); int i; for (i=0; i<7; i++) { int ofs = i * 188; ret[ofs + 60] = 0x78; ret[ofs + 61] = 0x55; ret[ofs + 62] = 0x58; ret[ofs + 63] = 0x78; strcpy(ret + ofs + 64, msg); } return ret; } int is_netmsg_packet(const unsigned char *buf, int bufsize) { if (bufsize < 64 || bufsize > FRAME_PACKET_SIZE) return 0; if (buf[1] != 0x1f && buf[2] != 0xff) // Look only at NULL packets return 0; // xUXx if (buf[60] == 0x78 && buf[61] == 0x55 && buf[62] == 0x58 && buf[63] == 0x78) return 1; return 0; }