Esempio n. 1
0
static void init(void) {
  main_init();
  count_down_init();
  sched_init();
  selector_init();
}
Esempio n. 2
0
int main(int argc, char *argv[])
{
    unsigned int loop;
    int newfd;
    tunala_world_t world;
    tunala_item_t *t_item;
    const char *proxy_ip;
    unsigned short proxy_port;
    /* Overridables */
    const char *proxyhost = def_proxyhost;
    const char *listenhost = def_listenhost;
    unsigned int max_tunnels = def_max_tunnels;
    const char *cacert = def_cacert;
    const char *cert = def_cert;
    const char *key = def_key;
    const char *dcert = def_dcert;
    const char *dkey = def_dkey;
    const char *engine_id = def_engine_id;
    int server_mode = def_server_mode;
    int flipped = def_flipped;
    const char *cipher_list = def_cipher_list;
    const char *dh_file = def_dh_file;
    const char *dh_special = def_dh_special;
    int tmp_rsa = def_tmp_rsa;
    int ctx_options = def_ctx_options;
    int verify_mode = def_verify_mode;
    unsigned int verify_depth = def_verify_depth;
    int out_state = def_out_state;
    unsigned int out_verify = def_out_verify;
    int out_totals = def_out_totals;
    int out_conns = def_out_conns;

/* Parse command-line arguments */
 next_arg:
    argc--;
    argv++;
    if (argc > 0) {
        if (strcmp(*argv, "-listen") == 0) {
            if (argc < 2)
                return usage("-listen requires an argument", 0);
            argc--;
            argv++;
            listenhost = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-proxy") == 0) {
            if (argc < 2)
                return usage("-proxy requires an argument", 0);
            argc--;
            argv++;
            proxyhost = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-maxtunnels") == 0) {
            if (argc < 2)
                return usage("-maxtunnels requires an argument", 0);
            argc--;
            argv++;
            if (!parse_max_tunnels(*argv, &max_tunnels))
                return 1;
            goto next_arg;
        } else if (strcmp(*argv, "-cacert") == 0) {
            if (argc < 2)
                return usage("-cacert requires an argument", 0);
            argc--;
            argv++;
            if (strcmp(*argv, "NULL") == 0)
                cacert = NULL;
            else
                cacert = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-cert") == 0) {
            if (argc < 2)
                return usage("-cert requires an argument", 0);
            argc--;
            argv++;
            if (strcmp(*argv, "NULL") == 0)
                cert = NULL;
            else
                cert = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-key") == 0) {
            if (argc < 2)
                return usage("-key requires an argument", 0);
            argc--;
            argv++;
            if (strcmp(*argv, "NULL") == 0)
                key = NULL;
            else
                key = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-dcert") == 0) {
            if (argc < 2)
                return usage("-dcert requires an argument", 0);
            argc--;
            argv++;
            if (strcmp(*argv, "NULL") == 0)
                dcert = NULL;
            else
                dcert = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-dkey") == 0) {
            if (argc < 2)
                return usage("-dkey requires an argument", 0);
            argc--;
            argv++;
            if (strcmp(*argv, "NULL") == 0)
                dkey = NULL;
            else
                dkey = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-engine") == 0) {
            if (argc < 2)
                return usage("-engine requires an argument", 0);
            argc--;
            argv++;
            engine_id = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-server") == 0) {
            if (argc < 2)
                return usage("-server requires an argument", 0);
            argc--;
            argv++;
            if (!parse_server_mode(*argv, &server_mode))
                return 1;
            goto next_arg;
        } else if (strcmp(*argv, "-flipped") == 0) {
            if (argc < 2)
                return usage("-flipped requires an argument", 0);
            argc--;
            argv++;
            if (!parse_server_mode(*argv, &flipped))
                return 1;
            goto next_arg;
        } else if (strcmp(*argv, "-cipher") == 0) {
            if (argc < 2)
                return usage("-cipher requires an argument", 0);
            argc--;
            argv++;
            cipher_list = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-dh_file") == 0) {
            if (argc < 2)
                return usage("-dh_file requires an argument", 0);
            if (dh_special)
                return usage("cannot mix -dh_file with " "-dh_special", 0);
            argc--;
            argv++;
            dh_file = *argv;
            goto next_arg;
        } else if (strcmp(*argv, "-dh_special") == 0) {
            if (argc < 2)
                return usage("-dh_special requires an argument", 0);
            if (dh_file)
                return usage("cannot mix -dh_file with " "-dh_special", 0);
            argc--;
            argv++;
            if (!parse_dh_special(*argv, &dh_special))
                return 1;
            goto next_arg;
        } else if (strcmp(*argv, "-no_tmp_rsa") == 0) {
            tmp_rsa = 0;
            goto next_arg;
        } else if (strcmp(*argv, "-no_ssl2") == 0) {
            ctx_options |= SSL_OP_NO_SSLv2;
            goto next_arg;
        } else if (strcmp(*argv, "-no_ssl3") == 0) {
            ctx_options |= SSL_OP_NO_SSLv3;
            goto next_arg;
        } else if (strcmp(*argv, "-no_tls1") == 0) {
            ctx_options |= SSL_OP_NO_TLSv1;
            goto next_arg;
        } else if (strcmp(*argv, "-v_peer") == 0) {
            verify_mode |= SSL_VERIFY_PEER;
            goto next_arg;
        } else if (strcmp(*argv, "-v_strict") == 0) {
            verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
            goto next_arg;
        } else if (strcmp(*argv, "-v_once") == 0) {
            verify_mode |= SSL_VERIFY_CLIENT_ONCE;
            goto next_arg;
        } else if (strcmp(*argv, "-v_depth") == 0) {
            if (argc < 2)
                return usage("-v_depth requires an argument", 0);
            argc--;
            argv++;
            if (!parse_verify_depth(*argv, &verify_depth))
                return 1;
            goto next_arg;
        } else if (strcmp(*argv, "-out_state") == 0) {
            out_state = 1;
            goto next_arg;
        } else if (strcmp(*argv, "-out_verify") == 0) {
            if (argc < 2)
                return usage("-out_verify requires an argument", 0);
            argc--;
            argv++;
            if (!parse_verify_level(*argv, &out_verify))
                return 1;
            goto next_arg;
        } else if (strcmp(*argv, "-out_totals") == 0) {
            out_totals = 1;
            goto next_arg;
        } else if (strcmp(*argv, "-out_conns") == 0) {
            out_conns = 1;
            goto next_arg;
        } else if ((strcmp(*argv, "-h") == 0) ||
                   (strcmp(*argv, "-help") == 0) ||
                   (strcmp(*argv, "-?") == 0)) {
            fprintf(stderr, "%s\n", helpstring);
            return 0;
        } else
            return usage(*argv, 1);
    }
    /* Run any sanity checks we want here */
    if (!cert && !dcert && server_mode)
        fprintf(stderr, "WARNING: you are running an SSL server without "
                "a certificate - this may not work!\n");

    /* Initialise network stuff */
    if (!ip_initialise())
        return err_str0("ip_initialise failed");
    /* Create the SSL_CTX */
    if ((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id,
                                            cacert, cert, key, dcert, dkey,
                                            cipher_list, dh_file, dh_special,
                                            tmp_rsa, ctx_options, out_state,
                                            out_verify, verify_mode,
                                            verify_depth)) == NULL)
        return err_str1("initialise_ssl_ctx(engine_id=%s) failed",
                        (engine_id == NULL) ? "NULL" : engine_id);
    if (engine_id)
        fprintf(stderr, "Info, engine '%s' initialised\n", engine_id);
    /* Create the listener */
    if ((world.listen_fd = ip_create_listener(listenhost)) == -1)
        return err_str1("ip_create_listener(%s) failed", listenhost);
    fprintf(stderr, "Info, listening on '%s'\n", listenhost);
    if (!ip_parse_address(proxyhost, &proxy_ip, &proxy_port, 0))
        return err_str1("ip_parse_address(%s) failed", proxyhost);
    fprintf(stderr, "Info, proxying to '%s' (%d.%d.%d.%d:%d)\n", proxyhost,
            (int)proxy_ip[0], (int)proxy_ip[1],
            (int)proxy_ip[2], (int)proxy_ip[3], (int)proxy_port);
    fprintf(stderr, "Info, set maxtunnels to %d\n", (int)max_tunnels);
    fprintf(stderr, "Info, set to operate as an SSL %s\n",
            (server_mode ? "server" : "client"));
    /* Initialise the rest of the stuff */
    world.tunnels_used = world.tunnels_size = 0;
    world.tunnels = NULL;
    world.server_mode = server_mode;
    selector_init(&world.selector);

