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
39439b80
Commit
39439b80
authored
Jan 14, 2013
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Client: rebase on the new BufferedSocket class
parent
396480cf
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
65 additions
and
303 deletions
+65
-303
Client.hxx
src/Client.hxx
+2
-2
ClientEvent.cxx
src/ClientEvent.cxx
+8
-82
ClientExpire.cxx
src/ClientExpire.cxx
+4
-11
ClientIdle.cxx
src/ClientIdle.cxx
+1
-3
ClientInternal.hxx
src/ClientInternal.hxx
+17
-17
ClientNew.cxx
src/ClientNew.cxx
+6
-25
ClientProcess.cxx
src/ClientProcess.cxx
+0
-4
ClientRead.cxx
src/ClientRead.cxx
+25
-68
ClientWrite.cxx
src/ClientWrite.cxx
+1
-90
Listen.cxx
src/Listen.cxx
+1
-1
No files found.
src/Client.hxx
View file @
39439b80
...
...
@@ -22,11 +22,11 @@
#include "gcc.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdarg.h>
struct
sockaddr
;
class
EventLoop
;
struct
Partition
;
class
Client
;
...
...
@@ -34,7 +34,7 @@ void client_manager_init(void);
void
client_manager_deinit
(
void
);
void
client_new
(
Partition
&
partition
,
client_new
(
EventLoop
&
loop
,
Partition
&
partition
,
int
fd
,
const
struct
sockaddr
*
sa
,
size_t
sa_length
,
int
uid
);
/**
...
...
src/ClientEvent.cxx
View file @
39439b80
...
...
@@ -19,92 +19,18 @@
#include "config.h"
#include "ClientInternal.hxx"
#include "Main.hxx"
#include "event/Loop.hxx"
#include <assert.h>
static
gboolean
client_out_event
(
G_GNUC_UNUSED
GIOChannel
*
source
,
GIOCondition
condition
,
gpointer
data
)
void
Client
::
OnSocketError
(
GError
*
error
)
{
Client
*
client
=
(
Client
*
)
data
;
assert
(
!
client
->
IsExpired
());
if
(
condition
!=
G_IO_OUT
)
{
client
->
SetExpired
();
return
false
;
}
client_write_deferred
(
client
);
g_warning
(
"error on client %d: %s"
,
num
,
error
->
message
);
g_error_free
(
error
);
if
(
client
->
IsExpired
())
{
client
->
Close
();
return
false
;
}
g_timer_start
(
client
->
last_activity
);
if
(
client
->
output_buffer
.
IsEmpty
())
{
/* done sending deferred buffers exist: schedule
read */
client
->
source_id
=
g_io_add_watch
(
client
->
channel
,
GIOCondition
(
G_IO_IN
|
G_IO_ERR
|
G_IO_HUP
),
client_in_event
,
client
);
return
false
;
}
/* write more */
return
true
;
SetExpired
();
}
gboolean
client_in_event
(
G_GNUC_UNUSED
GIOChannel
*
source
,
GIOCondition
condition
,
gpointer
data
)
void
Client
::
OnSocketClosed
()
{
Client
*
client
=
(
Client
*
)
data
;
enum
command_return
ret
;
assert
(
!
client
->
IsExpired
());
if
(
condition
!=
G_IO_IN
)
{
client
->
SetExpired
();
return
false
;
}
g_timer_start
(
client
->
last_activity
);
ret
=
client_read
(
client
);
switch
(
ret
)
{
case
COMMAND_RETURN_OK
:
case
COMMAND_RETURN_IDLE
:
case
COMMAND_RETURN_ERROR
:
break
;
case
COMMAND_RETURN_KILL
:
client
->
Close
();
main_loop
->
Break
();
return
false
;
case
COMMAND_RETURN_CLOSE
:
client
->
Close
();
return
false
;
}
if
(
client
->
IsExpired
())
{
client
->
Close
();
return
false
;
}
if
(
!
client
->
output_buffer
.
IsEmpty
())
{
/* deferred buffers exist: schedule write */
client
->
source_id
=
g_io_add_watch
(
client
->
channel
,
GIOCondition
(
G_IO_OUT
|
G_IO_ERR
|
G_IO_HUP
),
client_out_event
,
client
);
return
false
;
}
/* read more */
return
true
;
SetExpired
();
}
src/ClientExpire.cxx
View file @
39439b80
...
...
@@ -26,18 +26,11 @@ static guint expire_source_id;
void
Client
::
SetExpired
()
{
if
(
!
IsExpired
())
client_schedule_expire
();
if
(
source_id
!=
0
)
{
g_source_remove
(
source_id
);
source_id
=
0
;
}
if
(
IsExpired
())
return
;
if
(
channel
!=
NULL
)
{
g_io_channel_unref
(
channel
);
channel
=
nullptr
;
}
client_schedule_expire
();
BufferedSocket
::
Close
();
}
static
void
...
...
src/ClientIdle.cxx
View file @
39439b80
...
...
@@ -60,10 +60,8 @@ client_idle_add(Client *client, unsigned flags)
client
->
idle_flags
|=
flags
;
if
(
client
->
idle_waiting
&&
(
client
->
idle_flags
&
client
->
idle_subscriptions
))
{
&&
(
client
->
idle_flags
&
client
->
idle_subscriptions
))
client_idle_notify
(
client
);
client_write_output
(
client
);
}
}
static
void
...
...
src/ClientInternal.hxx
View file @
39439b80
...
...
@@ -24,8 +24,8 @@
#include "Client.hxx"
#include "ClientMessage.hxx"
#include "CommandListBuilder.hxx"
#include "event/BufferedSocket.hxx"
#include "command.h"
#include "util/PeakBuffer.hxx"
#include <set>
#include <string>
...
...
@@ -42,20 +42,13 @@ enum {
};
struct
Partition
;
class
PeakBuffer
;
class
Client
{
class
Client
final
:
private
BufferedSocket
{
public
:
Partition
&
partition
;
struct
playlist
&
playlist
;
struct
player_control
*
player_control
;
GIOChannel
*
channel
;
guint
source_id
;
/** the buffer for reading lines from the #channel */
struct
fifo_buffer
*
input
;
unsigned
permission
;
/** the uid of the client process, or -1 if unknown */
...
...
@@ -70,8 +63,6 @@ public:
unsigned
int
num
;
/* client number */
PeakBuffer
output_buffer
;
/** is this client waiting for an "idle" response? */
bool
idle_waiting
;
...
...
@@ -98,23 +89,35 @@ public:
*/
std
::
list
<
ClientMessage
>
messages
;
Client
(
Partition
&
partition
,
Client
(
EventLoop
&
loop
,
Partition
&
partition
,
int
fd
,
int
uid
,
int
num
);
~
Client
();
bool
IsConnected
()
const
{
return
BufferedSocket
::
IsDefined
();
}
gcc_pure
bool
IsSubscribed
(
const
char
*
channel_name
)
const
{
return
subscriptions
.
find
(
channel_name
)
!=
subscriptions
.
end
();
}
gcc_pure
bool
IsExpired
()
const
{
return
channel
==
nullptr
;
return
!
BufferedSocket
::
IsDefined
()
;
}
void
Close
();
void
SetExpired
();
using
BufferedSocket
::
Write
;
private
:
/* virtual methods from class BufferedSocket */
virtual
InputResult
OnSocketInput
(
const
void
*
data
,
size_t
length
)
override
;
virtual
void
OnSocketError
(
GError
*
error
)
override
;
virtual
void
OnSocketClosed
()
override
;
};
extern
unsigned
int
client_max_connections
;
...
...
@@ -142,9 +145,6 @@ enum command_return
client_process_line
(
Client
*
client
,
char
*
line
);
void
client_write_deferred
(
Client
*
client
);
void
client_write_output
(
Client
*
client
);
gboolean
...
...
src/ClientNew.cxx
View file @
39439b80
...
...
@@ -22,7 +22,6 @@
#include "ClientList.hxx"
#include "Partition.hxx"
#include "fd_util.h"
#include "util/fifo_buffer.h"
extern
"C"
{
#include "resolver.h"
}
...
...
@@ -47,45 +46,27 @@ extern "C" {
static
const
char
GREETING
[]
=
"OK MPD "
PROTOCOL_VERSION
"
\n
"
;
Client
::
Client
(
Partition
&
_partition
,
int
fd
,
int
_uid
,
int
_num
)
:
partition
(
_partition
),
Client
::
Client
(
EventLoop
&
_loop
,
Partition
&
_partition
,
int
_fd
,
int
_uid
,
int
_num
)
:
BufferedSocket
(
_fd
,
_loop
,
16384
,
client_max_output_buffer_size
),
partition
(
_partition
),
playlist
(
partition
.
playlist
),
player_control
(
&
partition
.
pc
),
input
(
fifo_buffer_new
(
4096
)),
permission
(
getDefaultPermissions
()),
uid
(
_uid
),
last_activity
(
g_timer_new
()),
num
(
_num
),
output_buffer
(
16384
,
client_max_output_buffer_size
),
idle_waiting
(
false
),
idle_flags
(
0
),
num_subscriptions
(
0
)
{
assert
(
fd
>=
0
);
channel
=
g_io_channel_new_socket
(
fd
);
/* GLib is responsible for closing the file descriptor */
g_io_channel_set_close_on_unref
(
channel
,
true
);
/* NULL encoding means the stream is binary safe; the MPD
protocol is UTF-8 only, but we are doing this call anyway
to prevent GLib from messing around with the stream */
g_io_channel_set_encoding
(
channel
,
NULL
,
NULL
);
/* we prefer to do buffering */
g_io_channel_set_buffered
(
channel
,
false
);
source_id
=
g_io_add_watch
(
channel
,
GIOCondition
(
G_IO_IN
|
G_IO_ERR
|
G_IO_HUP
),
client_in_event
,
this
);
}
Client
::~
Client
()
{
g_timer_destroy
(
last_activity
);
fifo_buffer_free
(
input
);
}
void
client_new
(
Partition
&
partition
,
client_new
(
EventLoop
&
loop
,
Partition
&
partition
,
int
fd
,
const
struct
sockaddr
*
sa
,
size_t
sa_length
,
int
uid
)
{
static
unsigned
int
next_client_num
;
...
...
@@ -124,7 +105,7 @@ client_new(Partition &partition,
return
;
}
Client
*
client
=
new
Client
(
partition
,
fd
,
uid
,
Client
*
client
=
new
Client
(
loop
,
partition
,
fd
,
uid
,
next_client_num
++
);
(
void
)
send
(
fd
,
GREETING
,
sizeof
(
GREETING
)
-
1
,
0
);
...
...
src/ClientProcess.cxx
View file @
39439b80
...
...
@@ -61,7 +61,6 @@ client_process_line(Client *client, char *line)
/* send empty idle response and leave idle mode */
client
->
idle_waiting
=
false
;
command_success
(
client
);
client_write_output
(
client
);
}
/* do nothing if the client wasn't idling: the client
...
...
@@ -97,7 +96,6 @@ client_process_line(Client *client, char *line)
if
(
ret
==
COMMAND_RETURN_OK
)
command_success
(
client
);
client_write_output
(
client
);
client
->
cmd_list
.
Reset
();
}
else
{
if
(
!
client
->
cmd_list
.
Add
(
line
))
{
...
...
@@ -130,8 +128,6 @@ client_process_line(Client *client, char *line)
if
(
ret
==
COMMAND_RETURN_OK
)
command_success
(
client
);
client_write_output
(
client
);
}
}
...
...
src/ClientRead.cxx
View file @
39439b80
...
...
@@ -19,91 +19,48 @@
#include "config.h"
#include "ClientInternal.hxx"
#include "util/fifo_buffer.h"
#include "Main.hxx"
#include "event/Loop.hxx"
#include <assert.h>
#include <string.h>
static
char
*
client_read_line
(
Client
*
client
)
BufferedSocket
::
InputResult
Client
::
OnSocketInput
(
const
void
*
data
,
size_t
length
)
{
size_t
length
;
const
char
*
p
=
(
const
char
*
)
fifo_buffer_read
(
client
->
input
,
&
length
);
if
(
p
==
NULL
)
return
NULL
;
g_timer_start
(
last_activity
);
const
char
*
p
=
(
const
char
*
)
data
;
const
char
*
newline
=
(
const
char
*
)
memchr
(
p
,
'\n'
,
length
);
if
(
newline
==
NULL
)
return
NULL
;
return
InputResult
::
MORE
;
char
*
line
=
g_strndup
(
p
,
newline
-
p
);
fifo_buffer_consume
(
client
->
input
,
newline
-
p
+
1
);
BufferedSocket
::
ConsumeInput
(
newline
+
1
-
p
);
return
g_strchomp
(
line
);
}
static
enum
command_return
client_input_received
(
Client
*
client
,
size_t
bytesRead
)
{
char
*
line
;
fifo_buffer_append
(
client
->
input
,
bytesRead
);
/* process all lines */
while
((
line
=
client_read_line
(
client
))
!=
NULL
)
{
enum
command_return
ret
=
client_process_line
(
client
,
line
);
enum
command_return
result
=
client_process_line
(
this
,
line
);
g_free
(
line
);
if
(
ret
==
COMMAND_RETURN_KILL
||
ret
==
COMMAND_RETURN_CLOSE
)
return
ret
;
if
(
client
->
IsExpired
())
return
COMMAND_RETURN_CLOSE
;
}
return
COMMAND_RETURN_OK
;
}
enum
command_return
client_read
(
Client
*
client
)
{
GError
*
error
=
NULL
;
GIOStatus
status
;
gsize
bytes_read
;
switch
(
result
)
{
case
COMMAND_RETURN_OK
:
case
COMMAND_RETURN_IDLE
:
case
COMMAND_RETURN_ERROR
:
break
;
assert
(
client
!=
NULL
);
assert
(
client
->
channel
!=
NULL
);
case
COMMAND_RETURN_KILL
:
Close
();
main_loop
->
Break
();
return
InputResult
::
CLOSED
;
size_t
max_length
;
char
*
p
=
(
char
*
)
fifo_buffer_write
(
client
->
input
,
&
max_length
);
if
(
p
==
NULL
)
{
g_warning
(
"[%u] buffer overflow"
,
client
->
num
);
return
COMMAND_RETURN_CLOSE
;
case
COMMAND_RETURN_CLOSE
:
Close
();
return
InputResult
::
CLOSED
;
}
status
=
g_io_channel_read_chars
(
client
->
channel
,
p
,
max_length
,
&
bytes_read
,
&
error
);
switch
(
status
)
{
case
G_IO_STATUS_NORMAL
:
return
client_input_received
(
client
,
bytes_read
);
case
G_IO_STATUS_AGAIN
:
/* try again later, after select() */
return
COMMAND_RETURN_OK
;
case
G_IO_STATUS_EOF
:
/* peer disconnected */
return
COMMAND_RETURN_CLOSE
;
case
G_IO_STATUS_ERROR
:
/* I/O error */
g_warning
(
"failed to read from client %d: %s"
,
client
->
num
,
error
->
message
);
g_error_free
(
error
);
return
COMMAND_RETURN_CLOSE
;
if
(
IsExpired
())
{
Close
();
return
InputResult
::
CLOSED
;
}
/* unreachable */
return
COMMAND_RETURN_CLOSE
;
return
InputResult
::
AGAIN
;
}
src/ClientWrite.cxx
View file @
39439b80
...
...
@@ -20,98 +20,9 @@
#include "config.h"
#include "ClientInternal.hxx"
#include <assert.h>
#include <string.h>
#include <stdio.h>
static
size_t
client_write_direct
(
Client
*
client
,
const
void
*
data
,
size_t
length
)
{
assert
(
client
!=
NULL
);
assert
(
client
->
channel
!=
NULL
);
assert
(
data
!=
NULL
);
assert
(
length
>
0
);
gsize
bytes_written
;
GError
*
error
=
NULL
;
GIOStatus
status
=
g_io_channel_write_chars
(
client
->
channel
,
(
const
gchar
*
)
data
,
length
,
&
bytes_written
,
&
error
);
switch
(
status
)
{
case
G_IO_STATUS_NORMAL
:
return
bytes_written
;
case
G_IO_STATUS_AGAIN
:
return
0
;
case
G_IO_STATUS_EOF
:
/* client has disconnected */
client
->
SetExpired
();
return
0
;
case
G_IO_STATUS_ERROR
:
/* I/O error */
client
->
SetExpired
();
g_warning
(
"failed to write to %i: %s"
,
client
->
num
,
error
->
message
);
g_error_free
(
error
);
return
0
;
}
/* unreachable */
assert
(
false
);
return
0
;
}
void
client_write_deferred
(
Client
*
client
)
{
assert
(
!
client_is_expired
(
client
));
while
(
true
)
{
size_t
length
;
const
void
*
data
=
client
->
output_buffer
.
Read
(
&
length
);
if
(
data
==
nullptr
)
break
;
size_t
nbytes
=
client_write_direct
(
client
,
data
,
length
);
if
(
nbytes
==
0
)
return
;
client
->
output_buffer
.
Consume
(
nbytes
);
if
(
nbytes
<
length
)
return
;
g_timer_start
(
client
->
last_activity
);
}
}
static
void
client_defer_output
(
Client
*
client
,
const
void
*
data
,
size_t
length
)
{
if
(
!
client
->
output_buffer
.
Append
(
data
,
length
))
{
g_warning
(
"[%u] output buffer size is "
"larger than the max (%lu)"
,
client
->
num
,
(
unsigned
long
)
client_max_output_buffer_size
);
/* cause client to close */
client
->
SetExpired
();
return
;
}
}
void
client_write_output
(
Client
*
client
)
{
if
(
client
->
IsExpired
())
return
;
client_write_deferred
(
client
);
}
/**
* Write a block of data to the client.
*/
...
...
@@ -122,7 +33,7 @@ client_write(Client *client, const char *data, size_t length)
if
(
client
->
IsExpired
()
||
length
==
0
)
return
;
client
_defer_output
(
client
,
data
,
length
);
client
->
Write
(
data
,
length
);
}
void
...
...
src/Listen.cxx
View file @
39439b80
...
...
@@ -46,7 +46,7 @@ static void
listen_callback
(
int
fd
,
const
struct
sockaddr
*
address
,
size_t
address_length
,
int
uid
,
G_GNUC_UNUSED
void
*
ctx
)
{
client_new
(
*
global_partition
,
client_new
(
*
main_loop
,
*
global_partition
,
fd
,
address
,
address_length
,
uid
);
}
...
...
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