1 /* 2 * Copyright 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 <sys/select.h> 22 #include <sys/socket.h> 23 #include <sys/types.h> 24 #include <sys/un.h> 25 #include <unistd.h> 26 27 #include "osi/include/osi.h" 28 #include "osi/include/socket_utils/socket_local.h" 29 #include "osi/include/socket_utils/sockets.h" 30 31 #define LISTEN_BACKLOG 4 32 33 /* Documented in header file. */ 34 int osi_socket_make_sockaddr_un(const char* name, int namespaceId, 35 struct sockaddr_un* p_addr, socklen_t* alen) { 36 memset(p_addr, 0, sizeof(*p_addr)); 37 size_t namelen; 38 39 switch (namespaceId) { 40 case ANDROID_SOCKET_NAMESPACE_ABSTRACT: 41 #if defined(__linux__) 42 namelen = strlen(name); 43 44 // Test with length +1 for the *initial* '\0'. 45 if ((namelen + 1) > sizeof(p_addr->sun_path)) { 46 goto error; 47 } 48 49 /* 50 * Note: The path in this case is *not* supposed to be 51 * '\0'-terminated. ("man 7 unix" for the gory details.) 52 */ 53 54 p_addr->sun_path[0] = 0; 55 memcpy(p_addr->sun_path + 1, name, namelen); 56 #else 57 /* this OS doesn't have the Linux abstract namespace */ 58 59 namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX); 60 /* unix_path_max appears to be missing on linux */ 61 if (namelen > 62 sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) { 63 goto error; 64 } 65 66 strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX); 67 strcat(p_addr->sun_path, name); 68 #endif 69 break; 70 71 case ANDROID_SOCKET_NAMESPACE_RESERVED: 72 namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX); 73 /* unix_path_max appears to be missing on linux */ 74 if (namelen > 75 sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) { 76 goto error; 77 } 78 79 strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX); 80 strcat(p_addr->sun_path, name); 81 break; 82 83 case ANDROID_SOCKET_NAMESPACE_FILESYSTEM: 84 namelen = strlen(name); 85 /* unix_path_max appears to be missing on linux */ 86 if (namelen > 87 sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) { 88 goto error; 89 } 90 91 strcpy(p_addr->sun_path, name); 92 break; 93 default: 94 // invalid namespace id 95 return -1; 96 } 97 98 p_addr->sun_family = AF_LOCAL; 99 *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; 100 return 0; 101 error: 102 return -1; 103 } 104 105 /** 106 * connect to peer named "name" on fd 107 * returns same fd or -1 on error. 108 * fd is not closed on error. that's your job. 109 * 110 * Used by AndroidSocketImpl 111 */ 112 int osi_socket_local_client_connect(int fd, const char* name, int namespaceId, 113 int type UNUSED_ATTR) { 114 struct sockaddr_un addr; 115 socklen_t alen; 116 int err; 117 118 err = osi_socket_make_sockaddr_un(name, namespaceId, &addr, &alen); 119 120 if (err < 0) { 121 goto error; 122 } 123 124 OSI_NO_INTR(err = connect(fd, (struct sockaddr*)&addr, alen)); 125 if (err < 0) { 126 goto error; 127 } 128 129 return fd; 130 131 error: 132 return -1; 133 } 134 135 /** 136 * connect to peer named "name" 137 * returns fd or -1 on error 138 */ 139 int osi_socket_local_client(const char* name, int namespaceId, int type) { 140 int s; 141 142 s = socket(AF_LOCAL, type, 0); 143 if (s < 0) return -1; 144 145 if (0 > osi_socket_local_client_connect(s, name, namespaceId, type)) { 146 close(s); 147 return -1; 148 } 149 150 return s; 151 } 152