/* * Return a 'struct hostent *' for an address. */ struct hostent *W32_CALL gethostbyaddr (const char *addr_name, int len, int type) { struct _hostent h; SOCK_DEBUGF (("\ngethostbyaddr: %s", (type == AF_INET && addr_name) ? inet_ntoa(*(struct in_addr*)addr_name) : (type == AF_INET6 && addr_name) ? _inet6_ntoa(addr_name) : "")); #if defined(USE_IPV6) if (type == AF_INET6 && len == sizeof(struct in6_addr)) { struct hostent *he; SOCK_ENTER_SCOPE(); he = gethostbyaddr6 (addr_name); SOCK_LEAVE_SCOPE(); return (he); } #endif if (gethostbyaddr_internal (addr_name, len, type, &h)) { SOCK_DEBUGF ((" `%s'", h.h_name)); if (!did_lookup) SOCK_DEBUGF ((", %s", h.h_timeout ? "cached" : "hosts-file")); return fill_hostent (&h); } SOCK_DEBUGF ((" failed (%s) ", did_lookup ? dom_strerror(dom_errno) : hstrerror(h_errno))); return (NULL); }
/* * Unhook signal-handlers and raise() signals we caught. */ int _sock_sig_restore (void) { int i; if (signal_depth == 0 || --signal_depth > 0) return (0); _sock_stop_timer(); for (i = 0; i < DIM(sig_tab); i++) { int sig = sig_tab[i].sig_num; #if (USE_SIGMASK) sigset_t pending, new_set; if (sigpending(&pending) == 0 && sigismember(&pending,sig)) { /* The signal became pending while we blocked it. * I.e. ^C was pressed, so act on it. */ sigemptyset (&new_set); sigaddset (&new_set, sig); SOCK_DEBUGF ((", raising %s", sig_tab[i].sig_name)); SOCK_ENTER_SCOPE(); sigprocmask (SIG_UNBLOCK, &new_set, NULL); SOCK_LEAVE_SCOPE(); } #else signal (sig, sig_tab[i].old); if (!sig_tab[i].caught) continue; sig_tab[i].caught = FALSE; if (sig_tab[i].exit && (sig_tab[i].old == SIG_DFL || sig_tab[i].old == SIG_IGN || sig_tab[i].old == sig_handler_watt)) { char buf[30]; strcpy (buf, "\nTerminating on "); strcat (buf, sig_tab[i].sig_name); sock_sig_exit (buf, sig); /* no return */ } SOCK_DEBUGF ((", raising %s", sig_tab[i].sig_name)); SOCK_ENTER_SCOPE(); raise (sig); SOCK_LEAVE_SCOPE(); return (-1); #endif } return (0); }
/* * Handle non-blocking SOCK_STREAM connection. * Only called on 2nd (3rd etc) time a non-blocking * connect() is called. */ static int nblk_connect (Socket *socket) { if (socket->so_state & SS_ISCONNECTED) { SOCK_DEBUGF ((", connected!")); socket->so_error = 0; return (0); } /* Don't let tcp_Retransmitter() timeout this socket * (unless there is a ARP timeout etc.) */ socket->tcp_sock->timeout = 0; if ((socket->so_state & (SS_ISDISCONNECTING | SS_CONN_REFUSED)) || (socket->tcp_sock->state >= tcp_StateCLOSED)) { if (socket->so_error != 0 && socket->so_error != EALREADY) { SOCK_DEBUGF ((", %s", short_strerror(socket->so_error))); SOCK_ERRNO (socket->so_error); } else if (chk_timeout(socket->nb_timer)) { socket->so_state &= ~SS_ISCONNECTING; SOCK_DEBUGF ((", ETIMEDOUT (%s)", socket->tcp_sock->err_msg)); socket->so_error = ETIMEDOUT; SOCK_ERRNO (ETIMEDOUT); } else { SOCK_DEBUGF ((", ECONNREFUSED")); socket->so_error = ECONNREFUSED; SOCK_ERRNO (ECONNREFUSED); /* could also be ECONNRESET */ } return (-1); } if (socket->so_state & SS_ISCONNECTING) { SOCK_DEBUGF ((", EALREADY")); socket->so_error = EALREADY; /* should be redundant */ SOCK_ERRNO (EALREADY); return (-1); } SOCK_FATAL (("%s (%d) Fatal: Unhandled non-block event\n", __FILE__, __LINE__)); return (-1); }
int W32_CALL getsockname (int s, struct sockaddr *name, int *namelen) { Socket *socket = _socklist_find (s); int sa_len; SOCK_PROLOGUE (socket, "\ngetsockname:%d", s); sa_len = (socket->so_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); if (!name || !namelen || (*namelen < sa_len)) { SOCK_DEBUGF ((", EINVAL")); SOCK_ERRNO (EINVAL); if (namelen) *namelen = 0; return (-1); } if (!socket->local_addr) { SOCK_DEBUGF ((", EINVAL")); SOCK_ERRNO (EINVAL); /* according to HP/UX manpage */ return (-1); } VERIFY_RW (name, *namelen); *namelen = sa_len; memcpy (name, socket->local_addr, sa_len); #if defined(USE_IPV6) if (socket->so_family == AF_INET6) { const struct sockaddr_in6 *la = (const struct sockaddr_in6*)socket->local_addr; SOCK_DEBUGF ((", %s (%d)", _inet6_ntoa(&la->sin6_addr), ntohs(la->sin6_port))); ARGSUSED (la); } else #endif { const struct sockaddr_in *la = socket->local_addr; SOCK_DEBUGF ((", %s (%d)", inet_ntoa(la->sin_addr), ntohs(la->sin_port))); ARGSUSED (la); } return (0); }
/* * Setup remote_addr for SOCK_RAW/SOCK_DGRAM (connectionless) protocols. * Must reconnect socket if 'remote_addr' and 'to' address are different. * I.e we're sending to another host/port than last time. */ static int setup_udp_raw (Socket *socket, const struct sockaddr *to, int tolen) { struct sockaddr_in *peer = (struct sockaddr_in*) to; DWORD keepalive = socket->keepalive; WORD lport = 0; char *rdata = NULL; int rc; if (socket->so_state & SS_ISCONNECTED) { /* Don't reconnect if same peer address/port. */ if (peer->sin_addr.s_addr == socket->remote_addr->sin_addr.s_addr && peer->sin_port == socket->remote_addr->sin_port) return (1); SOCK_DEBUGF ((socket, ", reconnecting")); free (socket->remote_addr); socket->remote_addr = NULL; /* Clear any effect of previous ICMP errors etc. */ socket->so_state &= ~(SS_CONN_REFUSED|SS_CANTSENDMORE|SS_CANTRCVMORE); socket->so_error = 0; if (socket->so_type == SOCK_DGRAM) { lport = socket->udp_sock->myport; rdata = (char*)socket->udp_sock->rdata; /* preserve current data */ } } /* For SOCK_DGRAM, udp_close() will be called when (re)opening socket. */ _sock_enter_scope(); rc = connect (socket->fd, to, tolen); _sock_leave_scope(); if (rc < 0) return (-1); if (rdata) /* Must be SOCK_DGRAM */ { udp_Socket *udp = socket->udp_sock; free (udp->rdata); /* free new rx-buffer set in connect() */ udp->rdata = (BYTE*) rdata; /* reuse previous data buffer */ udp->maxrdatalen = DEFAULT_RCV_WIN; grab_localport (lport); /* Restore freed localport */ } /* restore keepalive timer changed in connect() */ socket->keepalive = keepalive; return (1); }
int W32_CALL getpeername (int s, struct sockaddr *name, int *namelen) { Socket *socket = _socklist_find (s); int sa_len; SOCK_PROLOGUE (socket, "\ngetpeername:%d", s); sa_len = (socket->so_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); if (!name || !namelen || (*namelen < sa_len)) { SOCK_DEBUGF ((", EINVAL")); SOCK_ERRNO (EINVAL); if (namelen) *namelen = 0; return (-1); } if (!(socket->so_state & SS_ISCONNECTED)) { SOCK_DEBUGF ((", ENOTCONN")); SOCK_ERRNO (ENOTCONN); return (-1); } VERIFY_RW (name, *namelen); *namelen = sa_len; memcpy (name, socket->remote_addr, *namelen); #if defined(USE_IPV6) if (socket->so_family == AF_INET6) { const struct sockaddr_in6 *ra = (const struct sockaddr_in6*)socket->remote_addr; SOCK_DEBUGF ((", %s (%d)", _inet6_ntoa(&ra->sin6_addr), ntohs(ra->sin6_port))); ARGSUSED (ra); } else #endif { const struct sockaddr_in *ra = socket->remote_addr; SOCK_DEBUGF ((", %s (%d)", inet_ntoa(ra->sin_addr), ntohs(ra->sin_port))); ARGSUSED (ra); } return (0); }
/* * Check for catched signals */ static int chk_signals (void) { if (_sock_sig_pending()) { SOCK_DEBUGF ((", EINTR")); SOCK_ERRNO (EINTR); return (-1); } return (0); }
/* * Handle SOCK_DGRAM connection. Always blocking in _arp_resolve() */ static int udp_connect (Socket *socket) { #if defined(USE_IPV6) if (socket->so_family == AF_INET6) { const struct sockaddr_in6 *la = (const struct sockaddr_in6*) socket->local_addr; const struct sockaddr_in6 *ra = (const struct sockaddr_in6*) socket->remote_addr; if (!_UDP6_open (socket, &ra->sin6_addr, la->sin6_port, ra->sin6_port)) { SOCK_DEBUGF ((", no route (udp6)")); SOCK_ERRNO (EHOSTUNREACH); STAT (ip6stats.ip6s_noroute++); return (-1); } } else #endif if (!_UDP_open (socket, socket->remote_addr->sin_addr, socket->local_addr->sin_port, socket->remote_addr->sin_port)) { /* errno already set in udp_open() */ SOCK_DEBUGF ((", %s", socket->udp_sock->err_msg)); return (-1); } if ((socket->so_state & SS_PRIV) && socket->bcast_pool) { /* undo what udp_open() did above. * !!Fix me: clears recv data. */ sock_recv_init ((sock_type*)socket->udp_sock, socket->bcast_pool, socket->pool_size); } socket->so_state &= ~SS_UNCONNECTED; socket->so_state |= SS_ISCONNECTED; return (0); }
/* * Return a 'struct hostent *' for name. */ struct hostent * W32_CALL gethostbyname (const char *name) { struct _hostent h; const char *alias; SOCK_DEBUGF (("\ngethostbyname: `%s'", name)); if (gethostbyname_internal(name, &alias, &h)) { #if defined(USE_DEBUG) int i; for (i = 0; i < h.h_num_addr; i++) SOCK_DEBUGF ((" %s,", inet_ntoa(*(struct in_addr*)&h.h_address[i]))); if (!did_lookup) SOCK_DEBUGF ((" %s", h.h_timeout ? "cached" : from_where ? from_where : "hosts-file")); if (alias) SOCK_DEBUGF ((" (alias %s)", alias)); #endif return fill_hostent (&h); } if (called_from_resolve) SOCK_DEBUGF ((", unknown (called from resolve)")); else SOCK_DEBUGF ((", failed (%s)", did_lookup ? dom_strerror(dom_errno) : hstrerror(h_errno))); return (NULL); }
int _sock_sig_setup (void) { volatile int sig; if (signal_depth > 0) return (0); if (++signal_depth > 1) return (0); _sock_start_timer(); wat_brkmode = wathndlcbrk; wathndlcbrk = 0; watcbroke = 0; sigalrm_caught = sigbrk_caught = 0; sigint_caught = sigquit_caught = 0; old_sigint = signal (SIGINT, sig_catch); #if defined(SIGQUIT) old_sigquit = signal (SIGQUIT, sig_catch); #endif #if defined(SIGBREAK) old_sigbrk = signal (SIGBREAK, sig_catch); #endif #if defined(SIGPIPE) old_sigpipe = signal (SIGPIPE, sig_catch); #endif #if defined(SIGALRM) && TRAP_SIGALRM old_sigalrm = signal (SIGALRM, sig_catch); block_sigalrm(); #endif sig = setjmp (sig_jmp); if (sig == 0) return (0); /* We'll get here only when sig_catch() calls longjmp() */ SOCK_DEBUGF ((NULL, ", interrupted by %s\n", sig_name(sig))); _sock_sig_restore(); return (-1); }
int sock_fgets (char *buf, int max, FILE *stream) { int rc, s = fileno (stream); Socket *sock = _socklist_find (s); sock_type *sk = NULL; SOCK_PROLOGUE (sock, "\nsock_fgets:%d", s); if (sock->tcp_sock) sk = (sock_type*) sock->tcp_sock; else if (sock->udp_sock) sk = (sock_type*) sock->udp_sock; rc = sk ? sock_gets (sk, (BYTE*)buf, max) : -1; SOCK_DEBUGF ((", rc %d", rc)); return (rc); }
int main (void) { const struct hostent *h; const char *host_name = "test-host"; int wait_time; DWORD addr_list [MAX_ADDRESSES+1]; dbug_init(); sock_init(); print_hosts(); wait_time = netdbCacheLife + 1; memset (&addr_list, 0, sizeof(addr_list)); addr_list[0] = htonl (_inet_addr("80.22.33.45")); addr_list[1] = htonl (_inet_addr("222.22.33.46")); addr_list[2] = htonl (_inet_addr("217.22.33.47")); addr_list[3] = htonl (_inet_addr("81.22.33.48")); addr_list[4] = INADDR_NONE; SOCK_DEBUGF (("\nadd_hostent: `%s'", host_name)); add_hostent (NULL, host_name, "some.cname.org", &addr_list[1], addr_list[0], netdbCacheLife); h = gethostbyname (host_name); if (!h) { fprintf (stderr, "gethostbyname() failed!. h_errno = %d\n", h_errno); return (1); } fprintf (stderr, "Waiting for cache-entry to timeout.."); Sleep (wait_time); fprintf (stderr, "gethostbyname() should do a DNS lookup now.\n"); h = gethostbyname (host_name); if (h) fprintf (stderr, "entry didn't timeout!.\n"); #if defined(USE_FORTIFY) Fortify_ListAllMemory(); Fortify_OutputStatistics(); #endif return (0); }
void W32_CALL freehostent (struct hostent *he) { char *p; SOCK_DEBUGF (("\nfreehostent: %s ", he->h_name)); if (!he->h_name) /* possible double freeing */ return; free (he->h_name); he->h_name = NULL; for (p = he->h_addr_list[0]; p; p++) free (p); for (p = he->h_aliases[0]; p; p++) free (p); free (he->h_aliases); free (he->h_addr_list); free (he); }
/* * Allocate and fill local/remote addresses for 'clone'. * Take local address from 'socket', and remote address from * TCB of clone. */ static int alloc_addr (Socket *socket, Socket *clone) { struct in_addr peer; clone->local_addr = SOCK_CALLOC (sizeof(*clone->local_addr)); clone->remote_addr = SOCK_CALLOC (sizeof(*clone->remote_addr)); if (!clone->local_addr || !clone->remote_addr) { SOCK_DEBUGF ((socket, ", ENOMEM")); SOCK_ERR (ENOMEM); return (-1); } peer.s_addr = htonl (clone->tcp_sock->hisaddr); clone->local_addr->sin_family = AF_INET; clone->local_addr->sin_port = socket->local_addr->sin_port; clone->local_addr->sin_addr = socket->local_addr->sin_addr; clone->remote_addr->sin_family = AF_INET; clone->remote_addr->sin_port = htons (clone->tcp_sock->hisport); clone->remote_addr->sin_addr = peer; return (0); }
void DumpHostsCache (void) { struct _hostent *h; time_t now; if (!ReverseHostsList()) return; SOCK_DEBUGF ((" \n\nCached IPv4 hosts: " "Address TTL Alias\n")); now = time (NULL); for (h = host0; h; h = h->h_next) { const char *ip_str, *cache_time; int i; if (h->h_real_ttl == 0) /* skip fixed hosts-file records */ continue; cache_time = ((long)(h->h_timeout - now) < 0) ? "timedout" : hms_str(h->h_real_ttl); ip_str = (h->h_address[0] == INADDR_NONE) ? "<none>" : inet_ntoa(*(struct in_addr*)&h->h_address[0]); SOCK_DEBUGF ((" %-40s %-15s %8s ", h->h_name, ip_str, cache_time)); for (i = 0; h->h_aliases[i]; i++) SOCK_DEBUGF (("%s ", h->h_aliases[i])); if (i == 0) SOCK_DEBUGF (("<none>\n")); else SOCK_DEBUGF ((" \n")); for (i = 1; i < h->h_num_addr; i++) SOCK_DEBUGF (("%42s %s\n", "", inet_ntoa(*(struct in_addr*)&h->h_address[i]))); } }
/* * Raw IP transmitter */ static int ip_transmit (Socket *socket, const void *tx, int len) { eth_address eth; u_long dest; unsigned tx_len, tx_room; sock_type *sk = (sock_type*)socket->udp_sock; struct ip *ip = (struct ip*) tx; const BYTE *buf = (const BYTE*) tx; WORD flags = 0; DWORD offset; UINT h_len, o_len; tcp_tick (NULL); /* process other TCBs too */ tcp_Retransmitter (1); /* This should never happen */ if (ip && (socket->so_state & SS_NBIO) && sock_tbleft(sk) < (len + socket->send_lowat)) { SOCK_DEBUGF ((socket, ", EWOULDBLOCK")); SOCK_ERR (EWOULDBLOCK); return (-1); } if (ip) { offset = ntohs (ip->ip_off); flags = offset & ~IP_OFFMASK; offset = (offset & IP_OFFMASK) << 3; /* 0 <= ip_ofs <= 65536-8 */ } SOCK_DEBUGF ((socket, ", %s / Raw", inet_ntoa(socket->remote_addr->sin_addr))); if (ip && (socket->inp_flags & INP_HDRINCL)) { dest = ip->ip_dst.s_addr; tx_len = len; tx_room = mtu; } else { dest = socket->remote_addr->sin_addr.s_addr; tx_len = len + sizeof (*ip); tx_room = mtu + sizeof (*ip); } if (!dest || !_arp_resolve(ntohl(dest),ð,0)) { SOCK_DEBUGF ((socket, ", no route")); SOCK_ERR (EHOSTUNREACH); STAT (ipstats.ips_noroute++); return (-1); } #if defined(USE_FRAGMENTS) if (!(socket->inp_flags & INP_HDRINCL) && tx_len + socket->ip_opt_len > tx_room) { sk = (sock_type*)socket->raw_sock; if (flags & IP_DF) { SOCK_DEBUGF ((socket, ", EMSGSIZE")); SOCK_ERR (EMSGSIZE); STAT (ipstats.ips_toolong++); return (-1); } return SEND_IP_FRAGMENTS (sk, sk->raw.ip_type, dest, buf, len); } #else if (!(socket->inp_flags & INP_HDRINCL) && tx_len + socket->ip_opt_len > tx_room) { SOCK_DEBUGF ((socket, ", EMSGSIZE")); SOCK_ERR (EMSGSIZE); STAT (ipstats.ips_toolong++); return (-1); } #endif ip = (struct ip*) _eth_formatpacket (ð, IP_TYPE); if (socket->inp_flags & INP_HDRINCL) { memcpy (ip, buf, len); if (ip->ip_src.s_addr == 0) { ip->ip_src.s_addr = gethostid(); ip->ip_sum = 0; ip->ip_sum = ~checksum ((void*)ip, ip->ip_hl << 2); } if (ip->ip_sum == 0) ip->ip_sum = ~checksum ((void*)ip, ip->ip_hl << 2); } else { if (socket->ip_opt && socket->ip_opt_len > 0) { BYTE *data; o_len = min (socket->ip_opt_len, sizeof(socket->ip_opt->ip_opts)); h_len = sizeof(*ip) + o_len; data = (BYTE*)ip + h_len; memcpy (ip+1, &socket->ip_opt->ip_opts, o_len); memcpy (data, buf, len); tx_len += o_len; if (socket->ip_opt->ip_dst.s_addr) /* using source routing */ dest = socket->ip_opt->ip_dst.s_addr; } else { if (buf) memcpy (ip+1, buf, len); h_len = sizeof (*ip); } ip->ip_v = IPVERSION; ip->ip_hl = h_len >> 2; ip->ip_tos = socket->ip_tos; ip->ip_len = htons (tx_len); ip->ip_id = _get_ip_id(); ip->ip_off = 0; ip->ip_ttl = socket->ip_ttl; ip->ip_p = socket->so_proto; ip->ip_src.s_addr = gethostid(); ip->ip_dst.s_addr = dest; ip->ip_sum = 0; ip->ip_sum = ~checksum (ip, h_len); } DEBUG_TX (NULL, ip); if (!_eth_send(tx_len)) { SOCK_DEBUGF ((socket, ", ENETDOWN")); SOCK_ERR (ENETDOWN); return (-1); } if (buf) buf += tx_len; return (len); }
/* * UDP transmitter */ static int udp_transmit (Socket *socket, const void *buf, int len) { sock_type *sk = (sock_type*) socket->udp_sock; u_long dest = socket->remote_addr->sin_addr.s_addr; int tx_room, rc; int is_bcast, is_multi; if (!tcp_tick(sk)) { socket->so_state |= SS_CANTSENDMORE; SOCK_DEBUGF ((socket, ", ENOTCONN (can't send)")); /* !! or EPIPE */ SOCK_ERR (ENOTCONN); return (-1); } tcp_Retransmitter (1); if ((socket->so_state & SS_NBIO) && check_non_block_tx(socket,&len) < 0) { SOCK_DEBUGF ((socket, ", EWOULDBLOCK")); SOCK_ERR (EWOULDBLOCK); return (-1); } is_bcast = (dest == INADDR_BROADCAST || dest == INADDR_ANY); is_multi = IN_MULTICAST (ntohl(socket->remote_addr->sin_addr.s_addr)); SOCK_DEBUGF ((socket, ", %s (%d) / UDP %s", inet_ntoa(socket->remote_addr->sin_addr), ntohs(socket->remote_addr->sin_port), is_multi ? "(mc)" : "")); if (len == 0) /* 0-byte probe packet */ return ip_transmit (socket, NULL, 0); tx_room = sock_tbleft (sk); /* always MTU-28 */ /* Special tests for broadcast messages */ if (is_bcast) { if (len > tx_room) /* don't allow fragments */ { SOCK_DEBUGF ((socket, ", EMSGSIZE")); SOCK_ERR (EMSGSIZE); STAT (ipstats.ips_odropped++); return (-1); } if (_pktserial) /* Link-layer doesn't allow broadcast */ { SOCK_DEBUGF ((socket, ", EADDRNOTAVAIL")); SOCK_ERR (EADDRNOTAVAIL); STAT (ipstats.ips_odropped++); return (-1); } } /* set new TTL if setsockopt() used before sending to Class-D socket */ if (is_multi) sk->udp.ttl = socket->ip_ttl; #if defined(USE_FRAGMENTS) if ((long)len > USHRT_MAX - sizeof(udp_Header)) { SOCK_DEBUGF ((socket, ", EMSGSIZE")); SOCK_ERR (EMSGSIZE); STAT (ipstats.ips_toolong++); return (-1); } if (len > tx_room) return SEND_IP_FRAGMENTS (sk, UDP_PROTO, dest, buf, len); #endif rc = sock_write (sk, (BYTE*)buf, len); if (rc <= 0) /* error in udp_write() */ { SOCK_DEBUGF ((socket, ", ENETDOWN")); SOCK_ERR (ENETDOWN); return (-1); } return (rc); }
/* * TCP transmitter */ static int tcp_transmit (Socket *socket, const void *buf, int len, int flags) { sock_type *sk = (sock_type*)socket->tcp_sock; tcp_tick (sk); tcp_Retransmitter (1); if (sk->tcp.state < tcp_StateESTAB || sk->tcp.state >= tcp_StateLASTACK) { socket->so_state |= SS_CANTSENDMORE; SOCK_DEBUGF ((socket, ", ENOTCONN (%s)", /* !! or EPIPE */ (sk->tcp.locflags & LF_GOT_FIN) ? "got FIN" : "can't send")); SOCK_ERR (ENOTCONN); return (-1); } if (socket->so_state & SS_NBIO) { int in_len = len; if (check_non_block_tx(socket,&len) < 0) { SOCK_DEBUGF ((socket, ", EWOULDBLOCK")); SOCK_ERR (EWOULDBLOCK); return (-1); } if (in_len != len) SOCK_DEBUGF ((socket, " [%d]", len)); /* trace "len=x [y]" */ } SOCK_DEBUGF ((socket, ", %s (%d) / TCP", inet_ntoa(socket->remote_addr->sin_addr), ntohs(socket->remote_addr->sin_port))); #if 0 /* Must wait for room in send buffer */ if ((flags & MSG_WAITALL) || len > sock_tbleft(sk)) len = sock_write (sk, (BYTE*)buf, len); else len = sock_fastwrite (sk, (BYTE*)buf, len); #else /* This is more efficient. The above sock_fastwrite() would * effectively turn off Nagle's algorithm. */ ARGSUSED (flags); len = sock_write (sk, (BYTE*)buf, len); #endif if (len <= 0) /* error in tcp_write() */ { if (sk->tcp.state != tcp_StateESTAB) { SOCK_DEBUGF ((socket, ", ENOTCONN")); SOCK_ERR (ENOTCONN); /* maybe EPIPE? */ } else { SOCK_DEBUGF ((socket, ", ENETDOWN")); SOCK_ERR (ENETDOWN); } return (-1); } return (len); }
/* * Modify an expired cached entry or create a new node and * add it to the linked list. Not used for entries in hosts-file. */ static struct _hostent *add_hostent (struct _hostent *h, const char *name, /* Host name */ const char *cname, /* Canonical name (CNAME) */ DWORD *alist, /* List of alternate addresses */ DWORD addr, /* Main IP-address */ DWORD ttl) /* Time-to-live (sec) */ { DWORD real_ttl = ttl; int i; ttl = min (ttl, netdbCacheLife); /* clamp the TTL */ if (h) /* reuse expired entry */ { if (h->h_name) free (h->h_name); if (h->h_aliases[0]) free (h->h_aliases[0]); /* !! max 1 alias */ memset (&h->h_address[1], 0, /* clear old alternates */ sizeof(h->h_address)-sizeof(u_long)); h->h_aliases[0] = NULL; } else /* create a new node */ { h = (struct _hostent*) calloc (sizeof(*h), 1); if (h) { h->h_next = host0; host0 = h; } } if (!cname || !cname[0]) cname = NULL; if (addr != INADDR_NONE) SOCK_DEBUGF ((", CNAME %s, ttl %lus,", cname ? cname : "<none>", real_ttl)); if (h) { h->h_timeout = ttl ? time (NULL) + ttl : 0; h->h_real_ttl = real_ttl; h->h_address[0] = addr; h->h_num_addr = 1; for (i = 0; alist; i++) { if (alist[i] == INADDR_NONE || alist[i] == INADDR_ANY) break; h->h_address[i+1] = alist[i]; h->h_num_addr++; } if (cname) /* swap name with CNAME */ { h->h_name = strdup (cname); h->h_aliases[0] = strdup (name); /* !! only allow 1 alias */ } else h->h_name = strdup (name); } else SOCK_DEBUGF ((" ENOMEM")); #if defined(TEST_PROG) /* test updated cache */ if (h) { printf ("new entry: name %-30.30s -> address %s ", h->h_name, inet_ntoa(*(struct in_addr*)&h->h_address[0])); for (i = 1; i < h->h_num_addr; i++) printf (", %s", inet_ntoa(*(struct in_addr*)&h->h_address[i])); puts (""); } else printf ("new entry: ENOMEM\n"); #endif return (h); }
/* * transmit() flags: * MSG_DONTROUTE (not supported) * MSG_EOR Close sending side after data sent * MSG_TRUNC (not supported) * MSG_CTRUNC (not supported) * MSG_OOB (not supported) * MSG_WAITALL Wait till room in tx-buffer (not supported) */ static int transmit (const char *func, int s, const void *buf, int len, int flags, const struct sockaddr *to, int tolen) { Socket *socket = _socklist_find (s); int rc; SOCK_DEBUGF ((socket, "\n%s:%d, len=%d", func, s, len)); if (!socket) { if (_sock_dos_fd(s)) { SOCK_DEBUGF ((NULL, ", ENOTSOCK")); SOCK_ERR (ENOTSOCK); return (-1); } SOCK_DEBUGF ((NULL, ", EBADF")); SOCK_ERR (EBADF); return (-1); } if (socket->so_type == SOCK_STREAM || /* TCP-socket or */ (socket->so_state & SS_ISCONNECTED)) /* "connected" udp/raw */ { /* Note: SOCK_RAW doesn't really need a local address/port, but * makes the code more similar for all socket-types. * Disadvantage is that SOCK_RAW ties up a local port and a bit * more memory. */ if (!socket->local_addr) { SOCK_DEBUGF ((socket, ", no local_addr")); SOCK_ERR (ENOTCONN); return (-1); } if (!socket->remote_addr) { SOCK_DEBUGF ((socket, ", no remote_addr")); SOCK_ERR (ENOTCONN); return (-1); } if (socket->so_state & SS_CONN_REFUSED) { if (socket->so_error == ECONNRESET) /* set in tcp_sockreset() */ { SOCK_DEBUGF ((socket, ", ECONNRESET")); SOCK_ERR (ECONNRESET); } else { SOCK_DEBUGF ((socket, ", ECONNREFUSED")); SOCK_ERR (ECONNREFUSED); } return (-1); } } /* connectionless protocol setup */ if (socket->so_type == SOCK_DGRAM || socket->so_type == SOCK_RAW) { if (!to || tolen < sizeof(*to)) { SOCK_DEBUGF ((socket, ", no to-addr")); SOCK_ERR (EINVAL); return (-1); } if (setup_udp_raw(socket,to,tolen) < 0) return (-1); } VERIFY_RW (buf, len); /* Setup SIGINT handler now. */ if (_sock_sig_setup() < 0) { SOCK_ERR (EINTR); return (-1); } switch (socket->so_type) { case SOCK_DGRAM: rc = udp_transmit (socket, buf, len); break; case SOCK_STREAM: rc = tcp_transmit (socket, buf, len, flags); break; case SOCK_RAW: rc = ip_transmit (socket, buf, len); break; default: SOCK_DEBUGF ((socket, ", EPROTONOSUPPORT")); SOCK_ERR (EPROTONOSUPPORT); rc = -1; } _sock_sig_restore(); if (rc >= 0 && (flags & MSG_EOR)) msg_eor_close (socket); return (rc); }
/* * Unhook signal-handlers and optionally chain to previous handlers * if we caught signals. */ void _sock_sig_restore (void) { if (signal_depth == 0) return; if (--signal_depth > 0) return; _sock_stop_timer(); watcbroke = 0; wathndlcbrk = wat_brkmode; #if defined(SIGALRM) && TRAP_SIGALRM signal (SIGALRM, old_sigalrm); unblock_sigalrm(); #if 0 /* don't do this since a socket function might be called from an * alarm handler. This could cause serious recursion and stack fault. */ if (sigalrm_caught && old_sigalrm != SIG_IGN && old_sigalrm != SIG_DFL) { sigalrm_caught = 0; (*old_sigalrm) (SIGALRM); } #endif #endif #if defined(SIGBREAK) signal (SIGBREAK, old_sigbrk); if (sigbrk_caught && old_sigbrk != SIG_IGN && old_sigbrk != SIG_DFL) { sigbrk_caught = 0; (*old_sigbrk) (SIGBREAK); } #endif #if defined(SIGPIPE) signal (SIGPIPE, old_sigpipe); if (sigpipe_caught) { if (old_sigpipe != SIG_IGN && old_sigpipe != SIG_DFL) { sigpipe_caught = 0; (*old_sigpipe) (SIGPIPE); } else { outsnl (_LANG("Terminating on SIGPIPE")); exit (-1); } } #endif #if defined(SIGQUIT) signal (SIGQUIT, old_sigquit); if (sigquit_caught) { if (old_sigquit != SIG_IGN && old_sigquit != SIG_DFL) { sigquit_caught = 0; (*old_sigquit) (SIGQUIT); } else { SOCK_DEBUGF ((NULL, "\nExiting stuck program")); exit (-1); } } #endif signal (SIGINT, old_sigint); if (sigint_caught && old_sigint != SIG_IGN && old_sigint != SIG_DFL) { sigint_caught = 0; (*old_sigint) (SIGINT); } sigalrm_caught = sigbrk_caught = 0; sigint_caught = sigquit_caught = 0; sigpipe_caught = 0; }
/* * connect() * "connect" will attempt to open a connection on a foreign IP address and * foreign port address. This is achieved by specifying the foreign IP * address and foreign port number in the "servaddr". */ int W32_CALL connect (int s, const struct sockaddr *servaddr, int addrlen) { struct sockaddr_in *addr = (struct sockaddr_in*) servaddr; struct sockaddr_in6 *addr6 = (struct sockaddr_in6*) servaddr; struct Socket *socket = _socklist_find (s); volatile int rc, sa_len; BOOL is_ip6; SOCK_PROLOGUE (socket, "\nconnect:%d", s); is_ip6 = (socket->so_family == AF_INET6); sa_len = is_ip6 ? sizeof(*addr6) : sizeof(*addr); if (_sock_chk_sockaddr(socket, servaddr, addrlen) < 0) return (-1); if (socket->so_type == SOCK_STREAM) { if (socket->so_state & SS_ISCONNECTED) { SOCK_DEBUGF ((", EISCONN")); SOCK_ERRNO (EISCONN); return (-1); } if (socket->so_options & SO_ACCEPTCONN) { SOCK_DEBUGF ((", EOPNOTSUPP (listen sock)")); SOCK_ERRNO (EOPNOTSUPP); return (-1); } if (!is_ip6 && IN_MULTICAST(ntohl(addr->sin_addr.s_addr))) { SOCK_DEBUGF ((", EINVAL (mcast)")); SOCK_ERRNO (EINVAL); return (-1); } else if (is_ip6 && IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr)) { SOCK_DEBUGF ((", EINVAL (mcast)")); SOCK_ERRNO (EINVAL); return (-1); } } if (socket->remote_addr) { if ((socket->so_type == SOCK_STREAM) && (socket->so_state & SS_NBIO)) return nblk_connect (socket); SOCK_DEBUGF ((", connect already done!")); SOCK_ERRNO (EISCONN); return (-1); } socket->remote_addr = (struct sockaddr_in*) SOCK_CALLOC (sa_len); if (!socket->remote_addr) { SOCK_DEBUGF ((", ENOMEM (rem)")); SOCK_ERRNO (ENOMEM); return (-1); } #if defined(USE_IPV6) if (is_ip6) { struct sockaddr_in6 *ra = (struct sockaddr_in6*)socket->remote_addr; ra->sin6_family = AF_INET6; ra->sin6_port = addr6->sin6_port; memcpy (&ra->sin6_addr, &addr6->sin6_addr, sizeof(ra->sin6_addr)); } else #endif { socket->remote_addr->sin_family = AF_INET; socket->remote_addr->sin_port = addr->sin_port; socket->remote_addr->sin_addr = addr->sin_addr; } if (!socket->local_addr) { SOCK_DEBUGF ((", auto-binding")); socket->local_addr = (struct sockaddr_in*) SOCK_CALLOC (sa_len); if (!socket->local_addr) { free (socket->remote_addr); socket->remote_addr = NULL; SOCK_DEBUGF ((", ENOMEM (loc)")); SOCK_ERRNO (ENOMEM); return (-1); } #if defined(USE_IPV6) if (is_ip6) { struct sockaddr_in6 *la = (struct sockaddr_in6*)socket->local_addr; la->sin6_family = AF_INET6; la->sin6_port = htons (find_free_port(0,TRUE)); memcpy (&la->sin6_addr, &in6addr_my_ip, sizeof(la->sin6_addr)); } else #endif { socket->local_addr->sin_family = AF_INET; socket->local_addr->sin_port = htons (find_free_port(0,TRUE)); socket->local_addr->sin_addr.s_addr = htonl (my_ip_addr); } } SOCK_DEBUGF ((", src/dest ports: %u/%u", ntohs(socket->local_addr->sin_port), ntohs(socket->remote_addr->sin_port))); /* Not safe to run sock_daemon() now */ _sock_crit_start(); /* Setup SIGINT handler now. */ if (_sock_sig_setup() < 0) { SOCK_ERRNO (EINTR); SOCK_DEBUGF ((", EINTR")); _sock_crit_stop(); return (-1); } switch (socket->so_type) { case SOCK_STREAM: rc = tcp_connect (socket); break; case SOCK_DGRAM: rc = udp_connect (socket); break; case SOCK_RAW: rc = raw_connect (socket); break; default: SOCK_ERRNO (EPROTONOSUPPORT); rc = -1; break; } _sock_sig_restore(); _sock_crit_stop(); return (rc); }
/* * Handle SOCK_STREAM blocking connection. Or non-blocking connect * the first time connect() is called. */ static int tcp_connect (Socket *socket) { DWORD timeout; int status; #if defined(USE_IPV6) if (socket->so_family == AF_INET6) { const struct sockaddr_in6 *la = (const struct sockaddr_in6*) socket->local_addr; const struct sockaddr_in6 *ra = (const struct sockaddr_in6*) socket->remote_addr; if (!_TCP6_open (socket, &ra->sin6_addr, la->sin6_port, ra->sin6_port)) { /* errno already set in _TCP6_open() */ SOCK_DEBUGF ((", %s", socket->tcp_sock->err_msg)); return (-1); } } else #endif if (!_TCP_open (socket, socket->remote_addr->sin_addr, socket->local_addr->sin_port, socket->remote_addr->sin_port)) { /* errno already set in tcp_open() */ SOCK_DEBUGF ((", %s", socket->tcp_sock->err_msg)); return (-1); } /* Don't let tcp_Retransmitter() kill this socket * before our `socket->timeout' expires */ socket->tcp_sock->locflags |= LF_RCVTIMEO; /* We're here only when connect() is called the 1st time * (blocking or non-blocking socket). */ socket->so_state |= SS_ISCONNECTING; timeout = set_timeout (1000 * socket->timeout); if (socket->so_state & SS_NBIO) { /* if user calls getsockopt(SO_ERROR) before calling connect() again */ socket->so_error = EALREADY; socket->nb_timer = timeout; SOCK_DEBUGF ((", EINPROGRESS")); SOCK_ERRNO (EINPROGRESS); return (-1); } /* Handle blocking stream socket connect. * Maybe we should use select_s() instead ? * Maybe set LF_NOCLOSE for all BSD sockets? */ status = _ip_delay0 ((sock_type*)socket->tcp_sock, socket->timeout, (UserHandler)chk_signals, NULL); if (socket->so_error == EHOSTUNREACH) { SOCK_DEBUGF ((", %s", socket->tcp_sock->err_msg ? socket->tcp_sock->err_msg : "no route")); SOCK_ERRNO (EHOSTUNREACH); return (-1); } /* We got an ICMP_UNREACH from someone */ if (socket->so_state & SS_CONN_REFUSED) { socket->so_state &= ~SS_ISCONNECTING; SOCK_DEBUGF ((", ECONNREFUSED")); SOCK_ERRNO (ECONNREFUSED); return (-1); } if (status < 0 && chk_timeout(timeout)) { socket->so_state &= ~SS_ISCONNECTING; SOCK_DEBUGF ((", ETIMEDOUT")); SOCK_ERRNO (ETIMEDOUT); return (-1); } if (status < 0) { socket->so_state &= ~SS_ISCONNECTING; SOCK_DEBUGF ((", ECONNRESET")); SOCK_ERRNO (ECONNRESET); return (-1); } socket->so_state &= ~(SS_UNCONNECTED | SS_ISCONNECTING); socket->so_state |= SS_ISCONNECTED; return (0); }
int accept (int s, struct sockaddr *addr, int *addrlen) { Socket *clone, *socket; volatile DWORD timeout; volatile int newsock = -1; volatile int que_idx; volatile int maxconn; socket = _socklist_find (s); SOCK_PROLOGUE (socket, "\naccept:%d", s); if (!socket->local_addr) { SOCK_DEBUGF ((socket, ", not bound")); SOCK_ERR (ENOTCONN); return (-1); } if (socket->so_type != SOCK_STREAM) { SOCK_DEBUGF ((socket, ", EOPNOTSUPP")); SOCK_ERR (EOPNOTSUPP); return (-1); } if (!(socket->so_options & SO_ACCEPTCONN)) /* listen() not called */ { SOCK_DEBUGF ((socket, ", not SO_ACCEPTCONN")); SOCK_ERR (EINVAL); return (-1); } if (!(socket->so_state & (SS_ISLISTENING | SS_ISCONNECTING))) { SOCK_DEBUGF ((socket, ", not listening")); SOCK_ERR (ENOTCONN); return (-1); } if (addr && addrlen) { if (*addrlen < sizeof(*addr)) { SOCK_DEBUGF ((socket, ", EFAULT")); SOCK_ERR (EFAULT); return (-1); } VERIFY_RW (addr, *addrlen); } /* Get max possible TCBs on listen-queue. * Some (or all) may be NULL until a SYN comes in. */ maxconn = socket->backlog; if (maxconn < 1 || maxconn > SOMAXCONN) { SOCK_FATAL (("%s(%d): Illegal socket backlog %d", __FILE__, __LINE__, maxconn)); SOCK_ERR (EINVAL); return (-1); } if (socket->timeout) timeout = set_timeout (1000 * socket->timeout); else timeout = 0UL; if (_sock_sig_setup() < 0) { SOCK_ERR (EINTR); goto accept_fail; } /* Loop over all queue-slots and accept first connected TCB */ for (que_idx = 0; ; que_idx = (++que_idx % maxconn)) { tcp_Socket *sk = socket->listen_queue [que_idx]; tcp_tick (NULL); SOCK_YIELD(); /* No SYNs received yet. This shouldn't happen if we called 'accept()' * after 'select_s()' said that socket was readable. (At least one * connection on the listen-queue). */ if (sk) { /* This could happen if 'accept()' was called too long after connection * was established and then closed by peer. This could also happen if * someone did a portscan on us. I.e. he sent 'SYN', we replied with * 'SYN+ACK' and he never sent an 'ACK'. Thus we timeout in * 'tcp_Retransmitter()' and abort the TCB. * * Queue slot is in any case ready for another 'SYN' to come and be * handled by '_sock_append()'. */ if (sk->state >= tcp_StateLASTACK && sk->ip_type == 0) { SOCK_DEBUGF ((socket, ", aborted TCB (idx %d)", que_idx)); listen_free (socket, que_idx); continue; } /* !!to-do: Should maybe loop over all maxconn TCBs and accept the * one with oldest 'syn_timestamp'. */ if (tcp_established(sk)) { SOCK_DEBUGF ((socket, ", connected! (idx %d)", que_idx)); break; } } /* We've polled all listen-queue slots and none are connected. * Return fail if socket is non-blocking. */ if (que_idx == maxconn-1 && (socket->so_state & SS_NBIO)) { SOCK_DEBUGF ((socket, ", would block")); SOCK_ERR (EWOULDBLOCK); goto accept_fail; } if (chk_timeout(timeout)) { SOCK_DEBUGF ((socket, ", ETIMEDOUT")); SOCK_ERR (ETIMEDOUT); goto accept_fail; } } /* We're here only when above 'tcp_established()' succeeded. * Now duplicate 'socket' into a new listening socket 'clone' * with handle 'newsock'. */ _sock_enter_scope(); newsock = dup_bind (socket, &clone, que_idx); if (newsock < 0) goto accept_fail; if (alloc_addr(socket, clone) < 0) { SOCK_DEL_FD (newsock); goto accept_fail; } /* Clone is connected, but *not* listening/accepting. * Note: other 'so_state' bits from parent is unchanged. * e.g. clone may be non-blocking. */ clone->so_state |= SS_ISCONNECTED; clone->so_state &= ~(SS_ISLISTENING | SS_ISCONNECTING); clone->so_options &= ~SO_ACCEPTCONN; /* Prevent a PUSH on first segment sent. */ sock_noflush ((sock_type*)clone->tcp_sock); SOCK_DEBUGF ((clone, "\nremote %s (%d)", inet_ntoa (clone->remote_addr->sin_addr), ntohs (clone->remote_addr->sin_port))); if (addr && addrlen) { struct sockaddr_in *sa = (struct sockaddr_in*)addr; sa->sin_family = AF_INET; sa->sin_port = clone->remote_addr->sin_port; sa->sin_addr = clone->remote_addr->sin_addr; memset (sa->sin_zero, 0, sizeof(sa->sin_zero)); *addrlen = sizeof(*sa); } _sock_leave_scope(); _sock_sig_restore(); return (newsock); accept_fail: _sock_leave_scope(); _sock_sig_restore(); return (-1); }
/* * Called from tcp_fsm.c / tcp_listen_state() (via _tcp_syn_hook) to * append a new connection to the listen-queue of socket 'sock'. * * TCB on input ('orig') has received a SYN. Replace TCB on output * with a cloned TCB that we append to the listen-queue and eventually * is used by accept() to create a new socket. * * TCB on input ('orig') must still be listening for further connections * on the same port as specified in call to _TCP_listen(). */ int _sock_append (tcp_Socket **tcp) { tcp_Socket *clone; tcp_Socket *orig = *tcp; Socket *sock = NULL; /* associated socket for '*tcp' */ int i; /* Lookup BSD-socket for Wattcp TCB */ if (!_tcp_find_hook || (sock = (*_tcp_find_hook)(orig)) == NULL) { SOCK_DEBUGF ((NULL, "\n sock_append: not found!?")); return (0); /* i.e. could be a native Wattcp socket */ } SOCK_DEBUGF ((sock, "\n sock_append:%d", sock->fd)); if (!(sock->so_options & SO_ACCEPTCONN)) { SOCK_DEBUGF ((sock, ", not SO_ACCEPTCONN")); return (-1); /* How could this happen? */ } /* Find the first vacant slot for this clone */ for (i = 0; i < sock->backlog; i++) if (!sock->listen_queue[i]) break; if (i >= sock->backlog || i >= SOMAXCONN) { /* !!to-do: drop the oldest (or a random) slot in the listen-queue. */ SOCK_DEBUGF ((sock, ", queue full (idx %d)", i)); return (-1); } SOCK_DEBUGF ((sock, ", idx %d", i)); clone = SOCK_CALLOC (sizeof(*clone)); if (!clone) { SOCK_DEBUGF ((sock, ", ENOMEM")); return (-1); } /* Link in the semi-connected socket (SYN received, ACK will be sent) */ sock->listen_queue[i] = clone; sock->syn_timestamp[i] = set_timeout (0); /* Copy the TCB (except Tx-buffer) to clone */ memcpy (clone, orig, sizeof(*clone) - sizeof(clone->data)); clone->safetytcp = SAFETYTCP; /* Increase the TCP window (to 16kB) */ sock_setbuf ((sock_type*)clone, calloc(DEFAULT_RCV_WIN,1), DEFAULT_RCV_WIN); /* Undo what tcp_handler() and tcp_listen_state() did to * this listening socket. */ orig->hisport = 0; orig->hisaddr = 0; orig->myaddr = 0; orig->seqnum = INIT_SEQ(); /* set new ISS */ orig->unhappy = FALSE; CLR_PEER_MAC_ADDR (orig); #if defined(USE_DEBUG) /* !!needs some work */ orig->last_acknum[0] = orig->last_acknum[1] = 0; orig->last_seqnum[0] = orig->last_seqnum[1] = 0; #endif clone->next = _tcp_allsocs; _tcp_allsocs = clone; /* prepend clone to TCB-list */ *tcp = clone; /* clone is now the new TCB */ return (0); }
int sock_recv_from (sock_type *s, void *hisip, WORD *hisport, void *buffer, unsigned len, int peek) { #if !defined(USE_UDP_ONLY) _tcp_Socket *t; #endif recv_buf *p, *oldest = NULL; recv_data *r = (recv_data*) s->udp.rx_data; long seqnum = LONG_MAX; int i; if (r->recv_sig != RECV_USED) { SOCK_ERRNO (EBADF); /* To differentiate an error from 0-byte probe (also -1) */ return (-1); } switch (s->udp.ip_type) { case UDP_PROTO: p = (recv_buf*) r->recv_bufs; /* find the oldest used UDP buffer. */ for (i = 0; i < r->recv_bufnum; i++, p++) { switch (p->buf_sig) { case RECV_UNUSED: break; case RECV_USED: /* Drop looped packets sent by us (running * under Win32 DOS box using NDIS3PKT or SwsVpkt). */ if ((_eth_ndis3pkt || _eth_SwsVpkt) && !s->tcp.is_ip6 && p->buf_hisip == intel(my_ip_addr)) { p->buf_sig = RECV_UNUSED; continue; } if (p->buf_seqnum < seqnum) /* ignore wraps */ { seqnum = p->buf_seqnum; oldest = p; #if 0 SOCK_DEBUGF (("\nsock_recv_from(): buffer %d, " "seq-num %ld, len %d", i, seqnum, p->buf_len)); #endif } break; default: outsnl (_LANG("ERROR: sock_recv_init data err")); return (0); } } break; #if !defined(USE_UDP_ONLY) case TCP_PROTO: t = &s->tcp; len = min (len, (unsigned)t->rx_datalen); if (len) memcpy (buffer, r->recv_bufs, len); return (len); #endif } if (!oldest) return (0); /* found the oldest UDP packet */ p = oldest; if (p->buf_len < 0) /* a 0-byte probe packet */ len = -1; else { len = min ((unsigned)p->buf_len, len); memcpy (buffer, p->buf_data, len); } #if defined(USE_IPV6) if (s->tcp.is_ip6) { if (hisip) memcpy (hisip, &p->buf_hisip6, sizeof(ip6_address)); } else #endif if (hisip) *(DWORD*)hisip = p->buf_hisip; if (hisport) *hisport = p->buf_hisport; if (!peek) p->buf_sig = RECV_UNUSED; return (len); }
/* * AI_V4MAPPED + AF_INET6 * If no IPv6 address then a query for IPv4 and map returned values. * * AI_ALL + AI_V4MAPPED + AF_INET6 * Return IPv6 and IPv4 mapped. * * AI_ADDRCONFIG * Only return IPv6 / IPv4 address if there is an interface of that * type active. */ struct hostent * W32_CALL getipnodebyname (const char *name, int af, int flags, int *error) { struct hostent *he1 = NULL; struct hostent *he2 = NULL; struct in_addr in4; struct in6_addr in6; BOOL have_v4 = TRUE, have_v6 = TRUE; BOOL v4 = FALSE, v6 = FALSE; int tmp_err; SOCK_DEBUGF (("\ngetipnodebyname: %s ", name)); /* If we care about active interfaces then check. */ if (flags & AI_ADDRCONFIG) scan_interface (&have_v4, &have_v6); /* Check for literal address. */ v4 = inet_pton (AF_INET, name, &in4); if (!v4) v6 = inet_pton (AF_INET6, name, &in6); /* Impossible combination? */ if ((af == AF_INET6 && !(flags & AI_V4MAPPED) && v4) || (af == AF_INET && v6) || (!have_v4 && v4) || (!have_v6 && v6) || (!have_v4 && af == AF_INET) || ((!have_v6 && af == AF_INET6) && ((flags & AI_V4MAPPED) && have_v4)) || !(flags & AI_V4MAPPED)) { *error = HOST_NOT_FOUND; return (NULL); } /* Literal address? */ if (v4 || v6) { struct hostent he; char *addr_list[2]; char *aliases[1]; he.h_name = (char*) name; he.h_addr_list = addr_list; he.h_addr_list[0] = (v4 ? (char*)&in4 : (char*)&in6); he.h_addr_list[1] = NULL; he.h_aliases = aliases; he.h_aliases[0] = NULL; he.h_length = (v4 ? INADDRSZ : IN6ADDRSZ); he.h_addrtype = (v4 ? AF_INET : AF_INET6); return copyandmerge (&he, NULL, af, error); } tmp_err = NO_RECOVERY; if (have_v6 && af == AF_INET6) { #if defined(USE_IPV6) he1 = gethostbyname6 (name); #else he1 = NULL; #endif if (!he1) tmp_err = HOST_NOT_FOUND; } if (have_v4 && (af == AF_INET || (af == AF_INET6 && (flags & AI_V4MAPPED) && (!he1 || (flags & AI_ALL))))) { SOCK_ENTER_SCOPE(); he2 = gethostbyname (name); SOCK_LEAVE_SCOPE(); if (!he2 || !he1) { *error = HOST_NOT_FOUND; return (NULL); } } else *error = tmp_err; return copyandmerge (he1, he2, af, error); }
/* * Gets upcalled when data arrives. * We MUST set 'p->buf_len = -1' to signal a 0-byte UDP packet * not 0 */ static int sock_recvdaemon (sock_type *s, const void *data, unsigned len, const tcp_PseudoHeader *ph, const udp_Header *udp) { recv_data *r; recv_buf *p; unsigned i; switch (s->udp.ip_type) { case UDP_PROTO: r = (recv_data*) s->udp.rx_data; p = (recv_buf*) r->recv_bufs; if (r->recv_sig != RECV_USED) { outsnl (_LANG("ERROR: udp recv data conflict")); return (0); } /* find an unused buffer */ for (i = 0; i < r->recv_bufnum; i++, p++) switch (p->buf_sig) { case RECV_USED: break; case RECV_UNUSED: /* take this one */ p->buf_sig = RECV_USED; p->buf_hisport = udp->srcPort; p->buf_seqnum = seq_num++; #if defined(USE_IPV6) if (s->udp.is_ip6) memcpy (&p->buf_hisip6, &((tcp_PseudoHeader6*)ph)->src, sizeof(p->buf_hisip6)); else #endif p->buf_hisip = ph->src; len = min (len, sizeof(p->buf_data)); if (len > 0) { memcpy (p->buf_data, data, len); p->buf_len = (short) len; } else p->buf_len = -1; /* a 0-byte probe */ #if 0 SOCK_DEBUGF (("\nsock_recvdaemon(): buffer %d, " "seq-num %ld, len %d", i, seq_num-1, p->buf_len)); #endif return (0); default: outsnl (_LANG("ERROR: sock_recv_daemon data err")); return (0); } return (0); #if !defined(USE_UDP_ONLY) case TCP_PROTO: { _tcp_Socket *t = &s->tcp; r = (recv_data*) t->rx_data; if (r->recv_sig != RECV_USED) { outsnl (_LANG("ERROR: tcp recv data conflict")); return (0); } /* stick it on the end if you can */ i = t->max_rx_data - t->rx_datalen; if (i > 1) { /* we can accept some of this */ if (len > i) len = i; if (len > 0) memcpy (r->recv_bufs + t->rx_datalen, data, len); t->rx_datalen += len; return (len); } return (0); /* didn't take none */ } #endif } return (0); }
struct hostent * W32_CALL getipnodebyaddr (const void *src, size_t len, int af, int *error) { struct hostent *he1, *he2; const BYTE *cp = (const BYTE*) src; SOCK_DEBUGF (("\ngetipnodebyaddr: ")); if (!src) { *error = NO_RECOVERY; return (NULL); } switch (af) { case AF_INET: if (len < INADDRSZ) { *error = NO_RECOVERY; return (NULL); } break; #if defined(USE_IPV6) case AF_INET6: if (len < IN6ADDRSZ) { *error = NO_RECOVERY; return (NULL); } break; #endif default: *error = NO_RECOVERY; return (NULL); } /* Look up IPv4 and IPv4 mapped/compatible addresses. */ if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(cp)) || (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(cp)) || (af == AF_INET)) { if (af == AF_INET6) cp += 12; SOCK_ENTER_SCOPE(); he1 = gethostbyaddr ((const char*)cp, 4, AF_INET); SOCK_LEAVE_SCOPE(); if (af == AF_INET) goto ret_copy; /* Convert from AF_INET to AF_INET6. */ he2 = copyandmerge (he1, NULL, af, error); if (he2) { memcpy (he2->h_addr, src, len); /* Restore original address */ SOCK_DEBUGF (("%s", af == AF_INET ? inet_ntoa(*(struct in_addr*)&he2->h_addr) : _inet6_ntoa(he2->h_addr))); } return (he2); } he1 = gethostbyaddr (src, len, AF_INET6); /* Lookup IPv6 address */ ret_copy: if (!he1) { *error = HOST_NOT_FOUND; return (NULL); } return copyandmerge (he1, NULL, af, error); }