char * get_peer_ip(int fd) { size_t addr_size = sizeof(struct sockaddr_in6); struct sockaddr *sa = malloc(addr_size); if (getpeername(fd, sa, &addr_size) == -1) { return "\0"; } memset(ip_address, 0, INET6_ADDRSTRLEN); if (NULL == inet_ntop(sa->sa_family, get_inet_addr(sa), ip_address, INET6_ADDRSTRLEN)) { return "\0"; } free(sa); return ip_address; }
/*! @decl int bind(int|string port, void|function accept_callback, @ *! void|string ip, void|string reuse_port) *! *! Opens a socket and binds it to port number on the local machine. *! If the second argument is present, the socket is set to *! nonblocking and the callback funcition is called whenever *! something connects to it. The callback will receive the id for *! this port as argument and should typically call @[accept] to *! establish a connection. *! *! If the optional argument @[ip] is given, @[bind] will try to bind *! to an interface with that host name or IP number. Omitting this *! will bind to all available IPv4 addresses; specifying "::" will *! bind to all IPv4 and IPv6 addresses. *! *! If the OS supports TCP_FASTOPEN it is enabled automatically. *! *! If the OS supports SO_REUSEPORT it is enabled if the fourth argument is true. *! *! @returns *! 1 is returned on success, zero on failure. @[errno] provides *! further details about the error in the latter case. *! *! @seealso *! @[accept], @[set_id] */ static void port_bind(INT32 args) { struct port *p = THIS; PIKE_SOCKADDR addr; int addr_len,fd,tmp; do_close(p); if(args < 1) SIMPLE_WRONG_NUM_ARGS_ERROR("bind", 1); if(TYPEOF(Pike_sp[-args]) != PIKE_T_INT && (TYPEOF(Pike_sp[-args]) != PIKE_T_STRING || Pike_sp[-args].u.string->size_shift)) SIMPLE_ARG_TYPE_ERROR("bind", 1, "int|string(8bit)"); addr_len = get_inet_addr(&addr, (args > 2 && TYPEOF(Pike_sp[2-args])==PIKE_T_STRING? Pike_sp[2-args].u.string->str : NULL), (TYPEOF(Pike_sp[-args]) == PIKE_T_STRING? Pike_sp[-args].u.string->str : NULL), (TYPEOF(Pike_sp[-args]) == PIKE_T_INT? Pike_sp[-args].u.integer : -1), 0); INVALIDATE_CURRENT_TIME(); fd=fd_socket(SOCKADDR_FAMILY(addr), SOCK_STREAM, 0); if(fd < 0) { p->my_errno=errno; pop_n_elems(args); push_int(0); return; } #ifdef SO_REUSEPORT if( args > 3 && Pike_sp[3-args].u.integer ) { /* FreeBSD 7.x wants this to reuse portnumbers. * Linux 2.6.x seems to have reserved a slot for the option, but not * enabled it. Survive libc's with the option on kernels without. * * The emulated Linux runtime on MS Windows 10 fails this with EINVAL. */ int o=1; if((fd_setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&o, sizeof(int)) < 0) #ifdef ENOPROTOOPT && (errno != ENOPROTOOPT) #endif #ifdef EINVAL && (errno != EINVAL) #endif #ifdef WSAENOPROTOOPT && (errno != WSAENOPROTOOPT) #endif ){ p->my_errno=errno; while (fd_close(fd) && errno == EINTR) {} errno = p->my_errno; pop_n_elems(args); push_int(0); return; } } #endif #ifndef __NT__ { int o=1; if(fd_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(int)) < 0) { p->my_errno=errno; while (fd_close(fd) && errno == EINTR) {} errno = p->my_errno; pop_n_elems(args); push_int(0); return; } } #endif #if defined(IPV6_V6ONLY) && defined(IPPROTO_IPV6) if (SOCKADDR_FAMILY(addr) == AF_INET6) { /* Attempt to enable dual-stack (ie mapped IPv4 adresses). * Needed on WIN32. * cf http://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx */ int o = 0; fd_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&o, sizeof(int)); } #endif my_set_close_on_exec(fd,1); THREADS_ALLOW_UID(); if( !(tmp=fd_bind(fd, (struct sockaddr *)&addr, addr_len) < 0) ) #ifdef TCP_FASTOPEN tmp = 256, setsockopt(fd,SOL_TCP, TCP_FASTOPEN, &tmp, sizeof(tmp)), #endif (tmp = fd_listen(fd, 16384) < 0); THREADS_DISALLOW_UID(); if(!Pike_fp->current_object->prog) { if (fd >= 0) while (fd_close(fd) && errno == EINTR) {} Pike_error("Object destructed in Stdio.Port->bind()\n"); } if(tmp) { p->my_errno=errno; while (fd_close(fd) && errno == EINTR) {} errno = p->my_errno; pop_n_elems(args); push_int(0); return; } change_fd_for_box (&p->box, fd); if(args > 1) assign_accept_cb (p, Pike_sp+1-args); p->my_errno=0; pop_n_elems(args); push_int(1); }