8 #include <netinet/in.h>
11 #include "socket-client.h"
14 struct socket_client
{
15 struct pa_mainloop_api
*mainloop
;
18 void *io_source
, *fixed_source
;
19 void (*callback
)(struct socket_client
*c
, struct iochannel
*io
, void *userdata
);
23 static struct socket_client
*socket_client_new(struct pa_mainloop_api
*m
) {
24 struct socket_client
*c
;
27 c
= malloc(sizeof(struct socket_client
));
31 c
->io_source
= c
->fixed_source
= NULL
;
37 static void do_call(struct socket_client
*c
) {
40 assert(c
&& c
->callback
);
42 lerror
= sizeof(error
);
43 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &lerror
) < 0) {
44 fprintf(stderr
, "getsockopt(): %s\n", strerror(errno
));
48 if (lerror
!= sizeof(error
)) {
49 fprintf(stderr
, "getsocktop() returned invalid size.\n");
54 fprintf(stderr
, "connect(): %s\n", strerror(error
));
58 io
= iochannel_new(c
->mainloop
, c
->fd
, c
->fd
);
61 c
->callback(c
, io
, c
->userdata
);
68 c
->callback(c
, NULL
, c
->userdata
);
72 static void connect_fixed_cb(struct pa_mainloop_api
*m
, void *id
, void *userdata
) {
73 struct socket_client
*c
= userdata
;
74 assert(m
&& c
&& c
->fixed_source
== id
);
75 m
->cancel_fixed(m
, c
->fixed_source
);
76 c
->fixed_source
= NULL
;
80 static void connect_io_cb(struct pa_mainloop_api
*m
, void *id
, int fd
, enum pa_mainloop_api_io_events events
, void *userdata
) {
81 struct socket_client
*c
= userdata
;
82 assert(m
&& c
&& c
->io_source
== id
&& fd
>= 0 && events
== PA_MAINLOOP_API_IO_EVENT_OUTPUT
);
83 m
->cancel_io(m
, c
->io_source
);
88 static int do_connect(struct socket_client
*c
, const struct sockaddr
*sa
, socklen_t len
) {
90 assert(c
&& sa
&& len
);
92 make_nonblock_fd(c
->fd
);
94 if ((r
= connect(c
->fd
, sa
, len
)) < 0) {
95 if (r
!= EINPROGRESS
) {
96 fprintf(stderr
, "connect(): %s\n", strerror(errno
));
100 c
->io_source
= c
->mainloop
->source_io(c
->mainloop
, c
->fd
, PA_MAINLOOP_API_IO_EVENT_OUTPUT
, connect_io_cb
, c
);
101 assert(c
->io_source
);
103 c
->fixed_source
= c
->mainloop
->source_fixed(c
->mainloop
, connect_fixed_cb
, c
);
104 assert(c
->io_source
);
110 struct socket_client
* socket_client_new_ipv4(struct pa_mainloop_api
*m
, uint32_t address
, uint16_t port
) {
111 struct socket_client
*c
;
112 struct sockaddr_in sa
;
114 c
= socket_client_new(m
);
117 if ((c
->fd
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
118 fprintf(stderr
, "socket(): %s\n", strerror(errno
));
122 sa
.sin_family
= AF_INET
;
123 sa
.sin_port
= htons(port
);
124 sa
.sin_addr
.s_addr
= htonl(address
);
126 if (do_connect(c
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0)
132 socket_client_free(c
);
136 struct socket_client
* socket_client_new_unix(struct pa_mainloop_api
*m
, const char *filename
) {
137 struct socket_client
*c
;
138 struct sockaddr_un sa
;
140 c
= socket_client_new(m
);
143 if ((c
->fd
= socket(PF_LOCAL
, SOCK_STREAM
, 0)) < 0) {
144 fprintf(stderr
, "socket(): %s\n", strerror(errno
));
148 sa
.sun_family
= AF_LOCAL
;
149 strncpy(sa
.sun_path
, filename
, sizeof(sa
.sun_path
)-1);
150 sa
.sun_path
[sizeof(sa
.sun_path
) - 1] = 0;
152 if (do_connect(c
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0)
158 socket_client_free(c
);
162 void socket_client_free(struct socket_client
*c
) {
163 assert(c
&& c
->mainloop
);
165 c
->mainloop
->cancel_io(c
->mainloop
, c
->io_source
);
167 c
->mainloop
->cancel_fixed(c
->mainloop
, c
->fixed_source
);
173 void socket_client_set_callback(struct socket_client
*c
, void (*on_connection
)(struct socket_client
*c
, struct iochannel
*io
, void *userdata
), void *userdata
) {
175 c
->callback
= on_connection
;
176 c
->userdata
= userdata
;