Fix Lancer-patched libvorbis-aoTuV so it builds with GCC.
[vorbis-lancer-gcc.git] / vorbis-tools-1.2.0 / ogg123 / http_transport.c
blobe84aebe0c64ec3dac4ed2d40d8745242c539e5d7
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
9 * by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS *
10 * http://www.xiph.org/ *
11 * *
12 ********************************************************************
14 last mod: $Id: http_transport.c,v 1.12 2003/08/06 23:14:12 volsung Exp $
16 ********************************************************************/
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 #ifdef HAVE_CURL
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <signal.h>
28 #include <curl/curl.h>
29 #include <curl/easy.h>
30 #include <pthread.h>
32 #include "ogg123.h"
33 #include "transport.h"
34 #include "buffer.h"
35 #include "status.h"
36 #include "callbacks.h"
37 #include "i18n.h"
39 #define INPUT_BUFFER_SIZE 32768
41 extern stat_format_t *stat_format; /* FIXME Bad hack! Will fix after RC3! */
42 extern signal_request_t sig_request; /* Need access to global cancel flag */
44 typedef struct http_private_t {
45 int cancel_flag;
47 buf_t *buf;
49 pthread_t curl_thread;
51 CURL *curl_handle;
52 struct curl_slist *header_list;
53 char error[CURL_ERROR_SIZE];
55 data_source_t *data_source;
56 data_source_stats_t stats;
57 } http_private_t;
60 transport_t http_transport; /* Forward declaration */
62 /* -------------------------- curl callbacks ----------------------- */
64 size_t write_callback (void *ptr, size_t size, size_t nmemb, void *arg)
66 http_private_t *myarg = arg;
68 if (myarg->cancel_flag || sig_request.cancel)
69 return 0;
71 buffer_submit_data(myarg->buf, ptr, size*nmemb);
73 if (myarg->cancel_flag || sig_request.cancel)
74 return 0;
76 return size * nmemb;
79 int progress_callback (void *arg, size_t dltotal, size_t dlnow,
80 size_t ultotal, size_t ulnow)
82 http_private_t *myarg = arg;
83 print_statistics_arg_t *pstats_arg;
84 data_source_t *source = myarg->data_source;
86 if (myarg->cancel_flag || sig_request.cancel)
87 return -1;
89 pstats_arg = new_print_statistics_arg(stat_format,
90 source->transport->statistics(source),
91 NULL);
93 print_statistics_action(NULL, pstats_arg);
95 if (myarg->cancel_flag || sig_request.cancel)
96 return -1;
98 return 0;
102 /* -------------------------- Private functions --------------------- */
104 void set_curl_opts (http_private_t *private)
106 CURL *handle = private->curl_handle;
108 curl_easy_setopt(handle, CURLOPT_FILE, private);
109 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
110 curl_easy_setopt(handle, CURLOPT_URL, private->data_source->source_string);
112 if (inputOpts.ProxyPort)
113 curl_easy_setopt(handle, CURLOPT_PROXYPORT, inputOpts.ProxyPort);
114 if (inputOpts.ProxyHost)
115 curl_easy_setopt(handle, CURLOPT_PROXY, inputOpts.ProxyHost);
116 if (inputOpts.ProxyTunnel)
117 curl_easy_setopt (handle, CURLOPT_HTTPPROXYTUNNEL, inputOpts.ProxyTunnel);
119 #ifdef CURLOPT_MUTE
120 curl_easy_setopt(handle, CURLOPT_MUTE, 1);
121 #endif
122 curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, private->error);
123 curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, progress_callback);
124 curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, private);
125 curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0);
126 curl_easy_setopt(handle, CURLOPT_USERAGENT, "ogg123/"VERSION);
127 curl_easy_setopt(handle, CURLOPT_HTTPHEADER, private->header_list);
128 curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
132 void *curl_thread_func (void *arg)
134 http_private_t *myarg = (http_private_t *) arg;
135 CURLcode ret;
136 sigset_t set;
138 /* Block signals to this thread */
139 sigfillset (&set);
140 sigaddset (&set, SIGINT);
141 sigaddset (&set, SIGTSTP);
142 sigaddset (&set, SIGCONT);
143 if (pthread_sigmask (SIG_BLOCK, &set, NULL) != 0)
144 status_error(_("Error: Could not set signal mask."));
146 ret = curl_easy_perform((CURL *) myarg->curl_handle);
148 if (myarg->cancel_flag || sig_request.cancel) {
149 buffer_abort_write(myarg->buf);
150 ret = 0; // "error" was on purpose
151 } else
152 buffer_mark_eos(myarg->buf);
154 if (ret != 0)
155 status_error(myarg->error);
157 curl_easy_cleanup(myarg->curl_handle);
158 myarg->curl_handle = 0;
160 curl_slist_free_all(myarg->header_list);
161 myarg->header_list = NULL;
163 return (void *) ret;
167 /* -------------------------- Public interface -------------------------- */
169 int http_can_transport (char *source_string)
171 int tmp;
173 tmp = strchr(source_string, ':') - source_string;
174 return tmp < 10 &&
175 tmp + 2 < strlen(source_string) &&
176 !strncmp(source_string + tmp, "://", 3);
180 data_source_t* http_open (char *source_string, ogg123_options_t *ogg123_opts)
182 data_source_t *source;
183 http_private_t *private;
185 /* Allocate data source structures */
186 source = malloc(sizeof(data_source_t));
187 private = malloc(sizeof(http_private_t));
189 if (source != NULL && private != NULL) {
190 source->source_string = strdup(source_string);
191 source->transport = &http_transport;
192 source->private = private;
194 private->buf = buffer_create (ogg123_opts->input_buffer_size,
195 ogg123_opts->input_buffer_size *
196 ogg123_opts->input_prebuffer / 100.0,
197 NULL, NULL, /* No write callback, using
198 buffer in pull mode. */
199 0 /* Irrelevant */);
200 if (private->buf == NULL) {
201 status_error(_("Error: Unable to create input buffer.\n"));
202 exit(1);
205 private->curl_handle = NULL;
206 private->header_list = NULL;
207 private->data_source = source;
208 private->stats.transfer_rate = 0;
209 private->stats.bytes_read = 0;
210 private->stats.input_buffer_used = 0;
211 private->cancel_flag = 0;
213 } else {
214 fprintf(stderr, _("Error: Out of memory.\n"));
215 exit(1);
218 /* ogg123 only accepts Ogg files, and optionally FLAC as well */
219 #ifdef HAVE_LIBFLAC
220 private->header_list = curl_slist_append(NULL, "Accept: application/ogg, audio/ogg, video/ogg, audio/x-flac;q=0.9");
221 #else
222 private->header_list = curl_slist_append(NULL, "Accept: application/ogg, audio/ogg, video/ogg;q=0.9");
223 #endif
224 if (private->header_list == NULL)
225 goto fail;
227 /* Open URL */
228 private->curl_handle = curl_easy_init();
229 if (private->curl_handle == NULL)
230 goto fail;
232 set_curl_opts(private);
234 /* Start thread */
235 if (pthread_create(&private->curl_thread, NULL, curl_thread_func,
236 private) != 0)
237 goto fail;
240 stat_format[2].enabled = 0; /* remaining playback time */
241 stat_format[3].enabled = 0; /* total playback time */
242 stat_format[6].enabled = 1; /* Input buffer fill % */
243 stat_format[7].enabled = 1; /* Input buffer state */
245 return source;
248 fail:
249 if (private->curl_handle != NULL)
250 curl_easy_cleanup(private->curl_handle);
251 if (private->header_list != NULL)
252 curl_slist_free_all(private->header_list);
253 free(source->source_string);
254 free(private);
255 free(source);
257 return NULL;
261 int http_peek (data_source_t *source, void *ptr, size_t size, size_t nmemb)
264 http_private_t *private = source->private;
265 int items;
266 long start;
268 bytes_read = buffer_get_data(data->buf, ptr, size, nmemb);
270 private->stats.bytes_read += bytes_read;
273 return 0;
277 int http_read (data_source_t *source, void *ptr, size_t size, size_t nmemb)
279 http_private_t *private = source->private;
280 int bytes_read;
282 if (private->cancel_flag || sig_request.cancel)
283 return 0;
285 bytes_read = buffer_get_data(private->buf, ptr, size * nmemb);
287 private->stats.bytes_read += bytes_read;
289 return bytes_read;
293 int http_seek (data_source_t *source, long offset, int whence)
295 return -1;
299 data_source_stats_t *http_statistics (data_source_t *source)
301 http_private_t *private = source->private;
302 data_source_stats_t *data_source_stats;
303 buffer_stats_t *buffer_stats;
305 data_source_stats = malloc_data_source_stats(&private->stats);
306 data_source_stats->input_buffer_used = 1;
307 data_source_stats->transfer_rate = 0;
309 buffer_stats = buffer_statistics(private->buf);
310 data_source_stats->input_buffer = *buffer_stats;
311 free(buffer_stats);
313 return data_source_stats;
317 long http_tell (data_source_t *source)
319 return 0;
323 void http_close (data_source_t *source)
325 http_private_t *private = source->private;
327 private->cancel_flag = 1;
328 buffer_abort_write(private->buf);
329 pthread_join(private->curl_thread, NULL);
331 buffer_destroy(private->buf);
332 private->buf = NULL;
334 free(source->source_string);
335 free(source->private);
336 free(source);
340 transport_t http_transport = {
341 "http",
342 &http_can_transport,
343 &http_open,
344 &http_peek,
345 &http_read,
346 &http_seek,
347 &http_statistics,
348 &http_tell,
349 &http_close
352 #endif /* HAVE_CURL */