request *get_sock_request(int sock_fd) { int fd; /* socket */ #ifdef INET6 struct sockaddr_in6 remote_addr; #else struct sockaddr_in remote_addr; /* address */ #endif int remote_addrlen = sizeof(remote_addr); request *conn; /* connection */ if (max_connections != -1 && status.connections >= max_connections) return NULL; #ifdef INET6 remote_addr.sin6_family = 0xdead; #else remote_addr.sin_family = 0xdead; #endif fd = accept(sock_fd, (struct sockaddr *) &remote_addr, &remote_addrlen); if (fd == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) /* no requests */ return NULL; else { /* accept error */ log_error_time(); #if 0 perror("accept"); #endif return NULL; } } #ifdef DEBUGNONINET /* This shows up due to race conditions in some Linux kernels * when the client closes the socket sometime between * the select() and accept() syscalls. * Code and description by Larry Doolittle <*****@*****.**> */ #define HEX(x) (((x)>9)?(('a'-10)+(x)):('0'+(x))) if (remote_addr.sin_family != AF_INET) { struct sockaddr *bogus = (struct sockaddr *) &remote_addr; char *ap, ablock[44]; int i; close(fd); #ifdef BOA_TIME_LOG log_error_time(); #endif for (ap = ablock, i = 0; i < remote_addrlen && i < 14; i++) { *ap++ = ' '; *ap++ = HEX((bogus->sa_data[i] >> 4) & 0x0f); *ap++ = HEX(bogus->sa_data[i] & 0x0f); } *ap = '\0'; #ifdef BOA_TIME_LOG fprintf(stderr, "non-INET connection attempt: socket %d, " "sa_family = %hu, sa_data[%d] = %s\n", fd, bogus->sa_family, remote_addrlen, ablock); #endif return NULL; } #endif if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt, sizeof(sock_opt))) == -1){ die(NO_SETSOCKOPT); return NULL; } conn = new_request(); conn->fd = fd; conn->status = READ_HEADER; conn->header_line = conn->client_stream; conn->time_last = time_counter; #ifdef USE_CHARSET_HEADER conn->send_charset = 1; #endif /* nonblocking socket */ if (fcntl(conn->fd, F_SETFL, NOBLOCK) == -1) { #ifdef BOA_TIME_LOG log_error_time(); perror("request.c, fcntl"); #endif } /* set close on exec to true */ if (fcntl(conn->fd, F_SETFD, 1) == -1) { #ifdef BOA_TIME_LOG log_error_time(); perror("request.c, fcntl-close-on-exec"); #endif } /* large buffers */ if (setsockopt(conn->fd, SOL_SOCKET, SO_SNDBUF, (void *) &sockbufsize, sizeof(sockbufsize)) == -1) die(NO_SETSOCKOPT); /* for log file and possible use by CGI programs */ #ifdef INET6 if (getnameinfo((struct sockaddr *)&remote_addr, NRL_SA_LEN((struct sockaddr *)&remote_addr), conn->remote_ip_addr, 20, NULL, 0, NI_NUMERICHOST)) { #if 0 fprintf(stderr, "[IPv6] getnameinfo failed\n"); #endif conn->remote_ip_addr[0]=0; } #else strncpy(conn->remote_ip_addr, (char *) inet_ntoa(remote_addr.sin_addr), 20); #endif /* for possible use by CGI programs */ #ifdef INET6 conn->remote_port = ntohs(remote_addr.sin6_port); #else conn->remote_port = ntohs(remote_addr.sin_port); #endif if (virtualhost) { #ifdef INET6 char host[20]; struct sockaddr_in6 salocal; int dummy; dummy = sizeof(salocal); if (getsockname(conn->fd, (struct sockaddr *) &salocal, &dummy) == -1) die(SERVER_ERROR); if (getnameinfo((struct sockaddr *)&salocal, NRL_SA_LEN((struct sockaddr *)&salocal), host, 20, NULL, 0, NI_NUMERICHOST)) { #if 0 fprintf(stderr, "[IPv6] getnameinfo failed\n"); #endif }else conn->local_ip_addr = strdup(host); #else struct sockaddr_in salocal; int dummy; dummy = sizeof(salocal); if (getsockname(conn->fd, (struct sockaddr *) &salocal, &dummy) == -1){ die(SERVER_ERROR); return NULL; } conn->local_ip_addr = strdup(inet_ntoa(salocal.sin_addr)); #endif } status.requests++; status.connections++; /* Thanks to Jef Poskanzer <*****@*****.**> for this tweak */ { int one = 1; if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY, (void *) &one, sizeof(one)) == -1){ die(NO_SETSOCKOPT); return NULL; } } enqueue(&request_ready, conn); return conn; }
int getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { int serrno = errno; if (!sa || (addrlen != NRL_SA_LEN(sa))) return -1; if (host && (hostlen > 0)) switch(sa->sa_family) { case AF_INET: #ifdef AF_INET6 case AF_INET6: #endif /* AF_INET6 */ if (!(flags & NI_NUMERICHOST)) { struct hostent *h = NULL; #if HOSTTABLE #ifdef AF_INET6 if (sa->sa_family == AF_INET6) h = _addr2hostname_hosts((void *)&(((struct sockaddr_in6 *)sa)->sin6_addr), sizeof(struct in6_addr), AF_INET6); else #endif /* AF_INET6 */ h = _addr2hostname_hosts((void *)&(((struct sockaddr_in *)sa)->sin_addr), sizeof(struct in_addr), AF_INET); #endif /* HOSTTABLE */ if (!h) { #ifdef AF_INET6 if (sa->sa_family == AF_INET6) h = gethostbyaddr((void *)&(((struct sockaddr_in6 *)sa)->sin6_addr), sizeof(struct in6_addr), AF_INET6); else #endif /* INET6 */ h = gethostbyaddr((void *)&(((struct sockaddr_in *)sa)->sin_addr), sizeof(struct in_addr), AF_INET); endhostent(); }; if (h) { if (flags & NI_NOFQDN) { char *c, *c2; if ((c = nrl_domainname()) && (c = strstr(h->h_name, c)) && (c != h->h_name) && (*(--c) == '.')) { strncpy(host, h->h_name, min(hostlen, (c - h->h_name))); break; }; }; strncpy(host, h->h_name, hostlen); break; } } if (flags & NI_NAMEREQD) goto fail; { const char *c; #ifdef AF_INET6 if (sa->sa_family == AF_INET6) c = inet_ntop(AF_INET6, (void *)&(((struct sockaddr_in6 *)sa)->sin6_addr), host, hostlen); else #endif /* INET6 */ c = inet_ntop(AF_INET, (void *)&(((struct sockaddr_in *)sa)->sin_addr), host, hostlen); if (!c) goto fail; } break; case AF_LOCAL: if (!(flags & NI_NUMERICHOST)) { struct utsname utsname; if (!uname(&utsname)) { strncpy(host, utsname.nodename, hostlen); break; }; }; if (flags & NI_NAMEREQD) goto fail; strncpy(host, "localhost", hostlen); break; default: return -1; } if (serv && (servlen > 0)) switch(sa->sa_family) { case AF_INET: #ifdef AF_INET6 case AF_INET6: #endif /* INET6 */ if (!(flags & NI_NUMERICSERV)) { struct servent *s; if (s = getservbyport(((struct sockaddr_in *)sa)->sin_port, (flags & NI_DGRAM) ? "udp" : "tcp")) { strncpy(serv, s->s_name, servlen); break; }; }; snprintf(serv, servlen, "%d", ntohs(((struct sockaddr_in *)sa)->sin_port)); break; case AF_LOCAL: strncpy(serv, ((struct sockaddr_un *)sa)->sun_path, servlen); break; } if (host && (hostlen > 0)) host[hostlen-1] = 0; if (serv && (servlen > 0)) serv[servlen-1] = 0; errno = serrno; return 0; fail: errno = serrno; return -1; }