sender.c 8.95 KB
Newer Older
Benoit Steiner's avatar
Benoit Steiner committed
1 2 3 4 5 6 7 8
/* VideoLAN VLAN bridge : Sender thread
 *
 * Benoit Steiner, VIA, ECP, France <benny@via.ecp.fr>
 *
 * To-do-list:
 */


9 10 11
/* For Solaris */
#include <strings.h>
#include <errno.h>
Benoit Steiner's avatar
Benoit Steiner committed
12 13 14 15 16 17 18 19 20 21 22

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>

23
#include "debug.h"
Benoit Steiner's avatar
Benoit Steiner committed
24
#include "log.h"
25
#include "convert.h"
Benoit Steiner's avatar
Benoit Steiner committed
26 27 28 29 30 31 32 33 34 35 36
#include "performer.h"
#include "manager.h"
#include "connect.h"
#include "sender.h"
#include "fifo.h"
#include "define.h"
#include "common.h"


/* Used to communicate with the manager thread */
extern struct s_manager manager;
37 38

/* Connection state */
Benoit Steiner's avatar
Benoit Steiner committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
extern int iConnectionState;
extern pthread_mutex_t ConnectionLock;


#define MOD_NAME MOD_SENDER



/***************************************************************************/
/* Warn the sender							   */
/***************************************************************************/
int WarnSender(struct s_Sender* pssSender, struct s_Request* psrJob)
{
  int iRc = 0;

54 55 56
  ASSERT(pssSender);
  ASSERT(psrJob);

Benoit Steiner's avatar
Benoit Steiner committed
57 58 59
  /* Push the request in the manager FIFO */
  iRc = FifoPush(pssSender->psfWaitingAnswers, psrJob);

60 61
  //printf ("Push -> %d\n", iRc);
  //printf ("Signal sent: %d\n", psrJob->iNextStep);
Benoit Steiner's avatar
Benoit Steiner committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

  return iRc;
}


/*****************************************************************************/
/* Create the thread used to answer to VLANserver			     */
/*****************************************************************************/
int InitSender (struct s_Sender* sender)
{
  /* Thread initialisations */
  int iRc = pthread_cond_init(&sender->WakeUpSignal, NULL);
  iRc |= pthread_cond_init(&sender->SendSignal, NULL);
  iRc |= pthread_mutex_init(&sender->SendLock, NULL);

77 78
  ASSERT(sender);

Benoit Steiner's avatar
Benoit Steiner committed
79 80 81 82 83 84 85 86 87 88 89 90
  /* Init the FIFO */
  sender->psfWaitingAnswers = FifoCreate();
  if (sender->psfWaitingAnswers == NULL)
  {
    Log(LOG_ERROR, MOD_NAME, "Unable to create sender fifo");
    iRc = -1;
  }

  /* Now create the thread used to answer to the VLANserver */
  if (!iRc)
  {
    iRc = pthread_create(&(sender->tid), NULL, SenderThread, sender);
91

Benoit Steiner's avatar
Benoit Steiner committed
92
    if (!iRc)
93 94
      Log (LOG_NOTE, MOD_NAME, "Sender thread successfully created: id %d",
           sender->tid); 
Benoit Steiner's avatar
Benoit Steiner committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
  }

  return iRc;
}




/*****************************************************************************/
/*			     */
/*****************************************************************************/
int ParseAnswer (struct s_Request* psrMsg, char* strBuff)
{
  int iRc = 0;
  char* IP;
  char MAC[18];

112 113 114
  ASSERT(psrMsg);
  ASSERT(strBuff);

Benoit Steiner's avatar
Benoit Steiner committed
115
  /* Init the buffers */
116
  PZERO(strBuff);
Benoit Steiner's avatar
Benoit Steiner committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
  bzero(MAC, 18);

  /* Convert MAC adress */
  iRc = mac_btoa(MAC, (unsigned char *)&psrMsg->saClientMAC.sa_data);

  /* Convert IP adress */
  if (!iRc)
  {
    IP = inet_ntoa(psrMsg->saClientIP.sin_addr);
    if (IP == 0)
      iRc = 1;
  }
  
  /* Build answer */
  if (!iRc && (sprintf(strBuff, "%d %d %s %s %d %d\n", psrMsg->iStatus,
      psrMsg->iRequestId, MAC, IP, psrMsg->iVLANdst, psrMsg->iVLANsrc) <= 0))
    iRc = 1;

  return iRc;
}


