]> code.delx.au - pulseaudio/blob - src/socket-server.c
a bunch of fixes
[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
15 struct socket_server {
16 int fd;
17 char *filename;
18
19 void (*on_connection)(struct socket_server*s, struct iochannel *io, void *userdata);
20 void *userdata;
21
22 struct mainloop_source *mainloop_source;
23 };
24
25 static void callback(struct mainloop_source*src, int fd, enum mainloop_io_event event, void *userdata) {
26 struct socket_server *s = userdata;
27 struct iochannel *io;
28 int nfd;
29 assert(src && fd >= 0 && fd == s->fd && event == MAINLOOP_IO_EVENT_IN && s);
30
31 if ((nfd = accept(fd, NULL, NULL)) < 0) {
32 fprintf(stderr, "accept(): %s\n", strerror(errno));
33 return;
34 }
35
36 if (!s->on_connection) {
37 close(nfd);
38 return;
39 }
40
41 io = iochannel_new(mainloop_source_get_mainloop(src), nfd, nfd);
42 assert(io);
43 s->on_connection(s, io, s->userdata);
44 }
45
46 struct socket_server* socket_server_new(struct mainloop *m, int fd) {
47 struct socket_server *s;
48 assert(m && fd >= 0);
49
50 s = malloc(sizeof(struct socket_server));
51 assert(s);
52 s->fd = fd;
53 s->filename = NULL;
54 s->on_connection = NULL;
55 s->userdata = NULL;
56
57 s->mainloop_source = mainloop_source_new_io(m, fd, MAINLOOP_IO_EVENT_IN, callback, s);
58 assert(s->mainloop_source);
59
60 return s;
61 }
62
63 struct socket_server* socket_server_new_unix(struct mainloop *m, const char *filename) {
64 int fd = -1;
65 struct sockaddr_un sa;
66 struct socket_server *s;
67
68 assert(m && filename);
69
70 if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
71 fprintf(stderr, "socket(): %s\n", strerror(errno));
72 goto fail;
73 }
74
75 sa.sun_family = AF_LOCAL;
76 strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
77 sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
78
79 if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) {
80 fprintf(stderr, "bind(): %s\n", strerror(errno));
81 goto fail;
82 }
83
84 if (listen(fd, 5) < 0) {
85 fprintf(stderr, "listen(): %s\n", strerror(errno));
86 goto fail;
87 }
88
89 s = socket_server_new(m, fd);
90 assert(s);
91
92 s->filename = strdup(filename);
93 assert(s->filename);
94
95 return s;
96
97 fail:
98 if (fd >= 0)
99 close(fd);
100
101 return NULL;
102 }
103
104 struct socket_server* socket_server_new_ipv4(struct mainloop *m, uint32_t address, uint16_t port) {
105 int fd = -1;
106 struct sockaddr_in sa;
107 int on = 1;
108
109 assert(m && port);
110
111 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
112 fprintf(stderr, "socket(): %s\n", strerror(errno));
113 goto fail;
114 }
115
116 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
117 fprintf(stderr, "setsockopt(): %s\n", strerror(errno));
118
119 sa.sin_family = AF_INET;
120 sa.sin_port = htons(port);
121 sa.sin_addr.s_addr = htonl(address);
122
123 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
124 fprintf(stderr, "bind(): %s\n", strerror(errno));
125 goto fail;
126 }
127
128 if (listen(fd, 5) < 0) {
129 fprintf(stderr, "listen(): %s\n", strerror(errno));
130 goto fail;
131 }
132
133 return socket_server_new(m, fd);
134
135 fail:
136 if (fd >= 0)
137 close(fd);
138
139 return NULL;
140 }
141
142 void socket_server_free(struct socket_server*s) {
143 assert(s);
144 close(s->fd);
145
146 if (s->filename) {
147 unlink(s->filename);
148 free(s->filename);
149 }
150
151 mainloop_source_free(s->mainloop_source);
152
153 free(s);
154 }
155
156 void socket_server_set_callback(struct socket_server*s, void (*on_connection)(struct socket_server*s, struct iochannel *io, void *userdata), void *userdata) {
157 assert(s);
158
159 s->on_connection = on_connection;
160 s->userdata = userdata;
161 }