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; }
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); }
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); }
//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); }
/** 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); }
/* * 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 }
// 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; }