2 * mvcp_remote.c -- Remote Parser
3 * Copyright (C) 2002-2009 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* System header files */
29 /* Application header files */
31 #include <framework/mlt.h>
33 #define mlt_service void *
35 #include "mvcp_remote.h"
36 #include "mvcp_socket.h"
37 #include "mvcp_tokeniser.h"
38 #include "mvcp_util.h"
40 /** Private mvcp_remote structure.
52 pthread_mutex_t mutex
;
55 *mvcp_remote
, mvcp_remote_t
;
57 /** Forward declarations.
60 static mvcp_response
mvcp_remote_connect( mvcp_remote
);
61 static mvcp_response
mvcp_remote_execute( mvcp_remote
, char * );
62 static mvcp_response
mvcp_remote_receive( mvcp_remote
, char *, char * );
63 static mvcp_response
mvcp_remote_push( mvcp_remote
, char *, mlt_service
);
64 static void mvcp_remote_close( mvcp_remote
);
65 static int mvcp_remote_read_response( mvcp_socket
, mvcp_response
);
67 /** MVCP Parser constructor.
70 mvcp_parser
mvcp_parser_init_remote( char *server
, int port
)
72 mvcp_parser parser
= calloc( 1, sizeof( mvcp_parser_t
) );
73 mvcp_remote remote
= calloc( 1, sizeof( mvcp_remote_t
) );
77 parser
->connect
= (parser_connect
)mvcp_remote_connect
;
78 parser
->execute
= (parser_execute
)mvcp_remote_execute
;
79 parser
->push
= (parser_push
)mvcp_remote_push
;
80 parser
->received
= (parser_received
)mvcp_remote_receive
;
81 parser
->close
= (parser_close
)mvcp_remote_close
;
82 parser
->real
= remote
;
86 remote
->parser
= parser
;
87 remote
->server
= strdup( server
);
89 pthread_mutex_init( &remote
->mutex
, NULL
);
95 /** Thread for receiving and distributing the status information.
98 static void *mvcp_remote_status_thread( void *arg
)
100 mvcp_remote remote
= arg
;
104 mvcp_tokeniser tokeniser
= mvcp_tokeniser_init( );
105 mvcp_notifier notifier
= mvcp_parser_get_notifier( remote
->parser
);
106 mvcp_status_t status
;
109 mvcp_socket_write_data( remote
->status
, "STATUS\r\n", 8 );
111 while ( !remote
->terminated
&&
112 ( length
= mvcp_socket_read_data( remote
->status
, temp
+ offset
, sizeof( temp
) ) ) >= 0 )
114 if ( strchr( temp
, '\n' ) == NULL
)
120 mvcp_tokeniser_parse_new( tokeniser
, temp
, "\n" );
121 for ( index
= 0; index
< mvcp_tokeniser_count( tokeniser
); index
++ )
123 char *line
= mvcp_tokeniser_get_string( tokeniser
, index
);
124 if ( line
[ strlen( line
) - 1 ] == '\r' )
126 mvcp_util_chomp( line
);
127 mvcp_status_parse( &status
, line
);
128 mvcp_notifier_put( notifier
, &status
);
132 strcpy( temp
, line
);
133 offset
= strlen( temp
);
138 mvcp_notifier_disconnected( notifier
);
139 mvcp_tokeniser_close( tokeniser
);
140 remote
->terminated
= 1;
145 /** Forward reference.
148 static void mvcp_remote_disconnect( mvcp_remote remote
);
150 /** Connect to the server.
153 static mvcp_response
mvcp_remote_connect( mvcp_remote remote
)
155 mvcp_response response
= NULL
;
157 mvcp_remote_disconnect( remote
);
159 if ( !remote
->connected
)
161 #if !defined(__MINGW32__)
162 signal( SIGPIPE
, SIG_IGN
);
164 remote
->socket
= mvcp_socket_init( remote
->server
, remote
->port
);
165 remote
->status
= mvcp_socket_init( remote
->server
, remote
->port
);
167 if ( mvcp_socket_connect( remote
->socket
) == 0 )
169 response
= mvcp_response_init( );
170 mvcp_remote_read_response( remote
->socket
, response
);
173 if ( response
!= NULL
&& mvcp_socket_connect( remote
->status
) == 0 )
175 mvcp_response status_response
= mvcp_response_init( );
176 mvcp_remote_read_response( remote
->status
, status_response
);
177 if ( mvcp_response_get_error_code( status_response
) == 100 )
178 pthread_create( &remote
->thread
, NULL
, mvcp_remote_status_thread
, remote
);
179 mvcp_response_close( status_response
);
180 remote
->connected
= 1;
187 /** Execute the command.
190 static mvcp_response
mvcp_remote_execute( mvcp_remote remote
, char *command
)
192 mvcp_response response
= NULL
;
193 pthread_mutex_lock( &remote
->mutex
);
194 if ( mvcp_socket_write_data( remote
->socket
, command
, strlen( command
) ) == strlen( command
) )
196 response
= mvcp_response_init( );
197 mvcp_socket_write_data( remote
->socket
, "\r\n", 2 );
198 mvcp_remote_read_response( remote
->socket
, response
);
200 pthread_mutex_unlock( &remote
->mutex
);
204 /** Push a MLT XML document to the server.
207 static mvcp_response
mvcp_remote_receive( mvcp_remote remote
, char *command
, char *buffer
)
209 mvcp_response response
= NULL
;
210 pthread_mutex_lock( &remote
->mutex
);
211 if ( mvcp_socket_write_data( remote
->socket
, command
, strlen( command
) ) == strlen( command
) )
214 int length
= strlen( buffer
);
215 response
= mvcp_response_init( );
216 mvcp_socket_write_data( remote
->socket
, "\r\n", 2 );
217 sprintf( temp
, "%d", length
);
218 mvcp_socket_write_data( remote
->socket
, temp
, strlen( temp
) );
219 mvcp_socket_write_data( remote
->socket
, "\r\n", 2 );
220 mvcp_socket_write_data( remote
->socket
, buffer
, length
);
221 mvcp_socket_write_data( remote
->socket
, "\r\n", 2 );
222 mvcp_remote_read_response( remote
->socket
, response
);
224 pthread_mutex_unlock( &remote
->mutex
);
228 /** Push a producer to the server.
231 static mvcp_response
mvcp_remote_push( mvcp_remote remote
, char *command
, mlt_service service
)
233 mvcp_response response
= NULL
;
234 #ifndef MVCP_EMBEDDED
235 if ( service
!= NULL
)
237 mlt_consumer consumer
= mlt_factory_consumer( NULL
, "xml", "buffer" );
238 mlt_properties properties
= MLT_CONSUMER_PROPERTIES( consumer
);
241 mlt_properties_set( properties
, "store", "nle_" );
242 mlt_consumer_connect( consumer
, service
);
243 mlt_consumer_start( consumer
);
244 buffer
= mlt_properties_get( properties
, "buffer" );
245 response
= mvcp_remote_receive( remote
, command
, buffer
);
246 mlt_consumer_close( consumer
);
255 static void mvcp_remote_disconnect( mvcp_remote remote
)
257 if ( remote
!= NULL
&& remote
->terminated
)
259 if ( remote
->connected
)
260 pthread_join( remote
->thread
, NULL
);
261 mvcp_socket_close( remote
->status
);
262 mvcp_socket_close( remote
->socket
);
263 remote
->connected
= 0;
264 remote
->terminated
= 0;
268 /** Close the parser.
271 static void mvcp_remote_close( mvcp_remote remote
)
273 if ( remote
!= NULL
)
275 remote
->terminated
= 1;
276 mvcp_remote_disconnect( remote
);
277 pthread_mutex_destroy( &remote
->mutex
);
278 free( remote
->server
);
286 static int mvcp_remote_read_response( mvcp_socket socket
, mvcp_response response
)
292 while ( !terminated
&& ( length
= mvcp_socket_read_data( socket
, temp
, 10240 ) ) >= 0 )
295 temp
[ length
] = '\0';
296 mvcp_response_write( response
, temp
, length
);
297 position
= mvcp_response_count( response
) - 1;
298 if ( position
< 0 || temp
[ strlen( temp
) - 1 ] != '\n' )
300 switch( mvcp_response_get_error_code( response
) )
304 terminated
= !strcmp( mvcp_response_get_line( response
, position
), "" );
307 terminated
= mvcp_response_count( response
) >= 2;