示例#1
0
static struct watchman_client *make_new_client(w_stm_t stm) {
  struct watchman_client *client;
  pthread_attr_t attr;

  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

  client = calloc(1, derived_client_size);
  if (!client) {
    pthread_attr_destroy(&attr);
    return NULL;
  }
  client->stm = stm;
  w_log(W_LOG_DBG, "accepted client:stm=%p\n", client->stm);

  if (!w_json_buffer_init(&client->reader)) {
    // FIXME: error handling
  }
  if (!w_json_buffer_init(&client->writer)) {
    // FIXME: error handling
  }
  client->ping = w_event_make();
  if (!client->ping) {
    // FIXME: error handling
  }

  derived_client_ctor(client);

  pthread_mutex_lock(&w_client_lock);
  w_ht_set(clients, w_ht_ptr_val(client), w_ht_ptr_val(client));
  pthread_mutex_unlock(&w_client_lock);

  // Start a thread for the client.
  // We used to use libevent for this, but we have
  // a low volume of concurrent clients and the json
  // parse/encode APIs are not easily used in a non-blocking
  // server architecture.
  if (pthread_create(&client->thread_handle, &attr, client_thread, client)) {
    // It didn't work out, sorry!
    pthread_mutex_lock(&w_client_lock);
    w_ht_del(clients, w_ht_ptr_val(client));
    pthread_mutex_unlock(&w_client_lock);
    client_delete(client);
  }

  pthread_attr_destroy(&attr);

  return client;
}
示例#2
0
文件: buffer.c 项目: moul/junk
int		check_read_from_client(t_mgs_client *client, int *size)
{
  if (xioctl(client, client, size))
    return (1);
  if (client->sizein + *size >= BUF_SIZE)
    {
      printf("too long message\n");
      exit(0);
    }
  if (*size == 0)
    {
      client_delete(client);
      return (1);
    }
  return (0);
}
示例#3
0
文件: buffer.c 项目: moul/junk
int		read_from_client(t_mgs_client *client)
{
  int		size;
  int		tmp;

  if (check_read_from_client(client, &size))
    return (1);
  tmp = size;
  if (client->offin + client->sizein + size >= BUF_SIZE)
    tmp = BUF_SIZE - (client->offin + client->sizein);
  if (read(client->fd, client->buffin + client->sizein + client->offin,
	   tmp) < 0 || (tmp != size && read(client->fd, client->buffin,
					    size - tmp) < 0))
    {
      client_delete(client);
      return (1);
    }
  client->sizein += size;
  return (0);
}
示例#4
0
//read data from the client
void pthread_receive_from_client(CLIENT_NODE *p)
{
	int n,socket;
	char buff[50];
	socket = p->sockfd;

	fd_set rdfds;			//define a set of socket that we want to check
	struct timeval tv;		//define a time variable to set timeout
	int ret;				//keep the return value

	while(1)
	{
		if(p->no_check_in > 3)		//it has more than 3 times not checked in
		{
			DBG("\n%d client say goodbye to server\n", p->sockfd);
			break;
		}
		memset(buff,0,sizeof(buff));

		FD_ZERO(&rdfds);
		FD_SET(socket, &rdfds);
		tv.tv_sec = 5;			//set the timeout to about 5.5s
		tv.tv_usec = 500;

		//check if there is info can be read from the set of socket
		ret = select(socket + 1, &rdfds, NULL, NULL, &tv);
		if(ret < 0)
		{
			DBG("\n%d is Error\n", socket);
		}
		else if(ret == 0)
		{
			DBG("\n%d is Out Of Time\n", socket);
		}
		else	//that is ret > 0
		{
			if(FD_ISSET(socket, &rdfds))		//detect whether socket can be read
			{
				n = recv(socket, buff, 8, 0);
				if(n == -1)		//socket error 
				{
					DBG("\n%d socket is error: %s\n", socket, strerror(errno));
					break;
				}
				if(n == 0)		//socket closed normally
				{
					DBG("\n%d socket is closed\n", socket);
					break;
				}

				p->alive = 1;	//receive data successfully, so it is alive

				if(strstr(buff, "0000000$") != NULL)	//so the message is a i-am-alive-message	
				{
					DBG("\n%d received %d from client :%s\n", socket, n, buff);
					continue;	
				}
				else if(is_req_msg(buff, strlen(buff)))
				{
					//definetion and initilize the new message node by the connnected client socket
					//and data from the client and the length of data
					MESSAGE_NODE *new_message_node = (MESSAGE_NODE*)malloc(sizeof(MESSAGE_NODE));
					new_message_node->sockfd = socket;
					new_message_node->data = (char*)malloc(sizeof(char) * 10);
					strcpy(new_message_node->data, buff);
					new_message_node->size = strlen(buff);
					new_message_node->next = NULL;
					
					pthread_mutex_lock(&mutex_head_message);	//lock the gloable variable head_message
					message_insert(head_message, new_message_node);
					pthread_mutex_unlock(&mutex_head_message);	//unlock the gloable variable head_message
					//send to tty	
					int count = tty_send(_tty_fd, buff, strlen(buff));
					DBG("\n%d received %d from client :%s and %d is sended, REQ\n", socket, n, buff, count);
				}
				else
				{
					int count = tty_send(_tty_fd, buff, strlen(buff));
					DBG("\n%d received %d from client :%s and %d is sended\n", socket, n, buff, count);
				}
			}	
		}
	}
	DBG("\n\n%d will be finished at once\n\n", socket);
	client_delete(head, socket);
	close(socket);
	pthread_exit(NULL);
}
示例#5
0
/** Typeless helper function for use as destroy callback
 *
 * @param self pointer to client_t structure
 */
