8 #include <netinet/in.h>
11 #include "socket-client.h"
12 #include "socket-util.h"
15 struct pa_socket_client
{
16 struct pa_mainloop_api
*mainloop
;
19 void *io_source
, *fixed_source
;
20 void (*callback
)(struct pa_socket_client
*c
, struct pa_iochannel
*io
, void *userdata
);
24 static struct pa_socket_client
*pa_socket_client_new(struct pa_mainloop_api
*m
) {
25 struct pa_socket_client
*c
;
28 c
= malloc(sizeof(struct pa_socket_client
));
32 c
->io_source
= c
->fixed_source
= NULL
;
38 static void do_call(struct pa_socket_client
*c
) {
39 struct pa_iochannel
*io
;
41 assert(c
&& c
->callback
);
43 lerror
= sizeof(error
);
44 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &lerror
) < 0) {
45 fprintf(stderr
, "getsockopt(): %s\n", strerror(errno
));
49 if (lerror
!= sizeof(error
)) {
50 fprintf(stderr
, "getsocktop() returned invalid size.\n");
55 fprintf(stderr
, "connect(): %s\n", strerror(error
));
59 io
= pa_iochannel_new(c
->mainloop
, c
->fd
, c
->fd
);
62 c
->callback(c
, io
, c
->userdata
);
69 c
->callback(c
, NULL
, c
->userdata
);
73 static void connect_fixed_cb(struct pa_mainloop_api
*m
, void *id
, void *userdata
) {
74 struct pa_socket_client
*c
= userdata
;
75 assert(m
&& c
&& c
->fixed_source
== id
);
76 m
->cancel_fixed(m
, c
->fixed_source
);
77 c
->fixed_source
= NULL
;
81 static void connect_io_cb(struct pa_mainloop_api
*m
, void *id
, int fd
, enum pa_mainloop_api_io_events events
, void *userdata
) {
82 struct pa_socket_client
*c
= userdata
;
83 assert(m
&& c
&& c
->io_source
== id
&& fd
>= 0 && events
== PA_MAINLOOP_API_IO_EVENT_OUTPUT
);
84 m
->cancel_io(m
, c
->io_source
);
89 static int do_connect(struct pa_socket_client
*c
, const struct sockaddr
*sa
, socklen_t len
) {
91 assert(c
&& sa
&& len
);
93 pa_make_nonblock_fd(c
->fd
);
95 if ((r
= connect(c
->fd
, sa
, len
)) < 0) {
96 if (r
!= EINPROGRESS
) {
97 fprintf(stderr
, "connect(): %s\n", strerror(errno
));
101 c
->io_source
= c
->mainloop
->source_io(c
->mainloop
, c
->fd
, PA_MAINLOOP_API_IO_EVENT_OUTPUT
, connect_io_cb
, c
);
102 assert(c
->io_source
);
104 c
->fixed_source
= c
->mainloop
->source_fixed(c
->mainloop
, connect_fixed_cb
, c
);
105 assert(c
->fixed_source
);
111 struct pa_socket_client
* pa_socket_client_new_ipv4(struct pa_mainloop_api
*m
, uint32_t address
, uint16_t port
) {
112 struct pa_socket_client
*c
;
113 struct sockaddr_in sa
;
114 assert(m
&& address
&& port
);
116 c
= pa_socket_client_new(m
);
119 if ((c
->fd
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
120 fprintf(stderr
, "socket(): %s\n", strerror(errno
));
124 pa_socket_tcp_low_delay(c
->fd
);
126 sa
.sin_family
= AF_INET
;
127 sa
.sin_port
= htons(port
);
128 sa
.sin_addr
.s_addr
= htonl(address
);
130 if (do_connect(c
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0)
136 pa_socket_client_free(c
);
140 struct pa_socket_client
* pa_socket_client_new_unix(struct pa_mainloop_api
*m
, const char *filename
) {
141 struct pa_socket_client
*c
;
142 struct sockaddr_un sa
;
143 assert(m
&& filename
);
145 c
= pa_socket_client_new(m
);
148 if ((c
->fd
= socket(PF_LOCAL
, SOCK_STREAM
, 0)) < 0) {
149 fprintf(stderr
, "socket(): %s\n", strerror(errno
));
153 pa_socket_low_delay(c
->fd
);
155 sa
.sun_family
= AF_LOCAL
;
156 strncpy(sa
.sun_path
, filename
, sizeof(sa
.sun_path
)-1);
157 sa
.sun_path
[sizeof(sa
.sun_path
) - 1] = 0;
159 if (do_connect(c
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0)
165 pa_socket_client_free(c
);
169 void pa_socket_client_free(struct pa_socket_client
*c
) {
170 assert(c
&& c
->mainloop
);
172 c
->mainloop
->cancel_io(c
->mainloop
, c
->io_source
);
174 c
->mainloop
->cancel_fixed(c
->mainloop
, c
->fixed_source
);
180 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
) {
182 c
->callback
= on_connection
;
183 c
->userdata
= userdata
;