// Set default options that were not set by user.. static int set_undefined_options(ad_server_t *server) { int newentries = 0; char *default_options[][2] = AD_SERVER_OPTIONS; for (int i = 0; ! IS_EMPTY_STR(default_options[i][0]); i++) { if (! ad_server_get_option(server, default_options[i][0])) { ad_server_set_option(server, default_options[i][0], default_options[i][1]); newentries++; } DEBUG("%s=%s", default_options[i][0], ad_server_get_option(server, default_options[i][0])); } return newentries; }
/* Main HelpServ routine. */ void helpserv(const char *source, User *callerUser, char *buf) { TRACE_MAIN_FCLT(FACILITY_HELPSERV); if (IS_NULL(buf) || IS_EMPTY_STR(buf)) send_notice_lang_to_user(s_HelpServ, callerUser, GetCallerLang(), ERROR_ACCESS_DENIED); else if (buf[0] == '\001') { if (IS_EMPTY_STR(buf + 1)) LOG_SNOOP(s_HelpServ, "Invalid CTCP from \2%s\2", source); else if (str_equals_nocase(buf + 1, "PING")) { send_notice_to_user(s_HelpServ, callerUser, "\1%s", buf + 1); LOG_SNOOP(s_HelpServ, "CTCP: PING from \2%s\2", source); } else { if (buf[str_len(buf) - 1] == '\001') buf[str_len(buf) - 1] = '\0'; LOG_SNOOP(s_HelpServ, "CTCP: %s from \2%s\2", buf + 1, source); } } else { ServiceCommandData data; data.commandName = buf; data.userLevel = ULEVEL_NOACCESS; data.operMatch = TRUE; data.operName = NULL; data.agent = &a_HelpServ; handle_help(source, callerUser, &data); } }
STR str_tokenize(CSTR string, STR token, size_t token_len, char delimiter) { STR lim; if (IS_NULL(string) || IS_EMPTY_STR(string)) return NULL; lim = token + token_len - 1; while (*string && (token < lim)) { if (*string == delimiter) { *token = 0; return (STR) (string + 1); } *token++ = *string++; } *token = 0; return (STR)string; }
/** * Start server. * * @return 0 if successful, otherwise -1. */ int ad_server_start(ad_server_t *server) { DEBUG("Starting a server."); // Set default options that were not set by user.. set_undefined_options(server); // Hookup libevent's log message. if (_ad_log_level >= AD_LOG_DEBUG) { event_set_log_callback(libevent_log_cb); if (_ad_log_level >= AD_LOG_DEBUG2) { event_enable_debug_mode(); } } // Parse addr int port = ad_server_get_option_int(server, "server.port"); char *addr = ad_server_get_option(server, "server.addr"); struct sockaddr *sockaddr = NULL; size_t sockaddr_len = 0; if (addr[0] == '/') { // Unix socket. struct sockaddr_un unixaddr; bzero((void *) &unixaddr, sizeof(struct sockaddr_un)); if (strlen(addr) >= sizeof(unixaddr.sun_path)) { errno = EINVAL; DEBUG("Too long unix socket name. '%s'", addr); return -1; } unixaddr.sun_family = AF_UNIX; strcpy(unixaddr.sun_path, addr); // no need of strncpy() sockaddr = (struct sockaddr *) &unixaddr; sockaddr_len = sizeof(unixaddr); } else if (strstr(addr, ":")) { // IPv6 struct sockaddr_in6 ipv6addr; bzero((void *) &ipv6addr, sizeof(struct sockaddr_in6)); ipv6addr.sin6_family = AF_INET6; ipv6addr.sin6_port = htons(port); evutil_inet_pton(AF_INET6, addr, &ipv6addr.sin6_addr); sockaddr = (struct sockaddr *) &ipv6addr; sockaddr_len = sizeof(ipv6addr); } else { // IPv4 struct sockaddr_in ipv4addr; bzero((void *) &ipv4addr, sizeof(struct sockaddr_in)); ipv4addr.sin_family = AF_INET; ipv4addr.sin_port = htons(port); ipv4addr.sin_addr.s_addr = (IS_EMPTY_STR(addr)) ? INADDR_ANY : inet_addr(addr); sockaddr = (struct sockaddr *) &ipv4addr; sockaddr_len = sizeof(ipv4addr); } // SSL if (!server->sslctx && ad_server_get_option_int(server, "server.enable_ssl")) { char *cert_path = ad_server_get_option(server, "server.ssl_cert"); char *pkey_path = ad_server_get_option(server, "server.ssl_pkey"); server->sslctx = init_ssl(cert_path, pkey_path); if (server->sslctx == NULL) { ERROR("Couldn't load certificate file(%s) or private key file(%s).", cert_path, pkey_path); return -1; } DEBUG("SSL Initialized."); } // Bind if (! server->evbase) { server->evbase = event_base_new(); if (! server->evbase) { ERROR("Failed to create a new event base."); return -1; } } // Create a eventfd for notification channel. int notifyfd = eventfd(0, 0); server->notify_buffer = bufferevent_socket_new(server->evbase, notifyfd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(server->notify_buffer, NULL, notify_cb, NULL, server); if (! server->listener) { server->listener = evconnlistener_new_bind( server->evbase, listener_cb, (void *)server, LEV_OPT_THREADSAFE | LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, ad_server_get_option_int(server, "server.backlog"), sockaddr, sockaddr_len); if (! server->listener) { ERROR("Failed to bind on %s:%d", addr, port); return -1; } } // Listen INFO("Listening on %s:%d%s", addr, port, ((server->sslctx) ? " (SSL)" : "")); int exitstatus = 0; if (ad_server_get_option_int(server, "server.thread")) { DEBUG("Launching server as a thread.") server->thread = NEW_OBJECT(pthread_t); pthread_create(server->thread, NULL, &server_loop, (void *)server); //pthread_detach(server->thread); } else { int *retval = server_loop(server); exitstatus = *retval; free(retval); close_server(server); if (ad_server_get_option_int(server, "server.free_on_stop")) { ad_server_free(server); } } return exitstatus; }