/** * Обработчик соединения. * * @param[in] connection описание соединения. * @return не используется. */ void* handler(IN struct connection_vars_t* connection) { /* Поток должен запуститься только после окончания инициализации */ pthread_mutex_lock(&init_connection_lock); pthread_mutex_unlock(&init_connection_lock); TRACE; int status = user_interaction(connection); CHECK_ERRNO(status, "User interaction"); TRACE; #ifdef DEBUG dump_connection_vars(connection); #endif status = shutdown(connection->sockfd, SHUT_RDWR); CHECK_ERRNO(status, "Shutdown connection"); TRACE; status = close(connection->sockfd); CHECK_ERRNO(status, "Close connection"); pthread_mutex_lock(&connections_lock); remove_conn(connection); pthread_mutex_unlock(&connections_lock); return NULL; }
int main( int argc, char **argv ) { int num_polled = 1; struct pollfd *polls; struct sockaddr_in incoming; int i, n, pos, len; int new_fd; socklen_t addr_len; Connection *conn; IPP *response; signal( SIGUSR1, quit_handler ); // Temp printer for now if( argc < 2 ) { fprintf(stderr, "Missing argument pointing to location of printer definition file.\n" ); exit(1); } if(!init_printers( argv[1] )) { fprintf( stderr, "Unable to load printer definition file %s\n", argv[1] ); exit(1); } new_fd = StartListening(); polls = malloc( sizeof( struct pollfd ) * MAX_CLIENTS); polls[0].fd = new_fd; polls[0].events = POLLIN; for(;;) { // printf("."); for( conn = list_conn( NULL ), num_polled = 1; conn != NULL; conn = list_conn( conn ) ) { if( conn->state == CONN_BEGIN || conn->state == CONN_PRINTING_READ ) { polls[num_polled].fd = conn->fd; polls[num_polled++].events = POLLIN; } else if( conn->state == CONN_OUTPUT ) { polls[num_polled].fd = conn->fd; polls[num_polled++].events = POLLOUT; } } for( i = 0; i < array_len( printers ); i++ ) { printer = array_get( printers, i ); if( printer->state == PRINTER_PRINTING_WRITE ) { polls[num_polled].fd = printer->fd; polls[num_polled++].events = POLLOUT; } } poll( polls, num_polled, -1 ); // printf("o" ); for( i = 0; i < num_polled; i++ ) { if( polls[i].revents & POLLIN ) { // Read if( i == 0 ) { // Special case.. addr_len = sizeof( struct sockaddr_in ); new_fd = accept( polls[i].fd, (struct sockaddr *)&(incoming), &addr_len ); add_conn( new_fd ); } else { if( ( conn = get_conn( polls[i].fd ) ) ) { process_conn( conn ); } } } else if ( polls[i].revents & POLLNVAL ) { if( ( conn = get_conn( polls[i].fd ) ) ) remove_conn( conn ); } else if ( polls[i].revents & POLLOUT ) { if( ( conn = get_conn( polls[i].fd ) ) ) { if( ( n = write( conn->fd, conn->buffer+conn->buf_ptr, conn->used-conn->buf_ptr ) ) ) { conn->buf_ptr += n; if( conn->buf_ptr == conn->used ) { close( conn->fd ); remove_conn( conn ); } } } else { int e; for( e = 0; e < array_len( printers ); e++ ) { printer = array_get( printers, e ); if( printer->fd == polls[i].fd ) { if( ( n = write( printer->fd, printer->buffer+printer->buf_ptr, printer->used-printer->buf_ptr ) ) == 0 ) { #if 0 // ERROR WRITING TO PRINTER // Simple error support -- close printer fd if( ( conn = get_conn( printer->jobs->job.fd ) ) ) { fprintf( stderr, "Print job error.\n" ); response = ipp_new(); response->response = 0x0504; response->version = 256; // IPP 1.0 response->request_id = conn->ipp->request_id; ipp_add_tag( response, IPP_TAG_OPERATIONS, NULL, NULL, 0, 0 ); ipp_copy_tag( response, conn->ipp, IPP_TAG_OPERATIONS, "attributes-charset" ); ipp_copy_tag( response, conn->ipp, IPP_TAG_OPERATIONS, "attributes-natural-language" ); len = ipp_write( response, NULL, len ); pos = sprintf( conn->buffer, "HTTP/1.1 200 OK\r\nContent-Type: application/ipp\r\nContent-Length: %d\r\n\r\n", len ); ipp_write( response, conn->buffer+pos, len ); conn->used = len + pos; conn->buf_ptr = 0; conn->state = CONN_OUTPUT; ipp_free( response ); } fprintf( stderr, "Marking printer closed.\n" ); close(printer->fd ); printer->state = PRINTER_CLOSED; #endif /* 0 */ } else { printer->buf_ptr += n; if( printer->buf_ptr == printer->used ) { printer->state = PRINTER_PRINTING_WAIT; printer->buf_ptr = printer->used = 0; if( ( conn = get_conn( printer->jobs->job.fd ) ) == NULL ) { printf( "Bad printer state.\n" ); } if( conn->ipp->data_left ) conn->state = CONN_PRINTING_READ; else { int pos, len, val; struct _ipp_jobs *old_job; IPP *response; // Generate a done message response = ipp_new(); response->response = 0x0000; // Success response->request_id = conn->ipp->request_id; response->version = 256; ipp_add_tag( response, IPP_TAG_OPERATIONS, NULL, NULL, 0, 0 ); ipp_copy_tag( response, conn->ipp, IPP_TAG_OPERATIONS, "attributes-charset" ); ipp_copy_tag( response, conn->ipp, IPP_TAG_OPERATIONS, "attributes-natural-language" ); /* 2004/11/8 : Added to make XP printer utility report success status*/ ipp_add_tag( response, IPP_TAG_TEXT_WO_LANG, "status-message", "successful-ok", strlen( "successful-ok" ), 0 ); ipp_add_tag( response, IPP_TAG_JOBS, NULL, NULL, 0, 0 ); val = printer->jobs->job.id; ipp_add_tag( response, IPP_TAG_INTEGERS, "job-id", &val, 4, 0 ); val = 9; ipp_add_tag( response, IPP_TAG_ENUM, "job-state", &val, 4, 0 ); /* 9 = COMPLETED */ // Done len = ipp_write( response, NULL, len ); pos = sprintf( conn->buffer, "HTTP/1.1 200 OK\r\nContent-Type: application/ipp\r\nContent-Length: %d\r\n\r\n", len ); ipp_write( response, conn->buffer + pos, len ); conn->used = len + pos; conn->buf_ptr = 0; conn->state = CONN_OUTPUT; /* 2004/11/8: added to free response */ ipp_free( response ); // The JOB being is printed is ALWAYS the first one old_job = printer->jobs; printer->jobs = old_job->next; free( old_job ); // Free the job printf( "Going to next job...\n" ); if( printer->jobs ) { if( ( conn = get_conn( printer->jobs->job.fd ) ) ) { if( conn->buf_ptr < conn->used ) { memcpy( printer->buffer, conn->buffer + conn->buf_ptr, conn->used - conn->buf_ptr ); printer->used = conn->used - conn->buf_ptr; printer->buf_ptr = 0; printer->state = PRINTER_PRINTING_WRITE; conn->state = CONN_PRINTING_WAIT; conn->ipp->data_left -= conn->used - conn->buf_ptr; } else { if( conn->ipp->data_left ) { printer->state = PRINTER_PRINTING_WAIT; conn->state = CONN_PRINTING_READ; } } } else { printf( "Unable to get connection for FD - %d.\n", printer->jobs->job.fd ); } } else { /* printer->state = PRINTER_OPEN; */ /* 2004/11/5 : put back into closed state so that kernel can remove lp0 when printer unplugged */ close(printer->fd); printer->fd = 0; printer->state = PRINTER_CLOSED; } } } } } } } } } } }