/* 这个和pipe功能有相似之处,pipe是单工的,socketpair是双工的 * family只能是UNIX域的。 */ static int sock_socketpair(int family, int type, int protocol, unsigned long usockvec[2]) { int fd1, fd2, i; struct socket *sock1, *sock2; int er; DPRINTF((net_debug, "NET: sock_socketpair: family = %d, type = %d, protocol = %d\n", family, type, protocol)); /* * Obtain the first socket and check if the underlying protocol * supports the socketpair call. */ /* 如果创建失败,则直接返回 */ if ((fd1 = sock_socket(family, type, protocol)) < 0) return(fd1); sock1 = sockfd_lookup(fd1, NULL); if (!sock1->ops->socketpair) { sys_close(fd1); return(-EINVAL); } /* Now grab another socket and try to connect the two together. */ if ((fd2 = sock_socket(family, type, protocol)) < 0) { sys_close(fd1); return(-EINVAL); } sock2 = sockfd_lookup(fd2, NULL); if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) { sys_close(fd1); sys_close(fd2); return(i); } sock1->conn = sock2; sock2->conn = sock1; /* 完成socketpair操作后,则这只套接字的状态为连接状态 */ sock1->state = SS_CONNECTED; sock2->state = SS_CONNECTED; er=verify_area(VERIFY_WRITE, usockvec, 2 * sizeof(int)); if(er) return er; put_fs_long(fd1, &usockvec[0]); put_fs_long(fd2, &usockvec[1]); return(0); }
int ipc_wait_for_server(u16 port) { struct sockaddr_in sa; int fd; MZERO(sa); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr("127.0.0.1"); sa.sin_port = port; if ((fd = sock_socket(SOCK_STREAM, 0, 0)) < 0) { rg_error(LERR, "failed creating socket"); return -1; } /* Try to connect to server infinitely */ while (1) { if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) >= 0) break; /* Sleep for 10ms before trying again */ usleep(10000); } /* Once the server accepts the connection, it tries to send the client a * sync message. It will fail if we close the socket now. So we keep the * socket open until a sync is received, to keep the server happy. */ ipc_client_sync(fd); socket_close(fd); return 0; }
static int libcfs_sock_create (cfs_socket_t **sockp, int *fatal, __u32 local_ip, int local_port) { struct sockaddr_in locaddr; cfs_socket_t *sock; int option; int optlen; int rc; /* All errors are fatal except bind failure if the port is in use */ *fatal = 1; sock = _MALLOC(sizeof(cfs_socket_t), M_TEMP, M_WAITOK|M_ZERO); if (!sock) { CERROR("Can't allocate cfs_socket.\n"); return -ENOMEM; } *sockp = sock; sock->s_magic = CFS_SOCK_MAGIC; rc = -sock_socket(PF_INET, SOCK_STREAM, 0, libcfs_sock_upcall, sock, &C2B_SOCK(sock)); if (rc != 0) goto out; option = 1; optlen = sizeof(option); rc = -sock_setsockopt(C2B_SOCK(sock), SOL_SOCKET, SO_REUSEADDR, &option, optlen); if (rc != 0) goto out; /* can't specify a local port without a local IP */ LASSERT (local_ip == 0 || local_port != 0); if (local_ip != 0 || local_port != 0) { bzero (&locaddr, sizeof (locaddr)); locaddr.sin_len = sizeof(struct sockaddr_in); locaddr.sin_family = AF_INET; locaddr.sin_port = htons (local_port); locaddr.sin_addr.s_addr = (local_ip != 0) ? htonl(local_ip) : INADDR_ANY; rc = -sock_bind(C2B_SOCK(sock), (struct sockaddr *)&locaddr); if (rc == -EADDRINUSE) { CDEBUG(D_NET, "Port %d already in use\n", local_port); *fatal = 0; goto out; } if (rc != 0) { CERROR("Error trying to bind to port %d: %d\n", local_port, rc); goto out; } } return 0; out: if (C2B_SOCK(sock) != NULL) sock_close(C2B_SOCK(sock)); FREE(sock, M_TEMP); return rc; }
static int sock_socketpair(int family, int type, int protocol, int usockvec[2]) { int fd1, fd2, i; struct socket *sock1, *sock2; PRINTK("sys_socketpair: family = %d, type = %d, protocol = %d\n", family, type, protocol); /* * obtain the first socket and check if the underlying protocol * supports the socketpair call */ if ((fd1 = sock_socket(family, type, protocol)) < 0) return fd1; sock1 = sockfd_lookup(fd1, NULL); if (!sock1->ops->socketpair) { sys_close(fd1); return -EINVAL; } /* * now grab another socket and try to connect the two together */ if ((fd2 = sock_socket(family, type, protocol)) < 0) { sys_close(fd1); return -EINVAL; } sock2 = sockfd_lookup(fd2, NULL); if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) { sys_close(fd1); sys_close(fd2); return i; } sock1->conn = sock2; sock2->conn = sock1; sock1->state = SS_CONNECTED; sock2->state = SS_CONNECTED; verify_area(usockvec, 2 * sizeof(int)); put_fs_long(fd1, &usockvec[0]); put_fs_long(fd2, &usockvec[1]); return 0; }
errno_t xi_sock_socket(int domain, int type, int protocol, sock_upcall callback, void *cookie, xi_socket_t *new_so) { #ifdef __KPI_SOCKET__ return sock_socket(domain, type, protocol, callback, cookie, new_so); #else thread_funnel_set(network_flock, TRUE); errno_t error; error = socreate(domain, new_so, type, protocol); (void)thread_funnel_set(network_flock, FALSE); return error; #endif }
int ipc_listen_ip(u16 port, u32 addr) { int fd; if ((fd = sock_socket(SOCK_STREAM, addr, port)) < 0) return -1; /* 5 is a big enough queue length */ if (listen(fd, 5) < 0) { rg_error(LERR, "failed ipc listen %m"); goto Error; } return fd; Error: socket_close(fd); return -1; }
static int __ipc_connect_ip(u16 port, u32 addr, int quiet) { struct sockaddr_in sa; int fd = -1; while (1) { if ((fd = sock_socket(SOCK_STREAM, 0, 0)) < 0) return -1; MZERO(sa); sa.sin_family = AF_INET; sa.sin_addr.s_addr = addr; sa.sin_port = port; if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { socket_close(fd); if (!quiet) rg_error(LERR, "failed ipc connect %m"); return -1; } /* Linux 2.4 kernel has a bug with localhost connections. * After the server calls listen(), then the client calls * connect() and returns with success immediately, before * the server calls accept()! * Therefore, a SYNC_STR command is used to make sure the connect * succeeded. * This has not been tested on Linux 2.2 whether it too has * this bug. It probably does not exist on VxWorks, since VxWorks * TCP/IP stack is completely different (its BSD based). */ if (!ipc_client_sync(fd)) break; socket_close(fd); if (!quiet) rg_error(LWARN, "failed ipc connect sync - retrying"); sys_sleep(1); } return fd; }
int libcfs_ipif_query (char *name, int *up, __u32 *ip, __u32 *mask) { struct ifreq ifr; socket_t so; __u32 val; int nob; int rc; rc = -sock_socket(PF_INET, SOCK_STREAM, 0, NULL, NULL, &so); if (rc != 0) { CERROR ("Can't create socket: %d\n", rc); return rc; } nob = strnlen(name, IFNAMSIZ); if (nob == IFNAMSIZ) { CERROR("Interface name %s too long\n", name); rc = -EINVAL; goto out; } CLASSERT (sizeof(ifr.ifr_name) >= IFNAMSIZ); bzero(&ifr, sizeof(ifr)); strcpy(ifr.ifr_name, name); rc = -sock_ioctl (so, SIOCGIFFLAGS, &ifr); if (rc != 0) { CERROR("Can't get flags for interface %s\n", name); goto out; } if ((ifr.ifr_flags & IFF_UP) == 0) { CDEBUG(D_NET, "Interface %s down\n", name); *up = 0; *ip = *mask = 0; goto out; } *up = 1; bzero(&ifr, sizeof(ifr)); strcpy(ifr.ifr_name, name); *((struct sockaddr_in *)&ifr.ifr_addr) = blank_sin(); rc = -sock_ioctl(so, SIOCGIFADDR, &ifr); if (rc != 0) { CERROR("Can't get IP address for interface %s\n", name); goto out; } val = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; *ip = ntohl(val); bzero(&ifr, sizeof(ifr)); strcpy(ifr.ifr_name, name); *((struct sockaddr_in *)&ifr.ifr_addr) = blank_sin(); rc = -sock_ioctl(so, SIOCGIFNETMASK, &ifr); if (rc != 0) { CERROR("Can't get netmask for interface %s\n", name); goto out; } val = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; *mask = ntohl(val); out: sock_close(so); return rc; }
int libcfs_ipif_enumerate (char ***namesp) { /* Allocate and fill in 'names', returning # interfaces/error */ char **names; int toobig; int nalloc; int nfound; socket_t so; struct ifreq *ifr; struct ifconf ifc; int rc; int nob; int i; rc = -sock_socket(PF_INET, SOCK_STREAM, 0, NULL, NULL, &so); if (rc != 0) { CERROR ("Can't create socket: %d\n", rc); return (rc); } nalloc = 16; /* first guess at max interfaces */ toobig = 0; for (;;) { if (nalloc * sizeof(*ifr) > CFS_PAGE_SIZE) { toobig = 1; nalloc = CFS_PAGE_SIZE/sizeof(*ifr); CWARN("Too many interfaces: only enumerating first %d\n", nalloc); } LIBCFS_ALLOC(ifr, nalloc * sizeof(*ifr)); if (ifr == NULL) { CERROR ("ENOMEM enumerating up to %d interfaces\n", nalloc); rc = -ENOMEM; goto out0; } ifc.ifc_buf = (char *)ifr; ifc.ifc_len = nalloc * sizeof(*ifr); #if 1 /* * XXX Liang: * sock_ioctl(..., SIOCGIFCONF, ...) is not supposed to be used in * kernel space because it always try to copy result to userspace. * So we can't get interfaces name by sock_ioctl(...,SIOCGIFCONF,...). * I've created a bug for Apple, let's wait... */ nfound = 0; for (i = 0; i < 16; i++) { struct ifreq en; bzero(&en, sizeof(en)); snprintf(en.ifr_name, IFNAMSIZ, "en%d", i); rc = -sock_ioctl (so, SIOCGIFFLAGS, &en); if (rc != 0) continue; strcpy(ifr[nfound++].ifr_name, en.ifr_name); } #else /* NOT in using now */ rc = -sock_ioctl(so, SIOCGIFCONF, (caddr_t)&ifc); if (rc < 0) { CERROR ("Error %d enumerating interfaces\n", rc); goto out1; } nfound = ifc.ifc_len/sizeof(*ifr); LASSERT (nfound <= nalloc); #endif if (nfound < nalloc || toobig) break; LIBCFS_FREE(ifr, nalloc * sizeof(*ifr)); nalloc *= 2; } if (nfound == 0) goto out1; LIBCFS_ALLOC(names, nfound * sizeof(*names)); if (names == NULL) { rc = -ENOMEM; goto out1; } /* NULL out all names[i] */ memset (names, 0, nfound * sizeof(*names)); for (i = 0; i < nfound; i++) { nob = strnlen (ifr[i].ifr_name, IFNAMSIZ); if (nob == IFNAMSIZ) { /* no space for terminating NULL */ CERROR("interface name %.*s too long (%d max)\n", nob, ifr[i].ifr_name, IFNAMSIZ); rc = -ENAMETOOLONG; goto out2; } LIBCFS_ALLOC(names[i], IFNAMSIZ); if (names[i] == NULL) { rc = -ENOMEM; goto out2; } memcpy(names[i], ifr[i].ifr_name, nob); names[i][nob] = 0; } *namesp = names; rc = nfound; out2: if (rc < 0) libcfs_ipif_free_enumeration(names, nfound); out1: LIBCFS_FREE(ifr, nalloc * sizeof(*ifr)); out0: sock_close(so); return rc; }
/* * Do a remote procedure call (RPC) and wait for its reply. * If from_p is non-null, then we are doing broadcast, and * the address from whence the response came is saved there. */ int krpc_call( struct sockaddr_in *sa, u_int sotype, u_int prog, u_int vers, u_int func, mbuf_t *data, /* input/output */ struct sockaddr_in *from_p) /* output */ { socket_t so; struct sockaddr_in *sin; mbuf_t m, nam, mhead; struct rpc_call *call; struct rpc_reply *reply; int error, timo, secs; size_t len; static u_int32_t xid = ~0xFF; u_int16_t tport; size_t maxpacket = 1<<16; /* * Validate address family. * Sorry, this is INET specific... */ if (sa->sin_family != AF_INET) return (EAFNOSUPPORT); /* Free at end if not null. */ nam = mhead = NULL; /* * Create socket and set its recieve timeout. */ if ((error = sock_socket(AF_INET, sotype, 0, 0, 0, &so))) goto out1; { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; if ((error = sock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))) goto out; } /* * Enable broadcast if necessary. */ if (from_p && (sotype == SOCK_DGRAM)) { int on = 1; if ((error = sock_setsockopt(so, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)))) goto out; } /* * Bind the local endpoint to a reserved port, * because some NFS servers refuse requests from * non-reserved (non-privileged) ports. */ if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &m))) goto out; sin = mbuf_data(m); bzero(sin, sizeof(*sin)); mbuf_setlen(m, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; tport = IPPORT_RESERVED; do { tport--; sin->sin_port = htons(tport); error = sock_bind(so, (struct sockaddr*)sin); } while (error == EADDRINUSE && tport > IPPORT_RESERVED / 2); mbuf_freem(m); m = NULL; if (error) { printf("bind failed\n"); goto out; } /* * Setup socket address for the server. */ if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &nam))) goto out; sin = mbuf_data(nam); mbuf_setlen(nam, sa->sin_len); bcopy((caddr_t)sa, (caddr_t)sin, sa->sin_len); if (sotype == SOCK_STREAM) { struct timeval tv; tv.tv_sec = 60; tv.tv_usec = 0; error = sock_connect(so, mbuf_data(nam), MSG_DONTWAIT); if (error && (error != EINPROGRESS)) goto out; error = sock_connectwait(so, &tv); if (error) { if (error == EINPROGRESS) error = ETIMEDOUT; printf("krpc_call: error waiting for TCP socket connect: %d\n", error); goto out; } } /* * Prepend RPC message header. */ m = *data; *data = NULL; #if DIAGNOSTIC if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) panic("krpc_call: send data w/o pkthdr"); if (mbuf_pkthdr_len(m) < mbuf_len(m)) panic("krpc_call: pkthdr.len not set"); #endif len = sizeof(*call); if (sotype == SOCK_STREAM) len += 4; /* account for RPC record marker */ mhead = m; if ((error = mbuf_prepend(&mhead, len, MBUF_WAITOK))) goto out; if ((error = mbuf_pkthdr_setrcvif(mhead, NULL))) goto out; /* * Fill in the RPC header */ if (sotype == SOCK_STREAM) { /* first, fill in RPC record marker */ u_int32_t *recmark = mbuf_data(mhead); *recmark = htonl(0x80000000 | (mbuf_pkthdr_len(mhead) - 4)); call = (struct rpc_call *)(recmark + 1); } else { call = mbuf_data(mhead); } bzero((caddr_t)call, sizeof(*call)); xid++; call->rp_xid = htonl(xid); /* call->rp_direction = 0; */ call->rp_rpcvers = htonl(2); call->rp_prog = htonl(prog); call->rp_vers = htonl(vers); call->rp_proc = htonl(func); /* call->rp_auth = 0; */ /* call->rp_verf = 0; */ /* * Send it, repeatedly, until a reply is received, * but delay each re-send by an increasing amount. * If the delay hits the maximum, start complaining. */ timo = 0; for (;;) { struct msghdr msg; /* Send RPC request (or re-send). */ if ((error = mbuf_copym(mhead, 0, MBUF_COPYALL, MBUF_WAITOK, &m))) goto out; bzero(&msg, sizeof(msg)); if (sotype == SOCK_STREAM) { msg.msg_name = NULL; msg.msg_namelen = 0; } else { msg.msg_name = mbuf_data(nam); msg.msg_namelen = mbuf_len(nam); } error = sock_sendmbuf(so, &msg, m, 0, 0); if (error) { printf("krpc_call: sosend: %d\n", error); goto out; } m = NULL; /* Determine new timeout. */ if (timo < MAX_RESEND_DELAY) timo++; else printf("RPC timeout for server " IP_FORMAT "\n", IP_LIST(&(sin->sin_addr.s_addr))); /* * Wait for up to timo seconds for a reply. * The socket receive timeout was set to 1 second. */ secs = timo; while (secs > 0) { size_t readlen; if (m) { mbuf_freem(m); m = NULL; } if (sotype == SOCK_STREAM) { int maxretries = 60; struct iovec aio; aio.iov_base = &len; aio.iov_len = sizeof(u_int32_t); bzero(&msg, sizeof(msg)); msg.msg_iov = &aio; msg.msg_iovlen = 1; do { error = sock_receive(so, &msg, MSG_WAITALL, &readlen); if ((error == EWOULDBLOCK) && (--maxretries <= 0)) error = ETIMEDOUT; } while (error == EWOULDBLOCK); if (!error && readlen < aio.iov_len) { /* only log a message if we got a partial word */ if (readlen != 0) printf("short receive (%ld/%ld) from server " IP_FORMAT "\n", readlen, sizeof(u_int32_t), IP_LIST(&(sin->sin_addr.s_addr))); error = EPIPE; } if (error) goto out; len = ntohl(len) & ~0x80000000; /* * This is SERIOUS! We are out of sync with the sender * and forcing a disconnect/reconnect is all I can do. */ if (len > maxpacket) { printf("impossible packet length (%ld) from server " IP_FORMAT "\n", len, IP_LIST(&(sin->sin_addr.s_addr))); error = EFBIG; goto out; } do { readlen = len; error = sock_receivembuf(so, NULL, &m, MSG_WAITALL, &readlen); } while (error == EWOULDBLOCK); if (!error && (len > readlen)) { printf("short receive (%ld/%ld) from server " IP_FORMAT "\n", readlen, len, IP_LIST(&(sin->sin_addr.s_addr))); error = EPIPE; } } else { len = maxpacket; readlen = len; bzero(&msg, sizeof(msg)); msg.msg_name = from_p; msg.msg_namelen = (from_p == NULL) ? 0 : sizeof(*from_p); error = sock_receivembuf(so, &msg, &m, 0, &readlen); } if (error == EWOULDBLOCK) { secs--; continue; } if (error) goto out; len = readlen; /* Does the reply contain at least a header? */ if (len < MIN_REPLY_HDR) continue; if (mbuf_len(m) < MIN_REPLY_HDR) continue; reply = mbuf_data(m); /* Is it the right reply? */ if (reply->rp_direction != htonl(RPC_REPLY)) continue; if (reply->rp_xid != htonl(xid)) continue; /* Was RPC accepted? (authorization OK) */ if (reply->rp_astatus != 0) { error = ntohl(reply->rp_u.rpu_errno); printf("rpc denied, error=%d\n", error); /* convert rpc error to errno */ switch (error) { case RPC_MISMATCH: error = ERPCMISMATCH; break; case RPC_AUTHERR: error = EAUTH; break; } goto out; } if (mbuf_len(m) < REPLY_SIZE) { error = RPC_SYSTEM_ERR; } else { error = ntohl(reply->rp_u.rpu_ok.rp_rstatus); } /* Did the call succeed? */ if (error != 0) { printf("rpc status=%d\n", error); /* convert rpc error to errno */ switch (error) { case RPC_PROGUNAVAIL: error = EPROGUNAVAIL; break; case RPC_PROGMISMATCH: error = EPROGMISMATCH; break; case RPC_PROCUNAVAIL: error = EPROCUNAVAIL; break; case RPC_GARBAGE: error = EINVAL; break; case RPC_SYSTEM_ERR: error = EIO; break; } goto out; } goto gotreply; /* break two levels */ } /* while secs */ } /* forever send/receive */ error = ETIMEDOUT; goto out; gotreply: /* * Pull as much as we can into first mbuf, to make * result buffer contiguous. Note that if the entire * result won't fit into one mbuf, you're out of luck. * XXX - Should not rely on making the entire reply * contiguous (fix callers instead). -gwr */ #if DIAGNOSTIC if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) panic("krpc_call: received pkt w/o header?"); #endif len = mbuf_pkthdr_len(m); if (sotype == SOCK_STREAM) len -= 4; /* the RPC record marker was read separately */ if (mbuf_len(m) < len) { if ((error = mbuf_pullup(&m, len))) goto out; reply = mbuf_data(m); } /* * Strip RPC header */ len = sizeof(*reply); if (reply->rp_u.rpu_ok.rp_auth.rp_atype != 0) { len += ntohl(reply->rp_u.rpu_ok.rp_auth.rp_alen); len = (len + 3) & ~3; /* XXX? */ } mbuf_adj(m, len); /* result */ *data = m; out: sock_close(so); out1: if (nam) mbuf_freem(nam); if (mhead) mbuf_freem(mhead); return error; }
static void utun_cleanup_family( ifnet_t interface, protocol_family_t protocol) { errno_t result = 0; socket_t pf_socket = NULL; ifaddr_t *addresses = NULL; int i; if (protocol != PF_INET && protocol != PF_INET6) { printf("utun_cleanup_family - invalid protocol family %d\n", protocol); return; } /* Create a socket for removing addresses and detaching the protocol */ result = sock_socket(protocol, SOCK_DGRAM, 0, NULL, NULL, &pf_socket); if (result != 0) { if (result != EAFNOSUPPORT) printf("utun_cleanup_family - failed to create %s socket: %d\n", protocol == PF_INET ? "IP" : "IPv6", result); goto cleanup; } /* always set SS_PRIV, we want to close and detach regardless */ sock_setpriv(pf_socket, 1); result = utun_detach_ip(interface, protocol, pf_socket); if (result == 0 || result == ENXIO) { /* We are done! We either detached or weren't attached. */ goto cleanup; } else if (result != EBUSY) { /* Uh, not really sure what happened here... */ printf("utun_cleanup_family - utun_detach_ip failed: %d\n", result); goto cleanup; } /* * At this point, we received an EBUSY error. This means there are * addresses attached. We should detach them and then try again. */ result = ifnet_get_address_list_family(interface, &addresses, protocol); if (result != 0) { printf("fnet_get_address_list_family(%s%d, 0xblah, %s) - failed: %d\n", ifnet_name(interface), ifnet_unit(interface), protocol == PF_INET ? "PF_INET" : "PF_INET6", result); goto cleanup; } for (i = 0; addresses[i] != 0; i++) { utun_remove_address(interface, protocol, addresses[i], pf_socket); } ifnet_free_address_list(addresses); addresses = NULL; /* * The addresses should be gone, we should try the remove again. */ result = utun_detach_ip(interface, protocol, pf_socket); if (result != 0 && result != ENXIO) { printf("utun_cleanup_family - utun_detach_ip failed: %d\n", result); } cleanup: if (pf_socket != NULL) sock_close(pf_socket); if (addresses != NULL) ifnet_free_address_list(addresses); }
/* * System call vectors. Since I (RIB) want to rewrite sockets as streams, * we have this level of indirection. Not a lot of overhead, since more of * the work is done via read/write/select directly. */ asmlinkage int sys_socketcall(int call, unsigned long *args) { int er; switch(call) { case SYS_SOCKET: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_socket(get_fs_long(args+0), get_fs_long(args+1), get_fs_long(args+2))); case SYS_BIND: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_bind(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), get_fs_long(args+2))); case SYS_CONNECT: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_connect(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), get_fs_long(args+2))); case SYS_LISTEN: er=verify_area(VERIFY_READ, args, 2 * sizeof(long)); if(er) return er; return(sock_listen(get_fs_long(args+0), get_fs_long(args+1))); case SYS_ACCEPT: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_accept(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), (int *)get_fs_long(args+2))); case SYS_GETSOCKNAME: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_getsockname(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), (int *)get_fs_long(args+2))); case SYS_GETPEERNAME: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_getpeername(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), (int *)get_fs_long(args+2))); case SYS_SOCKETPAIR: er=verify_area(VERIFY_READ, args, 4 * sizeof(long)); if(er) return er; return(sock_socketpair(get_fs_long(args+0), get_fs_long(args+1), get_fs_long(args+2), (unsigned long *)get_fs_long(args+3))); case SYS_SEND: er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long)); if(er) return er; return(sock_send(get_fs_long(args+0), (void *)get_fs_long(args+1), get_fs_long(args+2), get_fs_long(args+3))); case SYS_SENDTO: er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long)); if(er) return er; return(sock_sendto(get_fs_long(args+0), (void *)get_fs_long(args+1), get_fs_long(args+2), get_fs_long(args+3), (struct sockaddr *)get_fs_long(args+4), get_fs_long(args+5))); case SYS_RECV: er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long)); if(er) return er; return(sock_recv(get_fs_long(args+0), (void *)get_fs_long(args+1), get_fs_long(args+2), get_fs_long(args+3))); case SYS_RECVFROM: er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long)); if(er) return er; return(sock_recvfrom(get_fs_long(args+0), (void *)get_fs_long(args+1), get_fs_long(args+2), get_fs_long(args+3), (struct sockaddr *)get_fs_long(args+4), (int *)get_fs_long(args+5))); case SYS_SHUTDOWN: er=verify_area(VERIFY_READ, args, 2* sizeof(unsigned long)); if(er) return er; return(sock_shutdown(get_fs_long(args+0), get_fs_long(args+1))); case SYS_SETSOCKOPT: er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long)); if(er) return er; return(sock_setsockopt(get_fs_long(args+0), get_fs_long(args+1), get_fs_long(args+2), (char *)get_fs_long(args+3), get_fs_long(args+4))); case SYS_GETSOCKOPT: er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long)); if(er) return er; return(sock_getsockopt(get_fs_long(args+0), get_fs_long(args+1), get_fs_long(args+2), (char *)get_fs_long(args+3), (int *)get_fs_long(args+4))); default: return(-EINVAL); } }
int system_cloud_connect(int protocol, const ServerAddress* address, sockaddr* saddrCache) { struct addrinfo* info = nullptr; CloudServerAddressType type = CLOUD_SERVER_ADDRESS_TYPE_NONE; bool clean = true; if (saddrCache && /* protocol == IPPROTO_UDP && */ saddrCache->sa_family != AF_UNSPEC) { char tmphost[INET6_ADDRSTRLEN] = {}; char tmpserv[8] = {}; if (!netdb_getnameinfo(saddrCache, saddrCache->sa_len, tmphost, sizeof(tmphost), tmpserv, sizeof(tmpserv), AI_NUMERICHOST | AI_NUMERICSERV)) { /* There is a cached address, use it, but still pass it to getaddrinfo */ struct addrinfo hints = {}; hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG; hints.ai_family = saddrCache->sa_family; hints.ai_protocol = protocol; /* FIXME: */ hints.ai_socktype = hints.ai_protocol == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; if (!netdb_getaddrinfo(tmphost, tmpserv, &hints, &info)) { type = CLOUD_SERVER_ADDRESS_TYPE_CACHED; } } } if (type == CLOUD_SERVER_ADDRESS_TYPE_NONE) { /* Check if we have another address to try from the cached addrinfo list */ if (s_state.addr && s_state.next) { info = s_state.next; type = CLOUD_SERVER_ADDRESS_TYPE_CACHED_ADDRINFO; } } if ((type == CLOUD_SERVER_ADDRESS_TYPE_NONE) && address) { /* Use passed ServerAddress */ switch (address->addr_type) { case IP_ADDRESS: { struct addrinfo hints = {}; hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG; /* XXX: IPv4-only */ hints.ai_family = AF_INET; hints.ai_protocol = protocol; /* FIXME: */ hints.ai_socktype = hints.ai_protocol == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; char tmphost[INET_ADDRSTRLEN] = {}; char tmpserv[8] = {}; struct in_addr in = {}; in.s_addr = htonl(address->ip); if (inet_inet_ntop(AF_INET, &in, tmphost, sizeof(tmphost))) { snprintf(tmpserv, sizeof(tmpserv), "%u", address->port); netdb_getaddrinfo(tmphost, tmpserv, &hints, &info); type = CLOUD_SERVER_ADDRESS_TYPE_NEW_ADDRINFO; } break; } case DOMAIN_NAME: { struct addrinfo hints = {}; hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG; hints.ai_protocol = protocol; /* FIXME: */ hints.ai_socktype = hints.ai_protocol == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; char tmphost[sizeof(address->domain) + 32] = {}; char tmpserv[8] = {}; /* FIXME: this should probably be moved into system_cloud_internal */ system_string_interpolate(address->domain, tmphost, sizeof(tmphost), system_interpolate_cloud_server_hostname); snprintf(tmpserv, sizeof(tmpserv), "%u", address->port); LOG(TRACE, "Resolving %s#%s", tmphost, tmpserv); netdb_getaddrinfo(tmphost, tmpserv, &hints, &info); type = CLOUD_SERVER_ADDRESS_TYPE_NEW_ADDRINFO; break; } } } int r = SYSTEM_ERROR_NETWORK; if (info == nullptr) { LOG(ERROR, "Failed to determine server address"); } LOG(TRACE, "Address type: %d", type); for (struct addrinfo* a = info; a != nullptr; a = a->ai_next) { /* Iterate over all the addresses and attempt to connect */ int s = sock_socket(a->ai_family, a->ai_socktype, a->ai_protocol); if (s < 0) { LOG(ERROR, "Cloud socket failed, family=%d, type=%d, protocol=%d, errno=%d", a->ai_family, a->ai_socktype, a->ai_protocol, errno); continue; } LOG(TRACE, "Cloud socket=%d, family=%d, type=%d, protocol=%d", s, a->ai_family, a->ai_socktype, a->ai_protocol); char serverHost[INET6_ADDRSTRLEN] = {}; uint16_t serverPort = 0; switch (a->ai_family) { case AF_INET: { inet_inet_ntop(a->ai_family, &((sockaddr_in*)a->ai_addr)->sin_addr, serverHost, sizeof(serverHost)); serverPort = ntohs(((sockaddr_in*)a->ai_addr)->sin_port); break; } case AF_INET6: { inet_inet_ntop(a->ai_family, &((sockaddr_in6*)a->ai_addr)->sin6_addr, serverHost, sizeof(serverHost)); serverPort = ntohs(((sockaddr_in6*)a->ai_addr)->sin6_port); break; } } LOG(INFO, "Cloud socket=%d, connecting to %s#%u", s, serverHost, serverPort); /* We are using fixed source port only for IPv6 connections */ if (protocol == IPPROTO_UDP && a->ai_family == AF_INET6) { struct sockaddr_storage saddr = {}; saddr.s2_len = sizeof(saddr); saddr.ss_family = a->ai_family; /* NOTE: Always binding to 5684 by default */ switch (a->ai_family) { case AF_INET: { ((sockaddr_in*)&saddr)->sin_port = htons(PORT_COAPS); break; } case AF_INET6: { ((sockaddr_in6*)&saddr)->sin6_port = htons(PORT_COAPS); break; } } const int one = 1; if (sock_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { LOG(ERROR, "Cloud socket=%d, failed to set SO_REUSEADDR, errno=%d", s, errno); sock_close(s); continue; } /* Bind socket */ if (sock_bind(s, (const struct sockaddr*)&saddr, sizeof(saddr))) { LOG(ERROR, "Cloud socket=%d, failed to bind, errno=%d"); sock_close(s); continue; } } /* FIXME: timeout for TCP */ /* NOTE: we do this for UDP sockets as well in order to automagically filter * on source address and port */ r = sock_connect(s, a->ai_addr, a->ai_addrlen); if (r) { LOG(ERROR, "Cloud socket=%d, failed to connect to %s#%u, errno=%d", s, serverHost, serverPort, errno); sock_close(s); continue; } LOG(TRACE, "Cloud socket=%d, connected to %s#%u", s, serverHost, serverPort); /* If we got here, we are most likely connected, however keep track of current addrinfo list * in order to try the next address if application layer fails to establish the connection */ if (protocol == IPPROTO_UDP && (type == CLOUD_SERVER_ADDRESS_TYPE_NEW_ADDRINFO || type == CLOUD_SERVER_ADDRESS_TYPE_CACHED_ADDRINFO)) { if (s_state.addr) { /* We are already iterating over a cached addrinfo list */ s_state.next = a->ai_next; if (a->ai_next) { s_state.next = a->ai_next; clean = false; } else { info = s_state.addr; s_state.addr = s_state.next = nullptr; } } else { if (a->ai_next) { s_state.addr = info; s_state.next = a->ai_next; clean = false; } } } s_state.socket = s; if (saddrCache) { memcpy(saddrCache, a->ai_addr, a->ai_addrlen); } unsigned int keepalive = 0; system_cloud_get_inet_family_keepalive(a->ai_family, &keepalive); system_cloud_set_inet_family_keepalive(a->ai_family, keepalive, 1); break; } if (clean) { netdb_freeaddrinfo(info); } return r; }
/* * Connect to hostname on specified port and return the created socket. * Assert Class: 3 */ SOCKET sock_connect_wto(const char *hostname, const int port, const int timeout) { SOCKET sockfd; struct sockaddr_in sin, server; struct hostent *host; struct hostent hostinfo; char buf[BUFSIZE]; int error; if (!hostname || !hostname[0]) { write_log(LOG_DEFAULT, "ERROR: sock_connect() called with NULL or empty hostname"); return INVALID_SOCKET; } else if (port <= 0) { write_log(LOG_DEFAULT, "ERROR: sock_connect() called with invalid port number"); return INVALID_SOCKET; } sockfd = sock_socket(AF_INET, SOCK_STREAM, 0); if (sockfd == INVALID_SOCKET) { sock_close(sockfd); return INVALID_SOCKET; } if (info.myhostname != NULL) { struct sockaddr_in localsin; memset(&localsin, 0, sizeof (struct sockaddr_in)); xa_debug(2, "DEBUG: Trying to bind to %s", info.myhostname); localsin.sin_addr = localaddr; localsin.sin_family = AF_INET; localsin.sin_port = 0; if (bind (sockfd, (struct sockaddr *) &localsin, sizeof (localsin)) == SOCKET_ERROR) { xa_debug(2, "DEBUG: Unable to bind", info.myhostname); write_log(LOG_DEFAULT, "ERROR: Bind to local address %s failed", info.myhostname); sock_close(sockfd); return INVALID_SOCKET; } } memset(&sin, 0, sizeof (sin)); memset(&server, 0, sizeof (struct sockaddr_in)); if (isdigit((int) hostname[0]) && isdigit((int) hostname[ice_strlen(hostname) - 1])) { if (inet_aton(hostname, (struct in_addr *) &sin.sin_addr) == 0) { write_log(LOG_DEFAULT, "ERROR: Invalid ip number %s", hostname); sock_close(sockfd); return INVALID_SOCKET; } memcpy(&server.sin_addr, &sin.sin_addr, sizeof (sin)); } else { host = ice_gethostbyname(hostname, &hostinfo, buf, BUFSIZE, &error); if (host == NULL) { xa_debug(1, "DEBUG: gethostbyname %s failed", hostname); sock_close(sockfd); ice_clean_hostent(); return INVALID_SOCKET; } memcpy(&server.sin_addr, host->h_addr, host->h_length); ice_clean_hostent(); } server.sin_family = AF_INET; server.sin_port = htons(port); { char buf[50]; makeasciihost(&server.sin_addr, buf); xa_debug(1, "Trying to connect to %s:%d", buf, port); } if (timeout > 0) { fd_set wfds; struct timeval tv; int retval; int val; socklen_t valsize = sizeof (int); xa_debug(3, "DEBUG: sock_connect(): doing a connection w/ timeout"); FD_ZERO(&wfds); FD_SET(sockfd, &wfds); tv.tv_sec = timeout; tv.tv_usec = 0; sock_set_blocking(sockfd, SOCK_NONBLOCK); retval = connect(sockfd, (struct sockaddr *) &server, sizeof (server)); if (retval == 0) { xa_debug(3, "DEBUG: sock_connect(): non blocking connect returned 0!"); sock_set_blocking(sockfd, SOCK_BLOCK); return sockfd; } else { #ifdef _WIN32 if (WSAGetLastError() == WSAEINPROGRESS) { #else if (!is_recoverable(errno)) { #endif xa_debug(3, "DEBUG: sock_connect(): connect didn't return EINPROGRESS!, was: %d", errno); sock_close(sockfd); return SOCKET_ERROR; } } if (select(sockfd + 1, NULL, &wfds, NULL, &tv)) { retval = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *) &val, (socklen_t *) & valsize); if ((retval == 0) && (val == 0)) { sock_set_blocking(sockfd, SOCK_BLOCK); return sockfd; } else { xa_debug(3, "DEBUG: sock_connect(): getsockopt returned %i, val = %i, valsize = %i, errno = %i!", retval, val, valsize, errno); sock_close(sockfd); return SOCKET_ERROR; } } else { xa_debug(3, "DEBUG: sock_connect(): select returned 0"); sock_close(sockfd); return SOCKET_ERROR; } } else { if (connect
/* * Create a socket for all incoming requests on specified port. * If info.myhostname is NULL, bind it to INADDR_ANY (all available interfaces). * If info.myhostname is not NULL, resolv it (if needed), and bind to that. * Return the socket for bound socket, or INVALID_SOCKET if failed. * Assert Class: 3 */ SOCKET sock_get_server_socket(const int port) { struct sockaddr_in sin; int sin_len, error; SOCKET sockfd; if (port < 0) { write_log(LOG_DEFAULT, "ERROR: Invalid port number %d. Cannot listen for requests, this is bad!", port); return INVALID_SOCKET; } xa_debug (2, "DEBUG: Getting socket for port %d", port); /* * get socket descriptor */ sockfd = sock_socket (AF_INET, SOCK_STREAM, 0); if (sockfd == INVALID_SOCKET) return INVALID_SOCKET; /* * Setup socket */ #ifdef HAVE_SETSOCKOPT { int tmp = 1; if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &tmp, sizeof (tmp)) != 0) write_log(LOG_DEFAULT, "ERROR: setsockopt() failed to set SO_REUSEADDR flag. (mostly harmless)"); } #endif /* * setup sockaddr structure */ sin_len = sizeof (sin); memset(&sin, 0, sin_len); sin.sin_family = AF_INET; if (info.myhostname != NULL && info.myhostname[0]) { if (isdigit((int) info.myhostname[0]) && isdigit((int) info. myhostname[ice_strlen(info.myhostname) - 1])) { if (inet_aton (info.myhostname, (struct in_addr *) &localaddr) == 0) { write_log(LOG_DEFAULT, "ERROR: Invalid ip number %s, will die now", info.myhostname); clean_shutdown(&info); } sin.sin_addr.s_addr = localaddr.s_addr; } else { struct hostent *hostinfoptr, hostinfo; char buf[BUFSIZE]; int error; hostinfoptr = ice_gethostbyname(info.myhostname, &hostinfo, buf, BUFSIZE, &error); if (hostinfoptr == NULL) { write_log(LOG_DEFAULT, "Unknown host %s, that's it for me!", info.myhostname); ice_clean_hostent(); clean_shutdown(&info); } sin.sin_addr.s_addr = localaddr.s_addr; memcpy((void *) &localaddr, hostinfoptr->h_addr, sizeof (localaddr)); ice_clean_hostent(); } } else { sin.sin_addr.s_addr = htonl(INADDR_ANY); } sin.sin_port = htons(port); /* * bind socket to port */ error = bind(sockfd, (struct sockaddr *) &sin, sin_len); if (error == SOCKET_ERROR) { write_log(LOG_DEFAULT, "Bind to socket on port %d failed. Shutting down now.", port); clean_shutdown(&info); } return sockfd; }