1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <stddef.h>
19#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22
23#include <cutils/sockets.h>
24
25#ifdef HAVE_WINSOCK
26
27int socket_local_client(const char *name, int namespaceId, int type)
28{
29    errno = ENOSYS;
30    return -1;
31}
32
33#else /* !HAVE_WINSOCK */
34
35#include <sys/socket.h>
36#include <sys/un.h>
37#include <sys/select.h>
38#include <sys/types.h>
39
40#include "socket_local.h"
41
42#define UNUSED __attribute__((unused))
43
44#define LISTEN_BACKLOG 4
45
46/* Documented in header file. */
47int socket_make_sockaddr_un(const char *name, int namespaceId,
48        struct sockaddr_un *p_addr, socklen_t *alen)
49{
50    memset (p_addr, 0, sizeof (*p_addr));
51    size_t namelen;
52
53    switch (namespaceId) {
54        case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
55#if defined(__linux__)
56            namelen  = strlen(name);
57
58            // Test with length +1 for the *initial* '\0'.
59            if ((namelen + 1) > sizeof(p_addr->sun_path)) {
60                goto error;
61            }
62
63            /*
64             * Note: The path in this case is *not* supposed to be
65             * '\0'-terminated. ("man 7 unix" for the gory details.)
66             */
67
68            p_addr->sun_path[0] = 0;
69            memcpy(p_addr->sun_path + 1, name, namelen);
70#else
71            /* this OS doesn't have the Linux abstract namespace */
72
73            namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
74            /* unix_path_max appears to be missing on linux */
75            if (namelen > sizeof(*p_addr)
76                    - offsetof(struct sockaddr_un, sun_path) - 1) {
77                goto error;
78            }
79
80            strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
81            strcat(p_addr->sun_path, name);
82#endif
83        break;
84
85        case ANDROID_SOCKET_NAMESPACE_RESERVED:
86            namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
87            /* unix_path_max appears to be missing on linux */
88            if (namelen > sizeof(*p_addr)
89                    - offsetof(struct sockaddr_un, sun_path) - 1) {
90                goto error;
91            }
92
93            strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
94            strcat(p_addr->sun_path, name);
95        break;
96
97        case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
98            namelen = strlen(name);
99            /* unix_path_max appears to be missing on linux */
100            if (namelen > sizeof(*p_addr)
101                    - offsetof(struct sockaddr_un, sun_path) - 1) {
102                goto error;
103            }
104
105            strcpy(p_addr->sun_path, name);
106        break;
107        default:
108            // invalid namespace id
109            return -1;
110    }
111
112    p_addr->sun_family = AF_LOCAL;
113    *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
114    return 0;
115error:
116    return -1;
117}
118
119/**
120 * connect to peer named "name" on fd
121 * returns same fd or -1 on error.
122 * fd is not closed on error. that's your job.
123 *
124 * Used by AndroidSocketImpl
125 */
126int socket_local_client_connect(int fd, const char *name, int namespaceId,
127        int type UNUSED)
128{
129    struct sockaddr_un addr;
130    socklen_t alen;
131    int err;
132
133    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
134
135    if (err < 0) {
136        goto error;
137    }
138
139    if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
140        goto error;
141    }
142
143    return fd;
144
145error:
146    return -1;
147}
148
149/**
150 * connect to peer named "name"
151 * returns fd or -1 on error
152 */
153int socket_local_client(const char *name, int namespaceId, int type)
154{
155    int s;
156
157    s = socket(AF_LOCAL, type, 0);
158    if(s < 0) return -1;
159
160    if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
161        close(s);
162        return -1;
163    }
164
165    return s;
166}
167
168#endif /* !HAVE_WINSOCK */
169