Main Page | Namespace List | Class Hierarchy | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages

GrTCPSink.h

Go to the documentation of this file.
00001 /* -*- Mode: c++ -*- */
00002 /*
00003  * Copyright 2002 Free Software Foundation, Inc.
00004  * 
00005  * This file is part of GNU Radio
00006  * 
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2, or (at your option)
00010  * any later version.
00011  * 
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with GNU Radio; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020  * Boston, MA 02111-1307, USA.
00021  */
00022 
00023 #ifndef _GRTCPSINK_H_
00024 #define _GRTCPSINK_H_
00025 
00026 #include <vector>
00027 #include <sys/socket.h>
00028 #include <netinet/in.h>
00029 #include <arpa/inet.h>
00030 #include <netdb.h>
00031 #include <fcntl.h>
00032 #include <stdio.h>
00033 #include <errno.h>
00034 
00035 using std::vector;
00036 
00037 /*
00038  * versions prior to gcc-3.x croak on volatile asm in templates,
00039  * hence the following workaround
00040  */
00041 static inline unsigned long int _local_htonl (unsigned long int hostlong)
00042 {
00043   return htonl (hostlong);
00044 }
00045 
00046 static inline unsigned short int _local_htons (unsigned short int hostshort)
00047 {
00048   return htons (hostshort);
00049 }
00050 
00051 template <class iType>
00052 class GrTCPSink : public VrSink<iType>
00053 {
00054 public:
00055   GrTCPSink (int port);
00056   virtual ~GrTCPSink ();
00057 
00058   
00059   virtual const char *name () { return "GrTCPSink"; }
00060   virtual int work3(VrSampleRange output, 
00061                     VrSampleRange inputs[], void *i[]);
00062 
00063 protected:
00064   int                   listen_socket;
00065   std::vector<int>      connection;     // open sockets
00066 
00067 };
00068 
00069 template <class iType>
00070 GrTCPSink<iType>::GrTCPSink (int port)
00071 {
00072   struct sockaddr_in server_addr;
00073 
00074   
00075   listen_socket = socket (AF_INET, SOCK_STREAM, 0);
00076   if (listen_socket == -1){
00077     perror ("GrTPCSink: socket");
00078     exit (1);
00079   }
00080 
00081   memset (&server_addr, 0, sizeof (server_addr));
00082   server_addr.sin_family = AF_INET;
00083   server_addr.sin_addr.s_addr = _local_htonl (INADDR_ANY);
00084   server_addr.sin_port = _local_htons (port);
00085 
00086   if (bind (listen_socket, (struct sockaddr *) &server_addr,
00087             sizeof (server_addr)) == -1){
00088     perror ("GrTCPSink: bind");
00089     exit (1);
00090   }
00091 
00092   if (listen (listen_socket, 5) == -1){
00093     perror ("GrTCPSink: listen");
00094     exit (1);
00095   }
00096 
00097   long file_flags = fcntl (listen_socket, F_GETFL);
00098   if (fcntl (listen_socket, F_SETFL, file_flags | O_NONBLOCK) == -1){
00099     perror ("GrTCPSink: fcntl / O_NONBLOCK");
00100     exit (1);
00101   }
00102 }
00103 
00104 template<class iType> int
00105 GrTCPSink<iType>::work3(VrSampleRange output, 
00106                          VrSampleRange inputs[], void *ai[]) 
00107 {
00108   iType *in = ((iType **)ai)[0];
00109 
00110   /*
00111    * We changed this so that it HANGS when there are no TCP
00112    * connections, rather than throwing away samples.  This will
00113    * hang the entire GNU Radio pipeline (in a tight loop
00114    * doing accept() calls).  We should add a significant
00115    * delay here, perhaps a select, which would stop burning
00116    * CPU time while waiting.  FIXME.  
00117    */
00118   do {
00119     // 
00120     // check for new connections
00121     // (FIXME, do this only every now and then, say 100 ms,
00122     //  to reduce number of system calls.)
00123     //
00124     int new_socket = accept (listen_socket, 0, 0);
00125     if (new_socket == -1){
00126       if (errno == EAGAIN){
00127         // no new connection, this is OK
00128       }
00129       else {
00130         perror ("GrTCPSink: accept");
00131         exit (1);
00132       }
00133     }
00134     else {      // got a new connection
00135       fprintf (stderr, "GrTCPSink: new connection\n");
00136       connection.push_back (new_socket);
00137     }
00138 
00139     //
00140     // handle normal output
00141     //
00142     
00143   } while (connection.size () == 0);
00144 
00145   /*
00146    * Before the above "while loop" was added, this test would discard
00147    * any samples that arrived when no TCP connections are currently
00148    * connected.  Now it's a no-op.
00149    */
00150   if (connection.size () == 0)
00151         // nothing to do, return success
00152     return output.size;
00153 
00154 
00155   long  nbytes_to_write = output.size * sizeof (iType);
00156 
00157   // iterate over all current connections
00158 
00159   vector<int>::iterator p = connection.begin ();
00160 
00161   while (p != connection.end ()){
00162     //
00163     // write whole mess
00164     //
00165     long         r;
00166     int         flags = 0;
00167 #ifdef MSG_NOSIGNAL
00168     flags = MSG_NOSIGNAL;
00169 #endif
00170     if ((r = send (*p, in, nbytes_to_write, flags)) != nbytes_to_write){
00171       if (r == -1 && errno == EPIPE){
00172         // other end was closed...
00173         fprintf (stderr, "GrTCPSink: closing connection\n");
00174         close (*p);
00175         p = connection.erase (p);
00176       }
00177       else {
00178         perror ("GrTCPSink: send");
00179       }
00180     }
00181     else
00182       p++;
00183   }
00184 
00185   return output.size;
00186 }
00187 
00188 
00189 template <class iType>
00190 GrTCPSink<iType>::~GrTCPSink ()
00191 {
00192   vector<int>::iterator p = connection.begin ();
00193   while (p != connection.end ()){
00194     close (*p);
00195     p++;
00196   }
00197 
00198   close (listen_socket);
00199 }
00200 
00201 
00202 #endif // _GRTCPSINK_H_

Generated on Tue Mar 30 21:31:49 2004 for GNU Radio by doxygen 1.3.2