コード例 #1
0
/* timeout is in milliseconds */
static int wait_for_start(struct bluetooth_data *data, int timeout)
{
	a2dp_state_t state = data->state;
	struct timeval tv;
	struct timespec ts;
	int err = 0;

#ifdef ENABLE_TIMING
	uint64_t begin, end;
	begin = get_microseconds();
#endif

	gettimeofday(&tv, (struct timezone *) NULL);
	ts.tv_sec = tv.tv_sec + (timeout / 1000);
	ts.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000L ) * 1000L;

	pthread_mutex_lock(&data->mutex);
	while (state != A2DP_STATE_STARTED) {
		if (state == A2DP_STATE_NONE)
			__set_command(data, A2DP_CMD_INIT);
		else if (state == A2DP_STATE_INITIALIZED)
			__set_command(data, A2DP_CMD_CONFIGURE);
		else if (state == A2DP_STATE_CONFIGURED) {
			__set_command(data, A2DP_CMD_START);
		}
again:
		err = pthread_cond_timedwait(&data->client_wait, &data->mutex, &ts);
		if (err) {
			/* don't timeout if we're done */
			if (data->state == A2DP_STATE_STARTED) {
				err = 0;
				break;
			}
			if (err == ETIMEDOUT)
				break;
			goto again;
		}

		if (state == data->state)
			goto again;

		state = data->state;

		if (state == A2DP_STATE_NONE) {
			err = ENODEV;
			break;
		}
	}
	pthread_mutex_unlock(&data->mutex);

#ifdef ENABLE_TIMING
	end = get_microseconds();
	print_time("wait_for_start", begin, end);
#endif

	/* pthread_cond_timedwait returns positive errors */
	return -err;
}
コード例 #2
0
static int avdtp_write(struct bluetooth_data *data)
{
	int ret = 0;
	struct rtp_header *header;
	struct rtp_payload *payload;

	uint64_t now;
	long duration = data->frame_duration * data->frame_count;
#ifdef ENABLE_TIMING
	uint64_t begin, end, begin2, end2;
	begin = get_microseconds();
#endif

	header = (struct rtp_header *)data->buffer;
#ifdef TN_JPN_NTT_BT_SCMS-T
	payload = (struct rtp_payload *)(data->buffer + sizeof(*header) + data->sizeof_scms_t);

	memset(data->buffer, 0, sizeof(*header) + sizeof(*payload) + data->sizeof_scms_t);

	if (data->sizeof_scms_t) {
		/*
		 * In theory, this should be setable on the fly to 0x01 to "protect"
		 * the stream and 0x00 to allow capture by remote device. In practice,
		 * all I've ever seem is "protect", or 0x01.
		 */
		data->buffer[sizeof(*header)] = SCMS_T_COPY_NOT_ALLOWED;
	}
#else
        payload = (struct rtp_payload *)(data->buffer + sizeof(*header));

	memset(data->buffer, 0, sizeof(*header) + sizeof(*payload));
#endif
	payload->frame_count = data->frame_count;
	header->v = 2;
	header->pt = 1;
	header->sequence_number = htons(data->seq_num);
	header->timestamp = htonl(data->nsamples);
	header->ssrc = htonl(1);

	data->stream.revents = 0;
#ifdef ENABLE_TIMING
	begin2 = get_microseconds();
#endif
	ret = poll(&data->stream, 1, POLL_TIMEOUT);
#ifdef ENABLE_TIMING
	end2 = get_microseconds();
	print_time("poll", begin2, end2);
#endif
	if (ret == 1 && data->stream.revents == POLLOUT) {
		long ahead = 0;
		now = get_microseconds();

		if (data->next_write) {
			ahead = data->next_write - now;
#ifdef ENABLE_TIMING
			DBG("duration: %ld, ahead: %ld", duration, ahead);
#endif
			if (ahead > 0) {
				/* too fast, need to throttle */
				usleep(ahead);
			}
		} else {
			data->next_write = now;
		}
		if (ahead <= -CATCH_UP_TIMEOUT * 1000) {
			/* fallen too far behind, don't try to catch up */
			VDBG("ahead < %d, reseting next_write timestamp", -CATCH_UP_TIMEOUT * 1000);
			data->next_write = 0;
		} else {
			data->next_write += duration;
		}

#ifdef ENABLE_TIMING
		begin2 = get_microseconds();
#endif
		ret = send(data->stream.fd, data->buffer, data->count, MSG_NOSIGNAL);
#ifdef ENABLE_TIMING
		end2 = get_microseconds();
		print_time("send", begin2, end2);
#endif
		if (ret < 0) {
			/* can happen during normal remote disconnect */
			VDBG("send() failed: %d (errno %s)", ret, strerror(errno));
		}
		if (ret == -EPIPE) {
			bluetooth_close(data);
		}
	} else {
		/* can happen during normal remote disconnect */
		VDBG("poll() failed: %d (revents = %d, errno %s)",
				ret, data->stream.revents, strerror(errno));
		data->next_write = 0;
	}

	/* Reset buffer of data to send */
#ifdef TN_JPN_NTT_BT_SCMS-T
	data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload) + data->sizeof_scms_t;
