2 * dvconnection.c -- DV Connection Handler
3 * Copyright (C) 2002-2003 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 /* Application header files */
38 #include "global_commands.h"
39 #include "dvconnection.h"
44 /** This is a generic replacement for fgets which operates on a file
45 descriptor. Unlike fgets, we can also specify a line terminator. Maximum
46 of (max - 1) chars can be read into buf from fd. If we reach the
47 end-of-file, *eof_chk is set to 1.
50 int fdgetline( int fd, char *buf, int max, char line_terminator, int *eof_chk )
57 while (count < max - 1) {
58 if (read (fd, tmp, 1) > 0) {
59 if (tmp [0] != line_terminator)
60 buf [count++] = tmp [0];
64 /* Is it an EOF character (ctrl-D, i.e. ascii 4)? If so we definitely want
82 static int connection_initiate( int );
83 static int connection_send( int, dv_response );
84 static int connection_read( int, char *, int );
85 static void connection_close( int );
87 static int connection_initiate( int fd )
90 dv_response response = dv_response_init( );
91 dv_response_set_error( response, 100, "VTR Ready" );
92 error = connection_send( fd, response );
93 dv_response_close( response );
97 static int connection_send( int fd, dv_response response )
101 int code = dv_response_get_error_code( response );
105 int items = dv_response_count( response );
108 dv_response_set_error( response, 500, "Unknown error" );
110 if ( code == 200 && items > 2 )
111 dv_response_set_error( response, 201, "OK" );
112 else if ( code == 200 && items > 1 )
113 dv_response_set_error( response, 202, "OK" );
115 code = dv_response_get_error_code( response );
116 items = dv_response_count( response );
118 for ( index = 0; !error && index < items; index ++ )
120 char *line = dv_response_get_line( response, index );
121 int length = strlen( line );
122 if ( length == 0 && index != dv_response_count( response ) - 1 && write( fd, " ", 1 ) != 1 )
124 else if ( length > 0 && write( fd, line, length ) != length )
126 if ( write( fd, "\r\n", 2 ) != 2 )
130 if ( ( code == 201 || code == 500 ) && strcmp( dv_response_get_line( response, items - 1 ), "" ) )
131 write( fd, "\r\n", 2 );
135 char *message = "500 Empty Response\r\n\r\n";
136 write( fd, message, strlen( message ) );
142 static int connection_read( int fd, char *command, int length )
145 int nchars = fdgetline( fd, command, length, '\n', &eof_chk );
146 char *cr = strchr( command, '\r');
149 if ( eof_chk || strncmp( command, "BYE", 3 ) == 0 )
154 int connection_status( int fd, dv1394_notifier notifier )
158 dv1394_status_t status;
160 dv_socket socket = dv_socket_init_fd( fd );
162 for ( index = 0; !error && index < MAX_UNITS; index ++ )
164 dv1394_notifier_get( notifier, &status, index );
165 dv1394_status_serialise( &status, text, sizeof( text ) );
166 error = dv_socket_write_data( socket, text, strlen( text ) ) != strlen( text );
171 if ( dv1394_notifier_wait( notifier, &status ) == 0 )
173 dv1394_status_serialise( &status, text, sizeof( text ) );
174 error = dv_socket_write_data( socket, text, strlen( text ) ) != strlen( text );
178 struct timeval tv = { 0, 0 };
184 if ( select( socket->fd + 1, &rfds, NULL, NULL, &tv ) )
189 dv_socket_close( socket );
194 static void connection_close( int fd )
199 void *parser_thread( void *arg )
202 connection_t *connection = arg;
204 char command[ 1024 ];
205 int fd = connection->fd;
206 dv_parser parser = connection->parser;
207 dv_response response = NULL;
209 /* We definitely want to ignore broken pipes. */
210 signal( SIGPIPE, SIG_IGN );
212 /* Get the connecting clients ip information */
213 he = gethostbyaddr( (char *) &( connection->sin.sin_addr.s_addr ), sizeof(u_int32_t), AF_INET);
215 strcpy( address, he->h_name );
217 inet_ntop( AF_INET, &( connection->sin.sin_addr.s_addr), address, 32 );
219 dv1394d_log( LOG_NOTICE, "Connection established with %s (%d)", address, fd );
221 /* Execute the commands received. */
222 if ( connection_initiate( fd ) == 0 )
226 while( !error && connection_read( fd, command, 1024 ) )
228 if ( strncmp( command, "STATUS", 6 ) )
230 response = dv_parser_execute( parser, command );
231 dv1394d_log( LOG_INFO, "%s \"%s\" %d", address, command, dv_response_get_error_code( response ) );
232 error = connection_send( fd, response );
233 dv_response_close( response );
237 error = connection_status( fd, dv_parser_get_notifier( parser ) );
242 /* Free the resources associated with this connection. */
243 connection_close( fd );
245 dv1394d_log( LOG_NOTICE, "Connection with %s (%d) closed", address, fd );