char * shmon_callback(shm_packet_t * packet) { shmon_packet_t * shmon_packet = (shmon_packet_t*)packet->dat; switch(shmon_packet->cmd) { case SHMON_CTRL_GRAB_PID: { /* Allocate shell and return its pid */ /* Read the user from shared memory */ char * user = shmon_packet->username; /* See if he is already logged in (through the hashmap) */ if(hashmap_contains(multishell_sessions, user)) { /* return the user's pid instead of the new one (if he's logged in) */ return respond_to_client((int)hashmap_get(multishell_sessions, user)); } else { /* the user is not logged in, spawn new shell */ spawn_shell(shells_forked, user); return respond_to_client(get_pid_from_hash(shells_forked++)); } break; } case SHMON_CTRL_ADD_USR: { /* Add a user to the hashmap */ /* Read the user from shared memory */ char * user = shmon_packet->username; int pid = atoi(shmon_packet->cmd_dat); hashmap_set(multishell_sessions, user, (void*)pid); break; } case SHMON_CTRL_GET_USR: { /* Get a user from the hashmap */ /* Grab process pid from user IF he exists */ /* Read the user from shared memory */ char * user = shmon_packet->username; if(hashmap_contains(multishell_sessions, user)) return respond_to_client((int)hashmap_get(multishell_sessions, user)); else return respond_to_client(-1); break; } case SHMON_CTRL_REDIR: { /* Sends packet to the destination process, causing that process to 'wake up'. */ char packet_dest[SHM_MAX_ID_SIZE]; sprintf(packet_dest, SHMON_CLIENT_LOGIN_FORMAT, atoi(shmon_packet->cmd_dat)); char shm_msg[16] = SHMON_MSG_PROC_WAKE; shm_packet_t * pack = create_packet(shmon_server, packet_dest, SHM_DEV_CLIENT, shm_msg, strlen(shm_msg)); shman_send_to_network_clear(shmon_server, pack, 0); free(pack); break; } } char * ret = malloc(SHM_MAX_PACKET_DAT_SIZE); ret[0] = 1; /* just tells it is finished really. The client won't be expecting data to return, so it's not important what number we put here */ return ret; }
void *serve_loop(void *listenFD) { Request req = {0}; int connectionFD; while (1) { pthread_mutex_lock(&lock); if ((connectionFD = accept_connection((long) listenFD)) == -1) { pthread_mutex_unlock(&lock); continue; } pthread_mutex_unlock(&lock); if (client_request(connectionFD, &req) != 3) goto FREE; respond_to_client(connectionFD, &req); FREE: close(connectionFD); free(req.method); req.method = NULL; free(req.resource); req.resource = NULL; free(req.protocol); req.protocol = NULL; } }
/* * * Function: main() * */ int main(int argc, char *argv[]) { char *program_name = argv[0]; int optc; /* option */ sa_family_t family; /* protocol family */ char *portnum = NULL; /* port number */ int sock_fd; /* socket binded open ports */ int background = 0; /* work in the background if non-zero */ fd_set read_fds; /* list of file descriptor for reading */ int max_read_fd = 0; /* maximum number in the read fds */ FILE *info_fp = stdout; /* FILE pointer to a information file */ int on; /* on/off at an socket option */ int err; /* return value of getaddrinfo */ struct addrinfo hints; /* hints for getaddrinfo() */ struct addrinfo *res; /* pointer to addrinfo */ debug = 0; family = PF_UNSPEC; /* Retrieve the options */ while ((optc = getopt(argc, argv, "f:p:bo:dh")) != EOF) { switch (optc) { case 'f': if (strncmp(optarg, "4", 1) == 0) family = PF_INET; /* IPv4 */ else if (strncmp(optarg, "6", 1) == 0) family = PF_INET6; /* IPv6 */ else { fprintf(stderr, "protocol family should be 4 or 6.\n"); usage(program_name, EXIT_FAILURE); } break; case 'p': { unsigned long int num; num = strtoul(optarg, NULL, 0); if (num < PORTNUMMIN || PORTNUMMAX < num) { fprintf(stderr, "The range of port is from %u to %u\n", PORTNUMMIN, PORTNUMMAX); usage(program_name, EXIT_FAILURE); } portnum = strdup(optarg); } break; case 'b': background = 1; break; case 'o': if ((info_fp = fopen(optarg, "w")) == NULL) { fprintf(stderr, "Cannot open %s\n", optarg); exit(EXIT_FAILURE); } break; case 'd': debug = 1; break; case 'h': usage(program_name, EXIT_SUCCESS); break; default: usage(program_name, EXIT_FAILURE); } } /* Check the family is spefied. */ if (family == PF_UNSPEC) { fprintf(stderr, "protocol family should be specified.\n"); usage(program_name, EXIT_FAILURE); } /* At first, SIGHUP is ignored. */ handler.sa_handler = SIG_IGN; if (sigfillset(&handler.sa_mask) < 0) fatal_error("sigfillset()"); handler.sa_flags = 0; if (sigaction(SIGHUP, &handler, NULL) < 0) fatal_error("sigaction()"); /* Set the hints to addrinfo() */ memset(&hints, '\0', sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_PASSIVE; /* Translate the network and service information of the server */ err = getaddrinfo(NULL, portnum, &hints, &res); if (err) { fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(err)); exit(EXIT_FAILURE); } if (res->ai_next) { fprintf(stderr, "getaddrinfo(): multiple address is found."); exit(EXIT_FAILURE); } /* Create a socket for listening. */ sock_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock_fd < 0) fatal_error("socket()"); #ifdef IPV6_V6ONLY /* Don't accept IPv4 mapped address if the protocol family is IPv6 */ if (res->ai_family == PF_INET6) { on = 1; if (setsockopt (sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int))) fatal_error("setsockopt()"); } #endif /* Enable to reuse the socket */ on = 1; if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int))) fatal_error("setsockopt()"); /* Bind to the local address */ if (bind(sock_fd, res->ai_addr, res->ai_addrlen) < 0) fatal_error("bind()"); freeaddrinfo(res); /* If -b option is specified, work as a daemon */ if (background) if (daemon(0, 0) < 0) fatal_error("daemon()"); /* Output any server information to the information file */ fprintf(info_fp, "PID: %u\n", getpid()); fflush(info_fp); if (info_fp != stdout) if (fclose(info_fp)) fatal_error("fclose()"); /* Catch SIGHUP */ handler.sa_handler = set_signal_flag; if (sigaction(SIGHUP, &handler, NULL) < 0) fatal_error("sigaction()"); /* Loop to wait a client access */ FD_ZERO(&read_fds); FD_SET(sock_fd, &read_fds); max_read_fd = sock_fd; for (;;) { int select_ret; /* return value of select() */ fd_set active_fds; /* list of the active file descriptor */ struct timeval select_timeout; /* timeout for select() */ /* When catch SIGHUP, exit the loop */ if (catch_sighup) break; active_fds = read_fds; select_timeout.tv_sec = 0; /* 0.5 sec */ select_timeout.tv_usec = 500000; select_ret = select(max_read_fd + 1, &active_fds, NULL, NULL, &select_timeout); if (select_ret < 0) { if (catch_sighup) break; else fatal_error("select()"); } else if (select_ret == 0) { continue; } else { if (FD_ISSET(sock_fd, &active_fds)) respond_to_client(sock_fd); } } /* Close the sockets */ if (close(sock_fd)) fatal_error("close()"); exit(EXIT_SUCCESS); }
void serve_clients(struct server *s, struct frame_buffers *fbs, double timeout) { fd_set read_set, write_set; int select_result, sock, client_sock, highest_sock_num = max(s->sock4, s->sock6); struct sockaddr_storage client_addr; socklen_t client_addr_len = sizeof(client_addr); struct client *c; struct timeval timeout_tv; double now; while (timeout > 0) { FD_ZERO(&read_set); FD_ZERO(&write_set); if (s->sock4 >= 0) { FD_SET(s->sock4, &read_set); } if (s->sock6 >= 0) { FD_SET(s->sock6, &read_set); } for (sock = 0; sock < FD_SETSIZE; sock++) { c = s->clients[sock]; if (c != NULL) { FD_SET(c->sock, &read_set); FD_SET(c->sock, &write_set); highest_sock_num = max(highest_sock_num, c->sock); } } double_to_timeval(timeout, &timeout_tv); now = gettime(); if ((select_result = select(highest_sock_num + 1, &read_set, &write_set, NULL, &timeout_tv)) < 0) { serrchk("select() failed"); } if (!select_result) { break; } for (sock = 0; sock <= highest_sock_num; sock++) { // Look over read_set if (FD_ISSET(sock, &read_set)) { if (sock == s->sock4 || sock == s->sock6) { // Accept client if ((client_sock = accept(sock, (struct sockaddr *) &client_addr, &client_addr_len)) < 0) { serrchk("accept() failed"); } add_client(s, client_sock, &client_addr, fbs); continue; } else { c = s->clients[sock]; if (c != NULL) { read_request(s, c, fbs); } } } // Look over write set if (FD_ISSET(sock, &write_set)) { c = s->clients[sock]; if (c != NULL) { respond_to_client(s, c); } } // Prune clinets that are not communicating if ((c = s->clients[sock]) != NULL) { if (now - c->last_communication > KEEP_ALIVE_TIMEOUT) { remove_client(s, c); } } } timeout -= gettime() - now; } }