]> code.delx.au - pulseaudio/blob - src/socket-server.c
add dependency script
[pulseaudio] / src / socket-server.c
1 #include <stdlib.h>
2 #include <assert.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <sys/un.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12
13 #include "socket-server.h"
14 #include "socket-util.h"
15
16 struct pa_socket_server {
17 int fd;
18 char *filename;
19
20 void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata);
21 void *userdata;
22
23 void *mainloop_source;
24 struct pa_mainloop_api *mainloop;
25 enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX } type;
26 };
27
28 static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) {
29 struct pa_socket_server *s = userdata;
30 struct pa_iochannel *io;
31 int nfd;
32 assert(s && s->mainloop == mainloop && s->mainloop_source == id && id && fd >= 0 && fd == s->fd && events == PA_MAINLOOP_API_IO_EVENT_INPUT);
33
34 if ((nfd = accept(fd, NULL, NULL)) < 0) {
35 fprintf(stderr, "accept(): %s\n", strerror(errno));
36 return;
37 }
38
39 if (!s->on_connection) {
40 close(nfd);
41 return;
42 }
43
44 /* There should be a check for socket type here */
45 if (s->type == SOCKET_SERVER_IPV4)
46 pa_socket_tcp_low_delay(fd);
47 else
48 pa_socket_low_delay(fd);
49
50 io = pa_iochannel_new(s->mainloop, nfd, nfd);
51 assert(io);
52 s->on_connection(s, io, s->userdata);
53 }
54
55 struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) {
56 struct pa_socket_server *s;
57 assert(m && fd >= 0);
58
59 s = malloc(sizeof(struct pa_socket_server));
60 assert(s);
61 s->fd = fd;
62 s->filename = NULL;
63 s->on_connection = NULL;
64 s->userdata = NULL;
65
66 s->mainloop = m;
67 s->mainloop_source = m->source_io(m, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, s);
68 assert(s->mainloop_source);
69
70 s->type = SOCKET_SERVER_GENERIC;
71
72 return s;
73 }
74
75 struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) {
76 int fd = -1;
77 struct sockaddr_un sa;
78 struct pa_socket_server *s;
79
80 assert(m && filename);
81
82 if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
83 fprintf(stderr, "socket(): %s\n", strerror(errno));
84 goto fail;
85 }
86
87 sa.sun_family = AF_LOCAL;
88 strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
89 sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
90
91 pa_socket_low_delay(fd);
92
93 if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) {
94 fprintf(stderr, "bind(): %s\n", strerror(errno));
95 goto fail;
96 }
97
98 if (listen(fd, 5) < 0) {
99 fprintf(stderr, "listen(): %s\n", strerror(errno));
100 goto fail;
101 }
102
103 s = pa_socket_server_new(m, fd);
104 assert(s);
105
106 s->filename = strdup(filename);
107 assert(s->filename);
108
109 s->type = SOCKET_SERVER_UNIX;
110
111 return s;
112
113 fail:
114 if (fd >= 0)
115 close(fd);
116
117 return NULL;
118 }
119
120 struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) {
121 struct pa_socket_server *ss;
122 int fd = -1;
123 struct sockaddr_in sa;
124 int on = 1;
125
126 assert(m && port);
127
128 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
129 fprintf(stderr, "socket(): %s\n", strerror(errno));
130 goto fail;
131 }
132
133 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
134 fprintf(stderr, "setsockopt(): %s\n", strerror(errno));
135
136 pa_socket_tcp_low_delay(fd);
137
138 sa.sin_family = AF_INET;
139 sa.sin_port = htons(port);
140 sa.sin_addr.s_addr = htonl(address);
141
142 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
143 fprintf(stderr, "bind(): %s\n", strerror(errno));
144 goto fail;
145 }
146
147 if (listen(fd, 5) < 0) {
148 fprintf(stderr, "listen(): %s\n", strerror(errno));
149 goto fail;
150 }
151
152 if ((ss = pa_socket_server_new(m, fd)))
153 ss->type = SOCKET_SERVER_IPV4;
154
155 return ss;
156
157 fail:
158 if (fd >= 0)
159 close(fd);
160
161 return NULL;
162 }
163
164 void pa_socket_server_free(struct pa_socket_server*s) {
165 assert(s);
166 close(s->fd);
167
168 if (s->filename) {
169 unlink(s->filename);
170 free(s->filename);
171 }
172
173
174 s->mainloop->cancel_io(s->mainloop, s->mainloop_source);
175
176 free(s);
177 }
178
179 void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata) {
180 assert(s);
181
182 s->on_connection = on_connection;
183 s->userdata = userdata;
184 }