/*****************************************************************************/
/*			     */
/*****************************************************************************/
int WaitSocket(struct s_Sender* pssSender)
{
  int iRc = pthread_mutex_lock(&ConnectionLock);
145 146

  ASSERT(pssSender);
Benoit Steiner's avatar
Benoit Steiner committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  
  if (!iRc)
  { 
    if (iConnectionState == 0)
    {
      /* Wait for the signal of the main thread */
      iRc = pthread_cond_wait(&pssSender->WakeUpSignal, &ConnectionLock);
    }

    iRc |= pthread_mutex_unlock(&ConnectionLock);
  }
 
  return iRc;
}


/*****************************************************************************/
/* A refaire, le test du iConnectionOK est trop eloigne dans tps du send     */
/*****************************************************************************/
int Answer(struct s_Sender *share)
{
  char buff[VLAN_MSG_LEN]; /*= calloc(MAX_MSG_LEN, sizeof (char));*/
  struct s_Request* psrAnswer = NULL;
  int iRc = 0;
  int iConnectionOK = 1 ;

173 174 175 176 177
  pthread_cond_t conds;
  pthread_mutex_t mutexs;
  pthread_mutex_init (&mutexs, NULL);
  pthread_cond_init (&conds, NULL);

178 179
  ASSERT(share);
  
Benoit Steiner's avatar
Benoit Steiner committed
180 181 182
  while (iConnectionOK > 0)
  { 
    /* Wait for a message if the FIFO is empty */
183
//    printf("Sender -> Waiting for a message from manager\n");
Benoit Steiner's avatar
Benoit Steiner committed
184
    iRc = FifoPull(share->psfWaitingAnswers, &psrAnswer);
185
//    printf("Sender -> Message received\n");
Benoit Steiner's avatar
Benoit Steiner committed
186 187 188 189 190 191 192 193 194 195
    /* Convert the msg to ascii */
    iRc = ParseAnswer(psrAnswer, buff);
    /* Message is no more used */
    free (psrAnswer);

    if (iRc)
      Log(LOG_ERROR, MOD_NAME, "Could not convert answer to ASCII: answer not sent");
    else
    {
      Log(LOG_NOTE, MOD_NAME, "Sending answer to VLANserver: %s", buff);
196 197 198 199

     /* We need those testcancel() for classical system calls are not
         cancellation points at the present time */
      pthread_testcancel();
Benoit Steiner's avatar
Benoit Steiner committed
200
      iConnectionOK = send(share->iSockFd, buff, strlen(buff), 0);
201
      pthread_testcancel();
Benoit Steiner's avatar
Benoit Steiner committed
202 203 204 205 206
      
      /* Check what we sended */
      if (iConnectionOK <= 0)
      { /* Connection lost : can't do anything else as waiting for a new connexion */
	iRc = errno;
Benoit Steiner's avatar
Benoit Steiner committed
207
	Log (LOG_WARN, MOD_NAME, "Send error: %s", strerror(errno));
Benoit Steiner's avatar
Benoit Steiner committed
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
	break;
      }
    }
  }

  return iRc;
}


/*****************************************************************************/
/* Thread sending the answers to the VLANserver				     */
/*****************************************************************************/
#define sender ((struct s_Sender *)arg)

