Example #1
0
int cliser_client(lua_State *L) {
#ifdef USE_CUDA
   // sometimes cutorch is loaded late, this is a good spot to try and register...
   Lcliser_CudaInit(L);
#endif
   const char *host;
   const char *port;
   if (lua_type(L, 1) == LUA_TSTRING) {
      host = lua_tostring(L, 1);
      port = lua_tostring(L, 2);
   } else {
      host = DEFAULT_HOST;
      port = lua_tostring(L, 1);
   }
   socklen_t addrlen = sizeof(struct sockaddr);
   struct sockaddr addr;
   int ret = get_sockaddr(L, host, port, &addr, &addrlen);
   if (ret) return ret;
   struct timeval tv;
   gettimeofday(&tv, NULL);
   uint32_t t = tv.tv_sec + DEFAULT_TIMEOUT_SECONDS;
   int sock = -1;
   while (tv.tv_sec < t) {
      ret = socket(PF_INET, SOCK_STREAM, 0);
      if (ret <= 0) return LUA_HANDLE_ERROR(L, errno);
      sock = ret;
      int value = 1;
      ret = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value));
      if (ret) break;
      ret = connect(sock, &addr, addrlen);
      if (!ret) break;
      close(sock);
      sleep(1);
      gettimeofday(&tv, NULL);
   }
   if (ret) {
      close(sock);
      return LUA_HANDLE_ERROR(L, errno);
   }
   addrlen = sizeof(struct sockaddr);
   struct sockaddr bind_addr;
   ret = getsockname(sock, &bind_addr, &addrlen);
   if (ret) {
      close(sock);
      return LUA_HANDLE_ERROR(L, errno);
   }
   int use_fastpath = can_use_fastpath(L, sock, ((struct sockaddr_in *)&bind_addr)->sin_addr.s_addr, ((struct sockaddr_in *)&addr)->sin_addr.s_addr);
   client_t *client = (client_t *)calloc(1, sizeof(client_t));
   client->sock = sock;
   client->send_rb = ringbuffer_create(SEND_RECV_SIZE);
   client->recv_rb = ringbuffer_create(SEND_RECV_SIZE);
   client->ref_count = 1;
   client->copy_context.use_fastpath = use_fastpath;
   client_t **clientp = (client_t **)lua_newuserdata(L, sizeof(client_t *));
   *clientp = client;
   luaL_getmetatable(L, "ipc.client");
   lua_setmetatable(L, -2);
   return 1;
}
Example #2
0
int main(int argc, char *argv[])
{
    pthread_t pub, sub;
    double u = 0;

    struct ringbuffer *r = ringbuffer_create(6553600, sizeof(entry_t) + 2000);
    struct timeval t[2];

    if (argc > 1)
        MAXSEQ = atoll(argv[1]);

    gettimeofday(&t[0], NULL);
    pthread_create(&pub, NULL, write_thread, r);
    pthread_create(&sub, NULL, read_thread, r);

    pthread_join(pub, NULL);
    printf("join pub\n");

    pthread_join(sub, NULL);
    printf("join sub\n");

    gettimeofday(&t[1], NULL);

    u = (double)t[1].tv_sec + (double)t[1].tv_usec / 1000000 - (double)t[0].tv_sec -
        (double)t[0].tv_usec / 1000000;

    printf("time = %lfs, %lf/s\n", u, MAXSEQ / u);
    ringbuffer_destroy(r);

    return 0;
}
Example #3
0
int map_open(lua_State *L) {
   uint32_t num_threads = lua_tonumber(L, 1);
   if (lua_type(L, 2) != LUA_TFUNCTION) return LUA_HANDLE_ERROR_STR(L, "map arg #2 expected a function");
   map_thread_t *threads = (map_thread_t *)calloc(num_threads, sizeof(map_thread_t));
   int k = lua_gettop(L);
   for (uint32_t i = 0; i < num_threads; i++) {
      threads[i].rb = ringbuffer_create(MAX_ARG_SIZE);
      for (int j = 2; j <= k; j++) {
         int ret = rb_save_with_growth(L, j, threads[i].rb);
         if (ret) return LUA_HANDLE_ERROR(L, ret);
      }
      lua_pushinteger(L, i + 1);
      int ret = rb_save_with_growth(L, k + 1, threads[i].rb);
      if (ret) return LUA_HANDLE_ERROR(L, ret);
      lua_pop(L, 1);
      ret = pthread_create(&threads[i].thread, NULL, thread_func, &threads[i]);
      if (ret) return LUA_HANDLE_ERROR(L, ret);
   }
   map_t *map = (map_t *)lua_newuserdata(L, sizeof(map_t));
   map->num_threads = num_threads;
   map->threads = threads;
   luaL_getmetatable(L, "ipc.map");
   lua_setmetatable(L, -2);
   return 1;
}
Example #4
0
void taskloop_init()
{
    ringbuffer_create(&taskqueue.tasks, (void*)taskqueue.taskdata, sizeof(task_callback), kMAXTASKS);
    taskqueue.flags = 0;

    taskloop_set_sleep(1);
}
Example #5
0
static void workqueue_init_queue(queue_t *queue, size_t size) {
   pthread_mutexattr_t mutex_attr;
   pthread_mutexattr_init(&mutex_attr);
   pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
   pthread_mutex_init(&queue->mutex, &mutex_attr);
   pthread_cond_init(&queue->read_avail_cond, NULL);
   pthread_cond_init(&queue->write_avail_cond, NULL);
   queue->rb = ringbuffer_create(size);
}
Example #6
0
bool JackClient::Attach(const std::string &ClientName) {
    if(m_Attached) return true;

    /* jack_client_new is now deprecated (Oct 2010)
       m_Client = jack_client_new(ClientName.c_str());

       if (!m_Client)
       {
       error("jack server not running? client_new returns %p", m_Client);
       return false;
       } */
    m_Client =
        jack_client_open(ClientName.c_str(),
                         (jack_options_t)(JackNullOption | JackNoStartServer), NULL);
    if(!m_Client) {
        error("jack server not running?", m_Client);
        return false;
    }

    jack_set_process_callback(m_Client, JackClient::Process, this);
    jack_set_sample_rate_callback(m_Client, JackClient::OnSRateChange, 0);
    jack_on_shutdown(m_Client, JackClient::OnJackShutdown, this);

    m_InputPortMap.clear();
    m_OutputPortMap.clear();

    // tell the JACK server that we are ready to roll
    if(jack_activate(m_Client)) {
        error("cannot activate client");
        return false;
    }

    m_Attached = true;

    audio_mix_ring = ringbuffer_create(4096 * 512 * 4);         //1024 not enought, must be the same size_t
    // as buf_fred set up in OggTheoraEncoder::init
    first = ringbuffer_create(4096 * 512 * 4);  //first jack Input ring buffer
    return true;
}
Example #7
0
VideoEncoder::VideoEncoder()
    : Entry(), JSyncThread() {

    initialized = false;
    encbuf = NULL;
    use_audio = false;

    write_to_disk   = false;
    write_to_stream = false;

    filedump_fd = NULL;

    status = NULL;
    audio_kbps = 0;
    video_kbps = 0;
    bytes_encoded = 0;
    m_ElapsedTime = 0;
    m_Streamed = 0;
    enc_y = enc_u = enc_v = NULL;

    fps = new FPS();
    fps->init(25); // default FPS
    // initialize the encoded data pipe
    // TODO: set the size to width * height * 4 * nframes (3-4)
    ringbuffer = ringbuffer_create(1048 * 2096);

    shout_init();
    if((ice = shout_new()) != NULL) {

        if(shout_set_protocol(ice, SHOUT_PROTOCOL_HTTP))
            error("shout_set_protocol: %s", shout_get_error(ice));

        if(shout_set_format(ice, SHOUT_FORMAT_OGG))
            error("shout_set_format: %s", shout_get_error(ice));

        if(shout_set_agent(ice, "FreeJ - freej.dyne.org"))
            error("shout_set_agent: %s", shout_get_error(ice));

        if(shout_set_public(ice, 1))
            error("shout_set_public: %s", shout_get_error(ice));
    }

    func("init picture_yuv for colorspace conversion (avcodec)");
    gettimeofday(&m_OldTime, NULL);

    //uncomment this and beyond to see how long it takes between two frames
    /*  m_OldTime.tv_sec = m_lastTime.tv_sec;
       m_OldTime.tv_usec = m_lastTime.tv_usec;*/
}
Example #8
0
int main(void)
{
	struct ringbuffer *ring_buf;
	pthread_t produce_pid, consume_pid; 

	ring_buf = ringbuffer_create(FIFO_SIZE);
	if (!ring_buf) {
		perror("ringbuffer_create()");
		exit(1);
	}

	printf("multi thread test.......\n");

	produce_pid  = producer_thread((void*)ring_buf);
	consume_pid  = consumer_thread((void*)ring_buf);

	pthread_join(produce_pid, NULL);
	pthread_join(consume_pid, NULL);

	ringbuffer_destroy(ring_buf);

	return 0;
}
Example #9
0
void * DMXThread(void * v_arg)
{
	pthread_t file_thread;
	struct filenames_t filename_data;
	char filename_extension[3];
	ringbuffer_data_t vec[2];
	ssize_t written;
	ssize_t todo;
	ssize_t todo2;
	unsigned char buf[TS_SIZE];
	int     offset = 0;
	ssize_t r = 0;
	struct pollfd pfd = {*(int*)v_arg, POLLIN|POLLERR,0 };
	int pres;

	ringbuffer_t * ringbuf = ringbuffer_create(ringbuffersize);

	filename_data.ringbuffer = ringbuf;

	if (v_arg == &dvrfd)
	{
		filename_data.extension = "ts";
	}
	else
	{
		for (int i = 0; i < MAXPIDS; i++)
			if (v_arg == (&(demuxfd[i])))
				sprintf(filename_extension, "%u", i);
		filename_data.extension = filename_extension;
	}

	pthread_create(&file_thread, 0, FileThread, &filename_data);

	if (v_arg == &dvrfd)
		while (exit_flag == STREAM2FILE_STATUS_RUNNING)
		{
			if ((pres=poll (&pfd, 1, 15000))>0)
			{
				if (!(pfd.revents&POLLIN))
				{
					printf ("PANIC: error reading from demux, bailing out\n");
					exit_flag = STREAM2FILE_STATUS_READ_FAILURE;
				}
				r = read(*(int *)v_arg, &(buf[0]), TS_SIZE);
				if (r > 0)
				{
					offset = sync_byte_offset(&(buf[0]), r);
					if (offset != -1)
						break;
				}
			}
			else if (!pres)
			{
				printf ("[stream2file]: timeout from demux\n");
			}
		}
	else
		offset = 0;

	written = ringbuffer_write(ringbuf, (char *)&(buf[offset]), r - offset);
	// TODO: Retry
	if (written != r - offset) {
		printf("PANIC: wrote less than requested to ringbuffer, written %d, requested %d\n", written, r - offset);
		exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW;
	}
	todo = IN_SIZE - (r - offset);

	/* IN_SIZE > TS_SIZE => todo > 0 */

	while (exit_flag == STREAM2FILE_STATUS_RUNNING)
	{
		ringbuffer_get_write_vector(ringbuf, &(vec[0]));
		todo2 = todo - vec[0].len;
		if (todo2 < 0)
		{
			todo2 = 0;
		}
		else
		{
			if (((size_t)todo2) > vec[1].len)
			{
				printf("PANIC: not enough space in ringbuffer, available %d, needed %d\n", vec[0].len + vec[1].len, todo + todo2);
				exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW;
			}
			todo = vec[0].len;
		}

		while (exit_flag == STREAM2FILE_STATUS_RUNNING)
		{
			if ((pres=poll (&pfd, 1, 15000))>0)
			{
				if (!(pfd.revents&POLLIN))
				{
					printf ("PANIC: error reading from demux, bailing out\n");
					exit_flag = STREAM2FILE_STATUS_READ_FAILURE;
				}
				r = read(*(int *)v_arg, vec[0].buf, todo);
				if (r > 0)
				{
					ringbuffer_write_advance(ringbuf, r);
	
					if (todo == r)
					{
						if (todo2 == 0)
							goto next;
	
						todo = todo2;
						todo2 = 0;
						vec[0].buf = vec[1].buf;
					}
					else
					{
						vec[0].buf += r;
						todo -= r;
					}
				}
			}
			else if (!pres){
				printf ("[stream2file]: timeout reading from demux\n");
				goto next;
			}
		}
		next:
			todo = IN_SIZE;
	}

	if (v_arg == &dvrfd)
		close(*(int *)v_arg);
	else
		unsetPesFilter(*(int *)v_arg);

	pthread_join(file_thread, NULL);

	ringbuffer_free(ringbuf);

	if (v_arg == &dvrfd)
		while (demuxfd_count > 0)
			unsetPesFilter(demuxfd[--demuxfd_count]);

	DEC_BUSY_COUNT;

	if ((v_arg == &dvrfd) || (v_arg == (&(demuxfd[0]))))
	{
		CEventServer eventServer;
		eventServer.registerEvent2(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, "/tmp/neutrino.sock");
		stream2file_status2_t s;
		s.status = exit_flag;
		strncpy(s.dir,dirname(myfilename),100);
		eventServer.sendEvent(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, &s, sizeof(s));
		printf("[stream2file] pthreads exit code: %u\n", exit_flag);
	}

	pthread_exit(NULL);
}
Example #10
0
int
main (int argc, char ** argv) {

	int pid;
	int pids[MAXPIDS];
	char *fname;
	ssize_t written;
	int i;
	pthread_t rcst;
	int fd;

	if (argc < 4 ) {
		dprintf("Usage: streamfile file vpid apid [ pid3 pid4 ... ] (HEX-values without leading 0x!)\n");
		dprintf("file: filename without trailing '.ts'\n");
		return EXIT_FAILURE;
	}

	// set signal handler for clean termination
	signal(SIGTERM, clean_exit);

	buf = (unsigned char *) malloc(IN_SIZE);
	memset(buf, 0x00, IN_SIZE);

	if (buf == NULL) {
		perror("malloc buf");
		return EXIT_FAILURE;
	}

	i = 1;
	while (argv[i][0] == '-') {
		if (!strcmp(argv[i], "-s"))
			silent = 1;
		if (!strcmp(argv[i], "-l"))
			sscanf(argv[++i], "%d", &limit);
		i++;
	}
	if (limit <= 0)
		limit=2;

	fname = argv[i++];
	for (; i < argc; i++) {
		sscanf(argv[i], "%x", &pid);

		if (pid>0x1fff){
			printf ("invalid pid 0x%04x specified\n",pid);
			return EXIT_FAILURE;
		}
		
		pids[demuxfd_count] = pid;

		if ((demuxfd[demuxfd_count] = setPesFilter(pid)) < 0)
			break;

		dprintf("set filter for pid 0x%x\n", pid);

		demuxfd_count++;
	}

	// create and delete temp-file to wakeup the disk from standby
	sprintf(buf, "%s.tmp", fname);
	fd = open(buf, O_SYNC | O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, S_IRUSR | S_IWUSR);
	write(fd, buf, IN_SIZE);
	fdatasync(fd);
	close(fd);
	unlink(buf);

	if ((dvrfd = open(DVRDEV, O_RDONLY)) < 0) {
		free(buf);
		perror ("[streamfile]: open dvr");
		return EXIT_FAILURE;
	}

	ringbuf = ringbuffer_create (RINGBUFFERSIZE);
	pthread_create (&rcst, 0, FileThread, fname);
	
	/* write raw transport stream */
	int offset=0;

	ringbuffer_data_t vec[2];
	ssize_t r=0;
	ssize_t todo;
	ssize_t todo2;

	while (!exit_flag)
	{
		r = read(dvrfd, buf, IN_SIZE);
		if (r > 0)
		{
			offset = sync_byte_offset(buf, r);
			if (offset != -1)
				break;
		}
	}

	written = ringbuffer_write(ringbuf, buf + offset, r - offset);
	// TODO: Retry
	if (written != r - offset) {
		dprintf("PANIC: wrote less than requested to ringbuffer, written %d, requested %d\n", written, r - offset);
		exit_flag = 1;
	}
	todo = IN_SIZE - (r - offset);

	if (todo == 0)
		todo = IN_SIZE;

	while (!exit_flag)
	{
		ringbuffer_get_write_vector(ringbuf, &(vec[0]));
		todo2 = todo - vec[0].len;
		if (todo2 < 0)
		{
			todo2 = 0;
		}
		else
		{
			if (todo2 > vec[1].len)
			{
				dprintf("PANIC: not enough space in ringbuffer, available %d, needed %d\n", vec[0].len + vec[1].len, todo + todo2);
				exit_flag = 1;
			}
			todo = vec[0].len;
		}

		while (!exit_flag)
		{
			r = read(dvrfd, vec[0].buf, todo);
			
			if (r > 0)
			{
				ringbuffer_write_advance(ringbuf, r);

				if (todo == r)
				{
					if (todo2 == 0)
						goto next;

					todo = todo2;
					todo2 = 0;
					vec[0].buf = vec[1].buf;
				}
				else
				{
					vec[0].buf += r;
					todo -= r;
				}
			}
		}
	next:
		todo = IN_SIZE;
	}
	//sleep(1); // give FileThread some time to write remaining content of ringbuffer to file
	//	pthread_kill(rcst, SIGKILL);

	while (demuxfd_count > 0)
		unsetPesFilter(demuxfd[--demuxfd_count]);

	close(dvrfd);

	pthread_join(rcst,NULL);
	
	free(buf);

	ringbuffer_free(ringbuf);

	dprintf("End of main(). All filters are unset now.\n");
	return EXIT_SUCCESS;
}
Example #11
0
void cRecord::DMXThread()
{
	pthread_t         file_thread;
	
	ringbuffer_data_t vec[2];
	ssize_t           written;
	ssize_t           todo = 0;
	ssize_t           todo2;
	unsigned char        buf[TS_SIZE];
	int                offset = 0;
	ssize_t            r = 0;
	struct pollfd       pfd;
	int                pres;

fprintf(stderr, "%s:%s >\n", __FILE__, __FUNCTION__);

        pfd.fd = dvrfd;
        pfd.events = POLLIN|POLLERR;
	pfd.revents = 0;
	
	ringbuffer_t * ringbuf = ringbuffer_create(ringbuffersize);

	if (!ringbuf)
	{
		exit_flag = STREAM2FILE_STATUS_WRITE_OPEN_FAILURE;
		fprintf(stderr, "[stream2file]: error allocating ringbuffer! (out of memory?)\n"); 
	}
	else
		fprintf(stderr, "[stream2file] allocated ringbuffer size: %ld\n", ringbuffer_write_space(ringbuf));

	ringbuffer = ringbuf;

	if (pthread_create(&file_thread, 0, execute_file_thread, this) != 0)
	{
		exit_flag = STREAM2FILE_STATUS_WRITE_OPEN_FAILURE;
		fprintf(stderr, "[stream2file]: error creating file_thread! (out of memory?)\n"); 
	}

	while (exit_flag == STREAM2FILE_STATUS_RUNNING)
	{
		if ((pres=poll (&pfd, 1, 15000))>0)
		{
			if (!(pfd.revents&POLLIN))
			{
				fprintf(stderr, "[stream2file]: PANIC: error reading from demux, bailing out\n");
				exit_flag = STREAM2FILE_STATUS_READ_FAILURE;
			}
			r = read(dvrfd, &(buf[0]), TS_SIZE);
			if (r > 0)
			{
				offset = sync_byte_offset(&(buf[0]), r);
				if (offset != -1)
					break;
			}
		}
		else if (!pres)
		{
			fprintf(stderr, "[stream2file]: timeout from demux\n");
		}
	}

	if (exit_flag == STREAM2FILE_STATUS_RUNNING)
	{
		written = ringbuffer_write(ringbuf, (char *)&(buf[offset]), r - offset);
		// TODO: Retry
		if (written != r - offset) {
			fprintf(stderr, "PANIC: wrote less than requested to ringbuffer, written %d, requested %d\n", written, r - offset);
			exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW;
		}
		todo = IN_SIZE - (r - offset);
	}

	/* IN_SIZE > TS_SIZE => todo > 0 */

	while (exit_flag == STREAM2FILE_STATUS_RUNNING)
	{
		ringbuffer_get_write_vector(ringbuf, &(vec[0]));
		todo2 = todo - vec[0].len;
		if (todo2 < 0)
		{
			todo2 = 0;
		}
		else
		{
			if (((size_t)todo2) > vec[1].len)
			{
				fprintf(stderr, "PANIC: not enough space in ringbuffer, available %d, needed %d\n", vec[0].len + vec[1].len, todo + todo2);
				exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW;
			}
			todo = vec[0].len;
		}

		while (exit_flag == STREAM2FILE_STATUS_RUNNING)
		{
			if ((pres=poll (&pfd, 1, 5000))>0)
			{
				if (!(pfd.revents&POLLIN))
				{
					fprintf(stderr, "PANIC: error reading from demux, bailing out\n");
					exit_flag = STREAM2FILE_STATUS_READ_FAILURE;
				}
				r = read(dvrfd, vec[0].buf, todo);
				if (r > 0)
				{
					ringbuffer_write_advance(ringbuf, r);
	
					if (todo == r)
					{
						if (todo2 == 0)
							goto next;
	
						todo = todo2;
						todo2 = 0;
						vec[0].buf = vec[1].buf;
					}
					else
					{
						vec[0].buf += r;
						todo -= r;
					}
				}
			}
			else if (!pres){
				fprintf(stderr, "[stream2file]: timeout reading from demux\n");
				exit_flag = STREAM2FILE_STATUS_READ_FAILURE;
			}
		}
		next:
			todo = IN_SIZE;
	}

	close(dvrfd);

	pthread_join(file_thread, NULL);

	if (ringbuf)
		ringbuffer_free(ringbuf);

	while (demuxfd_count > 0)
		unsetPesFilter(demuxfd[--demuxfd_count]);

#ifdef needed
//fixme: do we need it?
	CEventServer eventServer;
	eventServer.registerEvent2(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, "/tmp/neutrino.sock");
	stream2file_status2_t s;
	s.status = exit_flag;
	strncpy(s.filename,basename(myfilename),512);
	s.filename[511] = '\0';
	strncpy(s.dir,dirname(myfilename),100);
	s.dir[99] = '\0';
	eventServer.sendEvent(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, &s, sizeof(s));
	fprintf(stderr, "[stream2file]: pthreads exit code: %i, dir: '%s', filename: '%s' myfilename: '%s'\n", exit_flag, s.dir, s.filename, myfilename);
#endif

fprintf(stderr, "%s:%s <\n", __FILE__, __FUNCTION__);
	pthread_exit(NULL);
}
Example #12
0
int cliser_server_clients(lua_State *L) {
   server_t *server = (server_t *)lua_touserdata(L, 1);
   uint32_t wait;
   const char *tag;
   int fi;
   int invert_order;
   if (lua_type(L, 2) == LUA_TFUNCTION) {
      wait = 0;
      fi = 2;
      if (lua_type(L, 3) == LUA_TSTRING) {
         tag = luaL_optstring(L, 3, NULL);
         invert_order = luaL_optinteger(L, 4, 0);
      } else {
         tag = NULL;
         invert_order = luaL_optinteger(L, 3, 0);
      }
   } else {
      wait = luaL_checkint(L, 2);
      if (lua_type(L, 3) != LUA_TFUNCTION) return LUA_HANDLE_ERROR_STR(L, "expected a callback function as argument #3");
      fi = 3;
      tag = NULL;
      invert_order = 0;
   }
   while (wait > server->num_clients) {
      struct sockaddr addr;
      socklen_t addrlen = sizeof(addr);
      int ret = accept(server->sock, &addr, &addrlen);
      if (ret <= 0) return LUA_HANDLE_ERROR(L, errno);
      int sock = ret;
      int value = 1;
      ret = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value));
      if (ret) return LUA_HANDLE_ERROR(L, errno);
      int use_fastpath = can_use_fastpath(L, sock, server->ip_address, ((struct sockaddr_in *)&addr)->sin_addr.s_addr);
      client_t *client = (client_t *)calloc(1, sizeof(client_t));
      client->sock = sock;
      client->send_rb = ringbuffer_create(SEND_RECV_SIZE);
      client->recv_rb = ringbuffer_create(SEND_RECV_SIZE);
      client->copy_context.use_fastpath = use_fastpath;
      insert_client(server, client);
   }
   client_t **clients = alloca(server->num_clients * sizeof(client_t*));
   client_t *client = server->clients;
   uint32_t i = 0;
   while (client) {
      if (!tag || (client->tag && strcmp(tag, client->tag) == 0)) {
         clients[i] = client;
         i++;
      }
      client = client->next;
   }
   if (invert_order) {
      qsort(clients, i, sizeof(client_t*), compare_clients_inverted);
   } else {
      qsort(clients, i, sizeof(client_t*), compare_clients);
   }
   for (uint32_t j = 0; j < i; j++) {
      lua_pushvalue(L, fi);
      server_client_t *server_client = (server_client_t *)lua_newuserdata(L, sizeof(server_client_t));
      server_client->server = server;
      server_client->client = clients[j];
      luaL_getmetatable(L, "ipc.server.client");
      lua_setmetatable(L, -2);
      lua_call(L, 1, 0);
      server_client->server = NULL;
      server_client->client = NULL;
   }
   lua_pushinteger(L, i);
   return 1;
}