1 /* Icecast
2  *
3  * This program is distributed under the GNU General Public License, version 2.
4  * A copy of this license is included with this source.
5  *
6  * Copyright 2012-2015, Karl Heyes <karl@kheyes.plus.com>,
7  * Copyright 2000-2004, Jack Moffitt <jack@xiph.org>,
8  *                      Michael Smith <msmith@xiph.org>,
9  *                      oddsock <oddsock@xiph.org>,
10  *                      Karl Heyes <karl@xiph.org>
11  *                      and others (see AUTHORS for details).
12  */
13 
14 #ifdef HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17 
18 #include "compat.h"
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #ifdef HAVE_SYS_STAT_H
24 #include <sys/stat.h>
25 #endif
26 #include <errno.h>
27 #ifdef HAVE_FCNTL_H
28 #include <fcntl.h>
29 #endif
30 
31 #ifdef HAVE_POLL
32 #include <sys/poll.h>
33 #endif
34 
35 #ifdef _MSC_VER
36 #include <winsock2.h>
37 #include <windows.h>
38 #else
39 #include <unistd.h>
40 #include <sys/time.h>
41 # ifdef HAVE_SYS_SOCKET_H
42 #  include <sys/socket.h>
43 # endif
44 # ifndef SCN_OFF_T
45 #  define SCN_OFF_T SCNdMAX
46 # endif
47 # ifndef PRI_OFF_T
48 #  define PRI_OFF_T PRIdMAX
49 # endif
50 #endif
51 #ifndef O_CLOEXEC
52 #define O_CLOEXEC 0
53 #endif
54 #ifndef O_BINARY
55 #define O_BINARY 0
56 #endif
57 
58 #include "thread/thread.h"
59 #include "avl/avl.h"
60 #include "httpp/httpp.h"
61 #include "net/sock.h"
62 
63 #include "fserve.h"
64 #include "connection.h"
65 #include "global.h"
66 #include "refbuf.h"
67 #include "client.h"
68 #include "stats.h"
69 #include "format.h"
70 #include "logging.h"
71 #include "cfgfile.h"
72 #include "util.h"
73 #include "admin.h"
74 #include "slave.h"
75 
76 #include "format_mp3.h"
77 
78 #undef CATMODULE
79 #define CATMODULE "fserve"
80 
81 #define BUFSIZE 4096
82 
83 static spin_t pending_lock;
84 static avl_tree *mimetypes = NULL;
85 static avl_tree *fh_cache = NULL;
86 #ifndef HAVE_PREAD
87 static mutex_t seekread_lock;
88 #endif
89 
90 typedef struct {
91     char *ext;
92     char *type;
93 } mime_type;
94 
95 typedef struct {
96     fbinfo finfo;
97     mutex_t lock;
98     int prev_count;
99     int refcount;
100     int peak;
101     int max;
102     icefile_handle f;
103     time_t stats_update;
104     time_t expire;
105     long frame_start_pos;
106     stats_handle_t stats;
107     format_plugin_t *format;
108     struct rate_calc *out_bitrate;
109     avl_tree *clients;
110 } fh_node;
111 
112 int fserve_running;
113 
114 static int _delete_mapping(void *mapping);
115 static int prefile_send (client_t *client);
116 static int file_send (client_t *client);
117 static int _compare_fh(void *arg, void *a, void *b);
118 static int _delete_fh (void *mapping);
119 static void remove_fh_from_cache (fh_node *fh);
120 
121 static fh_node no_file;
122 
123 
fserve_initialize(void)124 void fserve_initialize(void)
125 {
126     if (fserve_running) return;
127 
128     ice_config_t *config = config_get_config();
129 
130     mimetypes = NULL;
131     thread_spin_create (&pending_lock);
132 #ifndef HAVE_PREAD
133     thread_mutex_create (&seekread_lock);
134 #endif
135     fh_cache = avl_tree_new (_compare_fh, NULL);
136 
137     fserve_recheck_mime_types (config);
138     config_release_config();
139 
140     stats_event_flags (NULL, "file_connections", "0", STATS_COUNTERS);
141     fserve_running = 1;
142     memset (&no_file, 0, sizeof (no_file));
143     thread_mutex_create (&no_file.lock);
144     no_file.clients = avl_tree_new (client_compare, NULL);
145     no_file.refcount = 1;
146     no_file.expire = (time_t)-1;
147     no_file.f = -1;
148     avl_insert (fh_cache, &no_file);
149     INFO0("file serving started");
150 }
151 
fserve_shutdown(void)152 void fserve_shutdown(void)
153 {
154     fserve_running = 0;
155     if (mimetypes)
156         avl_tree_free (mimetypes, _delete_mapping);
157     if (fh_cache)
158     {
159         int count = 20;
160         avl_delete (fh_cache, &no_file, NULL);
161         while (fh_cache->length > 1 && count)
162         {
163             fh_node *fh = fh_cache->root->right->key;
164             if (fh && fh->refcount == 0)
165             {
166                 remove_fh_from_cache (fh);
167                 continue;
168             }
169             DEBUG1 ("waiting for %u entries to clear", fh_cache->length);
170             thread_sleep (100000);
171             count--;
172         }
173         avl_tree_free (fh_cache, _delete_fh);
174     }
175 
176     thread_spin_destroy (&pending_lock);
177 #ifndef HAVE_PREAD
178     thread_mutex_destroy (&seekread_lock);
179 #endif
180     INFO0("file serving stopped");
181 }
182 
183 
184 /* string returned needs to be free'd */
fserve_content_type(const char * path)185 char *fserve_content_type (const char *path)
186 {
187     char *ext = util_get_extension(path);
188     mime_type exttype = { NULL, NULL };
189     void *result;
190     char *type;
191 
192     if (ext == NULL)
193         return strdup ("text/html");
194     exttype.ext = strdup (ext);
195 
196     thread_spin_lock (&pending_lock);
197     if (mimetypes && !avl_get_by_key (mimetypes, &exttype, &result))
198     {
199         mime_type *mime = result;
200         type = strdup (mime->type);
201     }
202     else
203         type = strdup ("application/octet-stream");
204     thread_spin_unlock (&pending_lock);
205     free (exttype.ext);
206     return type;
207 }
208 
209 
_compare_fh(void * arg,void * a,void * b)210 static int _compare_fh(void *arg, void *a, void *b)
211 {
212     fh_node *x = a, *y = b;
213     int r = 0;
214 
215     if (x->finfo.mount == NULL && y->finfo.mount)
216        return -1;
217     if (x->finfo.mount && y->finfo.mount == NULL)
218        return 1;
219     if (x->finfo.mount && y->finfo.mount)
220     {
221         r = strcmp (x->finfo.mount, y->finfo.mount);
222         if (r) return r;
223     }
224     r = (int)x->finfo.flags - y->finfo.flags;
225     return r;
226 }
227 
228 
_delete_fh(void * mapping)229 static int _delete_fh (void *mapping)
230 {
231     fh_node *fh = mapping;
232     if (fh == &no_file)
233     {
234         ERROR0 ("no file handle free detected");
235         return 0;
236     }
237     if (fh->refcount)
238         WARN2 ("handle for %s has refcount %d", fh->finfo.mount, fh->refcount);
239     else
240         thread_mutex_destroy (&fh->lock);
241 
242     file_close (&fh->f);
243     if (fh->format)
244     {
245         free (fh->format->mount);
246         format_plugin_clear (fh->format, NULL);
247         free (fh->format);
248     }
249     if (fh->clients)
250         avl_tree_free (fh->clients, NULL);
251     rate_free (fh->out_bitrate);
252     free (fh->finfo.mount);
253     free (fh->finfo.fallback);
254     free (fh);
255 
256     return 1;
257 }
258 
259 
remove_fh_from_cache(fh_node * fh)260 static void remove_fh_from_cache (fh_node *fh)
261 {
262     if (fh->refcount)
263         WARN2 ("removing %s with %d still on", fh->finfo.mount, fh->refcount);
264     avl_delete (fh_cache, fh, NULL);
265 }
266 
267 
remove_from_fh(fh_node * fh,client_t * client)268 static void remove_from_fh (fh_node *fh, client_t *client)
269 {
270     thread_mutex_lock (&fh->lock);
271     fh->refcount--;
272     if (fh->clients)
273     {
274         avl_delete (fh->clients, client, NULL);
275         if ((fh->refcount != fh->clients->length && fh->finfo.mount) || ((fh->refcount != fh->clients->length+1) && fh->finfo.mount == NULL))
276             ERROR3 (" on %s, with ref %d, len %d", fh->finfo.mount, fh->refcount, fh->clients->length);
277     }
278     if (fh->refcount == 0 && fh->finfo.mount)
279     {
280         rate_free (fh->out_bitrate);
281         if ((fh->finfo.flags & FS_FALLBACK) == 0)
282         {
283             fh->out_bitrate = NULL;
284             if (fh->finfo.flags & FS_DELETE)
285             {
286                 thread_mutex_unlock (&fh->lock);
287                 _delete_fh (fh);
288                 return;
289             }
290             DEBUG1 ("setting timeout as no clients on %s", fh->finfo.mount);
291             fh->expire = time(NULL) + 10;
292         }
293         fh->out_bitrate = rate_setup (10000, 1000);
294     }
295     thread_mutex_unlock (&fh->lock);
296 }
297 
298 
find_fh(fbinfo * finfo)299 static fh_node *find_fh (fbinfo *finfo)
300 {
301     char *s = finfo->mount;
302     fh_node fh, *result = NULL;
303     if (finfo->mount == NULL)
304     {
305         ERROR0 ("missing name");
306         return NULL;
307     }
308     memcpy (&fh.finfo, finfo, sizeof (fbinfo));
309     if (strncmp (s, "fallback-", 9) == 0)
310     {
311         fh.finfo.flags |= FS_FALLBACK;
312         fh.finfo.mount = s+9;
313     }
314     else if (strncmp (s, "file-", 5) == 0)
315         fh.finfo.mount = s+5;
316     if (avl_get_by_key (fh_cache, &fh, (void**)&result) == 0)
317     {
318         DEBUG2 ("mount %s (%d)", finfo->mount, finfo->flags);
319         return result;
320     }
321     DEBUG2 ("%s (%d) not found in cache", finfo->mount, finfo->flags);
322     return NULL;
323 }
324 
325 
fh_add_client(fh_node * fh,client_t * client)326 static void fh_add_client (fh_node *fh, client_t *client)
327 {
328     if (fh->clients == NULL)
329         return;
330     avl_insert (fh->clients, client);
331     fh->refcount++;
332     if ((fh->refcount != fh->clients->length && fh->finfo.mount) || ((fh->refcount != fh->clients->length+1) && fh->finfo.mount == NULL))
333         ERROR3 (" on %s, with ref %d, len %d", fh->finfo.mount, fh->refcount, fh->clients->length);
334     if (fh->refcount > fh->peak)
335         fh->peak = fh->refcount;
336     if (fh->finfo.mount)
337         DEBUG2 ("refcount now %d for %s", fh->refcount, fh->finfo.mount);
338 }
339 
340 
341 /* find/create handle and return it with the structure in a locked state */
open_fh(fbinfo * finfo)342 static fh_node *open_fh (fbinfo *finfo)
343 {
344     fh_node *fh, *result;
345 
346     if (finfo->mount == NULL)
347         finfo->mount = "";
348     fh = calloc (1, sizeof (fh_node));
349     memcpy (&fh->finfo, finfo, sizeof (fbinfo));
350     if (avl_get_by_key (fh_cache, fh, (void**)&result) == 0)
351     {
352         free (fh);
353         thread_mutex_lock (&result->lock);
354         avl_tree_unlock (fh_cache);
355         if (finfo->flags & FS_FALLBACK)
356         {
357             if (result->finfo.type != finfo->type && finfo->type != FORMAT_TYPE_UNDEFINED)
358             {
359                 WARN1 ("format mismatched for %s", finfo->mount);
360                 thread_mutex_unlock (&result->lock);
361                 return NULL;
362             }
363             result->expire = (time_t)-1;
364         }
365         return result;
366     }
367 
368     // insert new one
369     if (fh->finfo.mount[0])
370     {
371         char *fullpath= util_get_path_from_normalised_uri (fh->finfo.mount, fh->finfo.flags&FS_USE_ADMIN);
372         char *contenttype = fserve_content_type (fullpath);
373         format_type_t type = format_get_type (contenttype);
374 
375         if (fh->finfo.type == FORMAT_TYPE_UNDEFINED)
376             fh->finfo.type = type;
377         if (finfo->flags & FS_FALLBACK)
378         {
379             if (fh->finfo.type != type && type != FORMAT_TYPE_UNDEFINED && fh->finfo.type != FORMAT_TYPE_UNDEFINED)
380             {
381                 avl_tree_unlock (fh_cache);
382                 free (contenttype);
383                 free (fullpath);
384                 free (fh);
385                 WARN1 ("format mismatched for %s", finfo->mount);
386                 return NULL;
387             }
388             fh->expire = (time_t)-1;
389             INFO2 ("lookup of fallback file \"%s\" (%d)", finfo->mount, finfo->limit);
390         }
391         else
392             INFO1 ("lookup of \"%s\"", finfo->mount);
393         if (file_open (&fh->f, fullpath) < 0)
394         {
395             INFO1 ("Failed to open \"%s\"", fullpath);
396             avl_tree_unlock (fh_cache);
397             free (contenttype);
398             free (fullpath);
399             free (fh);
400             return NULL;
401         }
402         free (fullpath);
403         fh->format = calloc (1, sizeof (format_plugin_t));
404         fh->format->type = fh->finfo.type;
405         fh->format->contenttype = strdup (contenttype);
406         free (contenttype);
407         if (fh->finfo.type != FORMAT_TYPE_UNDEFINED)
408         {
409             fh->format->mount = strdup (fh->finfo.mount);
410             if (format_get_plugin (fh->format) < 0)
411             {
412                 avl_tree_unlock (fh_cache);
413                 file_close (&fh->f);
414                 free (fh->format);
415                 free (fh);
416                 return NULL;
417             }
418             format_check_t fcheck;
419             fcheck.fd = fh->f;
420             fcheck.desc = finfo->mount;
421             if (format_check_frames (&fcheck) < 0 || fcheck.type == FORMAT_TYPE_UNDEFINED)
422                 WARN1 ("different type detected for %s", finfo->mount);
423             else
424             {
425                 if (fh->finfo.limit && fcheck.bitrate > 0)
426                 {
427                     float ratio = (float)fh->finfo.limit / (fcheck.bitrate/8);
428                     if (ratio < 0.9 || ratio > 1.1)
429                         WARN3 ("bitrate from %s (%d), was expecting %d", finfo->mount, (fcheck.bitrate/1000), (fh->finfo.limit/1000*8));
430                 }
431             }
432         }
433         if (fh->finfo.limit)
434             fh->out_bitrate = rate_setup (10000, 1000);
435     }
436     fh->clients = avl_tree_new (client_compare, NULL);
437     thread_mutex_create (&fh->lock);
438     thread_mutex_lock (&fh->lock);
439     avl_insert (fh_cache, fh);
440     avl_tree_unlock (fh_cache);
441 
442     fh->refcount = 0;
443     fh->peak = 0;
444     fh->finfo.mount = strdup (finfo->mount);
445     fh->finfo.fallback = NULL;
446 
447     return fh;
448 }
449 
450 
451 /* client has requested a file, so check for it and send the file.  Do not
452  * refer to the client_t afterwards.  return 0 for success, -1 on error.
453  */
fserve_client_create(client_t * httpclient,const char * path)454 int fserve_client_create (client_t *httpclient, const char *path)
455 {
456     struct stat file_buf;
457     char *fullpath;
458     int m3u_requested = 0, m3u_file_available = 1;
459     int xspf_requested = 0, xspf_file_available = 1;
460     int ret = -1;
461     ice_config_t *config;
462     fbinfo finfo;
463     char fsize[20];
464 
465     fullpath = util_get_path_from_normalised_uri (path, 0);
466     DEBUG2 ("checking for file %s (%s)", path, fullpath);
467 
468     if (strcmp (util_get_extension (fullpath), "m3u") == 0)
469         m3u_requested = 1;
470 
471     if (strcmp (util_get_extension (fullpath), "xspf") == 0)
472         xspf_requested = 1;
473 
474     /* check for the actual file */
475     if (stat (fullpath, &file_buf) != 0)
476     {
477         /* the m3u can be generated, but send an m3u file if available */
478         if (m3u_requested == 0 && xspf_requested == 0)
479         {
480             if (redirect_client (path, httpclient) == 0)
481             {
482                 if ((httpclient->flags & CLIENT_SKIP_ACCESSLOG) == 0)
483                     WARN2 ("req for file \"%s\" %s", fullpath, strerror (errno));
484                 ret = client_send_404 (httpclient, "The file you requested could not be found");
485             }
486             free (fullpath);
487             return ret;
488         }
489         m3u_file_available = 0;
490         xspf_file_available = 0;
491     }
492 
493     client_set_queue (httpclient, NULL);
494     httpclient->refbuf = refbuf_new (4096);
495 
496     if (m3u_requested && m3u_file_available == 0)
497     {
498         const char  *host = httpp_getvar (httpclient->parser, "host"),
499                     *args = httpp_getvar (httpclient->parser, HTTPP_VAR_QUERYARGS),
500                     *at = "", *user = "", *pass ="";
501         char *sourceuri = strdup (path);
502         char *dot = strrchr (sourceuri, '.');
503         char *protocol = not_ssl_connection (&httpclient->connection) ? "http" : "https";
504         const char *agent = httpp_getvar (httpclient->parser, "user-agent");
505         int x;
506         char scratch[1000];
507 
508         if (agent)
509         {
510             if (strstr (agent, "QTS") || strstr (agent, "QuickTime"))
511                 protocol = "icy";
512         }
513         /* at least a couple of players (fb2k/winamp) are reported to send a
514          * host header but without the port number. So if we are missing the
515          * port then lets treat it as if no host line was sent */
516         if (host && strchr (host, ':') == NULL)
517             host = NULL;
518 
519         *dot = 0;
520         if (httpclient->username && httpclient->password)
521         {
522             at = "@";
523             user = httpclient->username;
524             pass = httpclient->password;
525         }
526         httpclient->respcode = 200;
527         if (host == NULL)
528         {
529             config = config_get_config();
530             x = snprintf (scratch, sizeof scratch,
531                     "%s://%s%s%s%s%s:%d%s%s\r\n",
532                     protocol,
533                     user, at[0]?":":"", pass, at,
534                     config->hostname, config->port,
535                     sourceuri,
536                     args?args:"");
537             config_release_config();
538         }
539         else
540         {
541             x = snprintf (scratch, sizeof scratch,
542                     "%s://%s%s%s%s%s%s%s\r\n",
543                     protocol,
544                     user, at[0]?":":"", pass, at,
545                     host,
546                     sourceuri,
547                     args?args:"");
548         }
549         snprintf (httpclient->refbuf->data, BUFSIZE,
550                 "HTTP/1.0 200 OK\r\n"
551                 "Content-Length: %d\r\n"
552                 "%s\r\n"
553                 "Content-Type: audio/x-mpegurl\r\n\r\n%s",
554                 x, client_keepalive_header (httpclient), scratch);
555         httpclient->refbuf->len = strlen (httpclient->refbuf->data);
556         free (sourceuri);
557         free (fullpath);
558         return fserve_setup_client_fb (httpclient, NULL);
559     }
560     if (xspf_requested && xspf_file_available == 0)
561     {
562         xmlDocPtr doc;
563         char *reference = strdup (path);
564         char *eol = strrchr (reference, '.');
565         if (eol)
566             *eol = '\0';
567         doc = stats_get_xml (0, reference);
568         free (reference);
569         free (fullpath);
570         return admin_send_response (doc, httpclient, XSLT, "xspf.xsl");
571     }
572 
573     /* on demand file serving check */
574     config = config_get_config();
575     if (config->fileserve == 0)
576     {
577         config_release_config();
578         DEBUG1 ("on demand file \"%s\" refused", fullpath);
579         free (fullpath);
580         return client_send_404 (httpclient, "The file you requested could not be found");
581     }
582     config_release_config();
583 
584     if (S_ISREG (file_buf.st_mode) == 0)
585     {
586         WARN1 ("found requested file but there is no handler for it: %s", fullpath);
587         free (fullpath);
588         return client_send_404 (httpclient, "The file you requested could not be found");
589     }
590 
591     free (fullpath);
592     finfo.flags = 0;
593     finfo.mount = (char *)path;
594     finfo.fallback = NULL;
595     finfo.limit = 0;
596     finfo.type = FORMAT_TYPE_UNDEFINED;
597     snprintf (fsize, 20, "%" PRId64, (int64_t)file_buf.st_size);
598     httpp_setvar (httpclient->parser, "__FILESIZE", fsize);
599     stats_event_inc (NULL, "file_connections");
600 
601     return fserve_setup_client_fb (httpclient, &finfo);
602 }
603 
604 
605 
file_release(client_t * client)606 static void file_release (client_t *client)
607 {
608     fh_node *fh = client->shared_data;
609     int ret = -1;
610 
611     if ((fh->finfo.flags & FS_FALLBACK) && (client->flags & CLIENT_AUTHENTICATED))
612     {
613         // reduce from global count
614         global_lock();
615         global.listeners--;
616         global_unlock();
617     }
618 
619     client_set_queue (client, NULL);
620 
621     if (client->flags & CLIENT_AUTHENTICATED && client->parser->req_type == httpp_req_get)
622     {
623         const char *m = NULL;
624 
625         if (fh->finfo.flags & FS_FALLBACK)
626             m = httpp_getvar (client->parser, HTTPP_VAR_URI);
627         else if (client->mount)
628             m = client->mount;
629         else
630             m = fh->finfo.mount;
631         if (m)
632         {
633             ice_config_t *config;
634             char *mount = strdup (m);
635             mount_proxy *mountinfo;
636 
637             remove_from_fh (fh, client);
638             client->shared_data = NULL;
639             config = config_get_config ();
640             mountinfo = config_find_mount (config, mount);
641             if (mountinfo && mountinfo->access_log.name)
642                 logging_access_id (&mountinfo->access_log, client);
643             ret = auth_release_listener (client, mount, mountinfo);
644             config_release_config();
645             free (mount);
646         }
647         else
648             remove_from_fh (fh, client);
649     }
650     else
651         remove_from_fh (fh, client);
652     if (ret < 0)
653     {
654         client->shared_data = NULL;
655         client->flags &= ~CLIENT_AUTHENTICATED;
656         client_destroy (client);
657     }
658     global_reduce_bitrate_sampling (global.out_bitrate);
659 }
660 
661 
662 struct _client_functions buffer_content_ops =
663 {
664     prefile_send,
665     file_release
666 };
667 
668 
669 struct _client_functions file_content_ops =
670 {
671     file_send,
672     file_release
673 };
674 
675 
fserve_move_listener(client_t * client)676 static int fserve_move_listener (client_t *client)
677 {
678     fh_node *fh = client->shared_data;
679     int ret = 0;
680     fbinfo f;
681 
682     memset (&f, 0, sizeof (f));
683     if (client->refbuf && client->pos < client->refbuf->len)
684         client->flags |= CLIENT_HAS_INTRO_CONTENT; // treat it as a partial write needing completion
685     else
686         client_set_queue (client, NULL);
687     f.flags = fh->finfo.flags & (~FS_DELETE);
688     f.limit = fh->finfo.limit;
689     f.mount = fh->finfo.fallback;
690     f.type = fh->finfo.type;
691     if (move_listener (client, &f) < 0)
692     {
693         WARN1 ("moved failed, terminating listener on %s", fh->finfo.mount);
694         ret = -1;
695     }
696     else
697     {
698         DEBUG3 ("moved %s from %s (%d)", client->connection.ip, fh->finfo.mount, fh->finfo.flags);
699         ret = 0;
700         remove_from_fh (fh, client);
701     }
702     return ret;
703 }
704 
705 
fserve_change_worker(client_t * client)706 static int fserve_change_worker (client_t *client)
707 {
708     worker_t *this_worker = client->worker, *worker;
709     int ret = 0;
710 
711     if (this_worker->move_allocations == 0)
712         return 0;
713     thread_rwlock_rlock (&workers_lock);
714     worker = worker_selected ();
715     if (worker && worker != client->worker)
716     {
717         long diff = this_worker->move_allocations < 1000000 ? this_worker->count - worker->count : 1000;
718         if (diff > 10)
719         {
720             this_worker->move_allocations--;
721             ret = client_change_worker (client, worker);
722             if (ret)
723                 DEBUG2 ("moving listener from %p to %p", this_worker, worker);
724         }
725     }
726     thread_rwlock_unlock (&workers_lock);
727     return ret;
728 }
729 
730 
731 struct _client_functions throttled_file_content_ops;
732 
prefile_send(client_t * client)733 static int prefile_send (client_t *client)
734 {
735     int loop = 8, bytes, written = 0;
736     worker_t *worker = client->worker;
737 
738     while (loop)
739     {
740         refbuf_t *refbuf = client->refbuf;
741         fh_node *fh = client->shared_data;
742         loop--;
743         if (fserve_running == 0 || client->connection.error)
744             return -1;
745         if (refbuf == NULL || client->pos == refbuf->len)
746         {
747             if (fh->finfo.fallback && (client->flags & CLIENT_AUTHENTICATED))
748                 return fserve_move_listener (client);
749 
750             if (refbuf == NULL || refbuf->next == NULL)
751             {
752                 if ((client->flags & CLIENT_AUTHENTICATED) == 0)
753                     return -1;
754                 if (file_in_use (fh->f)) // is there a file to read from
755                 {
756                     if (fh->format->detach_queue_block)
757                         fh->format->detach_queue_block (NULL, client->refbuf);
758                     refbuf_release (client->refbuf);
759                     client->refbuf = NULL;
760                     client->pos = 0;
761                     client->intro_offset = fh->frame_start_pos;
762                     if (fh->finfo.limit)
763                     {
764                         client->ops = &throttled_file_content_ops;
765                         rate_add (fh->out_bitrate, 0, worker->time_ms);
766                         return 0;
767                     }
768                     client->ops = &file_content_ops;
769                     return client->ops->process (client);
770                 }
771                 if (client->respcode)
772                     return -1;
773                 return client_send_404 (client, NULL);
774             }
775             else
776             {
777                 refbuf_t *to_go = client->refbuf;
778                 refbuf = client->refbuf = to_go->next;
779                 to_go->next = NULL;
780                 if (fh->format && fh->format->detach_queue_block)
781                     fh->format->detach_queue_block (NULL, client->refbuf);
782                 refbuf_release (to_go);
783             }
784             client->pos = 0;
785         }
786         if (refbuf->flags & WRITE_BLOCK_GENERIC)
787             bytes = format_generic_write_to_client (client);
788         else
789             bytes = client->check_buffer (client);
790         if (bytes < 0)
791         {
792             client->schedule_ms = worker->time_ms + (written ? 150 : 300);
793             return 0;
794         }
795         written += bytes;
796         global_add_bitrates (global.out_bitrate, bytes, worker->time_ms);
797         if (written > 30000)
798             break;
799     }
800     return 0;
801 }
802 
803 
804 /* fast send routine */
file_send(client_t * client)805 static int file_send (client_t *client)
806 {
807     int loop = 6, bytes, written = 0;
808     fh_node *fh = client->shared_data;
809     worker_t *worker = client->worker;
810     time_t now;
811 
812 #if 0
813     if (fserve_change_worker (client)) // allow for balancing
814         return 1;
815 #endif
816     client->schedule_ms = worker->time_ms;
817     now = worker->current_time.tv_sec;
818     /* slowdown if max bandwidth is exceeded, but allow for short-lived connections to avoid
819      * this, eg admin requests */
820     if (throttle_sends > 1 && now - client->connection.con_time > 1)
821     {
822         client->schedule_ms += 300;
823         loop = 1;
824     }
825     while (loop && written < 48000)
826     {
827         loop--;
828         if (fserve_running == 0 || client->connection.error)
829             return -1;
830         if (format_file_read (client, fh->format, fh->f) < 0)
831             return -1;
832         bytes = client->check_buffer (client);
833         if (bytes < 0)
834         {
835             client->schedule_ms += (written ? 80 : 150);
836             return 0;
837         }
838         written += bytes;
839     }
840     client->schedule_ms += 4;
841     return 0;
842 }
843 
844 
845 
846 /* send routine for files sent at a target bitrate, eg fallback files. */
throttled_file_send(client_t * client)847 static int throttled_file_send (client_t *client)
848 {
849     int  bytes;
850     fh_node *fh = client->shared_data;
851     time_t now;
852     worker_t *worker = client->worker;
853     unsigned long secs;
854     unsigned int  rate = 0;
855     unsigned int limit = fh->finfo.limit;
856 
857     if (fserve_running == 0 || client->connection.error)
858         return -1;
859     now = worker->current_time.tv_sec;
860     secs = now - client->timer_start;
861     client->schedule_ms = worker->time_ms;
862     if (fh->finfo.fallback)
863         return fserve_move_listener (client);
864 
865     if (fserve_change_worker (client)) // allow for balancing
866         return 1;
867 
868     if (client->flags & CLIENT_WANTS_FLV) /* increase limit for flv clients as wrapping takes more space */
869         limit = (unsigned long)(limit * 1.01);
870     rate = secs ? (client->counter+1400)/secs : limit * 2;
871     // DEBUG3 ("counter %lld, duration %ld, limit %u", client->counter, secs, rate);
872     if (rate > limit)
873     {
874         if (limit >= 1400)
875             client->schedule_ms += 1000/(limit/1400);
876         else
877             client->schedule_ms += 50; // should not happen but guard against it
878         rate_add (fh->out_bitrate, 0, worker->time_ms);
879         global_add_bitrates (global.out_bitrate, 0, worker->time_ms);
880         if (client->counter > 8192)
881             return 0; // allow an initial amount without throttling
882     }
883     switch (format_file_read (client, fh->format, fh->f))
884     {
885         case -1: // DEBUG0 ("loop of file triggered");
886             client->intro_offset = 0;
887             client->schedule_ms += client->throttle ? client->throttle : 150;
888             return 0;
889         case -2: // DEBUG0 ("major failure on read, better leave");
890             return -1;
891         default: //DEBUG1 ("reading from offset %ld", client->intro_offset);
892             break;
893     }
894     bytes = client->check_buffer (client);
895     if (bytes < 0)
896         bytes = 0;
897     //DEBUG3 ("bytes %d, counter %ld, %ld", bytes, client->counter, client->worker->time_ms - (client->timer_start*1000));
898     rate_add (fh->out_bitrate, bytes, worker->time_ms);
899     global_add_bitrates (global.out_bitrate, bytes, worker->time_ms);
900     if (limit > 2800)
901         client->schedule_ms += (1000/(limit/1400*2));
902     else
903         client->schedule_ms += 50;
904 
905     /* progessive slowdown if max bandwidth is exceeded. */
906     if (throttle_sends > 1)
907         client->schedule_ms += 300;
908     return 0;
909 }
910 
911 
912 struct _client_functions throttled_file_content_ops =
913 {
914     throttled_file_send,
915     file_release
916 };
917 
918 
fserve_setup_client_fb(client_t * client,fbinfo * finfo)919 int fserve_setup_client_fb (client_t *client, fbinfo *finfo)
920 {
921     fh_node *fh = &no_file;
922     int ret = 0;
923 
924     if (finfo)
925     {
926         mount_proxy *minfo;
927         if (finfo->flags & FS_FALLBACK && finfo->limit == 0)
928             return -1;
929         avl_tree_wlock (fh_cache);
930         fh = find_fh (finfo);
931         minfo = config_find_mount (config_get_config(), finfo->mount);
932         if (fh)
933         {
934             thread_mutex_lock (&fh->lock);
935             avl_tree_unlock (fh_cache);
936             client->shared_data = NULL;
937             if (minfo)
938             {
939                 if (minfo->max_listeners >= 0 && fh->refcount > minfo->max_listeners)
940                 {
941                     thread_mutex_unlock (&fh->lock);
942                     config_release_config();
943                     return client_send_403redirect (client, finfo->mount, "max listeners reached");
944                 }
945                 if (check_duplicate_logins (finfo->mount, fh->clients, client, minfo->auth) == 0)
946                 {
947                     thread_mutex_unlock (&fh->lock);
948                     config_release_config();
949                     return client_send_403 (client, "Account already in use");
950                 }
951             }
952             config_release_config();
953         }
954         else
955         {
956             if (minfo && minfo->max_listeners == 0)
957             {
958                 avl_tree_unlock (fh_cache);
959                 config_release_config();
960                 client->shared_data = NULL;
961                 return client_send_403redirect (client, finfo->mount, "max listeners reached");
962             }
963             config_release_config();
964             fh = open_fh (finfo);
965             if (fh == NULL)
966                 return client_send_404 (client, NULL);
967             if (fh->finfo.limit)
968                 DEBUG2 ("request for throttled file %s (bitrate %d)", fh->finfo.mount, fh->finfo.limit*8);
969         }
970         if (fh->finfo.limit)
971         {
972             client->timer_start = client->worker->current_time.tv_sec;
973             if (client->connection.sent_bytes == 0)
974                 client->timer_start -= 2;
975             client->counter = 0;
976             global_reduce_bitrate_sampling (global.out_bitrate);
977         }
978     }
979     else
980     {
981         if (client->mount && (client->flags & CLIENT_AUTHENTICATED) && (client->respcode >= 300 || client->respcode < 200))
982         {
983             fh = calloc (1, sizeof (no_file));
984             fh->finfo.mount = strdup (client->mount);
985             fh->finfo.flags |= FS_DELETE;
986             fh->refcount = 1;
987             fh->f = SOCK_ERROR;
988             thread_mutex_create (&fh->lock);
989         }
990         thread_mutex_lock (&fh->lock);
991     }
992     client->mount = fh->finfo.mount;
993     if (fh->finfo.type == FORMAT_TYPE_UNDEFINED)
994     {
995         if (client->respcode == 0)
996         {
997             client->refbuf->len = 0;
998             ret = format_general_headers (fh->format, client);
999         }
1000     }
1001     else
1002     {
1003         if (fh->format->create_client_data && client->format_data == NULL)
1004             ret = fh->format->create_client_data (fh->format, client);
1005         if (fh->format->write_buf_to_client)
1006             client->check_buffer = fh->format->write_buf_to_client;
1007     }
1008     if (ret < 0)
1009     {
1010         thread_mutex_unlock (&fh->lock);
1011         client->mount = NULL;
1012         return client_send_416 (client);
1013     }
1014     fh_add_client (fh, client);
1015     thread_mutex_unlock (&fh->lock);
1016     client->shared_data = fh;
1017 
1018     if (client->check_buffer == NULL)
1019         client->check_buffer = format_generic_write_to_client;
1020 
1021     client->ops = &buffer_content_ops;
1022     client->flags &= ~CLIENT_HAS_INTRO_CONTENT;
1023     client->flags |= CLIENT_IN_FSERVE;
1024     if (client->flags & CLIENT_ACTIVE)
1025     {
1026         client->schedule_ms = client->worker->time_ms;
1027         if (finfo && finfo->flags & FS_FALLBACK)
1028             return 0; // prevent a recursive loop
1029         return client->ops->process (client);
1030     }
1031     else
1032     {
1033         worker_t *worker = client->worker;
1034         ret = (fh->finfo.limit) ? 0 : -1;
1035         client->flags |= CLIENT_ACTIVE;
1036         worker_wakeup (worker); /* worker may of already processed client but make sure */
1037     }
1038     return ret;
1039 }
1040 
1041 
fserve_setup_client(client_t * client)1042 int fserve_setup_client (client_t *client)
1043 {
1044     client->check_buffer = format_generic_write_to_client;
1045     return fserve_setup_client_fb (client, NULL);
1046 }
1047 
1048 
fserve_set_override(const char * mount,const char * dest,format_type_t type)1049 int fserve_set_override (const char *mount, const char *dest, format_type_t type)
1050 {
1051     fh_node fh, *result;
1052 
1053     fh.finfo.flags = FS_FALLBACK;
1054     fh.finfo.mount = (char *)mount;
1055     fh.finfo.fallback = NULL;
1056     fh.finfo.type = type;
1057 
1058     avl_tree_wlock (fh_cache);
1059     result = find_fh (&fh.finfo);
1060     if (result)
1061     {
1062         thread_mutex_lock (&result->lock);
1063 
1064         if (result->refcount > 0)
1065         {
1066             fh_node *copy = calloc (1, sizeof (*copy));
1067             avl_delete (fh_cache, result, NULL);
1068             copy->finfo = result->finfo;
1069             copy->finfo.mount = strdup (copy->finfo.mount);
1070             copy->prev_count = -1; // trigger stats update
1071             copy->expire = (time_t)-1;
1072             copy->stats = result->stats;
1073             copy->format = result->format;
1074             copy->f = result->f;
1075             thread_mutex_create (&copy->lock);
1076             copy->out_bitrate = rate_setup (10000, 1000);
1077             copy->clients = avl_tree_new (client_compare, NULL);
1078             avl_insert (fh_cache, copy);
1079 
1080             result->finfo.flags |= FS_DELETE;
1081             result->finfo.flags &= ~FS_FALLBACK;
1082             result->format = NULL;
1083             result->stats = 0;
1084             result->f = SOCK_ERROR;
1085             result->finfo.fallback = strdup (dest);
1086             result->finfo.type = type;
1087         }
1088         avl_tree_unlock (fh_cache);
1089         thread_mutex_unlock (&result->lock);
1090         INFO2 ("move clients from %s to %s", mount, dest);
1091         return 1;
1092     }
1093     avl_tree_unlock (fh_cache);
1094     return 0;
1095 }
1096 
_delete_mapping(void * mapping)1097 static int _delete_mapping(void *mapping) {
1098     mime_type *map = mapping;
1099     free(map->ext);
1100     free(map->type);
1101     free(map);
1102 
1103     return 1;
1104 }
1105 
_compare_mappings(void * arg,void * a,void * b)1106 static int _compare_mappings(void *arg, void *a, void *b)
1107 {
1108     return strcmp(
1109             ((mime_type *)a)->ext,
1110             ((mime_type *)b)->ext);
1111 }
1112 
1113 
1114 // write filename extension for matching mime type.
1115 // lookup matching mime type and write extension into buffer space provided
fserve_write_mime_ext(const char * mimetype,char * buf,unsigned int len)1116 void fserve_write_mime_ext (const char *mimetype, char *buf, unsigned int len)
1117 {
1118     avl_node *node;
1119     int semi;
1120 
1121     if (mimetype == NULL || buf == NULL || len > 2000) return;
1122     semi = strcspn (mimetype, "; ");
1123     if (semi == 0) return;
1124     if (mimetype [semi])
1125     {
1126         char *mt = alloca (++semi);
1127         snprintf (mt, semi, "%s", mimetype);
1128         mimetype = (const char *)mt;
1129     }
1130     thread_spin_lock (&pending_lock);
1131     node = avl_get_first (mimetypes);
1132     while (node)
1133     {
1134        mime_type *mime = (mime_type *)node->key;
1135        if (mime && strcmp (mime->type, mimetype) == 0)
1136        {
1137            snprintf (buf, len, "%s", mime->ext);
1138            break;
1139        }
1140        node = avl_get_next (node);
1141     }
1142     thread_spin_unlock (&pending_lock);
1143 }
1144 
1145 
fserve_recheck_mime_types(ice_config_t * config)1146 void fserve_recheck_mime_types (ice_config_t *config)
1147 {
1148     mime_type *mapping;
1149     int i;
1150     avl_tree *old_mimetypes = NULL, *new_mimetypes = avl_tree_new(_compare_mappings, NULL);
1151 
1152     mime_type defaults[] = {
1153         { "m3u",            "audio/x-mpegurl" },
1154         { "pls",            "audio/x-scpls" },
1155         { "xspf",           "application/xspf+xml" },
1156         { "ogg",            "application/ogg" },
1157         { "xml",            "text/xml" },
1158         { "mp3",            "audio/mpeg" },
1159         { "aac",            "audio/aac" },
1160         { "aacp",           "audio/aacp" },
1161         { "css",            "text/css" },
1162         { "txt",            "text/plain" },
1163         { "html",           "text/html" },
1164         { "jpg",            "image/jpg" },
1165         { "png",            "image/png" },
1166         { "gif",            "image/gif" },
1167         { NULL, NULL }
1168     };
1169 
1170     for (i=0; defaults[i].ext; i++)
1171     {
1172         mapping = malloc (sizeof(mime_type));
1173         mapping->ext = strdup (defaults [i].ext);
1174         mapping->type = strdup (defaults [i].type);
1175         if (avl_insert (new_mimetypes, mapping) != 0)
1176             _delete_mapping (mapping);
1177     }
1178     do
1179     {
1180         char *type, *ext, *cur;
1181         FILE *mimefile = NULL;
1182         char line[4096];
1183 
1184         if (config->mimetypes_fn == NULL)
1185         {
1186             INFO0 ("no mime types file defined, using defaults");
1187             break;
1188         }
1189         mimefile = fopen (config->mimetypes_fn, "r");
1190         if (mimefile == NULL)
1191         {
1192             WARN1 ("Cannot open mime types file %s, using defaults", config->mimetypes_fn);
1193             break;
1194         }
1195         while (fgets(line, sizeof line, mimefile))
1196         {
1197             line[4095] = 0;
1198 
1199             if(*line == 0 || *line == '#')
1200                 continue;
1201 
1202             type = line;
1203             cur = line;
1204 
1205             while(*cur != ' ' && *cur != '\t' && *cur)
1206                 cur++;
1207             if(*cur == 0)
1208                 continue;
1209 
1210             *cur++ = 0;
1211 
1212             while(1)
1213             {
1214                 while(*cur == ' ' || *cur == '\t')
1215                     cur++;
1216                 if(*cur == 0)
1217                     break;
1218 
1219                 ext = cur;
1220                 while(*cur != ' ' && *cur != '\t' && *cur != '\n' && *cur)
1221                     cur++;
1222                 *cur++ = 0;
1223                 if(*ext)
1224                 {
1225                     void *tmp;
1226                     /* Add a new extension->type mapping */
1227                     mapping = malloc(sizeof(mime_type));
1228                     mapping->ext = strdup(ext);
1229                     mapping->type = strdup(type);
1230                     if (!avl_get_by_key (new_mimetypes, mapping, &tmp))
1231                         avl_delete (new_mimetypes, mapping, _delete_mapping);
1232                     if (avl_insert (new_mimetypes, mapping) != 0)
1233                         _delete_mapping (mapping);
1234                 }
1235             }
1236         }
1237         fclose(mimefile);
1238     } while (0);
1239 
1240     thread_spin_lock (&pending_lock);
1241     old_mimetypes = mimetypes;
1242     mimetypes = new_mimetypes;
1243     thread_spin_unlock (&pending_lock);
1244     if (old_mimetypes)
1245         avl_tree_free (old_mimetypes, _delete_mapping);
1246 }
1247 
1248 
fserve_kill_client(client_t * client,const char * mount,int response)1249 int fserve_kill_client (client_t *client, const char *mount, int response)
1250 {
1251     int loop = 2, id;
1252     fbinfo finfo;
1253     xmlDocPtr doc;
1254     xmlNodePtr node;
1255     const char *idtext, *v = "0";
1256     char buf[50];
1257 
1258     finfo.flags = 0;
1259     finfo.mount = (char*)mount;
1260     finfo.limit = 0;
1261     finfo.fallback = NULL;
1262 
1263     idtext = httpp_get_query_param (client->parser, "id");
1264     if (idtext == NULL)
1265         return client_send_400 (client, "missing parameter id");
1266 
1267     id = atoi(idtext);
1268 
1269     doc = xmlNewDoc(XMLSTR("1.0"));
1270     node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
1271     xmlDocSetRootElement(doc, node);
1272     snprintf (buf, sizeof(buf), "Client %d not found", id);
1273 
1274     avl_tree_rlock (fh_cache);
1275     while (1)
1276     {
1277         avl_node *node;
1278         fh_node *fh = find_fh (&finfo);
1279         if (fh)
1280         {
1281             thread_mutex_lock (&fh->lock);
1282             avl_tree_unlock (fh_cache);
1283             node = avl_get_first (fh->clients);
1284             while (node)
1285             {
1286                 client_t *listener = (client_t *)node->key;
1287                 if (listener->connection.id == id)
1288                 {
1289                     listener->connection.error = 1;
1290                     snprintf (buf, sizeof(buf), "Client %d removed", id);
1291                     v = "1";
1292                     loop = 0;
1293                     break;
1294                 }
1295                 node = avl_get_next (node);
1296             }
1297             thread_mutex_unlock (&fh->lock);
1298             avl_tree_rlock (fh_cache);
1299         }
1300         if (loop == 0) break;
1301         loop--;
1302         if (loop == 1) finfo.flags = FS_FALLBACK;
1303     }
1304     avl_tree_unlock (fh_cache);
1305     xmlNewChild (node, NULL, XMLSTR("message"), XMLSTR(buf));
1306     xmlNewChild (node, NULL, XMLSTR("return"), XMLSTR(v));
1307     return admin_send_response (doc, client, response, "response.xsl");
1308 }
1309 
1310 
fserve_list_clients_xml(xmlNodePtr parent,fbinfo * finfo)1311 int fserve_list_clients_xml (xmlNodePtr parent, fbinfo *finfo)
1312 {
1313     int ret = 0;
1314     fh_node *fh;
1315     avl_node *anode;
1316 
1317     avl_tree_rlock (fh_cache);
1318     fh = find_fh (finfo);
1319     if (fh == NULL)
1320     {
1321         avl_tree_unlock (fh_cache);
1322         return 0;
1323     }
1324     thread_mutex_lock (&fh->lock);
1325     avl_tree_unlock (fh_cache);
1326 
1327     anode = avl_get_first (fh->clients);
1328     while (anode)
1329     {
1330         client_t *listener = (client_t *)anode->key;
1331 
1332         stats_listener_to_xml (listener, parent);
1333         ret++;
1334         anode = avl_get_next (anode);
1335     }
1336     thread_mutex_unlock (&fh->lock);
1337     return ret;
1338 }
1339 
1340 
fserve_list_clients(client_t * client,const char * mount,int response,int show_listeners)1341 int fserve_list_clients (client_t *client, const char *mount, int response, int show_listeners)
1342 {
1343     int ret;
1344     fbinfo finfo;
1345     xmlDocPtr doc;
1346     xmlNodePtr node, srcnode;
1347 
1348     finfo.flags = 0;
1349     finfo.mount = (char*)mount;
1350     finfo.limit = 0;
1351     finfo.fallback = NULL;
1352 
1353     doc = xmlNewDoc(XMLSTR("1.0"));
1354     node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
1355     xmlDocSetRootElement(doc, node);
1356     srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL);
1357     xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(mount));
1358 
1359     ret = fserve_list_clients_xml (srcnode, &finfo);
1360     if (ret == 0 && finfo.flags&FS_FALLBACK)
1361     {
1362         finfo.flags = 0; // retry
1363         ret = fserve_list_clients_xml (srcnode, &finfo);
1364     }
1365     if (ret)
1366     {
1367         char buf [20];
1368         snprintf (buf, sizeof(buf), "%d", ret);
1369         xmlNewChild (srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf));
1370         return admin_send_response (doc, client, response, "listclients.xsl");
1371     }
1372     xmlFreeDoc (doc);
1373     return client_send_400 (client, "mount does not exist");
1374 }
1375 
1376 
fserve_query_count(fbinfo * finfo)1377 int fserve_query_count (fbinfo *finfo)
1378 {
1379     int ret = -1;
1380     fh_node *fh;
1381 
1382     if (finfo->flags & FS_FALLBACK && finfo->limit)
1383     {
1384         avl_tree_wlock (fh_cache);
1385         fh = open_fh (finfo);
1386         if (fh)
1387         {
1388             ret = fh->refcount;
1389             thread_mutex_unlock (&fh->lock);
1390         }
1391     }
1392     else
1393     {
1394         avl_tree_rlock (fh_cache);
1395         fh = find_fh (finfo);
1396         if (fh)
1397         {
1398             thread_mutex_lock (&fh->lock);
1399             ret = fh->refcount;
1400             thread_mutex_unlock (&fh->lock);
1401         }
1402         avl_tree_unlock (fh_cache);
1403     }
1404     return ret;
1405 }
1406 
1407 
file_in_use(icefile_handle f)1408 int file_in_use (icefile_handle f)
1409 {
1410     return f != -1;
1411 }
1412 
1413 
file_close(icefile_handle * f)1414 void file_close (icefile_handle *f)
1415 {
1416    if (*f != -1)
1417        close (*f);
1418    *f = -1;
1419 }
1420 
1421 
file_open(icefile_handle * f,const char * fn)1422 int file_open (icefile_handle *f, const char *fn)
1423 {
1424     *f = open (fn, O_RDONLY|O_CLOEXEC|O_BINARY);
1425     return (*f) < 0 ? -1 : 0;
1426 }
1427 
1428 
1429 #ifndef HAVE_PREAD
pread(icefile_handle f,void * data,size_t count,off_t offset)1430 ssize_t pread (icefile_handle f, void *data, size_t count, off_t offset)
1431 {
1432     ssize_t bytes = -1;
1433 
1434     // we do not want another thread to modifiy handle between seek and read
1435     // win32 may be able to use the overlapped io struct in ReadFile
1436     thread_mutex_lock (&seekread_lock);
1437     if (lseek (f, offset, SEEK_SET) != (off_t)-1)
1438         bytes = read (f, data, count);
1439     thread_mutex_unlock (&seekread_lock);
1440     return bytes;
1441 }
1442 #endif
1443 
1444 
fserve_scan(time_t now)1445 void fserve_scan (time_t now)
1446 {
1447     avl_node *node;
1448 
1449     global_lock();
1450     if (global.running != ICE_RUNNING)
1451         now = (time_t)0;
1452     global_unlock();
1453 
1454     avl_tree_wlock (fh_cache);
1455     node = avl_get_first (fh_cache);
1456     while (node)
1457     {
1458         fh_node *fh = node->key;
1459         node = avl_get_next (node);
1460 
1461         thread_mutex_lock (&fh->lock);
1462 
1463         if (now == (time_t)0)
1464         {
1465             fh->expire = 0;
1466             thread_mutex_unlock (&fh->lock);
1467             continue;
1468         }
1469 
1470         if (fh->finfo.limit)
1471         {
1472             fbinfo *finfo = &fh->finfo;
1473             if (fh->stats == 0)
1474             {
1475                 int len = strlen (finfo->mount) + 10;
1476                 char *str = alloca (len);
1477                 char buf[30];
1478                 snprintf (str, len, "%s-%s", (finfo->flags & FS_FALLBACK) ? "fallback" : "file", finfo->mount);
1479                 fh->stats = stats_handle (str);
1480                 stats_set_flags (fh->stats, "fallback", "file", STATS_COUNTERS|STATS_HIDDEN);
1481                 stats_set_flags (fh->stats, "outgoing_kbitrate", "0", STATS_COUNTERS|STATS_HIDDEN);
1482                 snprintf (buf, sizeof (buf), "%d", fh->refcount);
1483                 stats_set_flags (fh->stats, "listeners", buf, STATS_GENERAL|STATS_HIDDEN);
1484                 snprintf (buf, sizeof (buf), "%d", fh->peak);
1485                 stats_set_flags (fh->stats, "listener_peak", buf, STATS_GENERAL|STATS_HIDDEN);
1486                 fh->prev_count = fh->refcount;
1487             }
1488             else
1489             {
1490                 stats_lock (fh->stats, NULL);
1491                 if (fh->prev_count != fh->refcount)
1492                 {
1493                     fh->prev_count = fh->refcount;
1494                     stats_set_args (fh->stats, "listeners", "%ld", fh->refcount);
1495                     stats_set_args (fh->stats, "listener_peak", "%ld", fh->peak);
1496                 }
1497             }
1498             if (fh->stats_update <= now)
1499             {
1500                 fh->stats_update = now + 5;
1501                 stats_set_args (fh->stats, "outgoing_kbitrate", "%ld",
1502                         (long)((8 * rate_avg (fh->out_bitrate))/1024));
1503             }
1504             stats_release (fh->stats);
1505         }
1506 
1507         if (fh->refcount == 0 && fh->expire >= 0 && now >= fh->expire)
1508         {
1509             DEBUG1 ("timeout of %s", fh->finfo.mount);
1510             if (fh->stats)
1511             {
1512                 stats_lock (fh->stats, NULL);
1513                 stats_set (fh->stats, NULL, NULL);
1514             }
1515             remove_fh_from_cache (fh);
1516             thread_mutex_unlock (&fh->lock);
1517             _delete_fh (fh);
1518             continue;
1519         }
1520         thread_mutex_unlock (&fh->lock);
1521     }
1522     avl_tree_unlock (fh_cache);
1523 }
1524 
1525 
1526 
fserve_contains(const char * name)1527 int fserve_contains (const char *name)
1528 {
1529     int ret = -1;
1530     fbinfo finfo;
1531 
1532     memset (&finfo, 0, sizeof (finfo));
1533     if (strncmp (name, "fallback-/", 10) == 0)
1534     {
1535         finfo.mount = (char*)name+9;
1536         finfo.flags = FS_FALLBACK;
1537     }
1538     else if (strncmp (name, "file-/", 6) == 0)
1539         finfo.mount = (char*)name;
1540     DEBUG1 ("looking for %s", name);
1541     avl_tree_rlock (fh_cache);
1542     if (find_fh (&finfo))
1543        ret = 0;
1544     avl_tree_unlock (fh_cache);
1545     return ret;
1546 }
1547 
1548