mvcp compilation under mingw32 support added
[melted] / src / mvcp / mvcp_remote.c
1 /*
2 * mvcp_remote.c -- Remote Parser
3 * Copyright (C) 2002-2009 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
5 *
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.
10 *
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.
15 *
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
19 */
20
21 /* System header files */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <signal.h>
26 #include <errno.h>
27 #include <pthread.h>
28
29 /* Application header files */
30 #ifndef MVCP_EMBEDDED
31 #include <framework/mlt.h>
32 #else
33 #define mlt_service void *
34 #endif
35 #include "mvcp_remote.h"
36 #include "mvcp_socket.h"
37 #include "mvcp_tokeniser.h"
38 #include "mvcp_util.h"
39
40 /** Private mvcp_remote structure.
41 */
42
43 typedef struct
44 {
45 int terminated;
46 char *server;
47 int port;
48 mvcp_socket socket;
49 mvcp_socket status;
50 pthread_t thread;
51 mvcp_parser parser;
52 pthread_mutex_t mutex;
53 int connected;
54 }
55 *mvcp_remote, mvcp_remote_t;
56
57 /** Forward declarations.
58 */
59
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 );
66
67 /** MVCP Parser constructor.
68 */
69
70 mvcp_parser mvcp_parser_init_remote( char *server, int port )
71 {
72 mvcp_parser parser = calloc( 1, sizeof( mvcp_parser_t ) );
73 mvcp_remote remote = calloc( 1, sizeof( mvcp_remote_t ) );
74
75 if ( parser != NULL )
76 {
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;
83
84 if ( remote != NULL )
85 {
86 remote->parser = parser;
87 remote->server = strdup( server );
88 remote->port = port;
89 pthread_mutex_init( &remote->mutex, NULL );
90 }
91 }
92 return parser;
93 }
94
95 /** Thread for receiving and distributing the status information.
96 */
97
98 static void *mvcp_remote_status_thread( void *arg )
99 {
100 mvcp_remote remote = arg;
101 char temp[ 10240 ];
102 int length = 0;
103 int offset = 0;
104 mvcp_tokeniser tokeniser = mvcp_tokeniser_init( );
105 mvcp_notifier notifier = mvcp_parser_get_notifier( remote->parser );
106 mvcp_status_t status;
107 int index = 0;
108
109 mvcp_socket_write_data( remote->status, "STATUS\r\n", 8 );
110
111 while ( !remote->terminated &&
112 ( length = mvcp_socket_read_data( remote->status, temp + offset, sizeof( temp ) ) ) >= 0 )
113 {
114 if ( strchr( temp, '\n' ) == NULL )
115 {
116 offset = length;
117 continue;
118 }
119 offset = 0;
120 mvcp_tokeniser_parse_new( tokeniser, temp, "\n" );
121 for ( index = 0; index < mvcp_tokeniser_count( tokeniser ); index ++ )
122 {
123 char *line = mvcp_tokeniser_get_string( tokeniser, index );
124 if ( line[ strlen( line ) - 1 ] == '\r' )
125 {
126 mvcp_util_chomp( line );
127 mvcp_status_parse( &status, line );
128 mvcp_notifier_put( notifier, &status );
129 }
130 else
131 {
132 strcpy( temp, line );
133 offset = strlen( temp );
134 }
135 }
136 }
137
138 mvcp_notifier_disconnected( notifier );
139 mvcp_tokeniser_close( tokeniser );
140 remote->terminated = 1;
141
142 return NULL;
143 }
144
145 /** Forward reference.
146 */
147
148 static void mvcp_remote_disconnect( mvcp_remote remote );
149
150 /** Connect to the server.
151 */
152
153 static mvcp_response mvcp_remote_connect( mvcp_remote remote )
154 {
155 mvcp_response response = NULL;
156
157 mvcp_remote_disconnect( remote );
158
159 if ( !remote->connected )
160 {
161 #if !defined(__MINGW32__)
162 signal( SIGPIPE, SIG_IGN );
163 #endif
164 remote->socket = mvcp_socket_init( remote->server, remote->port );
165 remote->status = mvcp_socket_init( remote->server, remote->port );
166
167 if ( mvcp_socket_connect( remote->socket ) == 0 )
168 {
169 response = mvcp_response_init( );
170 mvcp_remote_read_response( remote->socket, response );
171 }
172
173 if ( response != NULL && mvcp_socket_connect( remote->status ) == 0 )
174 {
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;
181 }
182 }
183
184 return response;
185 }
186
187 /** Execute the command.
188 */
189
190 static mvcp_response mvcp_remote_execute( mvcp_remote remote, char *command )
191 {
192 mvcp_response response = NULL;
193 pthread_mutex_lock( &remote->mutex );
194 if ( mvcp_socket_write_data( remote->socket, command, strlen( command ) ) == strlen( command ) )
195 {
196 response = mvcp_response_init( );
197 mvcp_socket_write_data( remote->socket, "\r\n", 2 );
198 mvcp_remote_read_response( remote->socket, response );
199 }
200 pthread_mutex_unlock( &remote->mutex );
201 return response;
202 }
203
204 /** Push a MLT XML document to the server.
205 */
206
207 static mvcp_response mvcp_remote_receive( mvcp_remote remote, char *command, char *buffer )
208 {
209 mvcp_response response = NULL;
210 pthread_mutex_lock( &remote->mutex );
211 if ( mvcp_socket_write_data( remote->socket, command, strlen( command ) ) == strlen( command ) )
212 {
213 char temp[ 20 ];
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 );
223 }
224 pthread_mutex_unlock( &remote->mutex );
225 return response;
226 }
227
228 /** Push a producer to the server.
229 */
230
231 static mvcp_response mvcp_remote_push( mvcp_remote remote, char *command, mlt_service service )
232 {
233 mvcp_response response = NULL;
234 #ifndef MVCP_EMBEDDED
235 if ( service != NULL )
236 {
237 mlt_consumer consumer = mlt_factory_consumer( NULL, "xml", "buffer" );
238 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
239 char *buffer = NULL;
240 // Temporary hack
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 );
247 }
248 #endif
249 return response;
250 }
251
252 /** Disconnect.
253 */
254
255 static void mvcp_remote_disconnect( mvcp_remote remote )
256 {
257 if ( remote != NULL && remote->terminated )
258 {
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;
265 }
266 }
267
268 /** Close the parser.
269 */
270
271 static void mvcp_remote_close( mvcp_remote remote )
272 {
273 if ( remote != NULL )
274 {
275 remote->terminated = 1;
276 mvcp_remote_disconnect( remote );
277 pthread_mutex_destroy( &remote->mutex );
278 free( remote->server );
279 free( remote );
280 }
281 }
282
283 /** Read response.
284 */
285
286 static int mvcp_remote_read_response( mvcp_socket socket, mvcp_response response )
287 {
288 char temp[ 10240 ];
289 int length;
290 int terminated = 0;
291
292 while ( !terminated && ( length = mvcp_socket_read_data( socket, temp, 10240 ) ) >= 0 )
293 {
294 int position = 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' )
299 continue;
300 switch( mvcp_response_get_error_code( response ) )
301 {
302 case 201:
303 case 500:
304 terminated = !strcmp( mvcp_response_get_line( response, position ), "" );
305 break;
306 case 202:
307 terminated = mvcp_response_count( response ) >= 2;
308 break;
309 default:
310 terminated = 1;
311 break;
312 }
313 }
314
315 return 0;
316 }