static isc_result_t configure_listener(isc_sockaddr_t *address, ns_lwresd_t *lwresd, isc_mem_t *mctx, ns_lwreslistenerlist_t *newlisteners) { ns_lwreslistener_t *listener, *oldlistener = NULL; char socktext[ISC_SOCKADDR_FORMATSIZE]; isc_result_t result; (void)find_listener(address, &oldlistener); listener = NULL; result = listener_create(mctx, lwresd, &listener); if (result != ISC_R_SUCCESS) { isc_sockaddr_format(address, socktext, sizeof(socktext)); isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, "lwres failed to configure %s: %s", socktext, isc_result_totext(result)); return (result); } /* * If there's already a listener, don't rebind the socket. */ if (oldlistener == NULL) { result = listener_bind(listener, address); if (result != ISC_R_SUCCESS) { ns_lwreslistener_detach(&listener); return (ISC_R_SUCCESS); } } else listener_copysock(oldlistener, listener); result = listener_startclients(listener); if (result != ISC_R_SUCCESS) { isc_sockaddr_format(address, socktext, sizeof(socktext)); isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, "lwres: failed to start %s: %s", socktext, isc_result_totext(result)); ns_lwreslistener_detach(&listener); return (ISC_R_SUCCESS); } if (oldlistener != NULL) { /* * Remove the old listener from the old list and shut it down. */ ISC_LIST_UNLINK(listeners, oldlistener, link); listener_shutdown(oldlistener); ns_lwreslistener_detach(&oldlistener); } else { isc_sockaddr_format(address, socktext, sizeof(socktext)); isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE, "lwres listening on %s", socktext); } ISC_LIST_APPEND(*newlisteners, listener, link); return (result); }
/* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in * the format "255.255.255.255" */ void add_listener(int port, const char *vhost_ip, int family, int ssl) { struct Listener *listener; struct rb_sockaddr_storage vaddr; /* * if no port in conf line, don't bother */ if(port == 0) return; memset(&vaddr, 0, sizeof(vaddr)); vaddr.ss_family = family; if(vhost_ip != NULL) { if(family == AF_INET) { if(rb_inet_pton(family, vhost_ip, &((struct sockaddr_in *)&vaddr)->sin_addr) <= 0) return; } #ifdef RB_IPV6 else { if(rb_inet_pton(family, vhost_ip, &((struct sockaddr_in6 *)&vaddr)->sin6_addr) <= 0) return; } #endif } else { switch(family) { case AF_INET: ((struct sockaddr_in *)&vaddr)->sin_addr.s_addr = INADDR_ANY; break; #ifdef RB_IPV6 case AF_INET6: memcpy(&((struct sockaddr_in6 *)&vaddr)->sin6_addr, &in6addr_any, sizeof(struct in6_addr)); break; default: return; #endif } } switch(family) { case AF_INET: SET_SS_LEN(&vaddr, sizeof(struct sockaddr_in)); ((struct sockaddr_in *)&vaddr)->sin_port = htons(port); break; #ifdef RB_IPV6 case AF_INET6: SET_SS_LEN(&vaddr, sizeof(struct sockaddr_in6)); ((struct sockaddr_in6 *)&vaddr)->sin6_port = htons(port); break; #endif default: break; } if((listener = find_listener(&vaddr))) { if(listener->F != NULL) return; } else { listener = make_listener(&vaddr); listener->next = ListenerPollList; ListenerPollList = listener; } listener->F = NULL; listener->ssl = ssl; if(inetport(listener)) listener->active = 1; else close_listener(listener); }
static int answer_to_connection(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t * upload_data_size, void **con_cls) { struct agent_core_t *core = (struct agent_core_t *)cls; struct http_priv_t *http; struct http_request request; struct connection_info_struct *con_info; (void)version; GET_PRIV(core, http); if (*con_cls == NULL) { ALLOC_OBJ(con_info); *con_cls = con_info; return (MHD_YES); } con_info = *con_cls; assert(core->config->userpass); log_request(connection, http, method, url); if (!strcmp(method, "OPTIONS")) { /* We need this for preflight requests (CORS). */ return (http_reply(connection, 200, NULL)); } else if (!strcmp(method, "GET") || !strcmp(method, "HEAD") || !strcmp(method, "DELETE")) { if (check_auth(connection, core, con_info)) return (MHD_YES); if (!strcmp(method, "DELETE")) request.method = M_DELETE; else request.method = M_GET; request.connection = connection; request.url = url; request.ndata = 0; if (find_listener(&request, http)) return (MHD_YES); } else if (!strcmp(method, "POST") || !strcmp(method, "PUT")) { if (*upload_data_size != 0) { if (*upload_data_size + con_info->progress >= RCV_BUFFER) { warnlog(http->logger, "Client input exceeded buffer size " "of %u bytes. Dropping client.", RCV_BUFFER); return (MHD_NO); } memcpy(con_info->answerstring + con_info->progress, upload_data, *upload_data_size); con_info->progress += *upload_data_size; *upload_data_size = 0; return (MHD_YES); } else if ((char *)con_info->answerstring != NULL) { if (check_auth(connection, core, con_info)) return (MHD_YES); if (!strcmp(method, "POST")) request.method = M_POST; else request.method = M_PUT; request.connection = connection; request.url = url; request.ndata = con_info->progress; request.data = con_info->answerstring; /* * FIXME */ ((char *)request.data)[con_info->progress] = '\0'; if (find_listener(&request, http)) return (MHD_YES); } } if (request.method == M_GET && !strcmp(url, "/")) { if (http->help_page == NULL) http->help_page = make_help(http); assert(http->help_page); return (http_reply(connection, 200, http->help_page)); } return (http_reply(connection, 500, "Failed")); }
static int answer_to_connection (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) { struct agent_core_t *core = (struct agent_core_t *)cls; struct http_priv_t *http; struct agent_plugin_t *plug; struct http_request request; struct connection_info_struct *con_info = NULL; int ret; (void)version; plug = plugin_find(core,"http"); http = (struct http_priv_t *) plug->data; assert(plug); assert(http); if (NULL == *con_cls) { con_info = malloc (sizeof (struct connection_info_struct)); assert(con_info); con_info->answerstring[0] = '\0'; con_info->progress = 0; con_info->authed = 0; *con_cls = con_info; return MHD_YES; } con_info = *con_cls; assert(core->config->userpass); log_request(connection, http, method, url); if (0 == strcmp (method, "GET") || !strcmp(method, "HEAD") || !strcmp(method,"DELETE")) { ret = check_auth(connection, core, con_info); if (ret == 1) return MHD_YES; if (!strcmp(method,"DELETE")) { request.method = M_DELETE; } else { request.method = M_GET; } request.connection = connection; request.url = url; request.ndata = 0; if (find_listener(&request, http)) return MHD_YES; } if (!strcmp(method, "POST") || !strcmp(method, "PUT")) { if (*upload_data_size != 0) { if (*upload_data_size + con_info->progress >= RCV_BUFFER) { warnlog(http->logger, "Client input exceeded buffer size of %u bytes. Dropping client.", RCV_BUFFER); return MHD_NO; } memcpy(con_info->answerstring + con_info->progress, upload_data, *upload_data_size); con_info->progress += *upload_data_size; *upload_data_size = 0; return MHD_YES; } else if (NULL != con_info->answerstring){ ret = check_auth(connection, core, con_info); if (ret == 1) return MHD_YES; if (!strcmp(method,"POST")) { request.method = M_POST; } else { request.method = M_PUT; } request.connection = connection; request.url = url; request.ndata = con_info->progress; request.data = con_info->answerstring; /* * FIXME */ ((char *)request.data)[con_info->progress] = '\0'; if (find_listener(&request, http)) return MHD_YES; } } if (request.method == M_GET && !strcmp(url, "/")) { if (http->help_page == NULL) http->help_page = make_help(http); assert (http->help_page); return send_response_ok(connection, http->help_page); } return send_response_fail (connection, "Failed\n"); }
static int inetport(struct Listener* listener) { struct irc_sockaddr lsin; int fd; int opt = 1; /* * At first, open a new socket */ fd = comm_open(DEF_FAM, SOCK_STREAM, 0, "Listener socket"); #ifdef IPV6 if (!IN6_ARE_ADDR_EQUAL((struct in6_addr *)&listener->addr, &in6addr_any)) { #else if (INADDR_ANY != listener->addr.sins.sin.s_addr) { #endif inetntop(DEF_FAM, &IN_ADDR(listener->addr), listener->vhost, HOSTLEN); listener->name = listener->vhost; } if (fd == -1) { report_error(L_ALL, "opening listener socket %s:%s", get_listener_name(listener), errno); return 0; } else if ((HARD_FDLIMIT - 10) < fd) { report_error(L_ALL, "no more connections left for listener %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * XXX - we don't want to do all this crap for a listener * set_sock_opts(listener); */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(opt))) { report_error(L_ALL, "setting SO_REUSEADDR for listener %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * Bind a port to listen for new connections if port is non-null, * else assume it is already open and try get something from it. */ memset(&lsin, 0, sizeof(struct irc_sockaddr)); S_FAM(lsin) = DEF_FAM; copy_s_addr(S_ADDR(lsin), IN_ADDR(listener->addr)); S_PORT(lsin) = htons(listener->port); if (bind(fd, (struct sockaddr*) &SOCKADDR(lsin), sizeof(struct irc_sockaddr))) { report_error(L_ALL, "binding listener socket %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } if (listen(fd, HYBRID_SOMAXCONN)) { report_error(L_ALL, "listen failed for %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * XXX - this should always work, performance will suck if it doesn't */ if (!set_non_blocking(fd)) report_error(L_ALL, NONB_ERROR_MSG, get_listener_name(listener), errno); listener->fd = fd; /* Listen completion events are READ events .. */ accept_connection(fd, listener); return 1; } static struct Listener* find_listener(int port, struct irc_inaddr *addr) { struct Listener* listener = NULL; struct Listener* last_closed = NULL; for (listener = ListenerPollList; listener; listener = listener->next) { if ( (port == listener->port) && (!memcmp(&PIN_ADDR(addr), &IN_ADDR(listener->addr), sizeof(struct irc_inaddr)))) { /* Try to return an open listener, otherwise reuse a closed one */ if (listener->fd == -1) last_closed = listener; else return listener; } } return last_closed; } /* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in * the format "255.255.255.255" */ void add_listener(int port, const char* vhost_ip) { struct Listener* listener; struct irc_inaddr vaddr; /* * if no port in conf line, don't bother */ if (port == 0) return; #ifdef IPV6 copy_s_addr(IN_ADDR(vaddr), &in6addr_any); #else copy_s_addr(IN_ADDR(vaddr), INADDR_ANY); #endif if (vhost_ip) { if(inetpton(DEF_FAM, vhost_ip, &IN_ADDR(vaddr)) <= 0) return; } if ((listener = find_listener(port, &vaddr))) { if (listener->fd > -1) return; } else { listener = make_listener(port, &vaddr); listener->next = ListenerPollList; ListenerPollList = listener; } listener->fd = -1; if (inetport(listener)) listener->active = 1; else close_listener(listener); } /* * close_listener - close a single listener */ void close_listener(struct Listener* listener) { assert(listener != NULL); if(listener == NULL) return; if (listener->fd >= 0) { fd_close(listener->fd); listener->fd = -1; } listener->active = 0; if (listener->ref_count) return; free_listener(listener); }
/* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in the format "255.255.255.255" * options - listener options * cp - listener default code page */ void add_listener(int port, const char* vhost_ip, char* options, char* cp) { struct Listener* listener; struct IN_ADDR vaddr; /* * if no port in conf line, don't bother */ if (0 == port) return; #ifdef IPV6 vaddr = INADDRANY; #else vaddr.s_addr = INADDRANY; #endif if (vhost_ip) { #ifdef IPV6 if(inetpton(AFINET, vhost_ip, &vaddr) == 0) return; #else vaddr.s_addr = inet_addr(vhost_ip); if (INADDR_NONE == vaddr.s_addr) return; #endif } if ((listener = find_listener(port, vaddr))) { listener->active = 1; return; } if(options && *options) irclog(L_NOTICE,"Adding listener for %s, port %d Options:%s", vhost_ip ? vhost_ip : "ANY", port, options ); else irclog(L_NOTICE,"Adding listener for %s, port %d", vhost_ip ? vhost_ip : "ANY", port); listener = make_listener(port, vaddr); if(options) { while(*options) { switch(*options) { case 's' : #ifdef HAVE_SSL if(no_ssl) irclog(L_WARN,"ignoring port with 's' option!"); else listener->options |= LST_SSL; #else irclog(L_WARN,"ircd compiled without SSL support, ignoring port with 's' option!"); #endif break; case 'S' : listener->options |= LST_SERVER; break; case 'W' : listener->options |= LST_WEBCHAT; break; case 'J' : listener->options |= LST_JAVACR; break; case 'n' : listener->options |= LST_NOSPOOF; break; } ++options; } } if(cp && cp[0]) { listener->codepage = codepage_find(cp); if(listener->codepage==-1) irclog(L_WARN,"Codepage %s defined on P:line was not loaded!", cp); } else listener->codepage=-1; if (inetport(listener)) { listener->active = 1; listener->next = ListenerPollList; ListenerPollList = listener; } else free_listener(listener); }