Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.openwrt.org/project/libubox.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-10-13 23:17:51 +0400
committerFelix Fietkau <nbd@openwrt.org>2010-10-13 23:29:08 +0400
commite82d74f89809c6c01f71168b3b8fdcf490e93fa7 (patch)
treeb031179f224fda2ab77077fa64878fd37879655e /usock.c
Initial import
Diffstat (limited to 'usock.c')
-rw-r--r--usock.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/usock.c b/usock.c
new file mode 100644
index 0000000..613b2dd
--- /dev/null
+++ b/usock.c
@@ -0,0 +1,102 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "usock.h"
+
+int usock(int type, const char *host, const char *service) {
+ int sock = -1;
+
+ if (service && !(type & USOCK_UNIX)) {
+ struct addrinfo *result, *rp;
+
+ struct addrinfo hints = {
+ .ai_family = (type & USOCK_IPV6ONLY) ? AF_INET6 :
+ (type & USOCK_IPV4ONLY) ? AF_INET : AF_UNSPEC,
+ .ai_socktype = ((type & 0xff) == USOCK_TCP)
+ ? SOCK_STREAM : SOCK_DGRAM,
+ .ai_flags = AI_ADDRCONFIG
+ | ((type & USOCK_SERVER) ? AI_PASSIVE : 0)
+ | ((type & USOCK_NUMERIC) ? AI_NUMERICHOST : 0),
+ };
+
+ if (getaddrinfo(host, service, &hints, &result)) {
+ return -1;
+ }
+
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ if ((sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))
+ == -1) {
+ continue;
+ }
+
+ if (!(type & USOCK_NOCLOEXEC)) {
+ fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
+ }
+
+ if (type & USOCK_NONBLOCK) {
+ fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
+ }
+
+ if (type & USOCK_SERVER) {
+ const int one = 1;
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+
+ if (!bind(sock, rp->ai_addr, rp->ai_addrlen)
+ && ((type & 0xff) != USOCK_TCP || !listen(sock, SOMAXCONN))) {
+ break;
+ }
+ } else {
+ if (!connect(sock, rp->ai_addr, rp->ai_addrlen)
+ || errno == EINPROGRESS) {
+ break;
+ }
+ }
+
+ close(sock);
+ sock = -1;
+ }
+ freeaddrinfo(result);
+ } else {
+ struct sockaddr_un sun = {.sun_family = AF_UNIX};
+ if (strlen(host) >= sizeof(sun.sun_path)) {
+ errno = EINVAL;
+ return -1;
+ }
+ strcpy(sun.sun_path, host);
+
+ if ((sock = socket(AF_UNIX, ((type & 0xff) == USOCK_TCP)
+ ? SOCK_STREAM : SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ if (!(type & USOCK_NOCLOEXEC)) {
+ fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
+ }
+
+ if (type & USOCK_NONBLOCK) {
+ fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
+ }
+
+ if (type & USOCK_SERVER) {
+ if (bind(sock, (struct sockaddr*)&sun, sizeof(sun)) ||
+ ((type & 0xff) == USOCK_TCP && listen(sock, SOMAXCONN))) {
+ close(sock);
+ return -1;
+ }
+ } else {
+ if (connect(sock, (struct sockaddr*)&sun, sizeof(sun))
+ && errno != EINPROGRESS) {
+ close(sock);
+ return -1;
+ }
+ }
+ }
+ return sock;
+}