static
void
client_delete_cb(void *self)
{
  client_delete(self);
}
示例#6
0
/*
 *	Find a per-socket client.
 */
RADCLIENT *client_listener_find(const rad_listen_t *listener,
				const fr_ipaddr_t *ipaddr, int src_port)
{
#ifdef WITH_DYNAMIC_CLIENTS
	int rcode;
	REQUEST *request;
	RADCLIENT *created;
#endif
	time_t now;
	RADCLIENT *client;
	RADCLIENT_LIST *clients;
	listen_socket_t *sock;

	rad_assert(listener != NULL);
	rad_assert(ipaddr != NULL);

	sock = listener->data;
	clients = sock->clients;

	/*
	 *	This HAS to have been initialized previously.
	 */
	rad_assert(clients != NULL);

	client = client_find(clients, ipaddr,sock->proto);
	if (!client) {
		char name[256], buffer[128];
					
#ifdef WITH_DYNAMIC_CLIENTS
	unknown:		/* used only for dynamic clients */
#endif

		/*
		 *	DoS attack quenching, but only in daemon mode.
		 *	If they're running in debug mode, show them
		 *	every packet.
		 */
		if (debug_flag == 0) {
			static time_t last_printed = 0;

			now = time(NULL);
			if (last_printed == now) return NULL;
			
			last_printed = now;
		}

		listener->print(listener, name, sizeof(name));

		radlog(L_ERR, "Ignoring request to %s from unknown client %s port %d"
#ifdef WITH_TCP
		       " proto %s"
#endif
		       , name, inet_ntop(ipaddr->af, &ipaddr->ipaddr,
					 buffer, sizeof(buffer)), src_port
#ifdef WITH_TCP
		       , (sock->proto == IPPROTO_UDP) ? "udp" : "tcp"
#endif
		       );
		return NULL;
	}

#ifndef WITH_DYNAMIC_CLIENTS
	return client;		/* return the found client. */
#else

	/*
	 *	No server defined, and it's not dynamic.  Return it.
	 */
	if (!client->client_server && !client->dynamic) return client;

	now = time(NULL);
	
	/*
	 *	It's a dynamically generated client, check it.
	 */
	if (client->dynamic && (src_port != 0)) {
		/*
		 *	Lives forever.  Return it.
		 */
		if (client->lifetime == 0) return client;
		
		/*
		 *	Rate-limit the deletion of known clients.
		 *	This makes them last a little longer, but
		 *	prevents the server from melting down if (say)
		 *	10k clients all expire at once.
		 */
		if (now == client->last_new_client) return client;

		/*
		 *	It's not dead yet.  Return it.
		 */
		if ((client->created + client->lifetime) > now) return client;
		
		/*
		 *	This really puts them onto a queue for later
		 *	deletion.
		 */
		client_delete(clients, client);

		/*
		 *	Go find the enclosing network again.
		 */
		client = client_find(clients, ipaddr, sock->proto);

		/*
		 *	WTF?
		 */
		if (!client) goto unknown;
		if (!client->client_server) goto unknown;

		/*
		 *	At this point, 'client' is the enclosing
		 *	network that configures where dynamic clients
		 *	can be defined.
		 */
		rad_assert(client->dynamic == 0);
	} else {
		/*
		 *	The IP is unknown, so we've found an enclosing
		 *	network.  Enable DoS protection.  We only
		 *	allow one new client per second.  Known
		 *	clients aren't subject to this restriction.
		 */
		if (now == client->last_new_client) goto unknown;
	}

	client->last_new_client = now;

	request = request_alloc();
	if (!request) goto unknown;

	request->listener = listener;
	request->client = client;
	request->packet = rad_recv(listener->fd, 0x02); /* MSG_PEEK */
	if (!request->packet) {				/* badly formed, etc */
		request_free(&request);
		goto unknown;
	}
	request->reply = rad_alloc_reply(request->packet);
	if (!request->reply) {
		request_free(&request);
		goto unknown;
	}
	request->packet->timestamp = request->timestamp;
	request->number = 0;
	request->priority = listener->type;
	request->server = client->client_server;
	request->root = &mainconfig;

	/*
	 *	Run a fake request through the given virtual server.
	 *	Look for FreeRADIUS-Client-IP-Address
	 *	         FreeRADIUS-Client-Secret
	 *		...
	 *
	 *	and create the RADCLIENT structure from that.
	 */
	DEBUG("server %s {", request->server);

	rcode = module_authorize(0, request);

	DEBUG("} # server %s", request->server);

	if (rcode != RLM_MODULE_OK) {
		request_free(&request);
		goto unknown;
	}

	/*
	 *	If the client was updated by rlm_dynamic_clients,
	 *	don't create the client from attribute-value pairs.
	 */
	if (request->client == client) {
		created = client_create(clients, request);
	} else {
		created = request->client;

		/*
		 *	This frees the client if it isn't valid.
		 */
		if (!client_validate(clients, client, created)) goto unknown;
	}
	request_free(&request);

	if (!created) goto unknown;

	return created;
#endif
}
示例#7
0
// The client thread reads and decodes json packets,
// then dispatches the commands that it finds
static void *client_thread(void *ptr)
{
  struct watchman_client *client = ptr;
  struct watchman_event_poll pfd[2];
  struct watchman_client_response *queued_responses_to_send;
  json_t *request;
  json_error_t jerr;
  bool send_ok = true;

  w_stm_set_nonblock(client->stm, true);
  w_set_thread_name("client=%p:stm=%p", client, client->stm);

  client->client_is_owner = w_stm_peer_is_owner(client->stm);

  w_stm_get_events(client->stm, &pfd[0].evt);
  pfd[1].evt = client->ping;

  while (!stopping) {
    // Wait for input from either the client socket or
    // via the ping pipe, which signals that some other
    // thread wants to unilaterally send data to the client

    ignore_result(w_poll_events(pfd, 2, 2000));

    if (stopping) {
      break;
    }

    if (pfd[0].ready) {
      request = w_json_buffer_next(&client->reader, client->stm, &jerr);

      if (!request && errno == EAGAIN) {
        // That's fine
      } else if (!request) {
        // Not so cool
        if (client->reader.wpos == client->reader.rpos) {
          // If they disconnected in between PDUs, no need to log
          // any error
          goto disconected;
        }
        send_error_response(client, "invalid json at position %d: %s",
            jerr.position, jerr.text);
        w_log(W_LOG_ERR, "invalid data from client: %s\n", jerr.text);

        goto disconected;
      } else if (request) {
        client->pdu_type = client->reader.pdu_type;
        dispatch_command(client, request, CMD_DAEMON);
        json_decref(request);
      }
    }

    if (pfd[1].ready) {
      w_event_test_and_clear(client->ping);
    }

    /* de-queue the pending responses under the lock */
    pthread_mutex_lock(&w_client_lock);
    queued_responses_to_send = client->head;
    client->head = NULL;
    client->tail = NULL;
    pthread_mutex_unlock(&w_client_lock);

    /* now send our response(s) */
    while (queued_responses_to_send) {
      struct watchman_client_response *response_to_send =
        queued_responses_to_send;

      if (send_ok) {
        w_stm_set_nonblock(client->stm, false);
        /* Return the data in the same format that was used to ask for it.
         * Don't bother sending any more messages if the client disconnects,
         * but still free their memory.
         */
        send_ok = w_ser_write_pdu(client->pdu_type, &client->writer,
                                  client->stm, response_to_send->json);
        w_stm_set_nonblock(client->stm, true);
      }

      queued_responses_to_send = response_to_send->next;

      json_decref(response_to_send->json);
      free(response_to_send);
    }
  }

disconected:
  w_set_thread_name("NOT_CONN:client=%p:stm=%p", client, client->stm);
  // Remove the client from the map before we tear it down, as this makes
  // it easier to flush out pending writes on windows without worrying
  // about w_log_to_clients contending for the write buffers
  pthread_mutex_lock(&w_client_lock);
  w_ht_del(clients, w_ht_ptr_val(client));
  pthread_mutex_unlock(&w_client_lock);

  client_delete(client);

  return NULL;
}