void* SenderThread (void* arg)
{
  /* True until the thread must be stopped */
  int iMustLoop = 1;
  int iRc = 0;

228
  ASSERT(arg);
229

Benoit Steiner's avatar
Benoit Steiner committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
#ifdef DEBUG
  Log (LOG_NOTE, MOD_NAME, "Sender thread is running");
#endif

  while (iMustLoop)
  {
    /* Get the sockfd on which one must send */
    iRc = WaitSocket(sender);

    /* Send the bridge answers to VLANserver */
    if (!iRc)
    {
      iRc = Answer(sender);

      /* Handle connection losts if needed */
      if (iRc)
      {
Benoit Steiner's avatar
Benoit Steiner committed
247
	Log (LOG_WARN, MOD_NAME, "Connection with VLANserver lost");
Benoit Steiner's avatar
Benoit Steiner committed
248 249 250 251 252 253 254 255

	/* Enter exclusive execution zone */
	iRc = pthread_mutex_lock(&ConnectionLock);

	if (!iRc)
	{
	  if (iConnectionState == 0 || iConnectionState != sender->iSockFd)
	  {
256 257 258 259
	    /* The sender has already handled the connection lost, and the
               VLANserver is either waiting for a new connection
               (iIsConnected == 0) or has already set up another connection:
               so there is nothing to do */
Benoit Steiner's avatar
Benoit Steiner committed
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
	  }
	  else
	    iRc = HandleDeadSocket(sender->iSockFd);
	}
 
	/* Leave exclusive execution zone */
	iRc |= pthread_mutex_unlock(&ConnectionLock);

	if (iRc)
	  Log(LOG_ERROR, MOD_NAME, "Connection lost could not be correctly handled by listener because of errors");
      }
    }
    else
    {
      Log(LOG_WARN, MOD_NAME, "Unable to get a valid socket file descriptor, retrying");
      /* Just loop */
    }
  }

  /* Exit the thread returning the NULL value */
  pthread_exit(NULL);
}



/*****************************************************************************/
/* Stop the running sender thread    					     */
/*****************************************************************************/
int CancelSender(struct s_Sender* pssSender)
{
  int iRc = 0;

292 293
  ASSERT(pssSender);
  
Benoit Steiner's avatar
Benoit Steiner committed
294 295
  if (pssSender->tid != 0)
  {
296 297 298
    Log(LOG_NOTE, MOD_NAME, "Stopping sender thread");

    iRc = pthread_cancel(pssSender->tid);
299
//    printf("Sender thread canceled with iRc %d and error %s\n", iRc, strerror(iRc));
300 301 302
    /* Synchronise ourselves with the destruction of the thread, to avoid to destroy
       the condition while the sender is waiting on it */
    iRc |= pthread_join(pssSender->tid, NULL);
303
//    printf("Sender thread joined with iRc %d and error %s\n", iRc, strerror(iRc));
304 305 306
    /* When the thread is cancelled while waiting for a a socket, it relocks
       the ConnectionLock, so that the sender thread cannot anymore work for
       it shares the ConnectionLock with the listener */
307 308
    pthread_mutex_trylock(&ConnectionLock);
    pthread_mutex_unlock(&ConnectionLock);
Benoit Steiner's avatar
Benoit Steiner committed
309 310 311 312 313 314 315 316 317 318 319 320 321 322
  }
  else
    Log(LOG_WARN, MOD_NAME, "Could not stop sender, none is running");

  return iRc;
}


/*****************************************************************************/
/* Free all ressources used by the running sender thread     		     */
/*****************************************************************************/
int FreeSender(struct s_Sender* pssSender)
{
  int iRc = 0;
323 324

  ASSERT(pssSender);
Benoit Steiner's avatar
Benoit Steiner committed
325 326
  
  if (pssSender->tid != 0)
327
  {
Benoit Steiner's avatar
Benoit Steiner committed
328
    iRc = pthread_cond_destroy(&pssSender->WakeUpSignal);
329
//    printf("Sender thread cond destoyed with iRc %d and error %s\n", iRc, strerror(iRc));
330

331
    iRc |= FifoDestroy(pssSender->psfWaitingAnswers);
332
//    printf("Sender thread FIFO destoyed with iRc %d and error %s\n", iRc, strerror(iRc));
333

Benoit Steiner's avatar
Benoit Steiner committed
334 335 336 337 338 339
    if (!iRc)
      Log(LOG_NOTE, MOD_NAME, "Sender thread destroyed");
    else
      Log(LOG_WARN, MOD_NAME, "Sender thread not cleanly destroyed");
  }
  else
340
    Log(LOG_WARN, MOD_NAME, "Could not destroy sender, none has been created");
Benoit Steiner's avatar
Benoit Steiner committed
341 342 343 344 345 346

  /* No more sender is running */
  pssSender->tid = 0;

  return iRc;
}