Exclude error code 477 which is sent by Freenode for some reason.
[vomak.git] / socket.c
blob16f90123c92ba2431474e16eec5396120fc5bd94
1 /*
2 * socket.c - - this file is part of vomak - a very simple IRC bot
4 * Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <string.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <netinet/in.h>
28 #include <glib.h>
29 #include <glib/gstdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <fcntl.h>
34 #include "socket.h"
36 #define SockDesc gint
37 #define SOCKET_IS_VALID(s) ((s) >= 0)
38 #define INVALID_SOCKET (-1)
41 /* (Unix domain) socket (taken from Geany, originally taken from Sylpheed, thanks) */
44 static gint socket_fd_open_unix (const gchar *path);
45 static gint socket_fd_check_io (gint fd, GIOCondition cond);
46 static gint socket_fd_read (gint sock, gchar *buf, gint len);
47 static gint socket_fd_recv (gint fd, gchar *buf, gint len, gint flags);
48 static gint socket_fd_connect_unix (const gchar *path);
52 static void remove_socket_link_full(socket_info_t *si)
54 g_unlink(si->file_name);
58 void socket_init(socket_info_t *si, const gchar *filename)
60 gint sock;
62 if (si->file_name == NULL)
63 si->file_name = g_strdup(filename);
65 sock = socket_fd_connect_unix(si->file_name);
66 if (sock < 0)
68 remove_socket_link_full(si); /* deletes the socket file and the symlink */
69 si->lock_socket = socket_fd_open_unix(si->file_name);
71 else
73 si->lock_socket = sock;
78 gint socket_finalize(socket_info_t *si)
80 if (si->lock_socket < 0) return -1;
82 if (si->lock_socket_tag > 0)
83 g_source_remove(si->lock_socket_tag);
84 if (si->read_ioc)
86 g_io_channel_shutdown(si->read_ioc, FALSE, NULL);
87 g_io_channel_unref(si->read_ioc);
88 si->read_ioc = NULL;
91 if (si->file_name != NULL)
93 remove_socket_link_full(si); /* deletes the socket file and the symlink */
94 g_free(si->file_name);
97 return 0;
101 static gint socket_fd_connect_unix(const gchar *path)
103 gint sock;
104 struct sockaddr_un addr;
106 sock = socket(PF_UNIX, SOCK_STREAM, 0);
107 if (sock < 0)
109 perror("socket_fd_connect_unix(): socket");
110 return -1;
113 memset(&addr, 0, sizeof(addr));
114 addr.sun_family = AF_UNIX;
115 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
117 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
119 socket_fd_close(sock);
120 return -1;
123 return sock;
127 static gint socket_fd_open_unix(const gchar *path)
129 gint sock;
130 struct sockaddr_un addr;
131 gint val;
133 sock = socket(PF_UNIX, SOCK_STREAM, 0);
135 if (sock < 0)
137 perror("sock_open_unix(): socket");
138 return -1;
141 val = 1;
142 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
144 perror("setsockopt");
145 socket_fd_close(sock);
146 return -1;
149 memset(&addr, 0, sizeof(addr));
150 addr.sun_family = AF_UNIX;
151 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
153 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
155 perror("bind");
156 socket_fd_close(sock);
157 return -1;
160 if (listen(sock, 1) < 0)
162 perror("listen");
163 socket_fd_close(sock);
164 return -1;
167 return sock;
171 gint socket_fd_close(gint fd)
173 if (fd != -1)
174 return close(fd);
175 else
176 return 0;
180 gint socket_fd_gets(gint fd, gchar *buf, gint len)
182 gchar *newline, *bp = buf;
183 gint n;
185 if (--len < 1)
186 return -1;
189 if ((n = socket_fd_recv(fd, bp, len, MSG_PEEK)) <= 0)
190 return -1;
191 if ((newline = memchr(bp, '\n', n)) != NULL)
192 n = newline - bp + 1;
193 if ((n = socket_fd_read(fd, bp, n)) < 0)
194 return -1;
195 bp += n;
196 len -= n;
197 } while (! newline && len);
199 *bp = '\0';
200 return bp - buf;
204 static gint socket_fd_recv(gint fd, gchar *buf, gint len, gint flags)
206 if (socket_fd_check_io(fd, G_IO_IN) < 0)
207 return -1;
209 return recv(fd, buf, len, flags);
213 static gint socket_fd_read(gint fd, gchar *buf, gint len)
215 if (socket_fd_check_io(fd, G_IO_IN) < 0)
216 return -1;
218 return read(fd, buf, len);
222 static gint socket_fd_check_io(gint fd, GIOCondition cond)
224 struct timeval timeout;
225 fd_set fds;
226 gint flags;
228 /// FIXME
229 return 0;
231 timeout.tv_sec = 60;
232 timeout.tv_usec = 0;
234 /* checking for non-blocking mode */
235 flags = fcntl(fd, F_GETFL, 0);
236 if (flags < 0)
238 perror("fcntl");
239 return 0;
242 if ((flags & O_NONBLOCK) != 0)
243 return 0;
245 FD_ZERO(&fds);
246 FD_SET(fd, &fds);
248 if (cond == G_IO_IN)
250 select(fd + 1, &fds, NULL, NULL, &timeout);
252 else
254 select(fd + 1, NULL, &fds, NULL, &timeout);
257 if (FD_ISSET(fd, &fds))
259 return 0;
261 else
263 g_print("Socket IO timeout\n");
264 return -1;