int command_check_hexstring(int argc, char **argv, int optind, int flags) { int ret = EXIT_SUCCESS; int i = optind-1; uint32_t strcrc, crc; long int cast; if(flags & CALC_PRINT_NUMERICAL) cast = (uint32_t) strtol(hexarg, NULL, 10); else cast = (uint32_t) strtol(hexarg, NULL, 16); if((cast == LONG_MIN || cast == LONG_MAX) && errno == ERANGE) cast = 0; strcrc = (uint32_t) cast; while(argv[++i]) { if(check_access_flags_v(argv[i], F_OK | R_OK, 1) != 0) { log_failure(argv[i], "not accessible, not a file or doesn't exist"); ret = EXIT_FAILURE; continue; } if((crc = compute_crc32(argv[i])) == strcrc) log_success(argv[i], "match"); else log_failure(argv[i], "mismatch: %08X is really %08X", strcrc, crc); } return ret; }
static int find_file () { struct parsed_cmd *parsed_get; if (cmd_parse_failed ((parsed_get = cmd_parse (r->cmd, NULL)))) return -1; /* * Checking whether the arguments are valid. If they are, retrieves the * data (stored in the cache) about the file to be downloaded */ if (parsed_get->argc == 1) { if (client_send (r->client, " < get: you need to specify a key\n") < 0) log_failure (log_file, "cr_get: client_send () failed"); goto error; } else { if (strlen (parsed_get->argv[1]) != FILE_KEY_SIZE) { if (client_send (r->client, " < get: hash size is not good, man\n") < 0) log_failure (log_file, "cr_get: client_send () failed"); goto error; } else { sem_wait (&file_cache_lock); file_to_dl = file_cache_get_by_key (file_cache, parsed_get->argv[1]); sem_post (&file_cache_lock); if (!file_to_dl) { if (client_send (r->client, " < get: key not in cache, please list\n") < 0) log_failure (log_file, "cr_get: client_send () failed"); goto error; } sprintf (answer, "< get : seeder is %s:%d\n", file_to_dl->seeders->ip, file_to_dl->seeders->port); if (client_send (r->client, answer) < 0) { log_failure (log_file, "cr_get: client_send () failed"); goto error; } } } cmd_parse_free (parsed_get); if (client_send (r->client, answer) < 0) { log_failure (log_file, "cr_get: client_send () failed"); return -1; } return 0; error: if (parsed_get) cmd_parse_free (parsed_get); return -1; }
int command_list_db(int argc, char **argv, int optind, int flags) { struct DBItem dbi = DBITEM_NULL; struct DBItem *e = NULL; char *p = NULL; int do_free_p = 0; int i = 0; for(i = optind; i < argc; ++i) { DBITEM_SET_NULL(dbi); e = NULL; if(access(argv[i], F_OK | R_OK) != 0 || DB_read(argv[i], &dbi) != 0) { log_failure(argv[i], "doesn't exist or isn't a valid database"); continue; } if(dbi.kbuf == NULL) { log_info(argv[i], "is empty"); continue; } e = &dbi; do { p = e->kbuf; if(flags & USE_REALPATH) p = get_realpath((const char*) e->kbuf, &do_free_p); log_success(argv[i], "%s -> %08X", p, e->crc); if(do_free_p == 1) { free(p); do_free_p = 0; } } while((e = e->next) != NULL); if(dbi.next != NULL) DB_item_free(dbi.next); } return EXIT_SUCCESS; }
int daemon_send (struct daemon *d, const char *msg) { int dest_sock; int nb_sent; int nb_sent_sum; int send_size; // char ending_char; // Log this (see ../util/logger.c to disactivate this) log_send (log_file, msg); dest_sock = d->socket; if (sem_wait (&d->socket_lock) < 0) { log_failure (log_file, "failed to sem_wait socket_lock, error: %s", strerror (errno)); return -1; } // Now the socket is locked for us, let's send! send_size = strlen (msg); // Send the command nb_sent_sum = 0; while (nb_sent_sum < send_size) { nb_sent = send (dest_sock, msg + nb_sent_sum, send_size - nb_sent_sum, 0); if (nb_sent < 0) { log_failure (log_file, "couldn't send to daemon socket, error: %s", strerror (errno)); return -1; } nb_sent_sum += nb_sent; } if (sem_post (&d->socket_lock) < 0) { log_failure (log_file, "failed to sem_post socket_lock, error: %s", strerror (errno)); } return 0; }
/* * Creates a struct file_cache. */ static struct file_cache * file_cache_new (const char *filename, const char *key, file_size_t size, const char *ip, int port) { struct file_cache *file_cache; file_cache = (struct file_cache *)malloc (sizeof (struct file_cache)); if (strlen (filename) > FILE_NAME_SIZE) { log_failure (log_file, "file_cache_new (): Too long filename"); free (file_cache); return NULL; } strncpy (file_cache->filename, filename, FILE_NAME_SIZE + 1); if (strlen (key) != FILE_KEY_SIZE) { log_failure (log_file, "file_cache_new (): Wrong key size"); free (file_cache); return NULL; } strncpy (file_cache->key, key, FILE_KEY_SIZE + 1); file_cache->size = size; file_cache->seeders = (struct seeder *)malloc (sizeof (struct seeder)); strncpy (file_cache->seeders->ip, ip, FILE_IP_SIZE + 1); file_cache->seeders->port = port; file_cache->seeders->next = NULL; if (sem_init (&file_cache->seeders_lock, 0, 1) < 0) { log_failure (log_file, "file_cache_new (): Unable to sem_init"); free (file_cache->seeders); free (file_cache); return NULL; } file_cache->left = NULL; file_cache->right = NULL; return file_cache; }
/* * We silently ignore options/arguments, according to the protocol. */ void * client_request_download (void *arg) { struct client_request *r; struct dl_file *tmp; struct stat stat_buf; char answer[512]; r = (struct client_request *) arg; if (!r) return NULL; sem_wait (&downloads_lock); if (!downloads) { sprintf (answer, "No files are currently being downloaded.\n"); if (client_send (r->client, answer) < 0) { log_failure (log_file, "client_request_download () : client_send () failed"); } sem_post (&downloads_lock); goto out; } for (tmp = downloads; tmp; tmp = tmp->next) { stat (tmp->path, &stat_buf); sprintf (answer, "Downloading file %s %.2f %c %d %d \n", tmp->path, (float) stat_buf.st_size/ (float)tmp->total_size * 100, '%', (int) stat_buf.st_size, (int) tmp->total_size); if (client_send (r->client, answer) < 0) { log_failure (log_file, "client_request_download () : client_send () failed"); } } sem_post (&downloads_lock); out: return NULL; }
int command_check(int argc, char **argv, int optind, int flags) { int ret = EXIT_SUCCESS; int i = optind-1; int ci, ti; uint32_t compcrc, matchcrc; char *string; char results[9]; regmatch_t rmatch; regex_t regex; while(argv[++i]) { if(check_access_flags_v(argv[i], F_OK | R_OK, 1) != 0) { log_info(argv[i], "Inaccessbile file, skipping."); continue; } string = get_basename((char*)argv[i]); compile_regex(®ex, crcregex, REG_ICASE); switch(regexec((const regex_t*) ®ex, string, 1, &rmatch, 0)) { case 0: for(ci = rmatch.rm_so, ti = 0; ci < rmatch.rm_eo; ++ci) results[ti++] = string[ci]; results[ti] = '\0'; break; case REG_NOMATCH: log_info(argv[i], "Does not contain a hexstring, ignoring."); continue; } regfree(®ex); compcrc = compute_crc32(argv[i]); matchcrc = (uint32_t) strtol(results, NULL, 16); if(compcrc == matchcrc) log_success(argv[i], "OK"); else { log_failure(argv[i], "Mismatch: %08X is really %08X", matchcrc, compcrc); ret = EXIT_FAILURE; } } /* while */ return ret; }
int command_merge(int argc, char **argv, int optind, int cmdflags) { char *dbsources[argc-optind+1]; int i, j; int do_truncate = 1; if(cmdflags & APPEND_TO_DB) do_truncate = 0; for(i = optind, j = 0; i < argc; ++i) { dbsources[j++] = argv[i]; } dbsources[j] = NULL; if(DB_merge(dbiofile, (const char**) dbsources, do_truncate) != 0) return EXIT_FAILURE; if(cmdflags & USE_REALPATH) if(DB_make_paths_absolute(dbiofile) != 0) log_failure(dbiofile, "couldn't make file paths absolute"); return EXIT_SUCCESS; }
/* Assume that reported resolution is constant */ static void clock_getres_verify(struct ctx *ctx) { struct timespec sanity; clock_getres_syscall_nofail(CLOCK_ID, &sanity); ctx_start_timer(ctx); while (!test_should_stop(ctx)) { struct timespec kres; struct timespec vres; clock_getres_syscall_nofail(CLOCK_ID, &kres); /* Check assumptions */ if (!timespecs_equal(&kres, &sanity)) { error(EXIT_FAILURE, 0, "clock resolution reported by kernel changed: " "from [%ld, %ld] to [%ld, %ld]", sanity.tv_sec, sanity.tv_nsec, kres.tv_sec, kres.tv_nsec); } if (!vdso_has_clock_getres()) continue; clock_getres_vdso_nofail(CLOCK_ID, &vres); if (!timespecs_equal(&kres, &vres)) { log_failure(ctx, "clock resolutions differ:\n" "\t[%ld, %ld] (kernel)\n" "\t[%ld, %ld] (vDSO)\n", kres.tv_sec, kres.tv_nsec, vres.tv_sec, vres.tv_nsec); } } ctx_cleanup_timer(ctx); }
int command_remove_tag(int argc, char **argv, int optind, int flags) { const char *filename = argv[argc-1]; char *str, *nstr, *p, *q; const char *d; int i; for(i = optind; i < argc; ++i) { check_access_flags(argv[i], F_OK | R_OK | W_OK, 1); str = get_basename((char*)argv[i]); if((nstr = strip_tag((const char*) str, crcregex_stripper)) == NULL) { log_failure(argv[i], "no hexstring found"); return EXIT_FAILURE; } d = (const char*) dirname((char*)argv[i]); p = pathcat(d, (const char*)str); q = pathcat(d, (const char*)nstr); if(rename((const char*) p, (const char*) q) != 0) LERROR(EXIT_FAILURE, errno, "rename() failed"); free(p); free(q); free(nstr); } return EXIT_SUCCESS; }
static void server_stop (int sig) { struct client *c; struct daemon *d; pool_destroy (slow_pool); pool_destroy (fast_pool); pool_destroy (clients_pool); pool_destroy (daemons_pool); (void) sig; log_failure (log_file, "Ok, received a signal"); sleep (2); sem_destroy (&clients_lock); sem_destroy (&daemons_lock); sem_destroy (&file_cache_lock); sem_destroy (&downloads_lock); if (clients) { while (clients) { c = clients->next; client_free (clients); clients = c; } log_success (log_file, "%s : all clients have been freed", __func__); } if (daemons) { while (daemons) { d = daemons->next; daemon_send (daemons, "quit\n"); daemon_free (daemons); daemons = d; } log_success (log_file, "%s : all daemons have been freed", __func__); } if (file_cache) { file_cache_free (file_cache); log_success (log_file, "%s : file cache has been freed", __func__); } if (unlink (prefs->lock_file) < 0) if (log_file) log_failure (log_file, "Could not destroy the lock file"); if (prefs) { conf_free (prefs); log_success (log_file, "%s : Preferences have been freed.", __func__); } if (log_file) { log_success (log_file, "Stopping server, waiting for SIGKILL"); fclose (log_file); } exit (EXIT_SUCCESS); }
void* client_request_get (void *arg) { r = (struct client_request *) arg; struct daemon_list *d_list; struct daemon_list *list_item_to_delete; struct daemon *next_d; int seeder_count; if (!r) return NULL; /* First we find the file in the cache */ if (find_file () < 0) return NULL; /* file_to_dl should now be the good one */ /* Find the daemons owning the file by checking its IP */ if ((d_list = find_daemons ()) != NULL) { if (client_send (r->client, " < no seeder for the requested file. Former seeders must have been disconnected.\n") < 0) log_failure (log_file, "cr_get: client_send () failed"); return NULL; } /* about handling multi-seeders and block-by-block download */ // we know the number of seeders seeder_count = d_list->id; /* FIXME : calculate smartly the blocks to consider, * given : * - number of seeders * - size of file to dl * - a max_size for a block ? Not implemented */ /* loop where we have to post a job for each seeder */ next_d = d_list->daemon; while (next_d != NULL) { // FIXME : act !!!! do something !!! list_item_to_delete = d_list; d_list = d_list->next; free (list_item_to_delete); } /* Sending the "get key begin end" message */ sprintf (answer, "get %s %d %ld\n", file_to_dl->key, 0, file_to_dl->size); if (daemon_send (d, answer) < 0) { log_failure (log_file, "cr_get: could not send the get command"); return NULL; } /* FIXME */ #if 0 sem_wait (&downloads_lock); char *full_path; struct dl_file *f; full_path = malloc (strlen (prefs->shared_folder) + strlen (file_to_dl->filename) + 2); if (!full_path) { log_failure (log_file, "OMG NO MALLOC IS POSSIBLE"); return NULL; } else { sprintf (full_path, "%s/%s", prefs->shared_folder, file_to_dl->filename); } f = dl_file_new (full_path); if (!f) { log_failure (log_file, "SHARED FOLDER : %S", prefs->shared_folder); log_failure (log_file, "f was NULL %s", full_path); } downloads = dl_file_add (downloads, f); if (!downloads) log_failure (log_file, "downlaods was NULL"); else log_failure (log_file, "downloads->path : %s", downloads->path); sem_post (&downloads_lock); #endif return NULL; }
void* daemon_request_list (void *arg) { struct daemon_request *r; char answer[512]; DIR *dir; struct dirent *entry; char entry_full_path[256]; struct stat entry_stat; char *key; /* OKAY, let's say all options/args are silently ignored */ r = (struct daemon_request *)arg; if (!r) return NULL; dir = opendir (prefs->shared_folder); if (dir == NULL) { log_failure (log_file, "daemon_request_list (): Unable to opendir %s", prefs->shared_folder); return NULL; } // Browsing my own files for (entry = readdir (dir); entry != NULL; entry = readdir (dir)) { // Listing all regular files if (entry->d_type == DT_REG) { sprintf (entry_full_path, "%s/%s", prefs->shared_folder, entry->d_name); if (stat (entry_full_path, &entry_stat) < 0) { log_failure (log_file, "daemon_request_list (): can't stat file %s", entry_full_path); continue; } key = get_md5 (entry_full_path); if (!key) continue; sprintf (answer, "file %s %s %d %s:%d\n", entry->d_name, key, (int) entry_stat.st_size, my_ip, prefs->daemon_port); if (daemon_send (r->daemon, answer) < 0) { log_failure (log_file, "daemon_request_list (): failed to send data to daemon"); } free (key); key = NULL; } } if (closedir (dir) < 0) { log_failure (log_file, "daemon_request_list () : can't close shared directory"); return NULL; } return NULL; }
struct file_cache * file_cache_add (struct file_cache *tree, const char *filename, const char *key, file_size_t size, const char *ip, int port) { /* bias determines if we go left or right in the binary tree */ int bias = 0; struct seeder *s; // If the tree is empty, we create it if (!tree) { tree = file_cache_new (filename, key, size, ip, port); if (!tree) { log_failure (log_file, "file_cache_add (): Unable to file_cache_new ()"); return NULL; } } // If the tree isn't empty, recursive call to find the right place else { bias = strcmp (key, tree->key); if (bias < 0) { tree->left = file_cache_add (tree->left, filename, key, size, ip, port); } else if (bias > 0) { tree->right = file_cache_add (tree->right, filename, key, size, ip, port); } /* If a node with the same key already exists */ else { /* Search if the seeder is already registered, if he is, leave */ sem_wait (&tree->seeders_lock); for (s = tree->seeders; s; s = s->next) if (strcmp (s->ip, ip) == 0 && s->port == port) return tree; sem_post (&tree->seeders_lock); /* If the seeder isn't registered, we must add him */ s = (struct seeder *)malloc (sizeof (struct seeder)); if (!s) { log_failure (log_file, "file_cache_add (): Unable to allocate seeder"); return tree; } strcpy (s->ip, ip); s->port = port; sem_wait (&tree->seeders_lock); s->next = tree->seeders; tree->seeders = s; sem_post (&tree->seeders_lock); } } return tree; }
void* daemon_request_ready (void* arg) { struct daemon_request *r; // Parse elements char *key, *delay, *ip, *port, *proto, *begin, *end; /* cmd version: */ int argc; char **argv; int dl_sock; struct sockaddr_in dl_addr; struct file_cache *file; int local_file; int nb_received; file_size_t nb_received_sum; char buffer[BUFFSIZE]; int nb_written; char *full_path; char error_buffer[BUFFSIZE]; r = (struct daemon_request *) arg; if (!r) return NULL; /* * cmd is supposedly: * ready KEY DELAY IP PORT PROTOCOL BEGINNING END */ argv = cmd_to_argc_argv (r->cmd, &argc); if (argc < 8) { cmd_free (argv); sprintf (error_buffer, "error %s: Invalid number of arguments", __FUNCTION__); daemon_send (r->daemon, error_buffer); return NULL; } key = argv[1]; delay = argv[2]; ip = argv[3]; port = argv[4]; proto = argv[5]; begin = argv[6]; end = argv[7]; /* TODO&FIXME: We should use all above arguments */ if ((dl_sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) { log_failure (log_file, "daemon_request_ready (): socket () failed"); return NULL; } dl_addr.sin_family = AF_INET; if (inet_pton (AF_INET, ip, &dl_addr.sin_addr) < 1) { log_failure (log_file, "dr_ready: inet_pton () failed"); return NULL; } // TODO: Verifications on port dl_addr.sin_port = htons (atoi (port)); file = file_cache_get_by_key (file_cache, key); if (!file) { log_failure (log_file, "dr_ready: file_cache_get_by_key () failed"); return NULL; } // TODO: Check if we actually asked for that file // TODO: Check if file already exists /* + 2 for '/' and '\0' */ full_path = (char *)malloc ((strlen (prefs->shared_folder) + strlen (file->filename) + 2) * sizeof (char)); sprintf (full_path, "%s/%s", prefs->shared_folder, file->filename); // FIXME: We should not truncate the file when downloading it by blocks local_file = open (full_path, O_WRONLY | O_TRUNC | O_CREAT, (mode_t)0644); //free (full_path); if (local_file < 0) { log_failure (log_file, "dr_ready: open () failed, error: %s", strerror (errno)); return NULL; } if (connect (dl_sock, (struct sockaddr *)&dl_addr, sizeof (dl_addr)) < 0) { log_failure (log_file, "dr_ready: connect () failed, error: %s", strerror (errno)); return NULL; } /* * Downloading the file */ /* Let's upload the download queue */ struct dl_file *f; f = dl_file_new (full_path, file->size); if (!f) { log_failure (log_file, "struct dl_file is NULL :("); goto out; } sem_wait (&downloads_lock); downloads = dl_file_add (downloads, f); if (!downloads) { log_failure (log_file, "Could not add the file to the download queue\n"); goto out; } sem_post (&downloads_lock); nb_received_sum = 0; // FIXME: nb_received_sum should be compared to end - begin sleep (2); while (nb_received_sum < file->size) { log_failure (log_file, "DBG %d %d", nb_received_sum, file->size); nb_received = recv (dl_sock, buffer, BUFFSIZE, 0); if (nb_received < 0) { log_failure (log_file, "dr_ready: recv () failed"); return NULL; } nb_received_sum += nb_received; while (nb_received) { nb_written = write (local_file, buffer, nb_received); if (nb_written < 0) { log_failure (log_file, "dr_ready: write () failed"); return NULL; } nb_received -= nb_written; } } /* * Releasing the file from the download queue */ sem_wait (&downloads_lock); downloads = dl_file_remove (downloads, f); dl_file_free (f); sem_post (&downloads_lock); log_success (log_file, "dr_ready: Received block completely %s", full_path); close (dl_sock); close (local_file); out: if (full_path) free (full_path); if (argv) cmd_free (argv); return NULL; }
void daemonize (void) { int lock; char str[10]; switch (fork ()) { case -1: exit (1); case 0: fclose (log_file); if (prefs) conf_free (prefs); exit (0); break; default: break; } setsid (); log_success (log_file, "setsid ok"); close (STDIN_FILENO); close (STDOUT_FILENO); close (STDERR_FILENO); log_success (log_file, "Closed stdin, stdout, stderr."); umask (027); log_success (log_file, "Set file permissions to 750."); lock = open (prefs->lock_file, O_RDWR | O_CREAT, 0640); if (lock < 0) { log_failure (log_file, "Failed to open lock file (%s).", prefs->lock_file); } else log_success (log_file, "Opened lock file (%s).", prefs->lock_file); if (lockf (lock, F_TLOCK, 0) < 0) { log_failure (log_file, "Could not lock %s", prefs->lock_file); } sprintf (str, "%d\n", getpid ()); write (lock, str, strlen (str)); if (close (lock) < 0) { log_failure (log_file, "Failed to close LOCK_FILE (%s).", prefs->lock_file); } else log_success (log_file, "Created lock file (%s)", prefs->lock_file); sigset_t mask; sigemptyset (&mask); sigaddset (&mask, SIGCHLD); sigaddset (&mask, SIGTSTP); sigaddset (&mask, SIGTTOU); sigaddset (&mask, SIGTTIN); sigprocmask (SIG_BLOCK, &mask, NULL); struct sigaction on_signal; sigemptyset (&on_signal.sa_mask); on_signal.sa_flags = 0; on_signal.sa_handler = signal_handler; sigaction (SIGHUP, &on_signal, NULL); on_signal.sa_handler = server_stop; sigaction (SIGINT, &on_signal, NULL); sigaction (SIGTERM, &on_signal, NULL); log_success (log_file, "Signals deferred or handled."); }
static void start_server (void) { int client_sd; int daemon_sd; int connected_sd; struct sockaddr_in client_sa; struct sockaddr_in daemon_sa; struct sockaddr_in connected_sa; socklen_t size; fd_set socket_set; int nfds; struct ifreq if_info; struct sockaddr_in *if_addr; char addr[INET_ADDRSTRLEN]; struct client *c; struct daemon *d; struct parsed_cmd *pcmd = NULL; char *ident_msg; int port; char *colon; /* Prepare all the threads */ slow_pool = NULL; fast_pool = NULL; clients_pool = NULL; daemons_pool = NULL; ABORT_IF (!(slow_pool = pool_create (prefs->nb_proc)), "Unable to create slow_pool") ABORT_IF (!(fast_pool = pool_create (prefs->nb_proc)), "Unable to create fast_pool") ABORT_IF (!(clients_pool = pool_create (prefs->max_clients)), "Unable to create clients_pool") ABORT_IF (!(daemons_pool = pool_create (prefs->max_daemons)), "Unable to create daemons_pool") /* Create the shared directory if it does not exist already */ ABORT_IF (create_dir (prefs->shared_folder, (mode_t)0755) < 0, "Unable to create shared directory") /* Initialize global pointers and their semaphores */ clients = NULL; ABORT_IF (sem_init (&clients_lock, 0, 1) < 0, "Unable to sem_init clients_lock") daemons = NULL; ABORT_IF (sem_init (&daemons_lock, 0, 1) < 0, "Unable to sem_init daemons_lock") file_cache = NULL; ABORT_IF (sem_init (&file_cache_lock, 0, 1) < 0, "Unable to sem_init file_cache_lock") list_client = NULL; ABORT_IF (sem_init (&list_lock, 0, 1) < 0, "Unable to sem_init list_lock") downloads = NULL; ABORT_IF (sem_init (&downloads_lock, 0, 1) < 0, "Unable to sem_init download_queue_lock") client_sa.sin_family = AF_INET; client_sa.sin_addr.s_addr = INADDR_ANY; client_sa.sin_port = htons (prefs->client_port); client_sd = socket_init (&client_sa); ABORT_IF (client_sd < 0, "Unable to socket_init client_sd") daemon_sa.sin_family = AF_INET; daemon_sa.sin_addr.s_addr = INADDR_ANY; daemon_sa.sin_port = htons (prefs->daemon_port); daemon_sd = socket_init (&daemon_sa); ABORT_IF (daemon_sd < 0, "Unable to socket_init daemon_sd") #if 1 /* We get our ip */ memcpy (if_info.ifr_name, prefs->interface, strlen (prefs->interface) + 1); if (ioctl (daemon_sd, SIOCGIFADDR, &if_info) == -1) { log_failure (log_file, "Can't get my ip from interface"); log_failure (log_file, "LOL ERRNO : %s\n", strerror (errno)); goto abort; } if_addr = (struct sockaddr_in *)&if_info.ifr_addr; inet_ntop (AF_INET, &if_addr->sin_addr, my_ip, INET_ADDRSTRLEN); log_success (log_file, "Found my IP : %s", my_ip); #endif /* socket_set contains both client_sd and daemon_sd */ FD_ZERO (&socket_set); size = sizeof (connected_sa); nfds = NFDS (client_sd, daemon_sd); for (;;) { /* * It is VERY important to FD_SET at each loop, because select * will FD_UNSET the socket descriptors */ FD_SET (client_sd, &socket_set); FD_SET (daemon_sd, &socket_set); /* Block until a socket is ready to accept */ if (select (nfds, &socket_set, NULL, NULL, NULL) < 0) { log_failure (log_file, "main () : select failed"); } if (FD_ISSET (client_sd, &socket_set)) { if ((connected_sd = (accept (client_sd, (struct sockaddr *) &connected_sa, &size))) < 0) { log_failure (log_file, "Failed to accept incoming connection."); break; } /* Can we handle this client? */ if (client_count () > prefs->max_clients) { socket_sendline (connected_sd, " < Too many clients\n"); goto close_socket; } /* Then, let's handle him */ if (!inet_ntop (AF_INET, &connected_sa.sin_addr, addr, INET_ADDRSTRLEN)) { socket_sendline (connected_sd, " < Oops\n"); goto close_socket; } if (!(c = client_new (connected_sd, addr))) { socket_sendline (connected_sd, " < Sorry pal :(\n"); } pool_queue (clients_pool, handle_client, c); } else if (FD_ISSET (daemon_sd, &socket_set)) { if ((connected_sd = (accept (daemon_sd, (struct sockaddr *) &connected_sa, &size))) < 0) { log_failure (log_file, "Failed to accept incoming connection."); break; } /* Can we handle this daemon? */ if (daemon_count () > prefs->max_daemons) { socket_sendline (connected_sd, " < Too many daemons\n"); goto close_socket; } /* Let's identify him first */ ident_msg = socket_try_getline (connected_sd, IDENTIFICATION_TIMEOUT); if (!ident_msg) { socket_sendline (connected_sd, "error: identification timed out\n"); goto close_socket; } if (cmd_parse_failed ((pcmd = cmd_parse (ident_msg, NULL)))) { pcmd = NULL; goto close_socket; } if (pcmd->argc < 2) goto close_socket; if (strcmp (pcmd->argv[0], "neighbour") != 0) goto close_socket; if (!(colon = strchr (pcmd->argv[1], ':'))) goto close_socket; port = atoi (colon + 1); free (ident_msg); cmd_parse_free (pcmd); pcmd = NULL; if (!inet_ntop (AF_INET, &connected_sa.sin_addr, addr, INET_ADDRSTRLEN)) { socket_sendline (connected_sd, " < Oops\n"); goto close_socket; } /* Now we've got his port, let him go in */ if (!(d = daemon_new (connected_sd, addr, port))) { socket_sendline (connected_sd, " < Sorry pal :(\n"); goto close_socket; } pool_queue (daemons_pool, handle_daemon, d); } else { /* This should never happen : neither client nor daemon!? */ log_failure (log_file, "Unknown connection"); } continue; close_socket: if (pcmd) { cmd_parse_free (pcmd); pcmd = NULL; } close (connected_sd); } abort: if (slow_pool) pool_destroy (slow_pool); if (fast_pool) pool_destroy (fast_pool); if (clients_pool) pool_destroy (clients_pool); if (daemons_pool) pool_destroy (daemons_pool); conf_free (prefs); exit (EXIT_FAILURE); }