#else
	data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
#endif
	data->frame_count = 0;
	data->samples = 0;
	data->seq_num++;

#ifdef ENABLE_TIMING
	end = get_microseconds();
	print_time("avdtp_write", begin, end);
#endif
	return 0; /* always return success */
}
コード例 #3
0
int a2dp_write(a2dpData d, const void* buffer, int count)
{
	struct bluetooth_data* data = (struct bluetooth_data*)d;
	uint8_t* src = (uint8_t *)buffer;
	int codesize;
	int err, ret = 0;
	long frames_left = count;
	int encoded;
	unsigned int written;
	const char *buff;
	int did_configure = 0;
#ifdef ENABLE_TIMING
	uint64_t begin, end;
	DBG("********** a2dp_write **********");
	begin = get_microseconds();
#endif

	err = wait_for_start(data, WRITE_TIMEOUT);
	if (err < 0)
		return err;

	codesize = data->codesize;

	while (frames_left >= codesize) {
		/* Enough data to encode (sbc wants 512 byte blocks) */
		encoded = sbc_encode(&(data->sbc), src, codesize,
					data->buffer + data->count,
					sizeof(data->buffer) - data->count,
					&written);
		if (encoded <= 0) {
			ERR("Encoding error %d", encoded);
			goto done;
		}
		VDBG("sbc_encode returned %d, codesize: %d, written: %d\n",
			encoded, codesize, written);

		src += encoded;
		data->count += written;
		data->frame_count++;
		data->samples += encoded;
		data->nsamples += encoded;

		/* No space left for another frame then send */
		if ((data->count + written >= data->link_mtu) ||
				(data->count + written >= BUFFER_SIZE)) {
			VDBG("sending packet %d, count %d, link_mtu %u",
					data->seq_num, data->count,
					data->link_mtu);
			err = avdtp_write(data);
			if (err < 0)
				return err;
		}

		ret += encoded;
		frames_left -= encoded;
	}

	if (frames_left > 0)
		ERR("%ld bytes left at end of a2dp_write\n", frames_left);

done:
#ifdef ENABLE_TIMING
	end = get_microseconds();
	print_time("a2dp_write total", begin, end);
#endif
	return ret;
}
コード例 #4
0
ファイル: init_linux.cpp プロジェクト: eoma/gm-engine
ubyte64 System::get_time()
{
	return (get_microseconds() / 1000);
}
コード例 #5
0
static int avdtp_write(struct bluetooth_data *data)
{
	int ret = 0;
	struct rtp_header *header;
	struct rtp_payload *payload;
	uint64_t now;
	long duration = data->frame_duration * data->frame_count;
#ifdef ENABLE_TIMING
	uint64_t begin, end, begin2, end2;
	begin = get_microseconds();
#endif

	header = (struct rtp_header *)data->buffer;
	payload = (struct rtp_payload *)(data->buffer + sizeof(*header));

	memset(data->buffer, 0, sizeof(*header) + sizeof(*payload));

	payload->frame_count = data->frame_count;
	header->v = 2;
	header->pt = 1;
	header->sequence_number = htons(data->seq_num);
	header->timestamp = htonl(data->nsamples);
	header->ssrc = htonl(1);

	data->stream.revents = 0;
#ifdef ENABLE_TIMING
	begin2 = get_microseconds();
#endif
	ret = poll(&data->stream, 1, POLL_TIMEOUT);
#ifdef ENABLE_TIMING
	end2 = get_microseconds();
	print_time("poll Time Taken", begin2, end2);
#endif
	if (ret == 1 && data->stream.revents == POLLOUT) {
		long ahead = 0;
		now = get_microseconds();

		if (data->next_write) {
			ahead = data->next_write - now;
#ifdef ENABLE_TIMING
			DBG("duration: %ld, ahead: %ld", duration, ahead);
#endif
			if (ahead > 0) {
				/* too fast, need to throttle */
				usleep(ahead);
			}
		} else {
			data->next_write = now;
		}

         //DBG("duration: %ld, ahead: %ld", duration, ahead);

	//DBG("decrease_bitpool %d",decrease_bitpool);
	if(ahead <= -30*1000){
		decrease_bitpool++;
		if(decrease_bitpool > 2 ) {
			DBG("duration: %ld, ahead: %ld", duration, ahead);
			VDBG("calibrating Bitpool Decrease");
			calibrate_bitpool(data,0);
			decrease_bitpool = 0;
			avdtp_good_counter=0; 
		}
	} else if(ahead >= 10000){
		if(data->sbc.bitpool != data->sbc_capabilities.max_bitpool){
		avdtp_good_counter++;	
		if(avdtp_good_counter > 1000){//about 10 secs
		DBG("duration: %ld, ahead: %ld avdtp_good_counter: %ld", duration, ahead, avdtp_good_counter);
		calibrate_bitpool(data,1);
                skip_avdtp_flow_check=0;
		}
		}
		decrease_bitpool = 0;
	
	}



		if (ahead <= -CATCH_UP_TIMEOUT * 1000) {
			/* fallen too far behind, don't try to catch up */
			DBG("ahead < %d, reseting next_write timestamp", -CATCH_UP_TIMEOUT * 1000);
			data->next_write = 0;
		} else {
			data->next_write += duration;
		}

#ifdef ENABLE_TIMING
		begin2 = get_microseconds();
#endif
		pthread_mutex_lock(&data->lock);
		if (data->stream.fd == -1) {
			pthread_mutex_unlock(&data->lock);
			return EBADF;
		} else {
			ret = send(data->stream.fd, data->buffer, data->count, MSG_NOSIGNAL);
		}
		pthread_mutex_unlock(&data->lock);
#ifdef ENABLE_TIMING
		end2 = get_microseconds();
		print_time("send", begin2, end2);
#endif
		if (ret < 0) {
			/* can happen during normal remote disconnect */
			VDBG("send() failed: %d (errno %s)", ret, strerror(errno));
		}
		if (ret == -EPIPE) {
			bluetooth_close(data);
		}
	} else {
		/* can happen during normal remote disconnect */
		VDBG("poll() failed: %d (revents = %d, errno %s)",
				ret, data->stream.revents, strerror(errno));
		data->next_write = 0;
	}

	/* Reset buffer of data to send */
	data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
	data->frame_count = 0;
	data->samples = 0;
	data->seq_num++;

#ifdef ENABLE_TIMING
	end = get_microseconds();
	print_time("avdtp_write", begin, end);
#endif
	return 0; /* always return success */
}
コード例 #6
0
ファイル: liba2dp.c プロジェクト: OmarBizreh/Sliding_XZ
static void a2dp_sig_thread(void *d) {
	struct bluetooth_data *data = d;
	a2dp_state_t state = data->state;
	int err = 0;
	struct timeval tv;
	struct timespec ts;

#ifdef ENABLE_TIMING
	uint64_t begin, end;
	begin = get_microseconds();
#endif
	gettimeofday(&tv, (struct timezone *) NULL);
	ts.tv_sec = tv.tv_sec + (WRITE_TIMEOUT / 1000);
	ts.tv_nsec = (tv.tv_usec + (WRITE_TIMEOUT % 1000) * 1000L ) * 1000L;

	pthread_mutex_lock(&data->mutex);
	while (state != A2DP_STATE_STARTED) {
		if (state == A2DP_STATE_NONE)
			__set_command(data, A2DP_CMD_INIT);
		else if (state == A2DP_STATE_INITIALIZED)
			__set_command(data, A2DP_CMD_CONFIGURE);
		else if (state == A2DP_STATE_CONFIGURED) {
			__set_command(data, A2DP_CMD_START);
		}
again:
		err = pthread_cond_timedwait(&data->client_wait, &data->mutex, &ts);
		if (err) {
			/* don't timeout if we're done */
			if (data->state == A2DP_STATE_STARTED) {
				err = 0;
				break;
			}
			if (err == ETIMEDOUT) {
				DBG(" Time out");
				break;
			}
			goto again;
		}

		if (state == data->state)
			goto again;

		state = data->state;

		if (state == A2DP_STATE_NONE) {
			err = ENODEV;
			break;
		}
	}
	pthread_mutex_unlock(&data->mutex);

#ifdef ENABLE_TIMING
	end = get_microseconds();
	print_time("signalling process took", begin, end);
#endif

	data->signalling_thread = 0;
	DBG("error returned is %d", err);
	/* pthread_cond_timedwait returns positive errors */
	return;
}
コード例 #7
0
my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
                    ulonglong fuzzydate, MYSQL_TIME_STATUS *status)
{
  ulong date[5];
  ulonglong value;
  const char *end=str+length, *end_of_days;
  my_bool found_days,found_hours, neg= 0;
  uint UNINIT_VAR(state);

  my_time_status_init(status);
  for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++)
    length--;
  if (str != end && *str == '-')
  {
    neg=1;
    str++;
    length--;
  }
  if (str == end)
  {
    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    goto err;
  }

  /* Check first if this is a full TIMESTAMP */
  if (length >= 12)
  {                                             /* Probably full timestamp */
    (void) str_to_datetime(str, length, l_time,
                           (fuzzydate & ~TIME_TIME_ONLY) | TIME_DATETIME_ONLY,
                            status);
    if (l_time->time_type >= MYSQL_TIMESTAMP_ERROR)
      return l_time->time_type == MYSQL_TIMESTAMP_ERROR;
    my_time_status_init(status);
  }

  l_time->neg= neg;
  /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
  for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
    value=value*10L + (long) (*str - '0');

  /* Skip all space after 'days' */
  end_of_days= str;
  for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++)
    ;

  found_days=found_hours=0;
  if ((uint) (end-str) > 1 && str != end_of_days &&
      my_isdigit(&my_charset_latin1, *str))
  {                                             /* Found days part */
    date[0]= (ulong) value;
    state= 1;                                   /* Assume next is hours */
    found_days= 1;
  }
  else if ((end-str) > 1 &&  *str == time_separator &&
           my_isdigit(&my_charset_latin1, str[1]))
  {
    date[0]= 0;                                 /* Assume we found hours */
    date[1]= (ulong) value;
    state=2;
    found_hours=1;
    str++;                                      /* skip ':' */
  }
  else
  {
    /* String given as one number; assume HHMMSS format */
    date[0]= 0;
    date[1]= (ulong) (value/10000);
    date[2]= (ulong) (value/100 % 100);
    date[3]= (ulong) (value % 100);
    state=4;
    goto fractional;
  }

  /* Read hours, minutes and seconds */
  for (;;)
  {
    for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
      value=value*10L + (long) (*str - '0');
    date[state++]= (ulong) value;
    if (state == 4 || (end-str) < 2 || *str != time_separator ||
        !my_isdigit(&my_charset_latin1,str[1]))
      break;
    str++;                                      /* Skip time_separator (':') */
  }

  if (state != 4)
  {                                             /* Not HH:MM:SS */
    /* Fix the date to assume that seconds was given */
    if (!found_hours && !found_days)
    {
      bmove_upp((uchar*) (date+4), (uchar*) (date+state),
                sizeof(long)*(state-1));
      bzero((uchar*) date, sizeof(long)*(4-state));
    }
    else
      bzero((uchar*) (date+state), sizeof(long)*(4-state));
  }

