Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
23eacbd1
Commit
23eacbd1
authored
Mar 15, 2014
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
input/curl: move code to CurlInputStream methods
parent
e9f16fca
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
231 additions
and
178 deletions
+231
-178
CurlInputPlugin.cxx
src/input/plugins/CurlInputPlugin.cxx
+231
-178
No files found.
src/input/plugins/CurlInputPlugin.cxx
View file @
23eacbd1
...
...
@@ -177,6 +177,63 @@ struct CurlInputStream {
CurlInputStream
(
const
CurlInputStream
&
)
=
delete
;
CurlInputStream
&
operator
=
(
const
CurlInputStream
&
)
=
delete
;
bool
Check
(
Error
&
error
);
bool
IsEOF
()
const
{
return
easy
==
nullptr
&&
buffers
.
empty
();
}
Tag
*
ReadTag
();
bool
IsAvailable
()
const
{
return
postponed_error
.
IsDefined
()
||
easy
==
nullptr
||
!
buffers
.
empty
();
}
size_t
Read
(
void
*
ptr
,
size_t
size
,
Error
&
error
);
/**
* Frees the current "libcurl easy" handle, and everything
* associated with it.
*
* Runs in the I/O thread.
*/
void
FreeEasy
();
/**
* Frees the current "libcurl easy" handle, and everything associated
* with it.
*
* The mutex must not be locked.
*/
void
FreeEasyIndirect
();
void
HeaderReceived
(
const
char
*
name
,
const
char
*
value
,
const
char
*
end
);
size_t
DataReceived
(
const
void
*
ptr
,
size_t
size
);
void
Resume
();
bool
FillBuffer
(
Error
&
error
);
/**
* Determine the total sizes of all buffers, including
* portions that have already been consumed.
*
* The caller must lock the mutex.
*/
gcc_pure
size_t
GetTotalBufferSize
()
const
;
void
CopyIcyTag
();
/**
* A HTTP request is finished.
*
* Runs in the I/O thread. The caller must not hold locks.
*/
void
RequestDone
(
CURLcode
result
,
long
status
);
};
class
CurlMulti
;
...
...
@@ -335,14 +392,14 @@ input_curl_find_request(CURL *easy)
return
(
CurlInputStream
*
)
p
;
}
static
void
input_curl_resume
(
CurlInputStream
*
c
)
inline
void
CurlInputStream
::
Resume
(
)
{
assert
(
io_thread_inside
());
if
(
c
->
paused
)
{
c
->
paused
=
false
;
curl_easy_pause
(
c
->
easy
,
CURLPAUSE_CONT
);
if
(
paused
)
{
paused
=
false
;
curl_easy_pause
(
easy
,
CURLPAUSE_CONT
);
if
(
curl_version_num
<
0x072000
)
/* libcurl older than 7.32.0 does not update
...
...
@@ -445,74 +502,55 @@ CurlMulti::Remove(CurlInputStream *c)
curl_multi_remove_handle
(
multi
,
c
->
easy
);
}
/**
* Frees the current "libcurl easy" handle, and everything associated
* with it.
*
* Runs in the I/O thread.
*/
static
void
input_curl_easy_free
(
CurlInputStream
*
c
)
void
CurlInputStream
::
FreeEasy
()
{
assert
(
io_thread_inside
());
assert
(
c
!=
nullptr
);
if
(
c
->
easy
==
nullptr
)
if
(
easy
==
nullptr
)
return
;
curl_multi
->
Remove
(
c
);
curl_multi
->
Remove
(
this
);
curl_easy_cleanup
(
c
->
easy
);
c
->
easy
=
nullptr
;
curl_easy_cleanup
(
easy
);
easy
=
nullptr
;
curl_slist_free_all
(
c
->
request_headers
);
c
->
request_headers
=
nullptr
;
curl_slist_free_all
(
request_headers
);
request_headers
=
nullptr
;
}
/**
* Frees the current "libcurl easy" handle, and everything associated
* with it.
*
* The mutex must not be locked.
*/
static
void
input_curl_easy_free_indirect
(
CurlInputStream
*
c
)
void
CurlInputStream
::
FreeEasyIndirect
()
{
BlockingCall
(
io_thread_get
(),
[
c
](){
input_curl_easy_free
(
c
);
BlockingCall
(
io_thread_get
(),
[
this
](){
FreeEasy
(
);
curl_multi
->
InvalidateSockets
();
});
assert
(
c
->
easy
==
nullptr
);
assert
(
easy
==
nullptr
);
}
/**
* A HTTP request is finished.
*
* Runs in the I/O thread. The caller must not hold locks.
*/
static
void
input_curl_request_done
(
CurlInputStream
*
c
,
CURLcode
result
,
long
status
)
inline
void
CurlInputStream
::
RequestDone
(
CURLcode
result
,
long
status
)
{
assert
(
io_thread_inside
());
assert
(
c
!=
nullptr
);
assert
(
c
->
easy
==
nullptr
);
assert
(
!
c
->
postponed_error
.
IsDefined
()
);
assert
(
!
postponed_error
.
IsDefined
()
);
FreeEasy
(
);
const
ScopeLock
protect
(
c
->
base
.
mutex
);
const
ScopeLock
protect
(
base
.
mutex
);
if
(
result
!=
CURLE_OK
)
{
c
->
postponed_error
.
Format
(
curl_domain
,
result
,
"curl failed: %s"
,
c
->
error_buffer
);
postponed_error
.
Format
(
curl_domain
,
result
,
"curl failed: %s"
,
error_buffer
);
}
else
if
(
status
<
200
||
status
>=
300
)
{
c
->
postponed_error
.
Format
(
http_domain
,
status
,
"got HTTP status %ld"
,
status
);
postponed_error
.
Format
(
http_domain
,
status
,
"got HTTP status %ld"
,
status
);
}
c
->
base
.
ready
=
true
;
c
->
base
.
cond
.
broadcast
();
base
.
ready
=
true
;
base
.
cond
.
broadcast
();
}
static
void
...
...
@@ -524,8 +562,7 @@ input_curl_handle_done(CURL *easy_handle, CURLcode result)
long
status
=
0
;
curl_easy_getinfo
(
easy_handle
,
CURLINFO_RESPONSE_CODE
,
&
status
);
input_curl_easy_free
(
c
);
input_curl_request_done
(
c
,
result
,
status
);
c
->
RequestDone
(
result
,
status
);
}
void
...
...
@@ -656,19 +693,11 @@ input_curl_finish(void)
curl_global_cleanup
();
}
/**
* Determine the total sizes of all buffers, including portions that
* have already been consumed.
*
* The caller must lock the mutex.
*/
gcc_pure
static
size_t
curl_total_buffer_size
(
const
CurlInputStream
*
c
)
size_t
CurlInputStream
::
GetTotalBufferSize
()
const
{
size_t
total
=
0
;
for
(
const
auto
&
i
:
c
->
buffers
)
for
(
const
auto
&
i
:
buffers
)
total
+=
i
.
TotalSize
();
return
total
;
...
...
@@ -678,46 +707,56 @@ CurlInputStream::~CurlInputStream()
{
delete
tag
;
input_curl_easy_free_indirect
(
this
);
FreeEasyIndirect
(
);
}
static
bool
input_curl_check
(
InputStream
*
is
,
Error
&
error
)
inline
bool
CurlInputStream
::
Check
(
Error
&
error
)
{
CurlInputStream
*
c
=
(
CurlInputStream
*
)
is
;
bool
success
=
!
c
->
postponed_error
.
IsDefined
();
bool
success
=
!
postponed_error
.
IsDefined
();
if
(
!
success
)
{
error
=
std
::
move
(
c
->
postponed_error
);
c
->
postponed_error
.
Clear
();
error
=
std
::
move
(
postponed_error
);
postponed_error
.
Clear
();
}
return
success
;
}
static
bool
input_curl_check
(
InputStream
*
is
,
Error
&
error
)
{
CurlInputStream
&
c
=
*
(
CurlInputStream
*
)
is
;
return
c
.
Check
(
error
);
}
inline
Tag
*
CurlInputStream
::
ReadTag
()
{
Tag
*
result
=
tag
;
tag
=
nullptr
;
return
result
;
}
static
Tag
*
input_curl_tag
(
InputStream
*
is
)
{
CurlInputStream
*
c
=
(
CurlInputStream
*
)
is
;
Tag
*
tag
=
c
->
tag
;
c
->
tag
=
nullptr
;
return
tag
;
CurlInputStream
&
c
=
*
(
CurlInputStream
*
)
is
;
return
c
.
ReadTag
();
}
static
bool
fill_buffer
(
CurlInputStream
*
c
,
Error
&
error
)
inline
bool
CurlInputStream
::
FillBuffer
(
Error
&
error
)
{
while
(
c
->
easy
!=
nullptr
&&
c
->
buffers
.
empty
())
c
->
base
.
cond
.
wait
(
c
->
base
.
mutex
);
while
(
easy
!=
nullptr
&&
buffers
.
empty
())
base
.
cond
.
wait
(
base
.
mutex
);
if
(
c
->
postponed_error
.
IsDefined
())
{
error
=
std
::
move
(
c
->
postponed_error
);
c
->
postponed_error
.
Clear
();
if
(
postponed_error
.
IsDefined
())
{
error
=
std
::
move
(
postponed_error
);
postponed_error
.
Clear
();
return
false
;
}
return
!
c
->
buffers
.
empty
();
return
!
buffers
.
empty
();
}
static
size_t
...
...
@@ -770,54 +809,47 @@ read_from_buffer(IcyMetaDataParser &icy, std::list<CurlInputBuffer> &buffers,
return
nbytes
;
}
static
void
copy_icy_tag
(
CurlInputStream
*
c
)
inline
void
CurlInputStream
::
CopyIcyTag
(
)
{
Tag
*
tag
=
c
->
icy
.
ReadTag
();
if
(
tag
==
nullptr
)
Tag
*
new_tag
=
icy
.
ReadTag
();
if
(
new_tag
==
nullptr
)
return
;
delete
c
->
tag
;
delete
tag
;
if
(
!
c
->
meta_name
.
empty
()
&&
!
tag
->
HasType
(
TAG_NAME
))
{
TagBuilder
tag_builder
(
std
::
move
(
*
tag
));
tag_builder
.
AddItem
(
TAG_NAME
,
c
->
meta_name
.
c_str
());
*
tag
=
tag_builder
.
Commit
();
if
(
!
meta_name
.
empty
()
&&
!
new_
tag
->
HasType
(
TAG_NAME
))
{
TagBuilder
tag_builder
(
std
::
move
(
*
new_
tag
));
tag_builder
.
AddItem
(
TAG_NAME
,
meta_name
.
c_str
());
*
new_
tag
=
tag_builder
.
Commit
();
}
c
->
tag
=
tag
;
tag
=
new_
tag
;
}
static
bool
input_curl_available
(
InputStream
*
is
)
{
CurlInputStream
*
c
=
(
CurlInputStream
*
)
is
;
return
c
->
postponed_error
.
IsDefined
()
||
c
->
easy
==
nullptr
||
!
c
->
buffers
.
empty
();
const
CurlInputStream
&
c
=
*
(
const
CurlInputStream
*
)
is
;
return
c
.
IsAvailable
();
}
static
size_t
input_curl_read
(
InputStream
*
is
,
void
*
ptr
,
size_t
size
,
Error
&
error
)
inline
size_t
CurlInputStream
::
Read
(
void
*
ptr
,
size_t
size
,
Error
&
error
)
{
CurlInputStream
*
c
=
(
CurlInputStream
*
)
is
;
bool
success
;
size_t
nbytes
=
0
;
char
*
dest
=
(
char
*
)
ptr
;
do
{
/* fill the buffer */
success
=
fill_buffer
(
c
,
error
);
if
(
!
success
)
if
(
!
FillBuffer
(
error
))
return
0
;
/* send buffer contents */
while
(
size
>
0
&&
!
c
->
buffers
.
empty
())
{
size_t
copy
=
read_from_buffer
(
c
->
icy
,
c
->
buffers
,
while
(
size
>
0
&&
!
buffers
.
empty
())
{
size_t
copy
=
read_from_buffer
(
icy
,
buffers
,
dest
+
nbytes
,
size
);
nbytes
+=
copy
;
...
...
@@ -825,24 +857,32 @@ input_curl_read(InputStream *is, void *ptr, size_t size,
}
}
while
(
nbytes
==
0
);
if
(
c
->
icy
.
IsDefined
())
copy_icy_tag
(
c
);
if
(
icy
.
IsDefined
())
CopyIcyTag
(
);
is
->
offset
+=
(
InputPlugin
::
offset_type
)
nbytes
;
base
.
offset
+=
(
InputPlugin
::
offset_type
)
nbytes
;
if
(
c
->
paused
&&
curl_total_buffer_size
(
c
)
<
CURL_RESUME_AT
)
{
c
->
base
.
mutex
.
unlock
();
if
(
paused
&&
GetTotalBufferSize
(
)
<
CURL_RESUME_AT
)
{
base
.
mutex
.
unlock
();
BlockingCall
(
io_thread_get
(),
[
c
](){
input_curl_resume
(
c
);
BlockingCall
(
io_thread_get
(),
[
this
](){
Resume
(
);
});
c
->
base
.
mutex
.
lock
();
base
.
mutex
.
lock
();
}
return
nbytes
;
}
static
size_t
input_curl_read
(
InputStream
*
is
,
void
*
ptr
,
size_t
size
,
Error
&
error
)
{
CurlInputStream
&
c
=
*
(
CurlInputStream
*
)
is
;
return
c
.
Read
(
ptr
,
size
,
error
);
}
static
void
input_curl_close
(
InputStream
*
is
)
{
...
...
@@ -854,76 +894,48 @@ input_curl_close(InputStream *is)
static
bool
input_curl_eof
(
gcc_unused
InputStream
*
is
)
{
CurlInputStream
*
c
=
(
CurlInputStream
*
)
is
;
return
c
->
easy
==
nullptr
&&
c
->
buffers
.
empty
();
const
CurlInputStream
&
c
=
*
(
const
CurlInputStream
*
)
is
;
return
c
.
IsEOF
();
}
/** called by curl when new data is available */
static
size_t
input_curl_headerfunction
(
void
*
ptr
,
size_t
size
,
size_t
nmemb
,
void
*
stream
)
inline
void
CurlInputStream
::
HeaderReceived
(
const
char
*
name
,
const
char
*
value
,
const
char
*
end
)
{
CurlInputStream
*
c
=
(
CurlInputStream
*
)
stream
;
char
name
[
64
];
size
*=
nmemb
;
const
char
*
header
=
(
const
char
*
)
ptr
;
const
char
*
end
=
header
+
size
;
const
char
*
value
=
(
const
char
*
)
memchr
(
header
,
':'
,
size
);
if
(
value
==
nullptr
||
(
size_t
)(
value
-
header
)
>=
sizeof
(
name
))
return
size
;
memcpy
(
name
,
header
,
value
-
header
);
name
[
value
-
header
]
=
0
;
/* skip the colon */
++
value
;
/* strip the value */
while
(
value
<
end
&&
IsWhitespaceOrNull
(
*
value
))
++
value
;
while
(
end
>
value
&&
IsWhitespaceOrNull
(
end
[
-
1
]))
--
end
;
if
(
StringEqualsCaseASCII
(
name
,
"accept-ranges"
))
{
/* a stream with icy-metadata is not seekable */
if
(
!
c
->
icy
.
IsDefined
())
c
->
base
.
seekable
=
true
;
if
(
!
icy
.
IsDefined
())
base
.
seekable
=
true
;
}
else
if
(
StringEqualsCaseASCII
(
name
,
"content-length"
))
{
char
buffer
[
64
];
if
((
size_t
)(
end
-
header
)
>=
sizeof
(
buffer
))
return
size
;
if
((
size_t
)(
end
-
value
)
>=
sizeof
(
buffer
))
return
;
memcpy
(
buffer
,
value
,
end
-
value
);
buffer
[
end
-
value
]
=
0
;
c
->
base
.
size
=
c
->
base
.
offset
+
ParseUint64
(
buffer
);
base
.
size
=
base
.
offset
+
ParseUint64
(
buffer
);
}
else
if
(
StringEqualsCaseASCII
(
name
,
"content-type"
))
{
c
->
base
.
mime
.
assign
(
value
,
end
);
base
.
mime
.
assign
(
value
,
end
);
}
else
if
(
StringEqualsCaseASCII
(
name
,
"icy-name"
)
||
StringEqualsCaseASCII
(
name
,
"ice-name"
)
||
StringEqualsCaseASCII
(
name
,
"x-audiocast-name"
))
{
c
->
meta_name
.
assign
(
value
,
end
);
meta_name
.
assign
(
value
,
end
);
delete
c
->
tag
;
delete
tag
;
TagBuilder
tag_builder
;
tag_builder
.
AddItem
(
TAG_NAME
,
c
->
meta_name
.
c_str
());
tag_builder
.
AddItem
(
TAG_NAME
,
meta_name
.
c_str
());
c
->
tag
=
tag_builder
.
CommitNew
();
tag
=
tag_builder
.
CommitNew
();
}
else
if
(
StringEqualsCaseASCII
(
name
,
"icy-metaint"
))
{
char
buffer
[
64
];
size_t
icy_metaint
;
if
((
size_t
)(
end
-
header
)
>=
sizeof
(
buffer
)
||
c
->
icy
.
IsDefined
())
return
size
;
if
((
size_t
)(
end
-
value
)
>=
sizeof
(
buffer
)
||
icy
.
IsDefined
())
return
;
memcpy
(
buffer
,
value
,
end
-
value
);
buffer
[
end
-
value
]
=
0
;
...
...
@@ -932,41 +944,82 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
FormatDebug
(
curl_domain
,
"icy-metaint=%zu"
,
icy_metaint
);
if
(
icy_metaint
>
0
)
{
c
->
icy
.
Start
(
icy_metaint
);
icy
.
Start
(
icy_metaint
);
/* a stream with icy-metadata is not
seekable */
c
->
base
.
seekable
=
false
;
base
.
seekable
=
false
;
}
}
return
size
;
}
/** called by curl when new data is available */
static
size_t
input_curl_
write
function
(
void
*
ptr
,
size_t
size
,
size_t
nmemb
,
void
*
stream
)
input_curl_
header
function
(
void
*
ptr
,
size_t
size
,
size_t
nmemb
,
void
*
stream
)
{
CurlInputStream
*
c
=
(
CurlInputStream
*
)
stream
;
CurlInputStream
&
c
=
*
(
CurlInputStream
*
)
stream
;
size
*=
nmemb
;
if
(
size
==
0
)
return
0
;
const
ScopeLock
protect
(
c
->
base
.
mutex
);
const
char
*
header
=
(
const
char
*
)
ptr
;
const
char
*
end
=
header
+
size
;
char
name
[
64
];
const
char
*
value
=
(
const
char
*
)
memchr
(
header
,
':'
,
size
);
if
(
value
==
nullptr
||
(
size_t
)(
value
-
header
)
>=
sizeof
(
name
))
return
size
;
memcpy
(
name
,
header
,
value
-
header
);
name
[
value
-
header
]
=
0
;
/* skip the colon */
++
value
;
/* strip the value */
while
(
value
<
end
&&
IsWhitespaceOrNull
(
*
value
))
++
value
;
while
(
end
>
value
&&
IsWhitespaceOrNull
(
end
[
-
1
]))
--
end
;
if
(
curl_total_buffer_size
(
c
)
+
size
>=
CURL_MAX_BUFFERED
)
{
c
->
paused
=
true
;
c
.
HeaderReceived
(
name
,
value
,
end
);
return
size
;
}
inline
size_t
CurlInputStream
::
DataReceived
(
const
void
*
ptr
,
size_t
size
)
{
assert
(
size
>
0
);
const
ScopeLock
protect
(
base
.
mutex
);
if
(
GetTotalBufferSize
()
+
size
>=
CURL_MAX_BUFFERED
)
{
paused
=
true
;
return
CURL_WRITEFUNC_PAUSE
;
}
c
->
buffers
.
emplace_back
(
ptr
,
size
);
c
->
base
.
ready
=
true
;
c
->
base
.
cond
.
broadcast
();
buffers
.
emplace_back
(
ptr
,
size
);
base
.
ready
=
true
;
base
.
cond
.
broadcast
();
return
size
;
}
/** called by curl when new data is available */
static
size_t
input_curl_writefunction
(
void
*
ptr
,
size_t
size
,
size_t
nmemb
,
void
*
stream
)
{
CurlInputStream
&
c
=
*
(
CurlInputStream
*
)
stream
;
size
*=
nmemb
;
if
(
size
==
0
)
return
0
;
return
c
.
DataReceived
(
ptr
,
size
);
}
static
bool
input_curl_easy_init
(
CurlInputStream
*
c
,
Error
&
error
)
{
...
...
@@ -1091,7 +1144,7 @@ input_curl_seek(InputStream *is, InputPlugin::offset_type offset,
c
->
base
.
mutex
.
unlock
();
input_curl_easy_free_indirect
(
c
);
c
->
FreeEasyIndirect
(
);
c
->
buffers
.
clear
();
is
->
offset
=
offset
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment