2 Copyright (C) 2006 by Jonas Kramer
3 Published under the terms of the GNU General Public License (GPL).
13 #include <sys/types.h>
14 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
24 #include <sys/select.h>
30 #include "interface.h"
40 static int stcpsck
= -1, sunixsck
= -1;
41 static int waitread(int, unsigned, unsigned);
43 #define REPLYBUFSIZE 1024
45 int tcpsock(const char * ip
, unsigned short port
) {
46 static const int one
= 1;
47 struct sockaddr_in host
;
48 struct hostent
* hostent
;
53 if(-1 == (stcpsck
= socket(AF_INET
, SOCK_STREAM
, PF_UNSPEC
))) {
54 fputs("Failed to create socket.\n", stderr
);
58 if(!(hostent
= gethostbyname(ip
))) {
59 fprintf(stderr
, "Failed to lookup host. %s.\n", hstrerror(h_errno
));
63 host
.sin_family
= PF_INET
;
64 host
.sin_port
= htons(port
);
65 host
.sin_addr
.s_addr
= * (unsigned *) hostent
->h_addr
;
67 if(-1 == setsockopt(stcpsck
, SOL_SOCKET
, SO_REUSEADDR
, & one
, sizeof one
))
68 fprintf(stderr
, "Couldn't make socket re-usable. %s\n", strerror(errno
));
70 if(bind(stcpsck
, (struct sockaddr
*) & host
, sizeof(struct sockaddr_in
))) {
71 fprintf(stderr
, "Failed to bind socket. %s.\n", strerror(errno
));
81 int unixsock(const char * path
) {
82 struct sockaddr_un host
;
88 if(!access(path
, F_OK
)) {
89 fprintf(stderr
, "%s already existing. UNIX socket not created.\n", path
);
94 if(-1 == (sunixsck
= socket(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
))) {
95 fputs("Failed to create socket.\n", stderr
);
100 memset(& host
, 0, sizeof(struct sockaddr_un
));
101 strncpy(host
.sun_path
, path
, sizeof(host
.sun_path
) - 1);
102 host
.sun_family
= AF_UNIX
;
105 if(bind(sunixsck
, (struct sockaddr
*) & host
, sizeof(struct sockaddr_un
))) {
106 fprintf(stderr
, "Failed to bind socket. %s.\n", strerror(errno
));
129 void sckif(int timeout
, int sck
) {
131 /* If the given socket is -1, try both sockets, unix and tcp. */
134 sckif(timeout
, stcpsck
);
137 sckif(timeout
, sunixsck
);
142 signal(SIGPIPE
, SIG_IGN
);
144 if(waitread(sck
, timeout
, 0)) {
145 struct sockaddr client
;
146 socklen_t scksize
= sizeof(struct sockaddr
);
148 int csck
= accept(sck
, & client
, & scksize
);
151 if(waitread(csck
, 0, 100000)) {
152 FILE * fd
= fdopen(csck
, "r");
155 char * line
= NULL
, * ptr
= NULL
, reply
[REPLYBUFSIZE
];
158 getln(& line
, & size
, fd
);
160 if(line
&& size
> 0 && !ferror(fd
)) {
161 if((ptr
= strchr(line
, 13)) || (ptr
= strchr(line
, 10)))
164 execcmd(line
, reply
);
171 write(csck
, reply
, strlen(reply
));
178 shutdown(csck
, SHUT_RDWR
);
184 void execcmd(const char * cmd
, char * reply
) {
185 char arg
[1024], * ptr
;
187 const char * known
[] = {
205 memset(arg
, 0, sizeof(arg
));
206 memset(reply
, 0, REPLYBUFSIZE
);
208 for(ncmd
= 0; ncmd
< (sizeof(known
) / sizeof(char *)); ++ncmd
) {
209 if(!strncmp(known
[ncmd
], cmd
, strlen(known
[ncmd
])))
214 case (sizeof(known
) / sizeof(char *)):
215 strncpy(reply
, "ERROR", REPLYBUFSIZE
);
219 if(sscanf(cmd
, "play %128[a-zA-Z0-9:/_ %,*.-]", arg
) == 1) {
244 strncpy(reply
, meta(cmd
+ 5, 0, & track
), REPLYBUFSIZE
);
245 else if(haskey(& rc
, "np-file-format"))
248 meta(value(& rc
, "np-file-format"), 0, & track
),
257 kill(playfork
, SIGCONT
);
261 kill(playfork
, SIGSTOP
);
271 if(sscanf(cmd
, "tag-artist %128s", arg
) == 1)
272 sendtag('a', arg
, track
);
276 if(sscanf(cmd
, "tag-album %128s", arg
) == 1)
277 sendtag('l', arg
, track
);
281 if(sscanf(cmd
, "tag-track %128s", arg
) == 1)
282 sendtag('t', arg
, track
);
286 if((ptr
= oldtags('a', track
)) != NULL
) {
287 strncpy(reply
, ptr
, REPLYBUFSIZE
);
294 if((ptr
= oldtags('l', track
)) != NULL
) {
295 strncpy(reply
, ptr
, REPLYBUFSIZE
);
302 if((ptr
= oldtags('t', track
)) != NULL
) {
303 strncpy(reply
, ptr
, REPLYBUFSIZE
);
312 kill(playfork
, SIGUSR1
);
318 static int waitread(int fd
, unsigned sec
, unsigned usec
) {
323 FD_SET(fd
, & readfd
);
328 return (select(fd
+ 1, & readfd
, NULL
, NULL
, & tv
) > 0);