int main(int argc, char *argv[]) { pid_t pid; int i, n; static pstring servicesf = CONFIGFILE; char buf[12]; TimeInit(); setup_logging(argv[0],True); charset_initialise(); lp_load(servicesf,False,False,False); message_init(); if (argc != 3) { fprintf(stderr, "%s: Usage - %s pid count\n", argv[0], argv[0]); exit(1); } pid = atoi(argv[1]); n = atoi(argv[2]); message_register(MSG_PONG, pong_message); for (i=0;i<n;i++) { message_send_pid(pid, MSG_PING, NULL, 0, True); } while (pong_count < i) { message_dispatch(); msleep(1); } /* Now test that the duplicate filtering code works. */ pong_count = 0; safe_strcpy(buf, "1234567890", sizeof(buf)-1); for (i=0;i<n;i++) { message_send_pid(getpid(), MSG_PING, NULL, 0, False); message_send_pid(getpid(), MSG_PING, buf, 11, False); } for (i=0;i<n;i++) { message_dispatch(); msleep(1); } if (pong_count != 2) { fprintf(stderr, "Duplicate filter failed (%d).\n", pong_count); exit(1); } return (0); }
static void wait_replies(BOOL multiple_replies) { time_t start_time = time(NULL); /* Wait around a bit. This is pretty disgusting - we have to busy-wait here as there is no nicer way to do it. */ do { message_dispatch(); if (num_replies > 0 && !multiple_replies) break; sleep(1); } while (timeout - (time(NULL) - start_time) > 0); }
void main() { /* init OS wrapper */ heap_size=0xffff - (word)&heap; /* calc heap size */ register_interfaces(); yx=(yx_t *)query_interface("yx"); /* init buddy */ buddy_init(); /* main loop */ while (TRUE) { buddy_harvest_events(); message_dispatch(); } }
static void wait_replies(BOOL multiple_replies) { time_t start_time = 0; /* Wait around a bit. This is pretty disgusting - we have to busy-wait here as there is no nicer way to do it. */ do { start_time = time(NULL); message_dispatch(); if (num_replies > 0 && !multiple_replies) break; do sleep(1); while ((5 + start_time - time(NULL)) > 0 && num_replies == 0); if (num_replies > 0 && !multiple_replies) break; } while (1); }
static void process(void) { BOOL run_election; BOOL no_subnets; while( True ) { time_t t = time(NULL); /* Check for internal messages */ message_dispatch(); /* * Check all broadcast subnets to see if * we need to run an election on any of them. * (nmbd_elections.c) */ run_election = check_elections(); /* * Read incoming UDP packets. * (nmbd_packets.c) */ if(listen_for_packets(run_election)) return; /* * Handle termination inband. */ if (got_sig_term) { got_sig_term = 0; terminate(); } /* * Process all incoming packets * read above. This calls the success and * failure functions registered when response * packets arrrive, and also deals with request * packets from other sources. * (nmbd_packets.c) */ run_packet_queue(); /* * Run any elections - initiate becoming * a local master browser if we have won. * (nmbd_elections.c) */ run_elections(t); /* * Send out any broadcast announcements * of our server names. This also announces * the workgroup name if we are a local * master browser. * (nmbd_sendannounce.c) */ announce_my_server_names(t); /* * Send out any LanMan broadcast announcements * of our server names. * (nmbd_sendannounce.c) */ announce_my_lm_server_names(t); /* * If we are a local master browser, periodically * announce ourselves to the domain master browser. * This also deals with syncronising the domain master * browser server lists with ourselves as a local * master browser. * (nmbd_sendannounce.c) */ announce_myself_to_domain_master_browser(t); /* * Fullfill any remote announce requests. * (nmbd_sendannounce.c) */ announce_remote(t); /* * Fullfill any remote browse sync announce requests. * (nmbd_sendannounce.c) */ browse_sync_remote(t); /* * Scan the broadcast subnets, and WINS client * namelists and refresh any that need refreshing. * (nmbd_mynames.c) */ refresh_my_names(t); /* * Scan the subnet namelists and server lists and * expire thos that have timed out. * (nmbd.c) */ expire_names_and_servers(t); /* * Write out a snapshot of our current browse list into * the browse.dat file. This is used by smbd to service * incoming NetServerEnum calls - used to synchronise * browse lists over subnets. * (nmbd_serverlistdb.c) */ write_browse_list(t, False); /* * If we are a domain master browser, we have a list of * local master browsers we should synchronise browse * lists with (these are added by an incoming local * master browser announcement packet). Expire any of * these that are no longer current, and pull the server * lists from each of these known local master browsers. * (nmbd_browsesync.c) */ dmb_expire_and_sync_browser_lists(t); /* * Check that there is a local master browser for our * workgroup for all our broadcast subnets. If one * is not found, start an election (which we ourselves * may or may not participate in, depending on the * setting of the 'local master' parameter. * (nmbd_elections.c) */ check_master_browser_exists(t); /* * If we are configured as a logon server, attempt to * register the special NetBIOS names to become such * (WORKGROUP<1c> name) on all broadcast subnets and * with the WINS server (if used). If we are configured * to become a domain master browser, attempt to register * the special NetBIOS name (WORKGROUP<1b> name) to * become such. * (nmbd_become_dmb.c) */ add_domain_names(t); /* * If we are a WINS server, do any timer dependent * processing required. * (nmbd_winsserver.c) */ initiate_wins_processing(t); /* * If we are a domain master browser, attempt to contact the * WINS server to get a list of all known WORKGROUPS/DOMAINS. * This will only work to a Samba WINS server. * (nmbd_browsesync.c) */ if (lp_enhanced_browsing()) collect_all_workgroup_names_from_wins_server(t); /* * Go through the response record queue and time out or re-transmit * and expired entries. * (nmbd_packets.c) */ retransmit_or_expire_response_records(t); /* * check to see if any remote browse sync child processes have completed */ sync_check_completion(); /* * regularly sync with any other DMBs we know about */ if (lp_enhanced_browsing()) sync_all_dmbs(t); /* * clear the unexpected packet queue */ clear_unexpected(t); /* * Reload the services file if we got a sighup. */ if(reload_after_sighup) { DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) ); msg_reload_nmbd_services(MSG_SMB_CONF_UPDATED, pid_to_procid(0), (void*) &no_subnets, 0, NULL); if(no_subnets) return; reload_after_sighup = 0; } /* check for new network interfaces */ if(reload_interfaces(t)) return; /* free up temp memory */ lp_TALLOC_FREE(); } }
static void process_loop(void) { /* We'll be doing this a lot */ while (1) { struct winbindd_cli_state *state; fd_set r_fds, w_fds; int maxfd, listen_sock, listen_priv_sock, selret; struct timeval timeout; /* Handle messages */ message_dispatch(); /* refresh the trusted domain cache */ rescan_trusted_domains(); /* Free up temporary memory */ lp_talloc_free(); main_loop_talloc_free(); /* Initialise fd lists for select() */ listen_sock = open_winbindd_socket(); listen_priv_sock = open_winbindd_priv_socket(); if (listen_sock == -1 || listen_priv_sock == -1) { perror("open_winbind_socket"); exit(1); } maxfd = MAX(listen_sock, listen_priv_sock); FD_ZERO(&r_fds); FD_ZERO(&w_fds); FD_SET(listen_sock, &r_fds); FD_SET(listen_priv_sock, &r_fds); timeout.tv_sec = WINBINDD_ESTABLISH_LOOP; timeout.tv_usec = 0; if (opt_dual_daemon) { maxfd = dual_select_setup(&w_fds, maxfd); } /* Set up client readers and writers */ state = winbindd_client_list(); while (state) { /* Dispose of client connection if it is marked as finished */ if (state->finished) { struct winbindd_cli_state *next = state->next; remove_client(state); state = next; continue; } /* Select requires we know the highest fd used */ if (state->sock > maxfd) maxfd = state->sock; /* Add fd for reading */ if (state->read_buf_len != sizeof(state->request)) FD_SET(state->sock, &r_fds); /* Add fd for writing */ if (state->write_buf_len) FD_SET(state->sock, &w_fds); state = state->next; } /* Call select */ selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout); if (selret == 0) continue; if ((selret == -1 && errno != EINTR) || selret == 0) { /* Select error, something is badly wrong */ perror("select"); exit(1); } /* Create a new connection if listen_sock readable */ if (selret > 0) { if (opt_dual_daemon) { dual_select(&w_fds); } if (FD_ISSET(listen_sock, &r_fds)) { while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) { DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n", WINBINDD_MAX_SIMULTANEOUS_CLIENTS)); if (!remove_idle_client()) { DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n", WINBINDD_MAX_SIMULTANEOUS_CLIENTS)); break; } } /* new, non-privileged connection */ new_connection(listen_sock, False); } if (FD_ISSET(listen_priv_sock, &r_fds)) { while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) { DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n", WINBINDD_MAX_SIMULTANEOUS_CLIENTS)); if (!remove_idle_client()) { DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n", WINBINDD_MAX_SIMULTANEOUS_CLIENTS)); break; } } /* new, privileged connection */ new_connection(listen_priv_sock, True); } /* Process activity on client connections */ for (state = winbindd_client_list(); state; state = state->next) { /* Data available for reading */ if (FD_ISSET(state->sock, &r_fds)) { /* Read data */ winbind_client_read(state); /* * If we have the start of a * packet, then check the * length field to make sure * the client's not talking * Mock Swedish. */ if (state->read_buf_len >= sizeof(uint32) && *(uint32 *) &state->request != sizeof(state->request)) { DEBUG(0,("process_loop: Invalid request size from pid %lu: %d bytes sent, should be %ld\n", (unsigned long)state->request.pid, *(uint32 *) &state->request, (unsigned long)sizeof(state->request))); DEBUGADD(0, ("This usually means that you are running old wbinfo, pam_winbind or libnss_winbind clients\n")); remove_client(state); break; } /* A request packet might be complete */ if (state->read_buf_len == sizeof(state->request)) { winbind_process_packet(state); } } /* Data available for writing */ if (FD_ISSET(state->sock, &w_fds)) client_write(state); } } #if 0 winbindd_check_cache_size(time(NULL)); #endif /* Check signal handling things */ if (do_sigterm) terminate(); if (do_sighup) { DEBUG(3, ("got SIGHUP\n")); msg_reload_services(MSG_SMB_CONF_UPDATED, (pid_t) 0, NULL, 0); do_sighup = False; } if (do_sigusr2) { print_winbindd_status(); do_sigusr2 = False; } } }
/**************************************************************************** do command ****************************************************************************/ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) { int i, n, v; int mtype; BOOL retval=False; int debuglevel_class[DBGC_LAST]; mtype = parse_type(msg_name); if (mtype == -1) { fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name); return(False); } switch (mtype) { case MSG_DEBUG: if (!params || !params[0]) { fprintf(stderr,"MSG_DEBUG needs a parameter\n"); return(False); } ZERO_ARRAY(debuglevel_class); if (!debug_parse_params(params, debuglevel_class)) { fprintf(stderr, "MSG_DEBUG error. Expected <class name>:level\n"); return(False); } else send_message(dest, MSG_DEBUG, debuglevel_class, sizeof(debuglevel_class), False); break; case MSG_PROFILE: if (!params || !params[0]) { fprintf(stderr,"MSG_PROFILE needs a parameter\n"); return(False); } if (strequal(params[0], "off")) { v = 0; } else if (strequal(params[0], "count")) { v = 1; } else if (strequal(params[0], "on")) { v = 2; } else if (strequal(params[0], "flush")) { v = 3; } else { fprintf(stderr, "MSG_PROFILE parameter must be off, count, on, or flush\n"); return(False); } send_message(dest, MSG_PROFILE, &v, sizeof(int), False); break; case MSG_FORCE_ELECTION: if (!strequal(dest, "nmbd")) { fprintf(stderr,"force-election can only be sent to nmbd\n"); return(False); } send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False); break; case MSG_REQ_PROFILELEVEL: if (!profilelevel_registered) { message_register(MSG_PROFILELEVEL, profilelevel_function); profilelevel_registered = True; } got_level = False; retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True); if (retval) { timeout_start = time(NULL); while (!got_level) { message_dispatch(); if ((time(NULL) - timeout_start) > MAX_WAIT) { fprintf(stderr,"profilelevel timeout\n"); break; } } } break; case MSG_REQ_DEBUGLEVEL: if (!debuglevel_registered) { message_register(MSG_DEBUGLEVEL, debuglevel_function); debuglevel_registered = True; } got_level = False; retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True); if (retval) { timeout_start = time(NULL); while (!got_level) { message_dispatch(); if ((time(NULL) - timeout_start) > MAX_WAIT) { fprintf(stderr,"debuglevel timeout\n"); break; } } } break; case MSG_PRINTER_NOTIFY: if (!strequal(dest, "smbd")) { fprintf(stderr,"printer-notify can only be sent to smbd\n"); return(False); } if (!params || !params[0]) { fprintf(stderr, "printer-notify needs a printer name\n"); return (False); } { char msg[8 + sizeof(fstring)+4]; SIVAL(msg,0,PRINTER_CHANGE_ALL); SIVAL(msg,4,0); fstrcpy(&msg[8], params[0]); SIVAL(msg,8+strlen(params[0])+1, PRINTER_MESSAGE_DRIVER); retval = send_message(dest, MSG_PRINTER_NOTIFY, msg, 8 + strlen(params[0]) + 1 + 4, False); } break; case MSG_SMB_FORCE_TDIS: if (!strequal(dest, "smbd")) { fprintf(stderr,"close-share can only be sent to smbd\n"); return(False); } if (!params || !params[0]) { fprintf(stderr, "close-share needs a share name or '*'\n"); return (False); } retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0], strlen(params[0]) + 1, False); break; case MSG_PING: if (!pong_registered) { message_register(MSG_PONG, pong_function); pong_registered = True; } if (!params || !params[0]) { fprintf(stderr,"MSG_PING needs a parameter\n"); return(False); } n = atoi(params[0]); pong_count = 0; for (i=0;i<n;i++) { if (iparams > 1) retval = send_message(dest, MSG_PING, params[1], strlen(params[1]) + 1, True); else retval = send_message(dest, MSG_PING, NULL, 0, True); if (retval == False) break; } if (retval) { timeout_start = time(NULL); while (pong_count < n) { message_dispatch(); if ((time(NULL) - timeout_start) > MAX_WAIT) { fprintf(stderr,"PING timeout\n"); break; } } } break; } return (True); }
static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_ports) { int num_interfaces = iface_count(); int num_sockets = 0; int fd_listenset[FD_SETSIZE]; fd_set listen_set; int s; int maxfd = 0; int i; char *ports; if (!is_daemon) { return open_sockets_inetd(); } #ifdef HAVE_ATEXIT { static int atexit_set; if(atexit_set == 0) { atexit_set=1; atexit(killkids); } } #endif #ifndef _XBOX /* Stop zombies */ CatchChild(); #endif FD_ZERO(&listen_set); /* use a reasonable default set of ports - listing on 445 and 139 */ if (!smb_ports) { ports = lp_smb_ports(); if (!ports || !*ports) { ports = smb_xstrdup(SMB_PORTS); } else { ports = smb_xstrdup(ports); } } else { ports = smb_xstrdup(smb_ports); } if (lp_interfaces() && lp_bind_interfaces_only()) { /* We have been given an interfaces line, and been told to only bind to those interfaces. Create a socket per interface and bind to only these. */ /* Now open a listen socket for each of the interfaces. */ for(i = 0; i < num_interfaces; i++) { struct in_addr *ifip = iface_n_ip(i); fstring tok; const char *ptr; if(ifip == NULL) { DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i)); continue; } for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) { unsigned port = atoi(tok); if (port == 0) { continue; } s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True); if(s == -1) return False; /* ready to listen */ set_socket_options(s,"SO_KEEPALIVE"); set_socket_options(s,user_socket_options); /* Set server socket to non-blocking for the accept. */ set_blocking(s,False); if (listen(s, SMBD_LISTEN_BACKLOG) == -1) { DEBUG(0,("listen: %s\n",strerror(errno))); close(s); return False; } FD_SET(s,&listen_set); maxfd = MAX( maxfd, s); num_sockets++; if (num_sockets >= FD_SETSIZE) { DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n")); return False; } } } } else { /* Just bind to 0.0.0.0 - accept connections from anywhere. */ fstring tok; const char *ptr; num_interfaces = 1; for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) { unsigned port = atoi(tok); if (port == 0) continue; /* open an incoming socket */ s = open_socket_in(SOCK_STREAM, port, 0, interpret_addr(lp_socket_address()),True); if (s == -1) return(False); /* ready to listen */ #ifndef _XBOX set_socket_options(s,"SO_KEEPALIVE"); #endif set_socket_options(s,user_socket_options); /* Set server socket to non-blocking for the accept. */ set_blocking(s,False); if (listen(s, SMBD_LISTEN_BACKLOG) == -1) { DEBUG(0,("open_sockets_smbd: listen: %s\n", strerror(errno))); close(s); return False; } fd_listenset[num_sockets] = s; FD_SET(s,&listen_set); maxfd = MAX( maxfd, s); num_sockets++; if (num_sockets >= FD_SETSIZE) { DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n")); return False; } } } SAFE_FREE(ports); /* Listen to messages */ message_register(MSG_SMB_SAM_SYNC, msg_sam_sync); message_register(MSG_SMB_SAM_REPL, msg_sam_repl); message_register(MSG_SHUTDOWN, msg_exit_server); message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed); message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated); #ifdef DEVELOPER message_register(MSG_SMB_INJECT_FAULT, msg_inject_fault); #endif /* now accept incoming connections - forking a new process for each incoming connection */ DEBUG(2,("waiting for a connection\n")); while (1) { fd_set lfds; int num; /* Free up temporary memory from the main smbd. */ lp_TALLOC_FREE(); /* Ensure we respond to PING and DEBUG messages from the main smbd. */ message_dispatch(); memcpy((char *)&lfds, (char *)&listen_set, sizeof(listen_set)); num = sys_select(maxfd+1,&lfds,NULL,NULL,NULL); if (num == -1 && errno == EINTR) { if (got_sig_term) { exit_server_cleanly(NULL); } /* check for sighup processing */ if (reload_after_sighup) { change_to_root_user(); DEBUG(1,("Reloading services after SIGHUP\n")); reload_services(False); reload_after_sighup = 0; } continue; } /* check if we need to reload services */ check_reload(time(NULL)); /* Find the sockets that are read-ready - accept on these. */ for( ; num > 0; num--) { struct sockaddr addr; socklen_t in_addrlen = sizeof(addr); s = -1; for(i = 0; i < num_sockets; i++) { if(FD_ISSET(fd_listenset[i],&lfds)) { s = fd_listenset[i]; /* Clear this so we don't look at it again. */ FD_CLR(fd_listenset[i],&lfds); break; } } smbd_set_server_fd(accept(s,&addr,&in_addrlen)); if (smbd_server_fd() == -1 && errno == EINTR) continue; if (smbd_server_fd() == -1) { DEBUG(0,("open_sockets_smbd: accept: %s\n", strerror(errno))); continue; } /* Ensure child is set to blocking mode */ set_blocking(smbd_server_fd(),True); if (smbd_server_fd() != -1 && interactive) { #ifdef _XBOX xb_IncClientCount(); #endif return True; } if (allowable_number_of_smbd_processes() && smbd_server_fd() != -1 && sys_fork()==0) { /* Child code ... */ /* close the listening socket(s) */ for(i = 0; i < num_sockets; i++) close(fd_listenset[i]); /* close our standard file descriptors */ close_low_fds(False); am_parent = 0; set_socket_options(smbd_server_fd(),"SO_KEEPALIVE"); set_socket_options(smbd_server_fd(),user_socket_options); /* this is needed so that we get decent entries in smbstatus for port 445 connects */ set_remote_machine_name(get_peer_addr(smbd_server_fd()), False); /* Reset the state of the random * number generation system, so * children do not get the same random * numbers as each other */ set_need_random_reseed(); /* tdb needs special fork handling - remove CLEAR_IF_FIRST flags */ if (tdb_reopen_all(1) == -1) { DEBUG(0,("tdb_reopen_all failed.\n")); smb_panic("tdb_reopen_all failed."); } return True; } /* The parent doesn't need this socket */ close(smbd_server_fd()); /* Sun May 6 18:56:14 2001 [email protected]: Clear the closed fd info out of server_fd -- and more importantly, out of client_fd in util_sock.c, to avoid a possible getpeername failure if we reopen the logs and use %I in the filename. */ smbd_set_server_fd(-1); /* Force parent to check log size after * spawning child. Fix from * [email protected]. The * parent smbd will log to logserver.smb. It * writes only two messages for each child * started/finished. But each child writes, * say, 50 messages also in logserver.smb, * begining with the debug_count of the * parent, before the child opens its own log * file logserver.client. In a worst case * scenario the size of logserver.smb would be * checked after about 50*50=2500 messages * (ca. 100kb). * */ force_check_log_size(); } /* end for num */ } /* end while 1 */ /* NOTREACHED return True; */ }
int main(int argc, char *argv[]) { struct event_context *evt_ctx; struct messaging_context *msg_ctx; pid_t pid; int i, n; char buf[12]; load_case_tables(); setup_logging(argv[0],True); lp_load(get_dyn_CONFIGFILE(),False,False,False,True); if (!(evt_ctx = event_context_init(NULL)) || !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) { fprintf(stderr, "could not init messaging context\n"); exit(1); } if (argc != 3) { fprintf(stderr, "%s: Usage - %s pid count\n", argv[0], argv[0]); exit(1); } pid = atoi(argv[1]); n = atoi(argv[2]); messaging_register(msg_ctx, NULL, MSG_PONG, pong_message); for (i=0; i<n; i++) { messaging_send(msg_ctx, pid_to_procid(pid), MSG_PING, &data_blob_null); } while (pong_count < i) { message_dispatch(msg_ctx); smb_msleep(1); } /* Now test that the duplicate filtering code works. */ pong_count = 0; safe_strcpy(buf, "1234567890", sizeof(buf)-1); for (i=0; i<n; i++) { messaging_send(msg_ctx, pid_to_procid(getpid()), MSG_PING, &data_blob_null); messaging_send_buf(msg_ctx, pid_to_procid(getpid()), MSG_PING, (uint8 *)buf, 11); } for (i=0; i<n; i++) { message_dispatch(msg_ctx); smb_msleep(1); } if (pong_count != 2) { fprintf(stderr, "Duplicate filter failed (%d).\n", pong_count); } /* Speed testing */ pong_count = 0; { struct timeval tv = timeval_current(); size_t timelimit = n; size_t ping_count = 0; printf("Sending pings for %d seconds\n", (int)timelimit); while (timeval_elapsed(&tv) < timelimit) { if(NT_STATUS_IS_OK(messaging_send_buf( msg_ctx, pid_to_procid(pid), MSG_PING, (uint8 *)buf, 11))) ping_count++; if(NT_STATUS_IS_OK(messaging_send( msg_ctx, pid_to_procid(pid), MSG_PING, &data_blob_null))) ping_count++; while (ping_count > pong_count + 20) { message_dispatch(msg_ctx); } } printf("waiting for %d remaining replies (done %d)\n", (int)(ping_count - pong_count), pong_count); while (timeval_elapsed(&tv) < 30 && pong_count < ping_count) { message_dispatch(msg_ctx); } if (ping_count != pong_count) { fprintf(stderr, "ping test failed! received %d, sent " "%d\n", pong_count, (int)ping_count); } printf("ping rate of %.0f messages/sec\n", (ping_count+pong_count)/timeval_elapsed(&tv)); } return (0); }