3091b0cafa3242a60debd101a324a1f506e7d466
2 * melted_connection.c -- Connection Handler
3 * Copyright (C) 2002-2009 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 /* System header files */
30 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <arpa/inet.h>
37 #include <mvcp/mvcp_socket.h>
39 /* Application header files */
40 #include "melted_commands.h"
41 #include "melted_connection.h"
42 #include "melted_server.h"
43 #include "melted_log.h"
45 /** This is a generic replacement for fgets which operates on a file
46 descriptor. Unlike fgets, we can also specify a line terminator. Maximum
47 of (max - 1) chars can be read into buf from fd. If we reach the
48 end-of-file, *eof_chk is set to 1.
51 int fdgetline( int fd
, char *buf
, int max
, char line_terminator
, int *eof_chk
)
58 while (count
< max
- 1) {
59 if (read (fd
, tmp
, 1) > 0) {
60 if (tmp
[0] != line_terminator
)
61 buf
[count
++] = tmp
[0];
65 /* Is it an EOF character (ctrl-D, i.e. ascii 4)? If so we definitely want
83 static int connection_initiate( int );
84 static int connection_send( int, mvcp_response
);
85 static int connection_read( int, char *, int );
86 static void connection_close( int );
88 static int connection_initiate( int fd
)
91 mvcp_response response
= mvcp_response_init( );
92 mvcp_response_set_error( response
, 100, "VTR Ready" );
93 error
= connection_send( fd
, response
);
94 mvcp_response_close( response
);
98 static int connection_send( int fd
, mvcp_response response
)
102 int code
= mvcp_response_get_error_code( response
);
106 int items
= mvcp_response_count( response
);
109 mvcp_response_set_error( response
, 500, "Unknown error" );
111 if ( code
== 200 && items
> 2 )
112 mvcp_response_set_error( response
, 201, "OK" );
113 else if ( code
== 200 && items
> 1 )
114 mvcp_response_set_error( response
, 202, "OK" );
116 code
= mvcp_response_get_error_code( response
);
117 items
= mvcp_response_count( response
);
119 for ( index
= 0; !error
&& index
< items
; index
++ )
121 char *line
= mvcp_response_get_line( response
, index
);
122 int length
= strlen( line
);
123 if ( length
== 0 && index
!= mvcp_response_count( response
) - 1 && write( fd
, " ", 1 ) != 1 )
125 else if ( length
> 0 && write( fd
, line
, length
) != length
)
127 if ( write( fd
, "\r\n", 2 ) != 2 )
131 if ( ( code
== 201 || code
== 500 ) && strcmp( mvcp_response_get_line( response
, items
- 1 ), "" ) )
132 if ( write( fd
, "\r\n", 2 ) != 2 )
133 melted_log( LOG_ERR
, "write(\"\\r\\n\") failed!" );
137 const char *message
= "500 Empty Response\r\n\r\n";
138 if ( write( fd
, message
, strlen( message
) ) != strlen( message
))
139 melted_log( LOG_ERR
, "write(%s) failed!", message
);
145 static int connection_read( int fd
, char *command
, int length
)
148 int nchars
= fdgetline( fd
, command
, length
, '\n', &eof_chk
);
149 char *cr
= strchr( command
, '\r');
152 if ( eof_chk
|| strncasecmp( command
, "BYE", 3 ) == 0 )
157 int connection_status( int fd
, mvcp_notifier notifier
)
161 mvcp_status_t status
;
163 mvcp_socket socket
= mvcp_socket_init_fd( fd
);
165 for ( index
= 0; !error
&& index
< MAX_UNITS
; index
++ )
167 mvcp_notifier_get( notifier
, &status
, index
);
168 mvcp_status_serialise( &status
, text
, sizeof( text
) );
169 error
= mvcp_socket_write_data( socket
, text
, strlen( text
) ) != strlen( text
);
174 if ( mvcp_notifier_wait( notifier
, &status
) == 0 )
176 mvcp_status_serialise( &status
, text
, sizeof( text
) );
177 error
= mvcp_socket_write_data( socket
, text
, strlen( text
) ) != strlen( text
);
181 struct timeval tv
= { 0, 0 };
187 if ( select( socket
->fd
+ 1, &rfds
, NULL
, NULL
, &tv
) )
192 mvcp_socket_close( socket
);
197 static void connection_close( int fd
)
202 void *parser_thread( void *arg
)
205 connection_t
*connection
= arg
;
206 mlt_properties owner
= connection
->owner
;
208 char command
[ 1024 ];
209 int fd
= connection
->fd
;
210 mvcp_parser parser
= connection
->parser
;
211 mvcp_response response
= NULL
;
213 /* Get the connecting clients ip information */
214 he
= gethostbyaddr( (char *) &( connection
->sin
.sin_addr
.s_addr
), sizeof(u_int32_t
), AF_INET
);
216 strcpy( address
, he
->h_name
);
218 inet_ntop( AF_INET
, &( connection
->sin
.sin_addr
.s_addr
), address
, 32 );
220 melted_log( LOG_NOTICE
, "Connection established with %s (%d)", address
, fd
);
222 /* Execute the commands received. */
223 if ( connection_initiate( fd
) == 0 )
227 while( !error
&& connection_read( fd
, command
, 1024 ) )
231 if ( !strcmp( command
, "" ) )
233 // Ignore blank lines
236 if ( !strncmp( command
, "PUSH ", 5 ) )
238 // Append XML as clip
243 mlt_service service
= NULL
;
245 connection_read( fd
, temp
, 20 );
246 bytes
= atoi( temp
);
247 buffer
= malloc( bytes
+ 1 );
248 while ( total
< bytes
)
250 int count
= read( fd
, buffer
+ total
, bytes
- total
);
256 buffer
[ bytes
] = '\0';
257 if ( bytes
> 0 && total
== bytes
)
259 if ( mlt_properties_get( owner
, "push-parser-off" ) == 0 )
261 mlt_profile profile
= mlt_profile_init( NULL
);
262 profile
->is_explicit
= 1;
263 service
= ( mlt_service
)mlt_factory_producer( profile
, "xml-string", buffer
);
266 mlt_properties_set_data( MLT_SERVICE_PROPERTIES( service
), "melted_profile", profile
,
267 0, (mlt_destructor
) mlt_profile_close
, NULL
);
268 mlt_events_fire( owner
, "push-received", &response
, command
, service
, NULL
);
269 if ( response
== NULL
)
270 response
= mvcp_parser_push( parser
, command
, service
);
274 response
= mvcp_response_init();
275 mvcp_response_set_error( response
, RESPONSE_BAD_FILE
, "Failed to load XML" );
280 response
= mvcp_parser_received( parser
, command
, buffer
);
283 melted_log( LOG_INFO
, "%s \"%s\" %d", address
, command
, mvcp_response_get_error_code( response
) );
284 error
= connection_send( fd
, response
);
285 mvcp_response_close( response
);
286 mlt_service_close( service
);
289 else if ( strncmp( command
, "STATUS", 6 ) )
291 // All other commands
292 mlt_events_fire( owner
, "command-received", &response
, command
, NULL
);
293 if ( response
== NULL
)
294 response
= mvcp_parser_execute( parser
, command
);
295 melted_log( LOG_INFO
, "%s \"%s\" %d", address
, command
, mvcp_response_get_error_code( response
) );
296 error
= connection_send( fd
, response
);
297 mvcp_response_close( response
);
301 // Start sending status repeatedly
302 error
= connection_status( fd
, mvcp_parser_get_notifier( parser
) );
307 /* Free the resources associated with this connection. */
308 connection_close( fd
);
310 melted_log( LOG_NOTICE
, "Connection with %s (%d) closed", address
, fd
);