seek: Ceil position to duration - 5s
[cmus.git] / server.c
blob72aceeb27083cdd58aa842e64b60263c648bdf45
1 /*
2 * Copyright 2004-2005 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include "server.h"
21 #include "prog.h"
22 #include "command_mode.h"
23 #include "options.h"
24 #include "debug.h"
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <netdb.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
38 int server_socket;
40 static union {
41 struct sockaddr sa;
42 struct sockaddr_un un;
43 struct sockaddr_in in;
44 } addr;
46 #define MAX_CLIENTS 10
48 static void read_commands(int fd)
50 char buf[1024];
51 int pos = 0;
52 int authenticated = addr.sa.sa_family == AF_UNIX;
54 while (1) {
55 int rc, s, i;
57 rc = read(fd, buf + pos, sizeof(buf) - pos);
58 if (rc == -1) {
59 break;
61 if (rc == 0) {
62 break;
64 pos += rc;
66 s = 0;
67 for (i = 0; i < pos; i++) {
68 const char *line;
70 if (buf[i] != '\n')
71 continue;
73 buf[i] = 0;
74 line = buf + s;
75 s = i + 1;
77 if (!authenticated) {
78 if (!server_password) {
79 d_print("password is unset, tcp/ip disabled\n");
80 return;
82 authenticated = !strcmp(line, server_password);
83 if (!authenticated) {
84 d_print("authentication failed\n");
85 return;
87 continue;
89 run_command(line);
91 memmove(buf, buf + s, pos - s);
92 pos -= s;
96 int server_serve(void)
98 struct sockaddr saddr;
99 socklen_t saddr_size = sizeof(saddr);
100 int fd;
102 fd = accept(server_socket, &saddr, &saddr_size);
103 if (fd == -1) {
104 return -1;
107 /* unix connection is secure, other insecure */
108 run_only_safe_commands = addr.sa.sa_family != AF_UNIX;
109 read_commands(fd);
110 run_only_safe_commands = 0;
112 close(fd);
113 return 0;
116 static void gethostbyname_failed(void)
118 const char *error = "Unknown error.";
120 switch (h_errno) {
121 case HOST_NOT_FOUND:
122 case NO_ADDRESS:
123 error = "Host not found.";
124 break;
125 case NO_RECOVERY:
126 error = "A non-recoverable name server error.";
127 break;
128 case TRY_AGAIN:
129 error = "A temporary error occurred on an authoritative name server.";
130 break;
132 die("gethostbyname: %s\n", error);
135 void server_init(char *address)
137 int port = DEFAULT_PORT;
138 int addrlen;
140 if (strchr(address, '/')) {
141 addr.sa.sa_family = AF_UNIX;
142 strncpy(addr.un.sun_path, address, sizeof(addr.un.sun_path) - 1);
144 addrlen = sizeof(struct sockaddr_un);
145 } else {
146 char *s = strchr(address, ':');
147 struct hostent *hent;
149 if (s) {
150 *s++ = 0;
151 port = atoi(s);
153 hent = gethostbyname(address);
154 if (!hent)
155 gethostbyname_failed();
157 addr.sa.sa_family = hent->h_addrtype;
158 switch (addr.sa.sa_family) {
159 case AF_INET:
160 memcpy(&addr.in.sin_addr, hent->h_addr_list[0], hent->h_length);
161 addr.in.sin_port = htons(port);
163 addrlen = sizeof(addr.in);
164 break;
165 default:
166 die("unsupported address type\n");
170 server_socket = socket(addr.sa.sa_family, SOCK_STREAM, 0);
171 if (server_socket == -1)
172 die_errno("socket");
174 if (bind(server_socket, &addr.sa, addrlen) == -1) {
175 int sock;
177 if (errno != EADDRINUSE)
178 die_errno("bind");
180 /* address already in use */
181 if (addr.sa.sa_family != AF_UNIX)
182 die("cmus is already listening on %s:%d\n", address, port);
184 /* try to connect to server */
185 sock = socket(AF_UNIX, SOCK_STREAM, 0);
186 if (sock == -1)
187 die_errno("socket");
189 if (connect(sock, &addr.sa, addrlen) == -1) {
190 if (errno != ENOENT && errno != ECONNREFUSED)
191 die_errno("connect");
193 /* server not running => dead socket */
195 /* try to remove dead socket */
196 if (unlink(addr.un.sun_path) == -1 && errno != ENOENT)
197 die_errno("unlink");
198 if (bind(server_socket, &addr.sa, addrlen) == -1)
199 die_errno("bind");
200 } else {
201 /* server already running */
202 die("cmus is already listening on socket %s\n", address);
204 close(sock);
207 if (listen(server_socket, MAX_CLIENTS) == -1)
208 die_errno("listen");
211 void server_exit(void)
213 close(server_socket);
214 if (addr.sa.sa_family == AF_UNIX)
215 unlink(addr.un.sun_path);