fractional:
  /* Get fractional second part */
  if (!status->warnings && str < end && *str == '.')
  {
    uint number_of_fields= 0;
    str++;
    get_microseconds(&date[4], status, &number_of_fields, &str, end);
  }
  else
    date[4]= 0;

  /* Check for exponent part: E<gigit> | E<sign><digit> */
  /* (may occur as result of %g formatting of time value) */
  if ((end - str) > 1 &&
      (*str == 'e' || *str == 'E') &&
      (my_isdigit(&my_charset_latin1, str[1]) ||
       ((str[1] == '-' || str[1] == '+') &&
        (end - str) > 2 &&
        my_isdigit(&my_charset_latin1, str[2]))))
  {
    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    goto err;
  }

  if (internal_format_positions[7] != 255)
  {
    /* Read a possible AM/PM */
    while (str != end && my_isspace(&my_charset_latin1, *str))
      str++;
    if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
    {
      if (str[0] == 'p' || str[0] == 'P')
      {
        str+= 2;
        date[1]= date[1]%12 + 12;
      }
      else if (str[0] == 'a' || str[0] == 'A')
        str+=2;
    }
  }

  /* Integer overflow checks */
  if (date[0] > UINT_MAX || date[1] > UINT_MAX ||
      date[2] > UINT_MAX || date[3] > UINT_MAX ||
      date[4] > UINT_MAX)
  {
    status->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
    goto err;
  }  

  l_time->year=         0;                      /* For protocol::store_time */
  l_time->month=        0;
  l_time->day=          0;
  l_time->hour=         date[1] + date[0] * 24; /* Mix days and hours */
  l_time->minute=       date[2];
  l_time->second=       date[3];
  l_time->second_part=  date[4];
  l_time->time_type= MYSQL_TIMESTAMP_TIME;

  /* Check if the value is valid and fits into MYSQL_TIME range */
  if (check_time_range(l_time, 6, &status->warnings))
    return TRUE;

  /* Check if there is garbage at end of the MYSQL_TIME specification */
  if (str != end)
  {
    do
    {
      if (!my_isspace(&my_charset_latin1,*str))
      {
        status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
        break;
      }
    } while (++str != end);
  }
  return FALSE;