/* We're ready to loop */
 main_loop:
    /* Should we listen for *new* tunnels? */
    if (world.tunnels_used < max_tunnels)
        selector_add_listener(&world.selector, world.listen_fd);
    /* We should add in our existing tunnels */
    for (loop = 0; loop < world.tunnels_used; loop++)
        selector_add_tunala(&world.selector, world.tunnels + loop);
    /* Now do the select */
    switch (selector_select(&world.selector)) {
    case -1:
        if (errno != EINTR) {
            fprintf(stderr, "selector_select returned a " "badness error.\n");
            goto shouldnt_happen;
        }
        fprintf(stderr, "Warn, selector interrupted by a signal\n");
        goto main_loop;
    case 0:
        fprintf(stderr, "Warn, selector_select returned 0 - signal?" "?\n");
        goto main_loop;
    default:
        break;
    }
    /* Accept new connection if we should and can */
    if ((world.tunnels_used < max_tunnels)
        && (selector_get_listener(&world.selector, world.listen_fd, &newfd) ==
            1)) {
        /* We have a new connection */
        if (!tunala_world_new_item(&world, newfd, proxy_ip,
                                   proxy_port, flipped))
            fprintf(stderr, "tunala_world_new_item failed\n");
        else if (out_conns)
            fprintf(stderr, "Info, new tunnel opened, now up to "
                    "%d\n", world.tunnels_used);
    }
    /*
     * Give each tunnel its moment, note the while loop is because it makes
     * the logic easier than with "for" to deal with an array that may shift
     * because of deletes.
     */
    loop = 0;
    t_item = world.tunnels;
    while (loop < world.tunnels_used) {
        if (!tunala_item_io(&world.selector, t_item)) {
            /*
             * We're closing whether for reasons of an error or a natural
             * close. Don't increment loop or t_item because the next item is
             * moving to us!
             */
            if (!out_totals)
                goto skip_totals;
            fprintf(stderr, "Tunnel closing, traffic stats follow\n");
            /* Display the encrypted (over the network) stats */
            fprintf(stderr, io_stats_dirty,
                    buffer_total_in(state_machine_get_buffer
                                    (&t_item->sm, SM_DIRTY_IN)),
                    buffer_total_out(state_machine_get_buffer
                                     (&t_item->sm, SM_DIRTY_OUT)));
            /*
             * Display the local (tunnelled) stats. NB: Data we *receive* is
             * data sent *out* of the state_machine on its 'clean' side.
             * Hence the apparent back-to-front OUT/IN mixup here :-)
             */
            fprintf(stderr, io_stats_clean,
                    buffer_total_out(state_machine_get_buffer
                                     (&t_item->sm, SM_CLEAN_OUT)),
                    buffer_total_in(state_machine_get_buffer
                                    (&t_item->sm, SM_CLEAN_IN)));
 skip_totals:
            tunala_world_del_item(&world, loop);
            if (out_conns)
                fprintf(stderr, "Info, tunnel closed, down to %d\n",
                        world.tunnels_used);
        } else {
            /* Move to the next item */
            loop++;
            t_item++;
        }
    }
    goto main_loop;
    /* Should never get here */
 shouldnt_happen:
    abort();
    return 1;
}
Esempio n. 3
0
/* Creates the rubinius object universe from scratch. */
void cpu_bootstrap(STATE) {
  OBJECT cls, obj, tmp, tmp2;
  int i;

  /* Class is created first by hand, and twittle to setup the internal
     recursion. */
  cls = NEW_OBJECT(Qnil, CLASS_FIELDS);
  cls->klass = cls;
  class_set_instance_fields(cls, I2N(CLASS_FIELDS));
  class_set_has_ivars(cls, Qtrue);
  class_set_object_type(cls, I2N(ClassType));
  cls->obj_type = ClassType;
  
  BC(class) = cls;
  obj = _object_basic_class(state, Qnil);
  BC(object) = obj;
  BC(module) = _module_basic_class(state, obj);
  class_set_superclass(cls, BC(module));
  BC(metaclass) = _metaclass_basic_class(state, cls);
  class_set_object_type(BC(metaclass), I2N(MetaclassType));
  
  BC(tuple) = _tuple_basic_class(state, obj);
  BC(hash) =  _hash_basic_class(state, obj);
  BC(lookuptable) = _lookuptable_basic_class(state, obj);
  BC(methtbl) = _methtbl_basic_class(state, BC(lookuptable));
  
  object_create_metaclass(state, obj, cls);
  object_create_metaclass(state, BC(module), object_metaclass(state, obj));
  object_create_metaclass(state, BC(class), object_metaclass(state, BC(module)));
  
  object_create_metaclass(state, BC(tuple), (OBJECT)0);
  object_create_metaclass(state, BC(hash), (OBJECT)0);
  object_create_metaclass(state, BC(lookuptable), (OBJECT)0);
  object_create_metaclass(state, BC(methtbl), (OBJECT)0);
  
  module_setup_fields(state, object_metaclass(state, obj));
  module_setup_fields(state, object_metaclass(state, BC(module)));
  module_setup_fields(state, object_metaclass(state, BC(class)));
  module_setup_fields(state, object_metaclass(state, BC(tuple)));
  module_setup_fields(state, object_metaclass(state, BC(hash)));
  module_setup_fields(state, object_metaclass(state, BC(lookuptable)));
  module_setup_fields(state, object_metaclass(state, BC(methtbl)));
  BC(symbol) = _symbol_class(state, obj);
  BC(array) = _array_class(state, obj);
  BC(bytearray) = _bytearray_class(state, obj);
  BC(string) = _string_class(state, obj);
  BC(symtbl) = _symtbl_class(state, obj);
  BC(cmethod) = _cmethod_class(state, obj);
  BC(io) = _io_class(state, obj);
  BC(blokenv) = _blokenv_class(state, obj);
  BC(icache) = _icache_class(state, obj);
  BC(staticscope) = _staticscope_class(state, obj);
 
  class_set_object_type(BC(bytearray), I2N(ByteArrayType));
  class_set_object_type(BC(string), I2N(StringType));
  class_set_object_type(BC(methtbl), I2N(MTType));
  class_set_object_type(BC(tuple), I2N(TupleType));
  class_set_object_type(BC(hash), I2N(HashType));
  class_set_object_type(BC(lookuptable), I2N(LookupTableType));
  
  /* The symbol table */
  state->global->symbols = symtbl_new(state);
  
  module_setup(state, obj, "Object");
  module_setup(state, cls, "Class");
  module_setup(state, BC(module), "Module");
  module_setup(state, BC(metaclass), "MetaClass");
  module_setup(state, BC(symbol), "Symbol");
  module_setup(state, BC(tuple), "Tuple");
  module_setup(state, BC(array), "Array");
  module_setup(state, BC(bytearray), "ByteArray");
  module_setup(state, BC(hash), "Hash");
  module_setup(state, BC(lookuptable), "LookupTable");
  module_setup(state, BC(string), "String");
  module_setup(state, BC(symtbl), "SymbolTable");
  module_setup(state, BC(methtbl), "MethodTable");
  module_setup(state, BC(cmethod), "CompiledMethod");
  module_setup(state, BC(io), "IO");
  module_setup(state, BC(blokenv), "BlockEnvironment");
  module_setup(state, BC(icache), "InlineCache");
  module_setup(state, BC(staticscope), "StaticScope");
 
  class_set_object_type(BC(array), I2N(ArrayType));
  class_set_object_type(BC(cmethod), I2N(CMethodType));
  class_set_object_type(BC(blokenv), I2N(BlockEnvType));
    
  rbs_const_set(state, obj, "Symbols", state->global->symbols);
  BC(nil_class) = rbs_class_new(state, "NilClass", 0, obj);
  BC(true_class) = rbs_class_new(state, "TrueClass", 0, obj);
  BC(false_class) = rbs_class_new(state, "FalseClass", 0, obj);
  tmp = rbs_class_new(state, "Numeric", 0, obj);
  tmp2 = rbs_class_new(state, "Integer", 0, tmp);
  BC(fixnum_class) = rbs_class_new(state, "Fixnum", 0, tmp2);
  class_set_object_type(BC(fixnum_class), I2N(FixnumType));
  
  BC(bignum) = rbs_class_new(state, "Bignum", 0, tmp2);
  class_set_object_type(BC(bignum), I2N(BignumType));
  bignum_init(state);
  
  BC(floatpoint) = rbs_class_new(state, "Float", 0, tmp);
  class_set_object_type(BC(floatpoint), I2N(FloatType));
  
  BC(undef_class) = rbs_class_new(state, "UndefClass", 0, obj);
  BC(fastctx) = rbs_class_new(state, "MethodContext", 0, obj);
  BC(methctx) = BC(fastctx);
  BC(blokctx) = rbs_class_new(state, "BlockContext", 0, BC(fastctx));
  
  BC(task) = rbs_class_new(state, "Task", 0, obj);
  class_set_object_type(BC(task), I2N(TaskType));
  
  BC(iseq) = rbs_class_new(state, "InstructionSequence", 0, BC(bytearray));
  class_set_object_type(BC(iseq), I2N(ISeqType));

  #define bcs(name, sup, string) BC(name) = _ ## name ## _class(state, sup); \
    module_setup(state, BC(name), string);
  
  /* the special_classes C array is use do quickly calculate the class
     of an immediate by just indexing into the array using (obj & 0x1f) */
  
  /* fixnum, symbol, and custom can have a number of patterns below
     0x1f, so we fill them all. */
     
  for(i = 0; i < SPECIAL_CLASS_SIZE; i += 4) {
    state->global->special_classes[i + 0] = Qnil;
    state->global->special_classes[i + 1] = BC(fixnum_class);
    state->global->special_classes[i + 2] = Qnil;
    if(((i + 3) & 0x7) == 0x3) {
      state->global->special_classes[i + 3] = BC(symbol);
    } else {
      state->global->special_classes[i + 3] = CUSTOM_CLASS;
    }
  }
  
  /* These only have one value, so they only need one spot in
     the array */
  state->global->special_classes[(intptr_t)Qundef] = BC(undef_class);
  state->global->special_classes[(intptr_t)Qfalse] = BC(false_class);
  state->global->special_classes[(intptr_t)Qnil  ] = BC(nil_class);
  state->global->special_classes[(intptr_t)Qtrue ] = BC(true_class);
    
  bcs(regexp, obj, "Regexp");
  class_set_object_type(BC(regexp), I2N(RegexpType));
  bcs(regexpdata, obj, "RegexpData");
  class_set_object_type(BC(regexpdata), I2N(RegexpDataType));
  bcs(matchdata, obj, "MatchData");
      
  cpu_bootstrap_exceptions(state);
  
  rbs_module_new(state, "Rubinius", BC(object));
  
  Init_list(state);
  Init_cpu_task(state);
  Init_ffi(state);
  regexp_init(state);
  selector_init(state);
  send_site_init(state);
    
  rbs_const_set(state, 
        rbs_const_get(state, BASIC_CLASS(object), "Rubinius"),
        "Primitives",
        cpu_populate_prim_names(state));
  
  state->global->external_ivars = lookuptable_new(state);

}
bool editor_init(int argc, char* argv[])
{
	// "register" map loader and saver functions
	editormapcreatefunction		= mapformat_b_create_function;
	editormaploadfunction 		= mapformat_b_load_function;
	editormapsavefunction 		= mapformat_b_save_function;
	editormapdestroyfunction	= mapformat_b_destroy_function;

	// this is to create the first blank map file
	#if 0
	editorlevel = editormapcreatefunction(editorlevelwidth, editorlevelheight);
	editor_save_level();
	return false;
	#endif



	// init SDL

	#ifdef __linux__
	//putenv("SDL_VIDEODRIVER=glSDL");
	#endif

	if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
	{
		fprintf(stderr, "SDL Library Initialization Failed!\n\tSDL Error: %s\n", SDL_GetError());
		return false;
	}

	editorscreen = SDL_SetVideoMode(editorwindowwidth, editorwindowheight, editorwindowbpp, SDL_HWSURFACE | SDL_DOUBLEBUF);

	if (!editorscreen)
	{
		fprintf(stderr, "SDL Screen Initialization Failed! %dx%d@%dbpp\n\tSDL Error: %s\n",
			editorwindowwidth,
			editorwindowheight,
			editorwindowbpp,
			SDL_GetError());
		return false;
	}

	// set the window caption
	SDL_WM_SetCaption("Basic SDL Map Editor v0.0.5 [wip.map] -- by Richard Marks <*****@*****.**>", 0);

	// create the SDL event handler instance
	editorevent = new SDL_Event;
	if (!editorevent)
	{
		fprintf(stderr, "Unable to create SDL_Event event handler instance!\n");
		return false;
	}

	if (-1 == TTF_Init())
	{
		fprintf(stderr, "Unable to initialize SDL_TTF!\nSDL_TTF Error: %s\n", TTF_GetError());
		return false;
	}


	editorfont = TTF_OpenFont("silkscreen.ttf", 8);
	if (!editorfont)
	{
		fprintf(stderr, "Unable to load \"silkscreen.ttf\"!\nSDL_TTF Error: %s\n", TTF_GetError());
		return false;
	}

	////////////////////////////////////////////////////////////////////////////

	// load the tileset
	SDL_Surface* preLoad = IMG_Load("tileset.png");
	if (!preLoad)
	{
		fprintf(stderr, "Failed to load \"tileset.png\"!\n");
		return false;
	}
	SDL_SetColorKey(preLoad, (SDL_SRCCOLORKEY | SDL_RLEACCEL), SDL_MapRGB(preLoad->format, 0xFF, 0x00, 0xFF));
	editortileset = SDL_DisplayFormat(preLoad);
	if (preLoad){SDL_FreeSurface(preLoad);}
	if (!editortileset)
	{
		fprintf(stderr, "SDL_DisplayFormat() failed or we have run out of memory!\n");
		return false;
	}

	// pre-calculate all tile coordinates
	unsigned int tilesperrow 	= (editortileset->w / editortilewidth);
	unsigned int tilecount 		= ((editortileset->w / editortilewidth) * (editortileset->h / editortileheight));
	editortilecoordinates 		= new SDL_Rect [tilecount];

	for (unsigned int index = 0; index < tilecount; index++)
	{
		int tilemodperrow 	= (index % tilesperrow);
		int tileoverperrow 	= (index / tilesperrow);

		editortilecoordinates[index].x = 1 + tilemodperrow + (tilemodperrow * editortilewidth);
		editortilecoordinates[index].y = 1 + tileoverperrow + (tileoverperrow * editortileheight);
		editortilecoordinates[index].w = editortilewidth;
		editortilecoordinates[index].h = editortileheight;
	}

	////////////////////////////////////////////////////////////////////////////


	editorscreenbgcolor = SDL_MapRGB(editorscreen->format, 0, 0, 0);
	editortextcolor = SDL_MapRGB(editorscreen->format, 255, 255, 255);

	editor_load_level();
	editorlevelchanged = false;

	editor_create_camera();

	editor_create_map_surfaces();
	editor_create_static_help_text();

	editor_create_gui_elements();
	editor_create_cursor_surface();

	editor_create_scene();

	SDL_GetKeyState(&editornumkeys);
	editorkeywaspressed = new bool [editornumkeys];
	for (int index = 0; index < editornumkeys; index++)
	{
		editorkeywaspressed[index] = false;
	}

	if (!selector_init(editortileset))
	{
		return false;
	}

	editor_set_mode(EditorBGEdit);

	// every 5 minutes we attempt an auto save
	editorautosavetimerid = SDL_AddTimer(300000, editor_auto_save, 0);

	editorrunning = true;
	return true;
}
Esempio n. 5
0
void server()
{
    struct sockaddr_in servaddr;
    int listenfd;
    selector s;

    /*set up server address*/
    address_init(&servaddr);
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        err_exit(errno);
    /*set up listen fd*/
    if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
        err_exit(errno);
    if (listen(listenfd, 10) == -1)
        err_exit(errno);

    /*select init*/
    selector_init(&s);
    selector_add(&s, listenfd, READ_EVENT);

    /*loop*/
    while (1) {
        //fd_set before and after select is different
        //the three fd_set parameters in select are key-result parameters
        fd_set temp_readset = s.readset;
        fd_set temp_writeset = s.writeset;
        fd_set temp_exceptset = s.exceptset;
        int n, i, temp_maxfd = s.maxfd;

        /*select wait*/
        n = select(temp_maxfd+1, &temp_readset, &temp_writeset, &temp_exceptset, NULL);

        if (n < 0) {
            err_exit(errno);
        } else if (n == 0) {
            continue;
        }

        /*i is fd*/
        for (i = 0; i <= temp_maxfd; i++) {
            if (FD_ISSET(i, &temp_readset)) {
                /*readable fd*/
                if (i == listenfd) {
                    /*accept new client*/
                    struct sockaddr_in cliaddr;
                    socklen_t clilen = sizeof(cliaddr);
                    char buf[MAXLINE];
                    int clientfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);
                    printf("Server: accept %s:%u\n", 
                            inet_ntop(AF_INET, &cliaddr.sin_addr, buf, MAXLINE),
                            ntohs(cliaddr.sin_port));

                    /*select add READ_EVENT*/
                    selector_add(&s, clientfd, READ_EVENT);

                } else if (i != listenfd) {
                    /*client job*/
                    int clientfd = i;
                    char buf[MAXLINE];
                    if (read(clientfd, buf, strlen(HELLO)) < 0)
                        err_exit(errno);

                    /*select remove READ_EVENT and add WRITE_EVENT*/
                    selector_del(&s, clientfd, READ_EVENT);
                    selector_add(&s, clientfd, WRITE_EVENT);

                }
            } else if (FD_ISSET(i, &temp_writeset)) {
                /*writable fd*/
                if (i == listenfd) {
                    continue;
                } else {
                    int clientfd = i;
                    /*write to clientfd*/
                    if (write(clientfd, HELLO, strlen(HELLO)) < 0)
                        err_exit(errno);

                    /*select remove clientfd*/
                    selector_del(&s, clientfd, WRITE_EVENT);
                    close(clientfd);
                }
            } else if (FD_ISSET(i, &temp_exceptset)) {
                /*select remove i*/
                int clientfd = i;
                selector_del(&s, clientfd, READ_EVENT | WRITE_EVENT);
                close(clientfd);
                /*exception fd*/
                err_exit(errno);
            }
        }
    }
}