2 * mod_notionflux/mod_notionflux/mod_notionflux.c
4 * Copyright (c) Tuomo Valkonen 2004-2005.
6 * This is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
18 #include <sys/types.h>
20 #include <sys/socket.h>
23 #include <ioncore/../version.h>
24 #include <ioncore/common.h>
25 #include <ioncore/global.h>
26 #include <ioncore/property.h>
27 #include <libmainloop/select.h>
28 #include <libtu/errorlog.h>
29 #include <libextl/extl.h>
31 #include "notionflux.h"
41 static int listenfd
=-1;
42 static char *listenfile
=NULL
;
43 static ExtlFn tostringfn
;
46 /* Without the 'or nil' kludge tostring may have no parameters. */
47 static const char tostringstr
[]=
49 "local callable=arg[1]\n"
50 "local result=callable()\n"
51 "if type(result)=='string' then\n"
52 " return string.format('%q', result)\n"
54 " return tostring(result)\n"
57 static void writes(int fd
, const char *s
)
60 write(fd
, s
, strlen(s
));
64 static void close_conn(Buf
*buf
)
69 mainloop_unregister_input_fd(buf
->fd
);
81 static void receive_data(int fd
, void *buf_
)
90 n
=read(fd
, buf
->data
+buf
->ndata
, MAX_DATA
-buf
->ndata
);
93 warn("Connection closed prematurely.");
99 if(errno
!=EAGAIN
&& errno
!=EINTR
){
100 writes(fd
, "Error: I/O");
107 if(buf
->data
[buf
->ndata
+i
]=='\0')
113 if(!end
&& buf
->ndata
+n
==MAX_DATA
){
114 writes(fd
, "Error: too much data\n");
123 if(extl_loadstring(buf
->data
, &fn
)){
125 if(extl_call(tostringfn
, "f", "s", fn
, &retstr
)){
135 if(el
.msgs
!=NULL
&& !success
){
139 errorlog_deinit(&el
);
145 static void connection_attempt(int lfd
, void *UNUSED(data
))
148 struct sockaddr_un from
;
149 socklen_t fromlen
=sizeof(from
);
151 fd
=accept(lfd
, (struct sockaddr
*)&from
, &fromlen
);
159 int fl
=fcntl(fd
, F_GETFL
);
161 fl
=fcntl(fd
, F_SETFL
, fl
|O_NONBLOCK
);
169 /* close socket on exec */ {
170 int fl
=fcntl(fd
, F_GETFD
);
172 fl
=fcntl(fd
, F_SETFD
, fl
|FD_CLOEXEC
);
181 for(i
=0; i
<MAX_SERVED
; i
++){
187 writes(fd
, "Error: busy\n");
192 assert(bufs
[i
].data
==NULL
&& bufs
[i
].ndata
==0);
194 bufs
[i
].data
=ALLOC_N(char, MAX_DATA
);
196 if(bufs
[i
].data
!=NULL
){
197 if(mainloop_register_input_fd(fd
, &(bufs
[i
]), receive_data
)){
203 writes(fd
, "Error: malloc\n");
208 static bool start_listening()
210 struct sockaddr_un addr
;
212 listenfile
=tmpnam(NULL
);
213 if(listenfile
==NULL
){
218 if(strlen(listenfile
)>SOCK_MAX
){
219 warn("Too long socket path");
223 listenfd
=socket(AF_UNIX
, SOCK_STREAM
, 0);
227 if(fchmod(listenfd
, S_IRUSR
|S_IWUSR
)<0)
230 addr
.sun_family
=AF_UNIX
;
231 strcpy(addr
.sun_path
, listenfile
);
234 int fl
=fcntl(listenfd
, F_GETFD
);
236 fl
=fcntl(listenfd
, F_SETFD
, fl
|FD_CLOEXEC
);
241 if(bind(listenfd
, (struct sockaddr
*) &addr
,
242 strlen(addr
.sun_path
)+sizeof(addr
.sun_family
))<0){
246 if(listen(listenfd
, MAX_SERVED
)<0)
249 if(!mainloop_register_input_fd(listenfd
, NULL
, connection_attempt
))
255 warn_err_obj("mod_notionflux listening socket");
262 /*if(listenfile!=NULL){
271 void close_connections()
276 mainloop_unregister_input_fd(listenfd
);
281 if(listenfile
!=NULL
){
287 for(i
=0; i
<MAX_SERVED
; i
++){
289 close_conn(&(bufs
[i
]));
292 extl_unref_fn(tostringfn
);
295 char mod_notionflux_ion_api_version
[]=ION_API_VERSION
;
297 static Atom flux_socket
=None
;
299 bool mod_notionflux_init()
304 for(i
=0; i
<MAX_SERVED
; i
++){
310 if(!extl_loadstring(tostringstr
, &tostringfn
))
313 if(!start_listening()){
314 extl_unref_fn(tostringfn
);
319 flux_socket
=XInternAtom(ioncore_g
.dpy
, "_NOTION_MOD_NOTIONFLUX_SOCKET", False
);
321 FOR_ALL_ROOTWINS(rw
){
322 xwindow_set_string_property(region_xwindow((WRegion
*)rw
), flux_socket
, listenfile
);
329 void mod_notionflux_deinit()
333 if(flux_socket
!=None
){
334 FOR_ALL_ROOTWINS(rw
){
335 XDeleteProperty(ioncore_g
.dpy
, region_xwindow((WRegion
*)rw
), flux_socket
);