1 /*
2 * A neon HTTP input plugin for Audacious
3 * Copyright (C) 2007 Ralf Ertzinger
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #define __STDC_FORMAT_MACROS
21 #include <inttypes.h>
22 #include <pthread.h>
23 #include <stdint.h>
24 #include <string.h>
25
26 #include <glib.h>
27
28 #include <libaudcore/audstrings.h>
29 #include <libaudcore/i18n.h>
30 #include <libaudcore/plugin.h>
31 #include <libaudcore/ringbuf.h>
32 #include <libaudcore/runtime.h>
33
34 #include <ne_auth.h>
35 #include <ne_session.h>
36 #include <ne_socket.h>
37 #include <ne_redirect.h>
38 #include <ne_request.h>
39 #include <ne_uri.h>
40 #include <ne_utils.h>
41
42 #include "cert_verification.h"
43
44 #define NEON_NETBLKSIZE (4096)
45 #define NEON_ICY_BUFSIZE (4096)
46 #define NEON_RETRY_COUNT 6
47 #undef feof
48
49 enum FillBufferResult {
50 FILL_BUFFER_SUCCESS,
51 FILL_BUFFER_ERROR,
52 FILL_BUFFER_EOF
53 };
54
55 enum neon_reader_t {
56 NEON_READER_INIT = 0,
57 NEON_READER_RUN = 1,
58 NEON_READER_ERROR,
59 NEON_READER_EOF,
60 NEON_READER_TERM
61 };
62
63 struct reader_status
64 {
65 bool reading = false;
66 neon_reader_t status = NEON_READER_INIT;
67
68 pthread_mutex_t mutex;
69 pthread_cond_t cond;
70
reader_statusreader_status71 reader_status ()
72 {
73 pthread_mutex_init (& mutex, nullptr);
74 pthread_cond_init (& cond, nullptr);
75 }
76
~reader_statusreader_status77 ~reader_status ()
78 {
79 pthread_mutex_destroy (& mutex);
80 pthread_cond_destroy (& cond);
81 }
82 };
83
84 struct icy_metadata
85 {
86 String stream_name;
87 String stream_title;
88 String stream_url;
89 String stream_contenttype;
90 int stream_bitrate = 0;
91 };
92
93 static const char * const neon_schemes[] = {"http", "https"};
94
95 class NeonTransport : public TransportPlugin
96 {
97 public:
98 static constexpr PluginInfo info = {N_("Neon HTTP/HTTPS Plugin"), PACKAGE};
99
NeonTransport()100 constexpr NeonTransport () : TransportPlugin (info, neon_schemes) {}
101
102 bool init ();
103 void cleanup ();
104
105 VFSImpl * fopen (const char * path, const char * mode, String & error);
106 };
107
108 EXPORT NeonTransport aud_plugin_instance;
109
init()110 bool NeonTransport::init ()
111 {
112 int ret = ne_sock_init ();
113
114 if (ret != 0)
115 {
116 AUDERR ("Could not initialize neon library: %d\n", ret);
117 return false;
118 }
119
120 return true;
121 }
122
cleanup()123 void NeonTransport::cleanup ()
124 {
125 ne_sock_exit ();
126 }
127
128 class NeonFile : public VFSImpl
129 {
130 public:
131 NeonFile (const char * url);
132 ~NeonFile ();
133
134 int open_handle (int64_t startbyte, String * error = nullptr);
135
136 protected:
137 int64_t fread (void * ptr, int64_t size, int64_t nmemb);
138 int fseek (int64_t offset, VFSSeekType whence);
139
140 int64_t ftell ();
141 int64_t fsize ();
142 bool feof ();
143
144 int64_t fwrite (const void * ptr, int64_t size, int64_t nmemb);
145 int ftruncate (int64_t length);
146 int fflush ();
147
148 String get_metadata (const char * field);
149
150 private:
151 String m_url; /* The URL, as passed to us */
152 ne_uri m_purl = ne_uri (); /* The URL, parsed into a structure */
153
154 unsigned char m_redircount = 0; /* Redirect count for the opened URL */
155 int64_t m_pos = 0; /* Current position in the stream
156 (number of last byte delivered to the player) */
157 int64_t m_content_start = 0; /* Start position in the stream */
158 int64_t m_content_length = -1; /* Total content length, counting from
159 content_start, if known. -1 if unknown */
160 bool m_can_ranges = false; /* true if the webserver advertised accept-range: bytes */
161 int64_t m_icy_metaint = 0; /* Interval in which the server will
162 send metadata announcements. 0 if no announcments */
163 int64_t m_icy_metaleft = 0; /* Bytes left until the next metadata block */
164 int m_icy_len = 0; /* Bytes in current metadata block */
165
166 bool m_eof = false;
167
168 RingBuf<char> m_rb; /* Ringbuffer for our data */
169 Index<char> m_icy_buf; /* Buffer for ICY metadata */
170 icy_metadata m_icy_metadata; /* Current ICY metadata */
171
172 ne_session * m_session = nullptr;
173 ne_request * m_request = nullptr;
174
175 pthread_t m_reader;
176 reader_status m_reader_status;
177
178 void kill_reader ();
179 int server_auth (const char * realm, int attempt, char * username, char * password);
180 void handle_headers ();
181 int open_request (int64_t startbyte, String * error);
182 FillBufferResult fill_buffer ();
183 void reader ();
184 int64_t try_fread (void * ptr, int64_t size, int64_t nmemb, bool & data_read);
185
server_auth_callback(void * data,const char * realm,int attempt,char * username,char * password)186 static int server_auth_callback (void * data, const char * realm, int attempt,
187 char * username, char * password)
188 { return ((NeonFile *) data)->server_auth (realm, attempt, username, password); }
189
reader_thread(void * data)190 static void * reader_thread (void * data)
191 { ((NeonFile *) data)->reader (); return nullptr; }
192 };
193
NeonFile(const char * url)194 NeonFile::NeonFile (const char * url) :
195 m_url (url)
196 {
197 int buffer_kb = aud_get_int ("net_buffer_kb");
198 m_rb.alloc (1024 * aud::clamp (buffer_kb, 16, 1024));
199 }
200
~NeonFile()201 NeonFile::~NeonFile ()
202 {
203 if (m_reader_status.reading)
204 kill_reader ();
205
206 if (m_request)
207 ne_request_destroy (m_request);
208 if (m_session)
209 ne_session_destroy (m_session);
210
211 ne_uri_free (& m_purl);
212 }
213
neon_strcmp(const char * str,const char * cmp)214 static bool neon_strcmp (const char * str, const char * cmp)
215 {
216 return ! g_ascii_strncasecmp (str, cmp, strlen (cmp));
217 }
218
add_icy(struct icy_metadata * m,const char * name,const char * value)219 static void add_icy (struct icy_metadata * m, const char * name, const char * value)
220 {
221 if (neon_strcmp (name, "StreamTitle"))
222 {
223 AUDDBG ("Found StreamTitle: %s\n", value);
224 m->stream_title = String (str_to_utf8 (value, -1));
225 }
226
227 if (neon_strcmp (name, "StreamUrl"))
228 {
229 AUDDBG ("Found StreamUrl: %s\n", value);
230 m->stream_url = String (str_to_utf8 (value, -1));
231 }
232 }
233
parse_icy(struct icy_metadata * m,char * metadata,int len)234 static void parse_icy (struct icy_metadata * m, char * metadata, int len)
235 {
236 enum TagReadState
237 {
238 STATE_READ_NAME,
239 STATE_WAIT_VALUE,
240 STATE_READ_VALUE,
241 STATE_WAIT_NAME,
242 };
243
244 TagReadState state = STATE_READ_NAME;
245
246 char * p = metadata;
247 char * tstart = metadata;
248 int pos = 1;
249
250 char name[NEON_ICY_BUFSIZE];
251 char value[NEON_ICY_BUFSIZE];
252
253 name[0] = 0;
254 value[0] = 0;
255
256 while (pos < len && p[0])
257 {
258 switch (state)
259 {
260 case STATE_READ_NAME:
261
262 /* Reading tag name */
263 if (p[0] == '=')
264 {
265 /* End of tag name. */
266 p[0] = 0;
267 g_strlcpy (name, tstart, NEON_ICY_BUFSIZE);
268 AUDDBG ("Found tag name: %s\n", name);
269 state = STATE_WAIT_VALUE;
270 }
271
272 break;
273
274 case STATE_WAIT_VALUE:
275
276 /* Waiting for start of value */
277 if (p[0] == '\'')
278 {
279 /* Leading ' of value */
280 tstart = p + 1;
281 state = STATE_READ_VALUE;
282 value[0] = 0;
283 }
284
285 break;
286
287 case STATE_READ_VALUE:
288
289 /* Reading value */
290 if (p[0] == '\'' && p[1] == ';')
291 {
292 /* End of value */
293 p[0] = 0;
294 g_strlcpy (value, tstart, NEON_ICY_BUFSIZE);
295 AUDDBG ("Found tag value: %s\n", value);
296 add_icy (m, name, value);
297 state = STATE_WAIT_NAME;
298 }
299
300 break;
301
302 case STATE_WAIT_NAME:
303
304 /* Waiting for next tag start */
305 if (p[0] == ';')
306 {
307 /* Next tag name starts after this char */
308 tstart = p + 1;
309 state = STATE_READ_NAME;
310 name[0] = 0;
311 value[0] = 0;
312 }
313
314 break;
315 }
316
317 p ++;
318 pos ++;
319 }
320 }
321
kill_reader()322 void NeonFile::kill_reader ()
323 {
324 AUDDBG ("Signaling reader thread to terminate\n");
325 pthread_mutex_lock (& m_reader_status.mutex);
326 m_reader_status.reading = false;
327 pthread_cond_broadcast (& m_reader_status.cond);
328 pthread_mutex_unlock (& m_reader_status.mutex);
329
330 AUDDBG ("Waiting for reader thread to die...\n");
331 pthread_join (m_reader, nullptr);
332 AUDDBG ("Reader thread has died\n");
333 }
334
server_auth(const char * realm,int attempt,char * username,char * password)335 int NeonFile::server_auth (const char * realm, int attempt, char * username, char * password)
336 {
337 if (! m_purl.userinfo || ! m_purl.userinfo[0])
338 {
339 AUDERR ("Authentication required, but no credentials set\n");
340 return 1;
341 }
342
343 char * * authtok = g_strsplit (m_purl.userinfo, ":", 2);
344
345 if (strlen (authtok[1]) > NE_ABUFSIZ - 1 || strlen (authtok[0]) > NE_ABUFSIZ - 1)
346 {
347 AUDERR ("Username/Password too long\n");
348 g_strfreev (authtok);
349 return 1;
350 }
351
352 g_strlcpy (username, authtok[0], NE_ABUFSIZ);
353 g_strlcpy (password, authtok[1], NE_ABUFSIZ);
354
355 AUDDBG ("Authenticating: Username: %s, Password: %s\n", username, password);
356
357 g_strfreev (authtok);
358
359 return attempt;
360 }
361
handle_headers()362 void NeonFile::handle_headers ()
363 {
364 const char * name;
365 const char * value;
366 void * cursor = nullptr;
367
368 AUDDBG ("Header responses:\n");
369
370 while ((cursor = ne_response_header_iterate (m_request, cursor, & name, & value)))
371 {
372 AUDDBG ("HEADER: %s: %s\n", name, value);
373
374 if (neon_strcmp (name, "accept-ranges"))
375 {
376 /* The server advertises range capability. we need "bytes" */
377 if (strstr (value, "bytes"))
378 {
379 AUDDBG ("server can_ranges\n");
380 m_can_ranges = true;
381 }
382 }
383 else if (neon_strcmp (name, "content-length"))
384 {
385 /* The server sent us the content length. Parse and store. */
386 char * endptr;
387 int64_t len = strtoll (value, & endptr, 10);
388
389 if (value[0] && ! endptr[0] && len >= 0)
390 {
391 /* Valid data. */
392 AUDDBG ("Content length as advertised by server: %" PRId64 "\n", len);
393 m_content_length = len;
394 }
395 else
396 AUDERR ("Invalid content length header: %s\n", value);
397 }
398 else if (neon_strcmp (name, "content-type"))
399 {
400 /* The server sent us a content type. Save it for later */
401 AUDDBG ("Content-Type: %s\n", value);
402 m_icy_metadata.stream_contenttype = String (str_to_utf8 (value, -1));
403 }
404 else if (neon_strcmp (name, "icy-metaint"))
405 {
406 /* The server sent us a ICY metaint header. Parse and store. */
407 char * endptr;
408 int64_t len = strtoll (value, & endptr, 10);
409
410 if (value[0] && ! endptr[0] && len > 0)
411 {
412 /* Valid data */
413 AUDDBG ("ICY MetaInt as advertised by server: %" PRId64 "\n", len);
414 m_icy_metaint = len;
415 m_icy_metaleft = len;
416 }
417 else
418 AUDERR ("Invalid ICY MetaInt header: %s\n", value);
419 }
420 else if (neon_strcmp (name, "icy-name"))
421 {
422 /* The server sent us a ICY name. Save it for later */
423 AUDDBG ("ICY stream name: %s\n", value);
424 m_icy_metadata.stream_name = String (value);
425 }
426 else if (neon_strcmp (name, "icy-br"))
427 {
428 /* The server sent us a bitrate. We might want to use it. */
429 AUDDBG ("ICY bitrate: %d\n", atoi (value));
430 m_icy_metadata.stream_bitrate = atoi (value);
431 }
432 }
433 }
434
neon_proxy_auth_cb(void * userdata,const char * realm,int attempt,char * username,char * password)435 static int neon_proxy_auth_cb (void * userdata, const char * realm, int attempt,
436 char * username, char * password)
437 {
438 String value = aud_get_str ("proxy_user");
439 g_strlcpy (username, value, NE_ABUFSIZ);
440
441 value = aud_get_str ("proxy_pass");
442 g_strlcpy (password, value, NE_ABUFSIZ);
443
444 return attempt;
445 }
446
open_request(int64_t startbyte,String * error)447 int NeonFile::open_request (int64_t startbyte, String * error)
448 {
449 int ret;
450 const ne_status * status;
451 ne_uri * rediruri;
452
453 if (m_purl.query && * (m_purl.query))
454 {
455 StringBuf tmp = str_concat ({m_purl.path, "?", m_purl.query});
456 m_request = ne_request_create (m_session, "GET", tmp);
457 }
458 else
459 m_request = ne_request_create (m_session, "GET", m_purl.path);
460
461 if (startbyte > 0)
462 ne_add_request_header (m_request, "Range", str_printf ("bytes=%" PRIu64 "-", startbyte));
463
464 ne_add_request_header (m_request, "Icy-MetaData", "1");
465
466 /* Try to connect to the server. */
467 AUDDBG ("<%p> Connecting...\n", this);
468 ret = ne_begin_request (m_request);
469 status = ne_get_status (m_request);
470 AUDDBG ("<%p> Return: %d, Status: %d\n", this, ret, status->code);
471
472 if (ret == NE_OK)
473 {
474 switch (status->code)
475 {
476 case 401:
477 /* Authorization required. Reconnect to authenticate */
478 AUDDBG ("Reconnecting due to 401\n");
479 ne_end_request (m_request);
480 ret = ne_begin_request (m_request);
481 break;
482
483 case 301:
484 case 302:
485 case 303:
486 case 307:
487 /* Redirect encountered. Reconnect. */
488 ne_end_request (m_request);
489 ret = NE_REDIRECT;
490 break;
491
492 case 407:
493 /* Proxy auth required. Reconnect to authenticate */
494 AUDDBG ("Reconnecting due to 407\n");
495 ne_end_request (m_request);
496 ret = ne_begin_request (m_request);
497 break;
498 }
499 }
500
501 switch (ret)
502 {
503 case NE_OK:
504 if (status->code > 199 && status->code < 300)
505 {
506 /* URL opened OK */
507 AUDDBG ("<%p> URL opened OK\n", this);
508 m_content_start = startbyte;
509 m_pos = startbyte;
510 handle_headers ();
511 return 0;
512 }
513
514 break;
515
516 case NE_REDIRECT:
517 /* We hit a redirect. Handle it. */
518 AUDDBG ("<%p> Redirect encountered\n", this);
519 m_redircount += 1;
520 rediruri = (ne_uri *) ne_redirect_location (m_session);
521 ne_request_destroy (m_request);
522 m_request = nullptr;
523
524 if (! rediruri)
525 {
526 if (error)
527 * error = String (_("Error parsing redirect"));
528
529 AUDERR ("<%p> Could not parse redirect response\n", this);
530 return -1;
531 }
532
533 ne_uri_free (& m_purl);
534 ne_uri_copy (& m_purl, rediruri);
535 return 1;
536 }
537
538 /* Something went wrong. */
539 const char * ne_error = ne_get_error (m_session);
540 if (error)
541 * error = String (ne_error ? ne_error : _("Unknown HTTP error"));
542
543 AUDERR ("<%p> Could not open URL: %d (%d)\n", this, ret, status->code);
544
545 if (ne_error)
546 AUDERR ("<%p> neon error string: %s\n", this, ne_error);
547
548 ne_request_destroy (m_request);
549 m_request = nullptr;
550 return -1;
551 }
552
open_handle(int64_t startbyte,String * error)553 int NeonFile::open_handle (int64_t startbyte, String * error)
554 {
555 int ret;
556 String proxy_host;
557 int proxy_port = 0;
558 String proxy_user (""); // ne_session_socks_proxy requires non NULL user and password
559 String proxy_pass ("");
560 bool socks_proxy = false;
561 ne_sock_sversion socks_type = NE_SOCK_SOCKSV4A;
562
563 bool use_proxy = aud_get_bool ("use_proxy");
564 bool use_proxy_auth = aud_get_bool ("use_proxy_auth");
565
566 if (use_proxy)
567 {
568 proxy_host = aud_get_str ("proxy_host");
569 proxy_port = aud_get_int ("proxy_port");
570 socks_proxy = aud_get_bool ("socks_proxy");
571
572 if (use_proxy_auth)
573 {
574 proxy_user = aud_get_str ("proxy_user");
575 proxy_pass = aud_get_str ("proxy_pass");
576 }
577
578 if (socks_proxy)
579 {
580 socks_type = aud_get_int ("socks_type") == 0 ? NE_SOCK_SOCKSV4A : NE_SOCK_SOCKSV5;
581 }
582 }
583
584 m_redircount = 0;
585
586 AUDDBG ("<%p> Parsing URL\n", this);
587
588 if (ne_uri_parse (m_url, & m_purl) != 0)
589 {
590 if (error)
591 * error = String (_("Error parsing URL"));
592
593 AUDERR ("<%p> Could not parse URL '%s'\n", this, (const char *) m_url);
594 return -1;
595 }
596
597 while (m_redircount < 10)
598 {
599 if (! m_purl.port)
600 m_purl.port = ne_uri_defaultport (m_purl.scheme);
601
602 AUDDBG ("<%p> Creating session to %s://%s:%d\n", this,
603 m_purl.scheme, m_purl.host, m_purl.port);
604 m_session = ne_session_create (m_purl.scheme,
605 m_purl.host, m_purl.port);
606 ne_redirect_register (m_session);
607 ne_add_server_auth (m_session, NE_AUTH_BASIC, server_auth_callback, this);
608 ne_set_session_flag (m_session, NE_SESSFLAG_ICYPROTO, 1);
609 ne_set_session_flag (m_session, NE_SESSFLAG_PERSIST, 0);
610 ne_set_connect_timeout (m_session, 10);
611 ne_set_read_timeout (m_session, 10);
612 ne_set_useragent (m_session, "Audacious/" PACKAGE_VERSION);
613
614 if (use_proxy)
615 {
616 AUDDBG ("<%p> Using proxy: %s:%d\n", this, (const char *) proxy_host, proxy_port);
617 if (socks_proxy)
618 {
619 ne_session_socks_proxy (m_session, socks_type, proxy_host, proxy_port, proxy_user, proxy_pass);
620 }
621 else
622 {
623 ne_session_proxy (m_session, proxy_host, proxy_port);
624 }
625
626 if (use_proxy_auth)
627 {
628 AUDDBG ("<%p> Using proxy authentication\n", this);
629 ne_add_proxy_auth (m_session, NE_AUTH_BASIC,
630 neon_proxy_auth_cb, (void *) this);
631 }
632 }
633
634 if (! strcmp ("https", m_purl.scheme))
635 {
636 ne_ssl_trust_default_ca (m_session);
637 ne_ssl_set_verify (m_session,
638 neon_vfs_verify_environment_ssl_certs, m_session);
639 }
640
641 AUDDBG ("<%p> Creating request\n", this);
642 ret = open_request (startbyte, error);
643
644 if (! ret)
645 return 0;
646
647 if (ret == -1)
648 {
649 ne_session_destroy (m_session);
650 m_session = nullptr;
651 return -1;
652 }
653
654 AUDDBG ("<%p> Following redirect...\n", this);
655 ne_session_destroy (m_session);
656 m_session = nullptr;
657 }
658
659 /* If we get here, our redirect count exceeded */
660 if (error)
661 * error = String (_("Too many redirects"));
662
663 AUDERR ("<%p> Redirect count exceeded for URL %s\n", this, (const char *) m_url);
664 return 1;
665 }
666
fill_buffer()667 FillBufferResult NeonFile::fill_buffer ()
668 {
669 char buffer[NEON_NETBLKSIZE];
670 int to_read;
671
672 pthread_mutex_lock (& m_reader_status.mutex);
673 to_read = aud::min (m_rb.space (), NEON_NETBLKSIZE);
674 pthread_mutex_unlock (& m_reader_status.mutex);
675
676 int bsize = ne_read_response_block (m_request, buffer, to_read);
677
678 if (! bsize)
679 {
680 AUDDBG ("<%p> End of file encountered\n", this);
681 return FILL_BUFFER_EOF;
682 }
683
684 if (bsize < 0)
685 {
686 AUDERR ("<%p> Error while reading from the network\n", this);
687 ne_request_destroy (m_request);
688 m_request = nullptr;
689 return FILL_BUFFER_ERROR;
690 }
691
692 AUDDBG ("<%p> Read %d bytes of %d\n", this, bsize, to_read);
693
694 pthread_mutex_lock (& m_reader_status.mutex);
695 m_rb.copy_in (buffer, bsize);
696 pthread_mutex_unlock (& m_reader_status.mutex);
697
698 return FILL_BUFFER_SUCCESS;
699 }
700
reader()701 void NeonFile::reader ()
702 {
703 pthread_mutex_lock (& m_reader_status.mutex);
704
705 while (m_reader_status.reading)
706 {
707 /* Hit the network only if we have more than NEON_NETBLKSIZE of free buffer */
708 if (m_rb.space () > NEON_NETBLKSIZE)
709 {
710 pthread_mutex_unlock (& m_reader_status.mutex);
711
712 FillBufferResult ret = fill_buffer ();
713
714 pthread_mutex_lock (& m_reader_status.mutex);
715
716 /* Wake up main thread if it is waiting. */
717 pthread_cond_broadcast (& m_reader_status.cond);
718
719 if (ret == FILL_BUFFER_ERROR)
720 {
721 AUDERR ("<%p> Error while reading from the network. "
722 "Terminating reader thread\n", this);
723 m_reader_status.status = NEON_READER_ERROR;
724 pthread_mutex_unlock (& m_reader_status.mutex);
725 return;
726 }
727 else if (ret == FILL_BUFFER_EOF)
728 {
729 AUDDBG ("<%p> EOF encountered while reading from the network. "
730 "Terminating reader thread\n", this);
731 m_reader_status.status = NEON_READER_EOF;
732 pthread_mutex_unlock (& m_reader_status.mutex);
733 return;
734 }
735 }
736 else
737 {
738 /* Not enough free space in the buffer.
739 * Sleep until the main thread wakes us up. */
740 pthread_cond_wait (& m_reader_status.cond, & m_reader_status.mutex);
741 }
742 }
743
744 AUDDBG ("<%p> Reader thread terminating gracefully\n", this);
745 m_reader_status.status = NEON_READER_TERM;
746 pthread_mutex_unlock (& m_reader_status.mutex);
747 }
748
fopen(const char * path,const char * mode,String & error)749 VFSImpl * NeonTransport::fopen (const char * path, const char * mode, String & error)
750 {
751 NeonFile * file = new NeonFile (path);
752
753 AUDDBG ("<%p> Trying to open '%s' with neon\n", file, path);
754
755 if (file->open_handle (0, & error) != 0)
756 {
757 AUDERR ("<%p> Could not open URL\n", file);
758 delete file;
759 return nullptr;
760 }
761
762 return file;
763 }
764
try_fread(void * ptr,int64_t size,int64_t nmemb,bool & data_read)765 int64_t NeonFile::try_fread (void * ptr, int64_t size, int64_t nmemb, bool & data_read)
766 {
767 if (! m_request)
768 {
769 AUDERR ("<%p> No request to read from, seek gone wrong?\n", this);
770 return 0;
771 }
772
773 if (! size || ! nmemb || m_eof)
774 return 0;
775
776 /* If the buffer is empty, wait for the reader thread to fill it. */
777 pthread_mutex_lock (& m_reader_status.mutex);
778
779 for (int retries = 0; retries < NEON_RETRY_COUNT; retries ++)
780 {
781 if (m_rb.len () / size > 0 || ! m_reader_status.reading ||
782 m_reader_status.status != NEON_READER_RUN)
783 break;
784
785 pthread_cond_broadcast (& m_reader_status.cond);
786 pthread_cond_wait (& m_reader_status.cond, & m_reader_status.mutex);
787 }
788
789 pthread_mutex_unlock (& m_reader_status.mutex);
790
791 if (! m_reader_status.reading)
792 {
793 if (m_reader_status.status != NEON_READER_EOF || m_content_length != -1)
794 {
795 /* There is no reader thread yet. Read the first bytes from
796 * the network ourselves, and then fire up the reader thread
797 * to keep the buffer filled up. */
798 AUDDBG ("<%p> Doing initial buffer fill\n", this);
799 FillBufferResult ret = fill_buffer ();
800
801 if (ret == FILL_BUFFER_ERROR)
802 {
803 AUDERR ("<%p> Error while reading from the network\n", this);
804 return 0;
805 }
806
807 /* We have some data in the buffer now.
808 * Start the reader thread if we did not reach EOF during
809 * the initial fill */
810 pthread_mutex_lock (& m_reader_status.mutex);
811
812 if (ret == FILL_BUFFER_SUCCESS)
813 {
814 m_reader_status.reading = true;
815 AUDDBG ("<%p> Starting reader thread\n", this);
816 pthread_create (& m_reader, nullptr, reader_thread, this);
817 m_reader_status.status = NEON_READER_RUN;
818 }
819 else if (ret == FILL_BUFFER_EOF)
820 {
821 AUDDBG ("<%p> No reader thread needed (stream has reached EOF during fill)\n", this);
822 m_reader_status.reading = false;
823 m_reader_status.status = NEON_READER_EOF;
824 }
825
826 pthread_mutex_unlock (& m_reader_status.mutex);
827 }
828 }
829 else
830 {
831 /* There already is a reader thread. Look if it is in good shape. */
832 pthread_mutex_lock (& m_reader_status.mutex);
833
834 switch (m_reader_status.status)
835 {
836 case NEON_READER_INIT:
837 case NEON_READER_RUN:
838 /* All is well, nothing to be done. */
839 break;
840
841 case NEON_READER_ERROR:
842 /* A reader error happened. Log it, and treat it like an EOF
843 * condition, by falling through to the NEON_READER_EOF codepath. */
844 AUDDBG ("<%p> NEON_READER_ERROR happened. Terminating reader thread and marking EOF.\n", this);
845 m_reader_status.status = NEON_READER_EOF;
846 pthread_mutex_unlock (& m_reader_status.mutex);
847
848 if (m_reader_status.reading)
849 kill_reader ();
850
851 pthread_mutex_lock (& m_reader_status.mutex);
852
853 case NEON_READER_EOF:
854 /* If there still is data in the buffer, carry on.
855 * If not, terminate the reader thread and return 0. */
856 if (! m_rb.len ())
857 {
858 AUDDBG ("<%p> Reached end of stream\n", this);
859 pthread_mutex_unlock (& m_reader_status.mutex);
860
861 if (m_reader_status.reading)
862 kill_reader ();
863
864 m_eof = true;
865 return 0;
866 }
867
868 break;
869
870 case NEON_READER_TERM:
871 /* The reader thread terminated gracefully, most likely on our own request.
872 * We should not get here. */
873 g_warn_if_reached ();
874 pthread_mutex_unlock (& m_reader_status.mutex);
875 return 0;
876 }
877
878 pthread_mutex_unlock (& m_reader_status.mutex);
879 }
880
881 /* Deliver data from the buffer */
882 pthread_mutex_lock (& m_reader_status.mutex);
883
884 if (m_rb.len ())
885 data_read = true;
886 else
887 {
888 /* The buffer is still empty, we can deliver no data! */
889 AUDERR ("<%p> Buffer still underrun, fatal.\n", this);
890 pthread_mutex_unlock (& m_reader_status.mutex);
891 return 0;
892 }
893
894 int64_t belem = m_rb.len () / size;
895
896 if (m_icy_metaint)
897 {
898 if (! m_icy_metaleft)
899 {
900 if (! m_icy_len)
901 {
902 /* The next data in the buffer is a ICY metadata announcement.
903 * Get the length byte */
904 m_icy_len = 16 * (unsigned char) m_rb.head ();
905 m_rb.pop ();
906
907 AUDDBG ("<%p> Expecting %d bytes of ICY metadata\n", this, m_icy_len);
908 }
909
910 if (m_icy_buf.len () < m_icy_len)
911 m_rb.move_out (m_icy_buf, -1, aud::min (m_icy_len - m_icy_buf.len (), m_rb.len ()));
912
913 if (m_icy_buf.len () >= m_icy_len)
914 {
915 /* Grab the metadata from the buffer and send it to the parser */
916 parse_icy (& m_icy_metadata, m_icy_buf.begin (), m_icy_buf.len ());
917
918 /* Reset countdown to next announcement */
919 m_icy_buf.clear ();
920 m_icy_len = 0;
921 m_icy_metaleft = m_icy_metaint;
922 }
923 }
924
925 /* The maximum number of bytes we can deliver is determined
926 * by the number of bytes left until the next metadata announcement */
927 belem = aud::min ((int64_t) m_rb.len (), m_icy_metaleft) / size;
928 }
929
930 nmemb = aud::min (belem, nmemb);
931 m_rb.move_out ((char *) ptr, nmemb * size);
932
933 /* Signal the network thread to continue reading */
934 if (m_reader_status.status == NEON_READER_EOF)
935 {
936 if (! m_rb.len ())
937 {
938 AUDDBG ("<%p> stream EOF reached and buffer empty\n", this);
939 m_eof = true;
940 }
941 }
942 else
943 pthread_cond_broadcast (& m_reader_status.cond);
944
945 pthread_mutex_unlock (& m_reader_status.mutex);
946
947 m_pos += nmemb * size;
948 m_icy_metaleft -= nmemb * size;
949
950 return nmemb;
951 }
952
953 /* try_fread will do only a partial read if the buffer underruns, so we
954 * must call it repeatedly until we have read the full request. */
fread(void * buffer,int64_t size,int64_t count)955 int64_t NeonFile::fread (void * buffer, int64_t size, int64_t count)
956 {
957 int64_t total = 0;
958
959 AUDDBG ("<%p> fread %d x %d\n", this, (int) size, (int) count);
960
961 while (count > 0)
962 {
963 bool data_read = false;
964 int64_t part = try_fread (buffer, size, count, data_read);
965 if (! data_read)
966 break;
967
968 buffer = (char *) buffer + size * part;
969 total += part;
970 count -= part;
971 }
972
973 AUDDBG ("<%p> fread = %d\n", this, (int) total);
974
975 return total;
976 }
977
fwrite(const void * ptr,int64_t size,int64_t nmemb)978 int64_t NeonFile::fwrite (const void * ptr, int64_t size, int64_t nmemb)
979 {
980 AUDERR ("<%p> NOT IMPLEMENTED\n", this);
981
982 return 0;
983 }
984
ftell()985 int64_t NeonFile::ftell ()
986 {
987 AUDDBG ("<%p> Current file position: %" PRId64 "\n", this, m_pos);
988
989 return m_pos;
990 }
991
feof()992 bool NeonFile::feof ()
993 {
994 AUDDBG ("<%p> EOF status: %s\n", this, m_eof ? "true" : "false");
995
996 return m_eof;
997 }
998
ftruncate(int64_t size)999 int NeonFile::ftruncate (int64_t size)
1000 {
1001 AUDERR ("<%p> NOT IMPLEMENTED\n", this);
1002
1003 return 0;
1004 }
1005
fflush()1006 int NeonFile::fflush ()
1007 {
1008 return 0; /* no-op */
1009 }
1010
fseek(int64_t offset,VFSSeekType whence)1011 int NeonFile::fseek (int64_t offset, VFSSeekType whence)
1012 {
1013 AUDDBG ("<%p> Seek requested: offset %" PRId64 ", whence %d\n", this, offset, whence);
1014
1015 /* To seek to a non-zero offset, two things must be satisfied:
1016 * - the server must advertise a content-length
1017 * - the server must advertise accept-ranges: bytes */
1018 if ((whence != VFS_SEEK_SET || offset) && (m_content_length < 0 || ! m_can_ranges))
1019 {
1020 AUDDBG ("<%p> Can not seek due to server restrictions\n", this);
1021 return -1;
1022 }
1023
1024 int64_t content_length = m_content_length + m_content_start;
1025 int64_t newpos;
1026
1027 switch (whence)
1028 {
1029 case VFS_SEEK_SET:
1030 newpos = offset;
1031 break;
1032
1033 case VFS_SEEK_CUR:
1034 newpos = m_pos + offset;
1035 break;
1036
1037 case VFS_SEEK_END:
1038 if (offset == 0)
1039 {
1040 m_pos = content_length;
1041 m_eof = true;
1042 return 0;
1043 }
1044
1045 newpos = content_length + offset;
1046 break;
1047
1048 default:
1049 AUDERR ("<%p> Invalid whence specified\n", this);
1050 return -1;
1051 }
1052
1053 AUDDBG ("<%p> Position to seek to: %" PRId64 ", current: %" PRId64 "\n", this, newpos, m_pos);
1054
1055 if (newpos < 0)
1056 {
1057 AUDERR ("<%p> Can not seek before start of stream\n", this);
1058 return -1;
1059 }
1060
1061 if (newpos && newpos >= content_length)
1062 {
1063 AUDERR ("<%p> Can not seek beyond end of stream (%" PRId64 " >= %"
1064 PRId64 "\n", this, newpos, content_length);
1065 return -1;
1066 }
1067
1068 if (newpos == m_pos)
1069 return 0;
1070
1071 /* To seek to the new position we have to
1072 * - stop the current reader thread, if there is one
1073 * - destroy the current request
1074 * - dump all data currently in the ringbuffer
1075 * - create a new request starting at newpos */
1076 if (m_reader_status.reading)
1077 kill_reader ();
1078
1079 if (m_request)
1080 {
1081 ne_request_destroy (m_request);
1082 m_request = nullptr;
1083 }
1084
1085 if (m_session)
1086 {
1087 ne_session_destroy (m_session);
1088 m_session = nullptr;
1089 }
1090
1091 m_rb.discard ();
1092 m_icy_buf.clear ();
1093 m_icy_len = 0;
1094
1095 if (open_handle (newpos) != 0)
1096 {
1097 AUDERR ("<%p> Error while creating new request!\n", this);
1098 return -1;
1099 }
1100
1101 /* Things seem to have worked. The next read request will start
1102 * the reader thread again. */
1103 m_eof = false;
1104
1105 return 0;
1106 }
1107
get_metadata(const char * field)1108 String NeonFile::get_metadata (const char * field)
1109 {
1110 AUDDBG ("<%p> Field name: %s\n", this, field);
1111
1112 if (! strcmp (field, "track-name") && m_icy_metadata.stream_title)
1113 return m_icy_metadata.stream_title;
1114
1115 if (! strcmp (field, "stream-name") && m_icy_metadata.stream_name)
1116 return m_icy_metadata.stream_name;
1117
1118 if (! strcmp (field, "content-type") && m_icy_metadata.stream_contenttype)
1119 return m_icy_metadata.stream_contenttype;
1120
1121 if (! strcmp (field, "content-bitrate"))
1122 return String (int_to_str (m_icy_metadata.stream_bitrate * 1000));
1123
1124 return String ();
1125 }
1126
fsize()1127 int64_t NeonFile::fsize ()
1128 {
1129 if (m_content_length < 0)
1130 {
1131 AUDDBG ("<%p> Unknown content length\n", this);
1132 return -1;
1133 }
1134
1135 return m_content_start + m_content_length;
1136 }
1137