TSP: The Transport Sample Protocol



Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

tsp_stream_sender.c

Go to the documentation of this file.
00001 
00038 #include "tsp_sys_headers.h"
00039   
00040 #include <netdb.h>
00041 #include <netinet/in.h>
00042 #include <netinet/tcp.h>
00043 #include <sys/socket.h>
00044 #include <signal.h>
00045 
00046 #ifndef VXWORKS
00047 #include <strings.h> /* for bzero */
00048 #endif
00049 #include <string.h>  /* for bzero too :=} */
00050 
00051 #ifndef SHUT_RDWR
00052 #define SHUT_RDWR 2
00053 #endif
00054 
00055 #include "tsp_stream_sender.h"
00056 #include "tsp_time.h"
00057 
00058 #define TSP_DATA_ADDRESS_STRING_SIZE 256
00059 
00060 /* (µs) */
00061 #define TSP_STREAM_SENDER_CONNECTION_POLL_TIME ((int)(1e5))
00062 
00063 /* (µs) */
00064 #define TSP_STREAM_SENDER_FIFO_POLL_TIME       ((int)(1e5))
00065 
00066 struct TSP_socket_t
00067 {
00068   int socketId;
00069   int hClient;
00070     
00072   char data_address[TSP_DATA_ADDRESS_STRING_SIZE + 1];
00073 
00078   int client_is_connected;
00079 
00083   TSP_stream_sender_ringbuf_t* out_ringbuf;
00084 
00088   TSP_stream_sender_item_t* out_item;
00089 
00093   int fifo_size;
00094 
00098   int buffer_size;
00099 
00100 
00104   pthread_t thread_id;
00105 
00109   int is_stopped;
00110 
00114   int connection_ok;
00115 
00116 
00117 };
00118 
00119 typedef struct TSP_socket_t TSP_socket_t;
00120 
00121 /* Signal functions */
00122 
00123 typedef void Sigfunc(int);
00124 
00125 Sigfunc* signal(int signo, Sigfunc* func)
00126 {
00127   struct sigaction act, oact;
00128   
00129   act.sa_handler = func;
00130   sigemptyset(&act.sa_mask);
00131   act.sa_flags = 0;
00132   if(signo == SIGALRM )
00133     {
00134 #ifdef SA_INTERRUPT
00135       act.sa_flags |= SA_INTERRUPT; /*SunOS 4;x */
00136 #endif
00137     }
00138   else
00139     {
00140 #ifdef SA_RESTART
00141       act.sa_flags |= SA_RESTART; /*SVR4, 4.4BSD*/
00142 #endif
00143     }
00144   if(sigaction(signo, &act, &oact) < 0)
00145     return(SIG_ERR);
00146   return (oact.sa_handler);
00147 } 
00148 
00149 
00150 void* TSP_streamer_sender_thread_sender(void* arg)
00151 {
00152   TSP_socket_t* sock = (TSP_socket_t*)arg;
00153   TSP_stream_sender_item_t* item = 0;
00154   int connection_ok = TRUE;
00155   static int status = 0;
00156      
00157   /* Wait for consumer connection before we send data */  
00158 
00159   STRACE_DEBUG(("Thread stream sender created : waiting for client to connect..."));
00160   while(!sock->client_is_connected)
00161     {
00162       tsp_usleep(TSP_STREAM_SENDER_CONNECTION_POLL_TIME);
00163      
00164     }
00165   STRACE_DEBUG(("Client connected ! Send loop starts !"));
00166 
00167   item = RINGBUF_PTR_GETBYADDR(sock->out_ringbuf);
00168   /* FIXME : gerer l'arret */
00169   /* Gerer l'impossibilité d'envoyer */
00170   while(connection_ok && !sock->is_stopped)
00171     {
00172       while (item && connection_ok)
00173         {
00174          
00175           connection_ok =  TSP_stream_sender_send(sock, TSP_STREAM_SENDER_ITEM_BUF(item), item->len);
00176           RINGBUF_PTR_GETBYADDR_COMMIT(sock->out_ringbuf);
00177           item = RINGBUF_PTR_GETBYADDR(sock->out_ringbuf);      
00178 
00179         }
00180           tsp_usleep(TSP_STREAM_SENDER_FIFO_POLL_TIME);
00181           item = RINGBUF_PTR_GETBYADDR(sock->out_ringbuf);      
00182     }
00183 
00184   if(!sock->is_stopped)
00185     {
00186       STRACE_DEBUG(("Connection with client was lost ! "));
00187     }
00188 
00189   STRACE_DEBUG(("End of fifo thread stream sender"));
00190   return &status;
00191 }
00192 
00193 
00199 static int TSP_stream_sender_init_bufferized(TSP_socket_t* sock)
00200 {
00201 
00202   int status;
00203 
00204   STRACE_IO(("-->IN"));
00205 
00206   RINGBUF_PTR_INIT(TSP_stream_sender_ringbuf_t,
00207                    sock->out_ringbuf,
00208                    TSP_stream_sender_item_t, 
00209                    sock->buffer_size,
00210                    RINGBUF_SZ(sock->fifo_size) );
00211 
00212   assert(sock->out_ringbuf);
00213 
00214   status = pthread_create(&sock->thread_id, NULL, TSP_streamer_sender_thread_sender,  sock);
00215   TSP_CHECK_THREAD(status, FALSE);
00216  
00217   STRACE_IO(("-->OUT"));
00218 
00219   return TRUE;
00220   
00221 }
00222 
00223 static void TSP_stream_sender_save_address_string(TSP_socket_t* sock, 
00224                                              char* host, unsigned short port)
00225 {   
00226   char strPort[10];
00227     
00228   sprintf(strPort,"%u",(int)port);
00229   strcpy(sock->data_address, host);
00230   strcat(sock->data_address, ":");    
00231   strcat(sock->data_address, strPort);
00232     
00233   STRACE_IO(("-->OUT address='%s'", sock->data_address));
00234 }
00235 
00236 static void* TSP_streamer_sender_connector(void* arg)
00237 {
00238   /* FIXME : When the client can't find us (somehow, ex : routing error on the network)
00239      this function badly leaks */
00240     
00241   TSP_socket_t* sock = (TSP_socket_t*)arg;
00242   int Len = 0;
00243     
00244   pthread_detach(pthread_self());
00245     
00246   /* Accept connection on socket */
00247   STRACE_DEBUG(("Thread acceptor started waiting for client to connect %d", sock->hClient));
00248   sock->hClient = accept(sock->socketId, NULL, &Len);
00249 
00250   if(sock->hClient > 0)
00251     {
00252 
00253       /* OK, the client is connected */
00254       sock->client_is_connected = TRUE;
00255       STRACE_DEBUG(("New connection accepted on socket client socket %d", sock->hClient));
00256     }
00257   else
00258     {
00259       STRACE_ERROR(("Accept error"));
00260       close(sock->socketId);
00261       return 0;
00262     }
00263     
00264   return 0;
00265 }
00266 
00267 const char* TSP_stream_sender_get_data_address_string(TSP_stream_sender_t sender)
00268 {   
00269     
00270   TSP_socket_t* sock = (TSP_socket_t*)sender;
00271     
00272   STRACE_IO(("-->IN"));
00273   STRACE_IO(("-->OUT address='%s'", sock->data_address));
00274 
00275   return sock->data_address;
00276 }
00277 
00278 TSP_stream_sender_t TSP_stream_sender_create(int fifo_size, int buffer_size)
00279 {
00280 
00281   int status = 0;
00282   int OptInt = 0;
00283   char host[TSP_MAXHOSTNAMELEN+1];
00284   TSP_socket_t* sock;
00285   pthread_t thread_connect_id;
00286   
00287   STRACE_IO(("-->IN"));
00288 
00289   /*First disable SIGPIPE signal to avoir being crashed by a disconnected client*/
00290   if( SIG_ERR == signal(SIGPIPE, SIG_IGN))
00291     {
00292       STRACE_ERROR(("Unable to disable SIGPIPE signal"));
00293       return 0;
00294     }
00295   
00296   if( -1 == gethostname(host, TSP_MAXHOSTNAMELEN))
00297     {
00298       STRACE_ERROR(("gethostname error"));
00299 
00300       return 0;
00301     }
00302   
00303   sock = (TSP_socket_t*)calloc(1, sizeof(TSP_socket_t));
00304   TSP_CHECK_ALLOC(sock, 0);
00305 
00306   sock->hClient = 0;
00307   sock->socketId = 0;
00308   sock->fifo_size = fifo_size;
00309   sock->buffer_size = buffer_size;
00310   sock->out_ringbuf = 0;
00311   sock->client_is_connected = FALSE;
00312   sock->is_stopped = FALSE;
00313   sock->connection_ok = TRUE;
00314   
00315   /* Init socket */
00316   sock->socketId = socket(AF_INET, SOCK_STREAM, 0);
00317 
00318   if (sock->socketId > 0)
00319     {
00320       OptInt = TSP_DATA_STREAM_SOCKET_FIFO_SIZE;
00321       status = setsockopt(sock->socketId, SOL_SOCKET, SO_SNDBUF, (void * )&OptInt, sizeof(OptInt));
00322       if (status == -1)
00323         {
00324           STRACE_ERROR(("Probleme with set socket size"));
00325 
00326           close(sock->socketId);
00327           return 0;
00328         }
00329  
00330       /* Local address reuse */
00331 
00332       OptInt = 1;
00333       status = setsockopt(sock->socketId, SOL_SOCKET, SO_REUSEADDR,
00334                           (void *) &OptInt, sizeof(OptInt));
00335       if (status == -1)
00336         {
00337           STRACE_ERROR(("pb set local address reuse"));
00338           close(sock->socketId);
00339           return 0;
00340         }
00341 
00342       /* No periodic connection state control */
00343       OptInt = 0;
00344       status = setsockopt(sock->socketId, SOL_SOCKET, SO_KEEPALIVE,
00345                           (void *) &OptInt, sizeof(OptInt));
00346       if (status == -1)
00347         {
00348           STRACE_ERROR(("pb set periodic state control"));
00349 
00350           close(sock->socketId);
00351           return 0;
00352         }
00353 
00354       /* TCP No delay */
00355       OptInt = 1;
00356       status = setsockopt(sock->socketId, IPPROTO_TCP, TCP_NODELAY, (void *) &OptInt,
00357                           sizeof(OptInt));
00358       if (status == -1)
00359         {
00360           STRACE_ERROR(("pb set TCP no delay"));
00361 
00362           close(sock->socketId);
00363           return 0;
00364         }
00365 
00366       /* Bind to socket : */
00367       {
00368 
00369         struct sockaddr_in ListenAddr;
00370 
00371         /* Bind to socket */
00372         bzero((char *) &ListenAddr, sizeof(struct sockaddr_in));
00373         ListenAddr.sin_family = AF_INET;
00374 #ifdef _SOCKADDR_LEN
00375         ListenAddr.sin_len = sizeof(ListenAddr);
00376 #endif
00377         ListenAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00378 
00379         /* The kernel will choose a free port */
00380         status = bind(sock->socketId, (struct sockaddr*) &ListenAddr, sizeof (struct sockaddr_in));
00381 
00382         if (status != -1)
00383           {
00384             /* Find the chosen port*/
00385             struct sockaddr_in buf_addr;
00386             int len = sizeof(buf_addr);
00387             if( 0 ==  getsockname(sock->socketId, (struct sockaddr*) &buf_addr, &len) )
00388               {
00389                 /* Save the address in the tsp_socket struct */
00390                 unsigned short port =  ntohs(buf_addr.sin_port);
00391                 TSP_stream_sender_save_address_string(sock, host, port);
00392               }
00393             else
00394               {
00395                 STRACE_ERROR(("getsockname failed"));
00396                   
00397                 close(sock->socketId);
00398                 return 0;
00399               }
00400           }
00401         else
00402           {
00403             STRACE_ERROR(("pb bind to socket"));
00404             
00405             close(sock->socketId);
00406             return 0;
00407           }
00408       }
00409       
00410 
00411       /* Try and listen onto socket */
00412       status = listen (sock->socketId, SOMAXCONN);
00413       if (status == -1)
00414         {
00415           STRACE_ERROR(("pb listening to socket"));
00416 
00417           close(sock->socketId);
00418           return 0;
00419         }
00420 
00421       /* If we want a bufferized connection, create a fifo, and launch the sender
00422          thread that will read the fifo */
00423       if(sock->fifo_size > 0 )  
00424         {
00425           if(!TSP_stream_sender_init_bufferized(sock))
00426             {
00427               STRACE_ERROR(("Function TSP_stream_sender_init_bufferized failed"));
00428               close(sock->socketId);      
00429               return 0;
00430             }
00431           
00432         }
00433       else
00434         {
00435           /* Only create a buffer, with no ringbuffer */
00436           sock->out_item = (TSP_stream_sender_item_t*)calloc(1, sizeof(TSP_stream_sender_item_t) + sock->buffer_size);
00437           TSP_CHECK_ALLOC(sock->out_item, 0);
00438         }
00439       
00440       /* When the client is be connected, the thread function
00441          TSP_streamer_sender_connector will set the client_is_connected  var to TRUE */            
00442       
00443       status = pthread_create(&thread_connect_id, NULL, TSP_streamer_sender_connector,  sock);
00444       TSP_CHECK_THREAD(status, FALSE);      
00445 
00446     }
00447 
00448   STRACE_IO(("-->OUT"));
00449     
00450   return sock;
00451 }
00452 
00453 void TSP_stream_sender_destroy(TSP_stream_sender_t sender)
00454 {
00455 
00456    TSP_socket_t* sock = (TSP_socket_t*)sender;
00457 
00458    STRACE_IO(("-->IN"));
00459   
00460    if( sock->fifo_size > 0)
00461      {
00462        RINGBUF_PTR_DESTROY(sock->out_ringbuf);
00463      }
00464    else
00465      {
00466          free(sock->out_item);sock->out_item = 0;
00467      }
00468    sock->out_ringbuf = 0;
00469    free(sock);     
00470 
00471    STRACE_IO(("-->OUT"));
00472 
00473 }
00474 
00475 void TSP_stream_sender_stop(TSP_stream_sender_t sender)
00476 {
00477 
00478    TSP_socket_t* sock = (TSP_socket_t*)sender;
00479 
00480    STRACE_IO(("-->IN"));
00481    
00482    sock->is_stopped = TRUE;
00483 
00484    shutdown(sock->socketId, SHUT_RDWR);
00485    shutdown(sock->hClient, SHUT_RDWR);
00486    close(sock->socketId);
00487    close(sock->hClient);
00488 
00489    /* Is there was a thread for the fifo, we must wait for it to end */
00490    if(sock->fifo_size > 0)
00491      {
00492        pthread_join(sock->thread_id, NULL);
00493      }
00494 
00495    STRACE_IO(("-->OUT"));
00496 }
00497 
00498 int TSP_stream_sender_send(TSP_stream_sender_t sender, const char *buffer, int bufferLen)
00499 {
00500   
00501   int Total;
00502   int nread;
00503   TSP_socket_t* sock = (TSP_socket_t*)sender;
00504   int identSocket = sock->hClient;
00505 
00506   STRACE_IO(("-->IN"));
00507 
00508   Total = 0;
00509   if(identSocket > 0)
00510     {      
00511       while (bufferLen > 0)
00512         {
00513           if( (nread = write(identSocket,  &buffer[Total], bufferLen)) <= 0 )
00514             {
00515               if( errno == EINTR )
00516                 {
00517                   /* The write might have been interrupted by a signal */
00518                   nread = 0;
00519                 }
00520               else 
00521                 {
00522                   
00523                   STRACE_DEBUG(("send failed"));
00524                   sock->connection_ok = FALSE;
00525                   return FALSE;
00526                 }
00527             }
00528           
00529           Total += nread;
00530           bufferLen -= nread;
00531         }
00532     }
00533   
00534   STRACE_IO(("-->OUT"));
00535 
00536   return(TRUE);
00537 }
00538 
00539 
00545 int TSP_stream_sender_is_client_connected(TSP_stream_sender_t sender)
00546 {
00547   TSP_socket_t* sock = (TSP_socket_t*)sender;
00548 
00549   return sock->client_is_connected;
00550 }
00551 
00552 int TSP_stream_sender_is_connection_ok(TSP_stream_sender_t sender)
00553 {
00554   TSP_socket_t* sock = (TSP_socket_t*)sender;
00555 
00556   return sock->connection_ok;
00557 }
00558 
00559 
00560 TSP_stream_sender_ringbuf_t* TSP_stream_sender_get_ringbuf(TSP_stream_sender_t sender)
00561 {
00562   TSP_socket_t* sock = (TSP_socket_t*)sender;
00563 
00564   return sock->out_ringbuf;
00565 }
00566 
00567 TSP_stream_sender_item_t* TSP_stream_sender_get_buffer(TSP_stream_sender_t sender)
00568 {
00569   TSP_socket_t* sock = (TSP_socket_t*)sender;
00570 
00571   return sock->out_item;
00572 }
Framework Home Page.

Beware !! TSP wave is coming...