/* * Original author : tridge@samba.org, January 2002 * * Copyright (c) 2005 Christophe Varoqui * Copyright (c) 2005 Alasdair Kergon, Redhat */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_SYSTEMD #include #endif #include "mpath_cmd.h" #include "memory.h" #include "uxsock.h" #include "debug.h" /* * Code is similar with mpath_recv_reply() with data size limitation * and debug-able malloc. * When limit == 0, it means no limit on data size, used for socket client * to receiving data from multipathd. */ static int _recv_packet(int fd, char **buf, unsigned int timeout, ssize_t limit); /* * create a unix domain socket and start listening on it * return a file descriptor open on the socket */ int ux_socket_listen(const char *name) { int fd; size_t len; #ifdef USE_SYSTEMD int num; #endif struct sockaddr_un addr; #ifdef USE_SYSTEMD num = sd_listen_fds(0); if (num > 1) { condlog(3, "sd_listen_fds returned %d fds", num); return -1; } else if (num == 1) { fd = SD_LISTEN_FDS_START + 0; condlog(3, "using fd %d from sd_listen_fds", fd); return fd; } #endif fd = socket(AF_LOCAL, SOCK_STREAM, 0); if (fd == -1) { condlog(3, "Couldn't create ux_socket, error %d", errno); return -1; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_LOCAL; addr.sun_path[0] = '\0'; len = strlen(name) + 1; if (len >= sizeof(addr.sun_path)) len = sizeof(addr.sun_path) - 1; memcpy(&addr.sun_path[1], name, len); len += sizeof(sa_family_t); if (bind(fd, (struct sockaddr *)&addr, len) == -1) { condlog(3, "Couldn't bind to ux_socket, error %d", errno); close(fd); return -1; } if (listen(fd, 10) == -1) { condlog(3, "Couldn't listen to ux_socket, error %d", errno); close(fd); return -1; } return fd; } /* * send a packet in length prefix format */ int send_packet(int fd, const char *buf) { if (mpath_send_cmd(fd, buf) < 0) return -errno; return 0; } static int _recv_packet(int fd, char **buf, unsigned int timeout, ssize_t limit) { int err = 0; ssize_t len = 0; *buf = NULL; len = mpath_recv_reply_len(fd, timeout); if (len == 0) return len; if (len < 0) return -errno; if ((limit > 0) && (len > limit)) return -EINVAL; (*buf) = MALLOC(len); if (!*buf) return -ENOMEM; err = mpath_recv_reply_data(fd, *buf, len, timeout); if (err != 0) { FREE(*buf); (*buf) = NULL; return -errno; } return err; } /* * receive a packet in length prefix format */ int recv_packet(int fd, char **buf, unsigned int timeout) { return _recv_packet(fd, buf, timeout, 0 /* no limit */); } int recv_packet_from_client(int fd, char **buf, unsigned int timeout) { return _recv_packet(fd, buf, timeout, _MAX_CMD_LEN); }