/* * \brief open a unix-domain socket and bind it to a file. * * The socket is accessed via CLICON_SOCK option, has 770 permissions * and group according to CLICON_SOCK_GROUP option. */ int config_socket_init(clicon_handle h) { int s; struct sockaddr_un addr; mode_t old_mask; char *config_sock; char *config_group; gid_t gid; struct stat st; /* first find sockpath and remove it if it exists (it shouldn't) */ if ((config_sock = clicon_sock(h)) == NULL) return -1; if (lstat(config_sock, &st) == 0 && unlink(config_sock) < 0){ clicon_err(OE_UNIX, errno, "%s: unlink(%s)", __FUNCTION__, config_sock); return -1; } /* then find configuration group (for clients) and find its groupid */ if ((config_group = clicon_sock_group(h)) == NULL) return -1; if (group_name2gid(config_group, &gid) < 0) return -1; #if 0 if (gid == 0) clicon_log(LOG_WARNING, "%s: No such group: %s\n", __FUNCTION__, config_group); #endif /* create unix socket */ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { clicon_err(OE_UNIX, errno, "%s: socket", __FUNCTION__); return -1; } // setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one)); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, config_sock, sizeof(addr.sun_path)-1); old_mask = umask(S_IRWXO | S_IXGRP | S_IXUSR); if (bind(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){ clicon_err(OE_UNIX, errno, "%s: bind", __FUNCTION__); umask(old_mask); goto err; } umask(old_mask); /* change socket path file group */ if (lchown(config_sock, -1, gid) < 0){ clicon_err(OE_UNIX, errno, "%s: lchown(%s, %s)", __FUNCTION__, config_sock, config_group); goto err; } clicon_debug(1, "Listen on server socket at %s", addr.sun_path); if (listen(s, 5) < 0){ clicon_err(OE_UNIX, errno, "%s: listen", __FUNCTION__); goto err; } return s; err: close(s); return -1; }
struct rost_etstats * ethtool_client_gstats(clicon_handle h, char *ifname, const char *label) { uint16_t etslen; struct clicon_msg *msg; struct rost_etstats *tmp, *ets = NULL; char *s; int i; msg = clicon_msg_call_encode(0, "ethtool", "ethtool_gstats", strlen(ifname), ifname, __FUNCTION__); if (msg == NULL) goto done; if ((s = clicon_sock(h)) == NULL) goto done; if (clicon_rpc_connect(msg, s, (char **)&tmp, &etslen, label) < 0) goto done; ets = tmp; for (i = 0; i < ets->ets_nstats; i++) ets->ets_stat[i].etse_value = htonll(tmp->ets_stat[i].etse_value); done: unchunk_group(__FUNCTION__); return ets; }
struct ethtool_cmd * ethtool_client_gset(clicon_handle h, char *ifname, const char *label) { uint16_t eclen; struct ethtool_cmd *tmp, *ec = NULL; struct clicon_msg *msg; char *s; msg = clicon_msg_call_encode(0, "ethtool", "ethtool_gset", strlen(ifname), ifname, __FUNCTION__); if (msg == NULL) goto done; if ((s = clicon_sock(h)) == NULL) goto done; if (clicon_rpc_connect(msg, s, (char **)&tmp, &eclen, label) < 0) goto done; ec = tmp; ec->cmd = ntohl(tmp->cmd); ec->supported = ntohl(tmp->supported); ec->advertising = ntohl(tmp->advertising); ec->speed = ntohs(tmp->speed); ec->maxtxpkt = ntohl(tmp->maxtxpkt); ec->maxrxpkt = ntohl(tmp->maxrxpkt); ec->speed_hi = ntohs(tmp->speed_hi); ec->eth_tp_mdix = ntohs(tmp->eth_tp_mdix); done: unchunk_group(__FUNCTION__); return ec; }
int ethtool_client_getlink(clicon_handle h, char *ifname, uint8_t *link) { int retval = -1; char *ret; uint16_t len; struct clicon_msg *msg; char *s; msg = clicon_msg_call_encode(0, "ethtool", "ethtool_getlink", strlen(ifname), ifname, __FUNCTION__); if (msg == NULL) goto done; if ((s = clicon_sock(h)) == NULL) goto done; if (clicon_rpc_connect(msg, s, (char **)&ret, &len, __FUNCTION__) < 0) goto done; *link = (uint8_t)*ret; retval = 0; done: unchunk_group(__FUNCTION__); return retval; }
/*! Send internal netconf rpc from client to backend * @param[in] h CLICON handle * @param[in] msg Encoded message. Deallocate woth free * @param[out] xret Return value from backend as xml tree. Free w xml_free * @param[inout] sock0 If pointer exists, do not close socket to backend on success * and return it here. For keeping a notify socket open * @note sock0 is if connection should be persistent, like a notification/subscribe api * @note xret is populated with yangspec according to standard handle yangspec */ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0, int *sock0) { int retval = -1; char *sock; int port; char *retdata = NULL; cxobj *xret = NULL; yang_stmt *yspec; #ifdef RPC_USERNAME_ASSERT assert(strstr(msg->op_body, "username")!=NULL); /* XXX */ #endif clicon_debug(1, "%s request:%s", __FUNCTION__, msg->op_body); if ((sock = clicon_sock(h)) == NULL){ clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set"); goto done; } /* What to do if inet socket? */ switch (clicon_sock_family(h)){ case AF_UNIX: if (clicon_rpc_connect_unix(msg, sock, &retdata, sock0) < 0){ #if 0 if (errno == ESHUTDOWN) /* Maybe could reconnect on a higher layer, but lets fail loud and proud */ cligen_exiting_set(cli_cligen(h), 1); #endif goto done; } break; case AF_INET: if ((port = clicon_sock_port(h)) < 0){ clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set"); goto done; } if (port < 0){ clicon_err(OE_FATAL, 0, "CLICON_SOCK_PORT not set"); goto done; } if (clicon_rpc_connect_inet(msg, sock, port, &retdata, sock0) < 0) goto done; break; } clicon_debug(1, "%s retdata:%s", __FUNCTION__, retdata); if (retdata){ yspec = clicon_dbspec_yang(h); if (xml_parse_string(retdata, yspec, &xret) < 0) goto done; } if (xret0){ *xret0 = xret; xret = NULL; } retval = 0; done: if (retdata) free(retdata); if (xret) xml_free(xret); return retval; }