4 This file is part of polypaudio.
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
36 #include "socket-client.h"
37 #include "socket-util.h"
40 struct pa_socket_client
{
41 struct pa_mainloop_api
*mainloop
;
44 void *io_source
, *fixed_source
;
45 void (*callback
)(struct pa_socket_client
*c
, struct pa_iochannel
*io
, void *userdata
);
49 static struct pa_socket_client
*pa_socket_client_new(struct pa_mainloop_api
*m
) {
50 struct pa_socket_client
*c
;
53 c
= malloc(sizeof(struct pa_socket_client
));
57 c
->io_source
= c
->fixed_source
= NULL
;
63 static void do_call(struct pa_socket_client
*c
) {
64 struct pa_iochannel
*io
;
66 assert(c
&& c
->callback
);
68 lerror
= sizeof(error
);
69 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &lerror
) < 0) {
70 fprintf(stderr
, "getsockopt(): %s\n", strerror(errno
));
74 if (lerror
!= sizeof(error
)) {
75 fprintf(stderr
, "getsocktop() returned invalid size.\n");
80 fprintf(stderr
, "connect(): %s\n", strerror(error
));
84 io
= pa_iochannel_new(c
->mainloop
, c
->fd
, c
->fd
);
87 c
->callback(c
, io
, c
->userdata
);
94 c
->callback(c
, NULL
, c
->userdata
);
98 static void connect_fixed_cb(struct pa_mainloop_api
*m
, void *id
, void *userdata
) {
99 struct pa_socket_client
*c
= userdata
;
100 assert(m
&& c
&& c
->fixed_source
== id
);
101 m
->cancel_fixed(m
, c
->fixed_source
);
102 c
->fixed_source
= NULL
;
106 static void connect_io_cb(struct pa_mainloop_api
*m
, void *id
, int fd
, enum pa_mainloop_api_io_events events
, void *userdata
) {
107 struct pa_socket_client
*c
= userdata
;
108 assert(m
&& c
&& c
->io_source
== id
&& fd
>= 0);
109 m
->cancel_io(m
, c
->io_source
);
114 static int do_connect(struct pa_socket_client
*c
, const struct sockaddr
*sa
, socklen_t len
) {
116 assert(c
&& sa
&& len
);
118 pa_make_nonblock_fd(c
->fd
);
120 if ((r
= connect(c
->fd
, sa
, len
)) < 0) {
121 if (errno
!= EINPROGRESS
) {
122 fprintf(stderr
, "connect(): %s\n", strerror(errno
));
126 c
->io_source
= c
->mainloop
->source_io(c
->mainloop
, c
->fd
, PA_MAINLOOP_API_IO_EVENT_OUTPUT
, connect_io_cb
, c
);
127 assert(c
->io_source
);
129 c
->fixed_source
= c
->mainloop
->source_fixed(c
->mainloop
, connect_fixed_cb
, c
);
130 assert(c
->fixed_source
);
136 struct pa_socket_client
* pa_socket_client_new_ipv4(struct pa_mainloop_api
*m
, uint32_t address
, uint16_t port
) {
137 struct pa_socket_client
*c
;
138 struct sockaddr_in sa
;
139 assert(m
&& address
&& port
);
141 c
= pa_socket_client_new(m
);
144 if ((c
->fd
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
145 fprintf(stderr
, "socket(): %s\n", strerror(errno
));
149 pa_socket_tcp_low_delay(c
->fd
);
151 sa
.sin_family
= AF_INET
;
152 sa
.sin_port
= htons(port
);
153 sa
.sin_addr
.s_addr
= htonl(address
);
155 if (do_connect(c
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0)
161 pa_socket_client_free(c
);
165 struct pa_socket_client
* pa_socket_client_new_unix(struct pa_mainloop_api
*m
, const char *filename
) {
166 struct pa_socket_client
*c
;
167 struct sockaddr_un sa
;
168 assert(m
&& filename
);
170 c
= pa_socket_client_new(m
);
173 if ((c
->fd
= socket(PF_LOCAL
, SOCK_STREAM
, 0)) < 0) {
174 fprintf(stderr
, "socket(): %s\n", strerror(errno
));
178 pa_socket_low_delay(c
->fd
);
180 sa
.sun_family
= AF_LOCAL
;
181 strncpy(sa
.sun_path
, filename
, sizeof(sa
.sun_path
)-1);
182 sa
.sun_path
[sizeof(sa
.sun_path
) - 1] = 0;
184 if (do_connect(c
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0)
190 pa_socket_client_free(c
);
194 struct pa_socket_client
* pa_socket_client_new_sockaddr(struct pa_mainloop_api
*m
, const struct sockaddr
*sa
, size_t salen
) {
195 struct pa_socket_client
*c
;
197 c
= pa_socket_client_new(m
);
200 if ((c
->fd
= socket(sa
->sa_family
, SOCK_STREAM
, 0)) < 0) {
201 fprintf(stderr
, "socket(): %s\n", strerror(errno
));
205 if (sa
->sa_family
== AF_INET
)
206 pa_socket_tcp_low_delay(c
->fd
);
208 pa_socket_low_delay(c
->fd
);
210 if (do_connect(c
, sa
, salen
) < 0)
216 pa_socket_client_free(c
);
221 void pa_socket_client_free(struct pa_socket_client
*c
) {
222 assert(c
&& c
->mainloop
);
224 c
->mainloop
->cancel_io(c
->mainloop
, c
->io_source
);
226 c
->mainloop
->cancel_fixed(c
->mainloop
, c
->fixed_source
);
232 void pa_socket_client_set_callback(struct pa_socket_client
*c
, void (*on_connection
)(struct pa_socket_client
*c
, struct pa_iochannel
*io
, void *userdata
), void *userdata
) {
234 c
->callback
= on_connection
;
235 c
->userdata
= userdata
;