err:
  bzero((char*) l_time, sizeof(*l_time));
  l_time->time_type= MYSQL_TIMESTAMP_ERROR;
  return TRUE;
}
コード例 #8
0
my_bool
str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
                ulonglong flags, MYSQL_TIME_STATUS *status)
{
  const char *end=str+length, *pos;
  uint number_of_fields= 0, digits, year_length, not_zero_date;
  DBUG_ENTER("str_to_datetime");
  bzero(l_time, sizeof(*l_time));

  if (flags & TIME_TIME_ONLY)
  {
    my_bool ret= str_to_time(str, length, l_time, flags, status);
    DBUG_RETURN(ret);
  }

  my_time_status_init(status);

  /* Skip space at start */
  for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++)
    ;
  if (str == end || ! my_isdigit(&my_charset_latin1, *str))
  {
    status->warnings= MYSQL_TIME_WARN_TRUNCATED;
    l_time->time_type= MYSQL_TIMESTAMP_NONE;
    DBUG_RETURN(1);
  }

  /*
    Calculate number of digits in first part.
    If length= 8 or >= 14 then year is of format YYYY.
    (YYYY-MM-DD,  YYYYMMDD, YYYYYMMDDHHMMSS)
  */
  pos= str;
  digits= skip_digits(&pos, end);

  if (pos < end && *pos == 'T') /* YYYYYMMDDHHMMSSThhmmss is supported too */
  {
    pos++;
    digits+= skip_digits(&pos, end);
  }
  if (pos < end && *pos == '.' && digits >= 12) /* YYYYYMMDDHHMMSShhmmss.uuuuuu is supported too */
  {
    pos++;
    skip_digits(&pos, end); // ignore the return value
  }

  if (pos == end)
  {
    /*
      Found date in internal format
      (only numbers like [YY]YYMMDD[T][hhmmss[.uuuuuu]])
    */
    year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
    if (get_digits(&l_time->year, &number_of_fields, &str, end, year_length) 
        || get_digits(&l_time->month, &number_of_fields, &str, end, 2)
        || get_digits(&l_time->day, &number_of_fields, &str, end, 2)
        || get_maybe_T(&str, end)
        || get_digits(&l_time->hour, &number_of_fields, &str, end, 2)
        || get_digits(&l_time->minute, &number_of_fields, &str, end, 2)
        || get_digits(&l_time->second, &number_of_fields, &str, end, 2))
     status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
  }
  else
  {
    const char *start= str;
    if (get_number(&l_time->year, &number_of_fields, &str, end))
      status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    year_length= str - start;

    if (!status->warnings &&
        (get_punct(&str, end)
         || get_number(&l_time->month, &number_of_fields, &str, end)
         || get_punct(&str, end)
         || get_number(&l_time->day, &number_of_fields, &str, end)
         || get_date_time_separator(&number_of_fields, flags, &str, end)
         || get_number(&l_time->hour, &number_of_fields, &str, end)
         || get_punct(&str, end)
         || get_number(&l_time->minute, &number_of_fields, &str, end)
         || get_punct(&str, end)
         || get_number(&l_time->second, &number_of_fields, &str, end)))
      status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
  }

  /* we're ok if date part is correct. even if the rest is truncated */
  if (number_of_fields < 3)
  {
    l_time->time_type= MYSQL_TIMESTAMP_NONE;
    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    DBUG_RETURN(TRUE);
  }

  if (!status->warnings && str < end && *str == '.')
  {
    str++;
    get_microseconds(&l_time->second_part, status,
                     &number_of_fields, &str, end);
  }

  not_zero_date = l_time->year || l_time->month || l_time->day ||
                  l_time->hour || l_time->minute || l_time->second ||
                  l_time->second_part;

  if (year_length == 2 && not_zero_date)
    l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);

  if (l_time->year > 9999 || l_time->month > 12 || l_time->day > 31 ||
      l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59)
  {
    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    goto err;
  }

  if (check_date(l_time, not_zero_date, flags, &status->warnings))
    goto err;

  l_time->time_type= (number_of_fields <= 3 ?
                      MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);

  for (; str != end ; str++)
  {
    if (!my_isspace(&my_charset_latin1,*str))
    {
      status->warnings= MYSQL_TIME_WARN_TRUNCATED;
      break;
    }
  }

  DBUG_RETURN(FALSE);

