sock_shutdown_test.c revision 47653588a022190d4b3e20194ef643dfb7b90632
1/*
2** Copyright 2009 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/** socket testing  */
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <errno.h>
22#include <sys/uio.h>
23#include <unistd.h>
24
25#include <pthread.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <unistd.h>
30#include <sys/socket.h>
31#include <sys/ioctl.h>
32#include <sys/poll.h>
33#include <sys/un.h>
34#include <netinet/in.h>
35
36#include <bluetooth/bluetooth.h>
37#include <bluetooth/rfcomm.h>
38#include <bluetooth/sco.h>
39#include <bluetooth/l2cap.h>
40
41enum sock_type {
42    UNIX = 0,
43    RFCOMM,
44    SCO,
45    L2CAP,
46    TCP,
47    SOCKETPAIR,
48};
49
50static void print_events(int events) {
51    if (events & POLLIN) printf("POLLIN ");
52    if (events & POLLPRI) printf("POLLPRI ");
53    if (events & POLLOUT) printf("POLLOUT ");
54    if (events & POLLERR) printf("POLLERR ");
55    if (events & POLLHUP) printf("POLLHUP ");
56    if (events & POLLNVAL) printf("POLLNVAL ");
57    printf("\n");
58}
59
60static void print_fds(struct pollfd *ufds, nfds_t nfds) {
61    unsigned int i;
62    for (i=0; i<nfds; i++)
63        printf("%d ", ufds[i].fd);
64}
65
66static int _socket(int type) {
67    int ret;
68    int family = -1;
69    int typ = -1;
70    int protocol = -1;
71
72    switch (type) {
73    case UNIX:
74        family = PF_UNIX;
75        typ = SOCK_STREAM;
76        protocol = 0;
77        break;
78    case RFCOMM:
79        family = PF_BLUETOOTH;
80        typ = SOCK_STREAM;
81        protocol = BTPROTO_RFCOMM;
82        break;
83    case SCO:
84        family = PF_BLUETOOTH;
85        typ = SOCK_SEQPACKET;
86        protocol = BTPROTO_SCO;
87        break;
88    case L2CAP:
89        family = PF_BLUETOOTH;
90        typ = SOCK_SEQPACKET;
91        protocol = BTPROTO_L2CAP;
92        break;
93    case TCP:
94        family = PF_INET;
95        typ = SOCK_STREAM;
96        protocol = 0;
97        break;
98    case SOCKETPAIR:
99        {
100            int fd[2];
101            printf("%d: socketpair()\n", gettid());
102            ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
103            printf("%d: socketpair() = %d\n", gettid(), ret);
104            if (ret) {
105                printf("\terr %d (%s)\n", errno, strerror(errno));
106                return -1;
107            }
108            return fd[0];
109        }
110    }
111
112    printf("%d: socket()\n", gettid());
113    ret = socket(family, typ, protocol);
114    printf("%d: socket() = %d\n", gettid(), ret);
115    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
116
117    return ret;
118}
119
120static int _close(int fd) {
121    int ret;
122
123    printf("%d: close(%d)\n", gettid(), fd);
124    ret = close(fd);
125    printf("%d: close(%d) = %d\n", gettid(), fd, ret);
126    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
127
128    return ret;
129}
130
131static int _shutdown(int fd) {
132    int ret;
133
134    printf("%d: shutdown(%d)\n", gettid(), fd);
135    ret = shutdown(fd, SHUT_RDWR);
136    printf("%d: shutdown(%d) = %d\n", gettid(), fd, ret);
137    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
138
139    return ret;
140}
141
142static int _poll(struct pollfd *ufds, nfds_t nfds, int timeout) {
143    int ret;
144    unsigned int i;
145
146    printf("%d: poll(", gettid());
147    print_fds(ufds, nfds);
148    printf(")\n");
149    ret = poll(ufds, nfds, timeout);
150    printf("%d: poll() = %d\n", gettid(), ret);
151    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
152    if (ret > 0) {
153        for (i=0; i<nfds; i++) {
154            if (ufds[i].revents) {
155                printf("\tfd %d ", ufds[i].fd); print_events(ufds[i].revents);
156            }
157        }
158    }
159    return ret;
160}
161
162static void thread_poll(int fd) {
163    struct pollfd pfd;
164    printf("%d: START\n", gettid());
165    pfd.fd = fd;
166    pfd.events = 0;
167    _poll(&pfd, 1, -1);
168    printf("%d: END\n", gettid());
169}
170
171static int do_poll_shutdown(int type) {
172    const int MAX_T = 2;
173    int fd;
174    pthread_t t[MAX_T];
175    int i;
176
177    fd = _socket(type);
178
179    for (i=0; i<MAX_T; i++)
180        pthread_create(&t[i], NULL, (void *)thread_poll, (void *)fd);
181
182    sleep(1);
183
184    _shutdown(fd);
185
186    for (i=0; i<MAX_T; i++)
187        pthread_join(t[i], NULL);
188
189    _close(fd);
190
191    return 0;
192}
193
194struct {
195    char *name;
196    enum sock_type type;
197} type_table[]  = {
198    {"unix", UNIX},
199    {"rfcomm", RFCOMM},
200    {"sco", SCO},
201    {"l2cap", L2CAP},
202    {"tcp", TCP},
203    {"socketpair", SOCKETPAIR},
204    {NULL, -1},
205};
206
207static void usage() {
208    int i;
209
210    printf("sock_shutdown_test TYPE\n");
211    printf("\nTYPE:\n");
212    for (i = 0; type_table[i].name; i++) {
213        printf("\t%s\n", type_table[i].name);
214    }
215}
216
217int main(int argc, char **argv) {
218    int i;
219    int type = -1;
220
221    if (argc != 2) {
222        usage();
223        return -1;
224    }
225    for (i = 0; type_table[i].name; i++) {
226        if (!strcmp(argv[1], type_table[i].name)) {
227            type = type_table[i].type;
228            printf("TYPE = %s\n", type_table[type].name);
229            return do_poll_shutdown(type);
230        }
231    }
232    usage();
233    return -1;
234}
235