static int tipc_setopt(nbio_sock_t socket, tipc_option opt, ...) { plsocket_ptr s; va_list args; int rc; if ( !(s = nbio_to_plsocket(socket)) ) return -1; va_start(args, opt); switch(opt) { case NB_TIPC_IMPORTANCE: { int val = va_arg(args, int); if ( setsockopt(plsocket_handle(s), SOL_TIPC, TIPC_IMPORTANCE, (const void *)&val, sizeof(val)) == -1 ) { nbio_error(h_errno, TCP_HERRNO); rc = -1; } else rc = 0; break; } case NB_TIPC_SRC_DROPPABLE: case NB_TIPC_DEST_DROPPABLE: { int val = va_arg(args, int); int level = (opt == NB_TIPC_SRC_DROPPABLE) ? TIPC_SRC_DROPPABLE : TIPC_DEST_DROPPABLE; if ( setsockopt(plsocket_handle(s), SOL_TIPC, level, (const void *) &val, sizeof(val)) == -1 ) { nbio_error(h_errno, TCP_HERRNO); rc = -1; } else rc = 0; break; } case NB_TIPC_CONN_TIMEOUT: { int val = va_arg(args, int); if ( setsockopt(plsocket_handle(s), SOL_TIPC, TIPC_CONN_TIMEOUT, (const void *) &val, sizeof(val)) == -1 ) { nbio_error(h_errno, TCP_HERRNO); rc = -1; } else rc = 0; break; } default: rc = -1; assert(0); } va_end(args); return rc; }
static foreign_t pl_host_to_address(term_t Host, term_t Ip) { struct in_addr ip; char *host_name; if ( PL_get_atom_chars(Host, &host_name) ) { struct addrinfo hints; struct addrinfo *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; if ( getaddrinfo(host_name, NULL, &hints, &res) == 0 ) { int rc; switch( res->ai_family ) { case AF_INET: { struct sockaddr_in *addr = (struct sockaddr_in*)res->ai_addr; rc = nbio_unify_ip4(Ip, ntohl(addr->sin_addr.s_addr)); break; } case AF_INET6: { rc = PL_warning("tcp_host_to_address/2: IPv6 address not supported"); break; } default: assert(0); rc = FALSE; } freeaddrinfo(res); return rc; } else { return nbio_error(h_errno, TCP_HERRNO); } } else if ( nbio_get_ip(Ip, &ip) ) { struct hostent *host; if ( (host = gethostbyaddr((char *)&ip, sizeof(ip), AF_INET)) ) return PL_unify_atom_chars(Host, host->h_name); else return nbio_error(h_errno, TCP_HERRNO); } return FALSE; }
static foreign_t pl_bind(term_t Socket, term_t Address) { struct sockaddr_in sockaddr; int socket; memset(&sockaddr, 0, sizeof(sockaddr)); if ( !tcp_get_socket(Socket, &socket) || !nbio_get_sockaddr(Address, &sockaddr) ) return FALSE; if ( nbio_bind(socket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0 ) return FALSE; if ( PL_is_variable(Address) ) { SOCKET fd = nbio_fd(socket); struct sockaddr_in addr; #ifdef __WINDOWS__ int len = sizeof(addr); #else socklen_t len = sizeof(addr); #endif if ( getsockname(fd, (struct sockaddr *) &addr, &len) ) return nbio_error(errno, TCP_ERRNO); return PL_unify_integer(Address, ntohs(addr.sin_port)); } return TRUE; }
static foreign_t udp_send(term_t Socket, term_t Data, term_t To, term_t Options) { struct sockaddr_in sockaddr; #ifdef __WINDOWS__ int alen = sizeof(sockaddr); #else int alen = sizeof(sockaddr); #endif int socket; int flags = 0L; char *data; size_t dlen; ssize_t n; if ( !PL_get_nchars(Data, &dlen, &data, CVT_ALL|CVT_EXCEPTION) ) return FALSE; if ( !tcp_get_socket(Socket, &socket) || !nbio_get_sockaddr(To, &sockaddr) ) return FALSE; if ( (n=nbio_sendto(socket, data, (int)dlen, flags, (struct sockaddr*)&sockaddr, alen)) == -1 ) return nbio_error(errno, TCP_ERRNO); return TRUE; }
static foreign_t pl_gethostname(term_t name) { static atom_t hname; if ( !hname ) { char buf[256]; if ( gethostname(buf, sizeof(buf)) == 0 ) { struct addrinfo *res; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; if ( getaddrinfo(buf, NULL, &hints, &res) == 0 ) { hname = PL_new_atom(res->ai_canonname); freeaddrinfo(res); } else hname = PL_new_atom(buf); } else { return nbio_error(h_errno, TCP_HERRNO); } } return PL_unify_atom(name, hname); }
static foreign_t pl_tipc_subscribe(term_t Socket, term_t Address, term_t timeout, term_t filter, term_t usr_handle) { struct sockaddr_tipc sockaddr; struct tipc_subscr subscr; int socket; unsigned time, filt; char *handle; size_t handle_len; SOCKET fd; memset(&subscr, 0, sizeof(subscr)); memset(&sockaddr, 0, sizeof(sockaddr)); if ( !tipc_get_socket(Socket, &socket) || !nbio_get_tipc_sockaddr(Address, &sockaddr)) return FALSE; if(sockaddr.addrtype != TIPC_ADDR_NAMESEQ) return pl_error(NULL, 0, NULL, ERR_DOMAIN, Address, "name_seq/3"); if( !get_uint(timeout, &time)) return pl_error(NULL, 0, NULL, ERR_DOMAIN, timeout, "integer"); if( !get_uint(filter, &filt)) return pl_error(NULL, 0, NULL, ERR_DOMAIN, filter, "integer"); if ( !PL_get_nchars(usr_handle, &handle_len, &handle, CVT_ALL|CVT_EXCEPTION) ) return FALSE; if(tipc_version > 1) { struct tipc_name_seq *p = &subscr.seq, *p1 = &sockaddr.addr.nameseq; p->type = htonl(p1->type); p->lower = htonl(p1->lower); p->upper = htonl(p1->upper); subscr.timeout = htonl(time); subscr.filter = htonl((filt == V1_TIPC_SUB_SERVICE) ? TIPC_SUB_SERVICE : filt); } else { memcpy(&subscr.seq, &sockaddr.addr.nameseq, sizeof(subscr.seq)); subscr.timeout = time; subscr.filter = filt; } memcpy(&subscr.usr_handle, handle, (handle_len < sizeof(subscr.usr_handle)) ? handle_len : sizeof(subscr.usr_handle)); fd = nbio_fd(socket); if ( (send(fd, &subscr, sizeof(subscr), 0)) != sizeof(subscr) ) return nbio_error(errno, TCP_ERRNO); else return TRUE; }
static foreign_t pl_close_socket(term_t socket) { int sock; if ( !tcp_get_socket(socket, &sock) ) return FALSE; if ( nbio_closesocket(sock) < 0 ) return nbio_error(errno, TCP_ERRNO);; return TRUE; }
static foreign_t pl_host_to_address(term_t Host, term_t Ip) { struct in_addr ip; struct hostent *host; char *host_name; if ( PL_get_atom_chars(Host, &host_name) ) { if ( (host = gethostbyname(host_name)) ) { if ( sizeof(ip) == host->h_length ) { memcpy(&ip, host->h_addr, host->h_length); return nbio_unify_ip4(Ip, ntohl(ip.s_addr)); } else return PL_warning("tcp_host_to_address/2: length mismatch in address"); } else return nbio_error(h_errno, TCP_HERRNO); } else if ( nbio_get_ip(Ip, &ip) ) { if ( (host = gethostbyaddr((char *)&ip, sizeof(ip), AF_INET)) ) return PL_unify_atom_chars(Host, host->h_name); else return nbio_error(h_errno, TCP_HERRNO); } return FALSE; }
static foreign_t pl_gethostname(term_t name) { static atom_t hname; if ( !hname ) { char buf[256]; if ( gethostname(buf, sizeof(buf)) == 0 ) { struct hostent *he; if ( (he = gethostbyname(buf)) ) hname = PL_new_atom(he->h_name); else hname = PL_new_atom(buf); } else { return nbio_error(h_errno, TCP_HERRNO); } } return PL_unify_atom(name, hname); }
static foreign_t pl_tipc_basic_get_name(term_t Socket, term_t t, int peer) { struct sockaddr_tipc addr; int socket; SOCKET fd; #ifdef __WINDOWS__ int alen = sizeof(addr); #else socklen_t alen = sizeof(addr); #endif memset(&addr, 0, sizeof(addr)); if ( !tipc_get_socket(Socket, &socket)) return FALSE; fd = nbio_fd(socket); if ( (peer) ? getpeername(fd, (struct sockaddr *) &addr, &alen) : getsockname(fd, (struct sockaddr *) &addr, &alen) ) return nbio_error(errno, TCP_ERRNO); else return unify_tipc_address(t, &addr); }
static foreign_t udp_receive(term_t Socket, term_t Data, term_t From, term_t options) { struct sockaddr_in sockaddr; #ifdef __WINDOWS__ int alen = sizeof(sockaddr); #else socklen_t alen = sizeof(sockaddr); #endif int socket; int flags = 0; char buf[UDP_MAXDATA]; ssize_t n; int as = PL_STRING; if ( !PL_get_nil(options) ) { term_t tail = PL_copy_term_ref(options); term_t head = PL_new_term_ref(); term_t arg = PL_new_term_ref(); while(PL_get_list(tail, head, tail)) { atom_t name; int arity; if ( PL_get_name_arity(head, &name, &arity) && arity == 1 ) { _PL_get_arg(1, head, arg); if ( name == ATOM_as ) { atom_t a; if ( !PL_get_atom(arg, &a) ) return pl_error(NULL, 0, NULL, ERR_TYPE, head, "atom"); if ( a == ATOM_atom ) as = PL_ATOM; else if ( a == ATOM_codes ) as = PL_CODE_LIST; else if ( a == ATOM_string ) as = PL_STRING; else return pl_error(NULL, 0, NULL, ERR_DOMAIN, arg, "as_option"); } } else return pl_error(NULL, 0, NULL, ERR_TYPE, head, "option"); } if ( !PL_get_nil(tail) ) return pl_error(NULL, 0, NULL, ERR_TYPE, tail, "list"); } if ( !tcp_get_socket(Socket, &socket) || !nbio_get_sockaddr(From, &sockaddr) ) return FALSE; if ( (n=nbio_recvfrom(socket, buf, sizeof(buf), flags, (struct sockaddr*)&sockaddr, &alen)) == -1 ) return nbio_error(errno, TCP_ERRNO); if ( !PL_unify_chars(Data, as, n, buf) ) return FALSE; return unify_address(From, &sockaddr); }
static foreign_t pl_tipc_receive_subscr_event(term_t Socket, term_t Data) { struct sockaddr_tipc sockaddr; #ifdef __WINDOWS__ int alen = sizeof(sockaddr); #else socklen_t alen = sizeof(sockaddr); #endif int socket; int flags = 0; union { char asCodes[sizeof(struct tipc_event)]; struct tipc_event asEvent; } buf; ssize_t n; struct tipc_event *event = &buf.asEvent; memset(&sockaddr, 0, sizeof(sockaddr)); if ( !tipc_get_socket(Socket, &socket)) return FALSE; if ( (n=nbio_recvfrom(socket, buf.asCodes, sizeof(buf.asCodes), flags, (struct sockaddr*)&sockaddr, &alen)) == -1 ) return nbio_error(errno, TCP_ERRNO); if(n != sizeof(*event)) return FALSE; if(tipc_version > 1) { struct tipc_name_seq *p = &event->s.seq; event->event = ntohl(event->event); event->found_lower = ntohl(event->found_lower); event->found_upper = ntohl(event->found_upper); event->port.ref = ntohl(event->port.ref); event->port.node = ntohl(event->port.node); p->type = ntohl(p->type); p->lower = ntohl(p->lower); p->upper = ntohl(p->upper); event->s.timeout = ntohl(event->s.timeout); event->s.filter = ntohl(event->s.filter); if(event->s.filter == TIPC_SUB_SERVICE) event->s.filter = V1_TIPC_SUB_SERVICE; } switch(event->event) { case TIPC_PUBLISHED: case TIPC_WITHDRAWN: { term_t Found = PL_new_term_ref(), Port_id = PL_new_term_ref(), Subscr = PL_new_term_ref(); const char *event_chars = (event->event == TIPC_PUBLISHED) ? "published" : "withdrawn"; if(!PL_unify_term(Subscr, PL_FUNCTOR_CHARS, "name_seq", 3, IntArg(event->s.seq.type), IntArg(event->s.seq.lower), IntArg(event->s.seq.upper))) return FALSE; if(!PL_unify_term(Found, PL_FUNCTOR_CHARS, "name_seq", 3, IntArg(event->s.seq.type), IntArg(event->found_lower), IntArg(event->found_upper))) return FALSE; if(!PL_unify_term(Port_id, PL_FUNCTOR_CHARS, "port_id", 2, IntArg(event->port.ref), IntArg(event->port.node))) return FALSE; if(!PL_unify_term(Data, PL_FUNCTOR_CHARS, "tipc_event", 4, AtomArg(event_chars), PL_TERM, Subscr, PL_TERM, Found, PL_TERM, Port_id)) return FALSE; return TRUE; } case TIPC_SUBSCR_TIMEOUT: { return PL_unify_term(Data, PL_FUNCTOR_CHARS, "subscr_timeout", 0); } default: return FALSE; }; return FALSE; }
static foreign_t udp_receive(term_t Socket, term_t Data, term_t From, term_t options) { struct sockaddr_in sockaddr; #ifdef __WINDOWS__ int alen = sizeof(sockaddr); #else socklen_t alen = sizeof(sockaddr); #endif int socket; int flags = 0; char smallbuf[UDP_DEFAULT_BUFSIZE]; char *buf = smallbuf; int bufsize = UDP_DEFAULT_BUFSIZE; term_t varport = 0; ssize_t n; int as = PL_STRING; int rc; if ( !PL_get_nil(options) ) { term_t tail = PL_copy_term_ref(options); term_t head = PL_new_term_ref(); term_t arg = PL_new_term_ref(); while(PL_get_list(tail, head, tail)) { atom_t name; size_t arity; if ( PL_get_name_arity(head, &name, &arity) && arity == 1 ) { _PL_get_arg(1, head, arg); if ( name == ATOM_as ) { atom_t a; if ( !PL_get_atom(arg, &a) ) return pl_error(NULL, 0, NULL, ERR_TYPE, head, "atom"); if ( a == ATOM_atom ) as = PL_ATOM; else if ( a == ATOM_codes ) as = PL_CODE_LIST; else if ( a == ATOM_string ) as = PL_STRING; else return pl_error(NULL, 0, NULL, ERR_DOMAIN, arg, "as_option"); } else if ( name == ATOM_max_message_size ) { if ( !PL_get_integer(arg, &bufsize) ) return pl_error(NULL, 0, NULL, ERR_TYPE, arg, "integer"); if ( bufsize < 0 || bufsize > UDP_MAXDATA ) return pl_error(NULL, 0, NULL, ERR_DOMAIN, arg, "0 - 65535"); } } else return pl_error(NULL, 0, NULL, ERR_TYPE, head, "option"); } if ( !PL_get_nil(tail) ) return pl_error(NULL, 0, NULL, ERR_TYPE, tail, "list"); } if ( !tcp_get_socket(Socket, &socket) || !nbio_get_sockaddr(From, &sockaddr, &varport) ) return FALSE; if ( bufsize > UDP_DEFAULT_BUFSIZE ) { if ( !(buf = malloc(bufsize)) ) return pl_error(NULL, 0, NULL, ERR_RESOURCE, "memory"); } if ( (n=nbio_recvfrom(socket, buf, bufsize, flags, (struct sockaddr*)&sockaddr, &alen)) == -1 ) { rc = nbio_error(errno, TCP_ERRNO); goto out; } rc = ( PL_unify_chars(Data, as, n, buf) && unify_address(From, &sockaddr) ); out: if ( buf != smallbuf ) free(buf); return rc; }