1 /* -*- c++ -*- */
2 /*
3  * Copyright 2004,2005,2013 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "file_descriptor_source_impl.h"
28 #include <gnuradio/io_signature.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <cstdio>
36 #include <stdexcept>
37 
38 #ifdef HAVE_IO_H
39 #include <io.h>
40 #endif
41 
42 namespace gr {
43 namespace blocks {
44 
45 file_descriptor_source::sptr
make(size_t itemsize,int fd,bool repeat)46 file_descriptor_source::make(size_t itemsize, int fd, bool repeat)
47 {
48     return gnuradio::get_initial_sptr(
49         new file_descriptor_source_impl(itemsize, fd, repeat));
50 }
51 
file_descriptor_source_impl(size_t itemsize,int fd,bool repeat)52 file_descriptor_source_impl::file_descriptor_source_impl(size_t itemsize,
53                                                          int fd,
54                                                          bool repeat)
55     : sync_block("file_descriptor_source",
56                  io_signature::make(0, 0, 0),
57                  io_signature::make(1, 1, itemsize)),
58       d_itemsize(itemsize),
59       d_fd(fd),
60       d_repeat(repeat),
61       d_residue(new unsigned char[itemsize]),
62       d_residue_len(0)
63 {
64 }
65 
~file_descriptor_source_impl()66 file_descriptor_source_impl::~file_descriptor_source_impl()
67 {
68     close(d_fd);
69     delete[] d_residue;
70 }
71 
read_items(char * buf,int nitems)72 int file_descriptor_source_impl::read_items(char* buf, int nitems)
73 {
74     assert(nitems > 0);
75     assert(d_residue_len < d_itemsize);
76 
77     int nbytes_read = 0;
78 
79     if (d_residue_len > 0) {
80         memcpy(buf, d_residue, d_residue_len);
81         nbytes_read = d_residue_len;
82         d_residue_len = 0;
83     }
84 
85     int r = read(d_fd, buf + nbytes_read, nitems * d_itemsize - nbytes_read);
86     if (r <= 0) {
87         handle_residue(buf, nbytes_read);
88         return r;
89     }
90 
91     r = handle_residue(buf, r + nbytes_read);
92 
93     if (r == 0) // block until we get something
94         return read_items(buf, nitems);
95 
96     return r;
97 }
98 
handle_residue(char * buf,int nbytes_read)99 int file_descriptor_source_impl::handle_residue(char* buf, int nbytes_read)
100 {
101     assert(nbytes_read >= 0);
102     int nitems_read = nbytes_read / d_itemsize;
103     d_residue_len = nbytes_read % d_itemsize;
104     if (d_residue_len > 0) {
105         // fprintf (stderr, "handle_residue: %d\n", d_residue_len);
106         memcpy(d_residue, buf + nbytes_read - d_residue_len, d_residue_len);
107     }
108     return nitems_read;
109 }
110 
work(int noutput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)111 int file_descriptor_source_impl::work(int noutput_items,
112                                       gr_vector_const_void_star& input_items,
113                                       gr_vector_void_star& output_items)
114 {
115     assert(noutput_items > 0);
116 
117     char* o = (char*)output_items[0];
118     int nread = 0;
119 
120     while (1) {
121         int r = read_items(o, noutput_items - nread);
122         if (r == -1) {
123             if (errno == EINTR)
124                 continue;
125             else {
126                 perror("file_descriptor_source[read]");
127                 return -1;
128             }
129         } else if (r == 0) { // end of file
130             if (!d_repeat)
131                 break;
132             else {
133                 flush_residue();
134                 if (lseek(d_fd, 0, SEEK_SET) == -1) {
135                     perror("file_descriptor_source[lseek]");
136                     return -1;
137                 }
138             }
139         } else {
140             o += r * d_itemsize;
141             nread += r;
142             break;
143         }
144     }
145 
146     if (nread == 0) // EOF
147         return -1;
148 
149     return nread;
150 }
151 
152 } /* namespace blocks */
153 } /* namespace gr */
154