err:
  bzero((char*) l_time, sizeof(*l_time));
  l_time->time_type= MYSQL_TIMESTAMP_ERROR;
  DBUG_RETURN(TRUE);
}
コード例 #9
0
unsigned int CL_System::get_time()
{
	return (unsigned int) (get_microseconds() / 1000);
}
コード例 #10
0
ファイル: client_thread.c プロジェクト: bramp/threadnetperf
/**
 Creates n client connects to address
 */
void* client_thread(void *data) {

	const struct client_request * const req = data;
	const struct client_request_details * details = req->details;

	// Make a copy of the global settings
	const struct settings settings = *req->settings;

	// The time in microseconds to wait between each send (to limit our bandwidth)
	const unsigned long long time_between_sends = settings.rate> 0 ? 1000000 / settings.rate : 0;
	unsigned long long next_send_time = 0;

	// Array of client sockets
	SOCKET *client = NULL;
	unsigned int clients = 0; // The number of clients
	unsigned int clients_temp = 0; // The number of clients

	SOCKET *c = NULL;

	char *buffer= NULL;

#ifdef USE_EPOLL
	int readFD_epoll = -1;
	struct epoll_event *events = NULL;
#else
	int nfds;

	fd_set readFD;
	fd_set writeFD;
#endif

	assert ( req != NULL );
	assert ( details != NULL );

	// Malloc the client array after we find out how many clients there are
	while (details != NULL) {
		clients += details->n;
		details = details->next;
	}

	if (clients == 0) {
		fprintf(stderr, "%s:%d Must have more than zero clients!\n", __FILE__, __LINE__ );
		goto cleanup;
	}

#ifndef USE_EPOLL
	if ( clients> FD_SETSIZE ) {
		fprintf(stderr, "%s:%d Client thread can have no more than %d connections\n", __FILE__, __LINE__, FD_SETSIZE );
		goto cleanup;
	}
#endif

	client = calloc(clients, sizeof(*client));

	if ( client == NULL ) {
		fprintf(stderr, "%s:%d calloc error\n", __FILE__, __LINE__ );
		goto cleanup;
	}

	// Blank client before we start
	for ( c = client; c < &client[ clients ]; c++)
		*c = INVALID_SOCKET;

	if ( settings.verbose )
		printf("Core %d: Started client thread\n", req->cores);

	if ( connect_connections(&settings, req, client, &clients_temp) ) {
		goto cleanup;
	}

	if ( clients != clients_temp ) {
		fprintf(stderr, "%s:%d Requested number of clients does not match actual clients (%d != %d)\n", __FILE__, __LINE__, clients, clients_temp );
		goto cleanup;
	}

	buffer = malloc( settings.message_size );

	if ( buffer == NULL ) {
		fprintf(stderr, "%s:%d malloc error\n", __FILE__, __LINE__ );
		goto cleanup;
	}

	memset( buffer, BUFFER_FILL, settings.message_size );
#ifdef USE_EPOLL
	readFD_epoll = epoll_create(clients);
	if(readFD_epoll == -1) {
		fprintf(stderr, "%s:%d epoll_create() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) );
		goto cleanup;
	}

	events = calloc( clients, sizeof(*events) );
	if ( events == NULL ) {
		fprintf(stderr, "%s:%d calloc error\n", __FILE__, __LINE__ );
		goto cleanup;
	}
#else
	nfds = (int)*client;
	FD_ZERO ( &readFD );
	FD_ZERO ( &writeFD );
#endif

	// Loop all client sockets
	for (c = client; c < &client [ clients ]; c++) {
		SOCKET s = *c;

#ifdef USE_EPOLL
		struct epoll_event event = {0};

		assert ( s != INVALID_SOCKET );

		event.events = EPOLLIN | EPOLLOUT;
		event.data.fd = s;

		if (epoll_ctl(readFD_epoll, EPOLL_CTL_ADD, s, &event) == -1) {
			fprintf(stderr, "%s:%d epoll() error adding client (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) );
			goto cleanup;
		}
#else
		assert ( s != INVALID_SOCKET );

		// Add them to FD sets
		FD_SET( s, &readFD);
		FD_SET( s, &writeFD);

		if ( (int)s >= nfds )
			nfds = (int)s + 1;

		assert ( FD_ISSET(s, &readFD ) );
		assert ( FD_ISSET(s, &writeFD ) );
#endif
	}

	 // Signal we are ready
	threads_signal_parent ( SIGNAL_READY_TO_GO, settings.threaded_model );

	// Wait for the go
	wait_for_nonzero( &go_mutex, &go_cond, &bGo );

	next_send_time = get_microseconds();

	// Now start the main loop
	while ( bRunning ) {

#ifdef USE_EPOLL
		int i;
		//This has been changed to re-try the epoll if we fail.
		int ready =  epoll_wait_ign_signal(readFD_epoll, events, clients, TRANSFER_TIMEOUT);

		for ( i = 0; i < ready; i++ ) {
			SOCKET s = events[i].data.fd;

			assert ( s != INVALID_SOCKET );

			if (events[i].events & (EPOLLHUP | EPOLLERR)) {
				//fprintf(stderr, "%s:%d epoll() error (%d) %s on socket %d\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) , s);
				closesocket( s );
				continue;
			}

			if( events[i].events & EPOLLIN) {
#else
				struct timeval waittime = {TRANSFER_TIMEOUT / 1000, 0}; // 1 second

				int ret = select_ign_signal(nfds, &readFD, &writeFD, NULL, &waittime);

				if ( ret == 0 )
					fprintf(stderr, "%s:%d select() timeout occured\n", __FILE__, __LINE__ );

				else if ( ret == SOCKET_ERROR ) {
					fprintf(stderr, "%s:%d select() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) );
					goto cleanup;
				}

				// Figure out which sockets have fired
				for (c = client; c < &client [ clients ]; c++ ) {
					SOCKET s = *c;

					assert ( s != INVALID_SOCKET );

					// Speed hack
					if ( ret == 0 ) {
						FD_SET( s, &readFD);
						FD_SET( s, &writeFD);
						continue;
					}

					// Check for reads
					if ( FD_ISSET( s, &readFD) ) {
#endif
						int len = recv_ign_signal( s, buffer, settings.message_size, 0);

						if ( len == SOCKET_ERROR ) {
							if ( ERRNO != ECONNRESET ) {
								fprintf(stderr, "%s:%d recv(%d) error (%d) %s\n", __FILE__, __LINE__, s, ERRNO, strerror(ERRNO) );
								goto cleanup;
							}
						}

#ifndef USE_EPOLL
						ret--;
#endif
						// The socket has closed
						if ( len <= 0 ) {

							if ( settings.verbose )
								printf("  Client: %d Removed client (%d/%d)\n", req->cores, (int)((c - client) / sizeof(*c)) + 1, clients );

#ifndef USE_EPOLL
							// Quickly check if this client was in the write set
							if ( FD_ISSET( s, &writeFD) ) {
								FD_CLR( s, &writeFD );
								ret--;
							}

							// Unset me from the set
							FD_CLR( s, &readFD );

							// Move this back
							move_down ( c, &client[ clients ] );
							c--;

							// Update the nfds
							nfds = (int)highest_socket(client, clients - 1) + 1;
#endif

							// Invalid this client
							closesocket_ign_signal( s );
							clients--;

							// If this is the last client then just give up!
							if ( clients == 0 )
								goto cleanup;

							// This socket is now closed, so lets go back up to the loop
							continue;
						}
#ifndef USE_EPOLL
					} else {
						// Set the socket on this FD, to save us doing it at the beginning of each loop
						FD_SET( s, &readFD);
					}
					// Check if we are ready to write
					if ( FD_ISSET( s, &writeFD) ) {
						ret--;
#else
					}
					if( events[i].events & EPOLLOUT) {
#endif
						// Rate limiting code
						if ( time_between_sends> 0 ) {
							const unsigned long long now = get_microseconds();

							if ( next_send_time > now )
								continue;

							next_send_time += time_between_sends;
						}

						if ( send_ign_signal( s, buffer, settings.message_size, 0 ) == SOCKET_ERROR ) {
							if ( ERRNO != EWOULDBLOCK && ERRNO != EPIPE ) {
								fprintf(stderr, "%s:%d send() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) );
								goto cleanup;
							}
						}
#ifdef USE_EPOLL
					}
#endif
#ifndef USE_EPOLL
						} else {
							// Set the socket on this FD, to save us doing it at the beginning of each loop
							FD_SET( s, &writeFD);
						}
					}
					// We have now looped over each socket, If we are here ret MUST be zero
					assert(ret == 0);
				}
#else
			}