• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /******************************************************************************
2   *
3   *  Copyright (C) 2014 Google, Inc.
4   *
5   *  Licensed under the Apache License, Version 2.0 (the "License");
6   *  you may not use this file except in compliance with the License.
7   *  You may obtain a copy of the License at:
8   *
9   *  http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   *
17   ******************************************************************************/
18  
19  #define LOG_TAG "bt_osi_socket"
20  
21  #include "osi/include/socket.h"
22  
23  #include <asm/ioctls.h>
24  #include <assert.h>
25  #include <errno.h>
26  #include <netinet/in.h>
27  #include <string.h>
28  #include <sys/ioctl.h>
29  #include <sys/socket.h>
30  #include <unistd.h>
31  
32  #include "osi/include/allocator.h"
33  #include "osi/include/log.h"
34  #include "osi/include/osi.h"
35  #include "osi/include/reactor.h"
36  
37  // The IPv4 loopback address: 127.0.0.1
38  static const in_addr_t LOCALHOST_ = 0x7f000001;
39  
40  struct socket_t {
41    int fd;
42    reactor_object_t *reactor_object;
43    socket_cb read_ready;
44    socket_cb write_ready;
45    void *context;                     // Not owned, do not free.
46  };
47  
48  static void internal_read_ready(void *context);
49  static void internal_write_ready(void *context);
50  
socket_new(void)51  socket_t *socket_new(void) {
52    socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t));
53  
54    ret->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
55    if (ret->fd == INVALID_FD) {
56      LOG_ERROR(LOG_TAG, "%s unable to create socket: %s", __func__, strerror(errno));
57      goto error;
58    }
59  
60    int enable = 1;
61    if (setsockopt(ret->fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
62      LOG_ERROR(LOG_TAG, "%s unable to set SO_REUSEADDR: %s", __func__, strerror(errno));
63      goto error;
64    }
65  
66    return ret;
67  
68  error:;
69    if (ret)
70      close(ret->fd);
71    osi_free(ret);
72    return NULL;
73  }
74  
socket_new_from_fd(int fd)75  socket_t *socket_new_from_fd(int fd) {
76    assert(fd != INVALID_FD);
77  
78    socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t));
79  
80    ret->fd = fd;
81    return ret;
82  }
83  
socket_free(socket_t * socket)84  void socket_free(socket_t *socket) {
85    if (!socket)
86      return;
87  
88    socket_unregister(socket);
89    close(socket->fd);
90    osi_free(socket);
91  }
92  
socket_listen(const socket_t * socket,port_t port)93  bool socket_listen(const socket_t *socket, port_t port) {
94    assert(socket != NULL);
95  
96    struct sockaddr_in addr;
97    addr.sin_family = AF_INET;
98    addr.sin_addr.s_addr = htonl(LOCALHOST_);
99    addr.sin_port = htons(port);
100    if (bind(socket->fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
101      LOG_ERROR(LOG_TAG, "%s unable to bind socket to port %u: %s", __func__, port, strerror(errno));
102      return false;
103    }
104  
105    if (listen(socket->fd, 10) == -1) {
106      LOG_ERROR(LOG_TAG, "%s unable to listen on port %u: %s", __func__, port, strerror(errno));
107      return false;
108    }
109  
110    return true;
111  }
112  
socket_accept(const socket_t * socket)113  socket_t *socket_accept(const socket_t *socket) {
114    assert(socket != NULL);
115  
116    int fd;
117    OSI_NO_INTR(fd = accept(socket->fd, NULL, NULL));
118    if (fd == INVALID_FD) {
119      LOG_ERROR(LOG_TAG, "%s unable to accept socket: %s", __func__, strerror(errno));
120      return NULL;
121    }
122  
123    socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t));
124  
125    ret->fd = fd;
126    return ret;
127  }
128  
socket_read(const socket_t * socket,void * buf,size_t count)129  ssize_t socket_read(const socket_t *socket, void *buf, size_t count) {
130    assert(socket != NULL);
131    assert(buf != NULL);
132  
133    ssize_t ret;
134    OSI_NO_INTR(ret = recv(socket->fd, buf, count, MSG_DONTWAIT));
135  
136    return ret;
137  }
138  
socket_write(const socket_t * socket,const void * buf,size_t count)139  ssize_t socket_write(const socket_t *socket, const void *buf, size_t count) {
140    assert(socket != NULL);
141    assert(buf != NULL);
142  
143    ssize_t ret;
144    OSI_NO_INTR(ret = send(socket->fd, buf, count, MSG_DONTWAIT));
145  
146    return ret;
147  }
148  
socket_write_and_transfer_fd(const socket_t * socket,const void * buf,size_t count,int fd)149  ssize_t socket_write_and_transfer_fd(const socket_t *socket, const void *buf, size_t count, int fd) {
150    assert(socket != NULL);
151    assert(buf != NULL);
152  
153    if (fd == INVALID_FD)
154      return socket_write(socket, buf, count);
155  
156    struct msghdr msg;
157    struct iovec iov;
158    char control_buf[CMSG_SPACE(sizeof(int))];
159  
160    iov.iov_base = (void *)buf;
161    iov.iov_len = count;
162  
163    msg.msg_iov = &iov;
164    msg.msg_iovlen = 1;
165    msg.msg_control = control_buf;
166    msg.msg_controllen = sizeof(control_buf);
167    msg.msg_name = NULL;
168    msg.msg_namelen = 0;
169  
170    struct cmsghdr *header = CMSG_FIRSTHDR(&msg);
171    header->cmsg_level = SOL_SOCKET;
172    header->cmsg_type = SCM_RIGHTS;
173    header->cmsg_len = CMSG_LEN(sizeof(int));
174    *(int *)CMSG_DATA(header) = fd;
175  
176    ssize_t ret;
177    OSI_NO_INTR(ret = sendmsg(socket->fd, &msg, MSG_DONTWAIT));
178  
179    close(fd);
180    return ret;
181  }
182  
socket_bytes_available(const socket_t * socket)183  ssize_t socket_bytes_available(const socket_t *socket) {
184    assert(socket != NULL);
185  
186    int size = 0;
187    if (ioctl(socket->fd, FIONREAD, &size) == -1)
188      return -1;
189    return size;
190  }
191  
socket_register(socket_t * socket,reactor_t * reactor,void * context,socket_cb read_cb,socket_cb write_cb)192  void socket_register(socket_t *socket, reactor_t *reactor, void *context, socket_cb read_cb, socket_cb write_cb) {
193    assert(socket != NULL);
194  
195    // Make sure the socket isn't currently registered.
196    socket_unregister(socket);
197  
198    socket->read_ready = read_cb;
199    socket->write_ready = write_cb;
200    socket->context = context;
201  
202    void (*read_fn)(void *) = (read_cb != NULL) ? internal_read_ready : NULL;
203    void (*write_fn)(void *) = (write_cb != NULL) ? internal_write_ready : NULL;
204  
205    socket->reactor_object = reactor_register(reactor, socket->fd, socket, read_fn, write_fn);
206  }
207  
socket_unregister(socket_t * socket)208  void socket_unregister(socket_t *socket) {
209    assert(socket != NULL);
210  
211    if (socket->reactor_object)
212      reactor_unregister(socket->reactor_object);
213    socket->reactor_object = NULL;
214  }
215  
internal_read_ready(void * context)216  static void internal_read_ready(void *context) {
217    assert(context != NULL);
218  
219    socket_t *socket = (void *)context;
220    socket->read_ready(socket, socket->context);
221  }
222  
internal_write_ready(void * context)223  static void internal_write_ready(void *context) {
224    assert(context != NULL);
225  
226    socket_t *socket = (void *)context;
227    socket->write_ready(socket, socket->context);
228  }
229