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.
17 #include <sys/types.h>
19 #include <sys/socket.h>
22 #include <ioncore/../version.h>
23 #include <ioncore/common.h>
24 #include <ioncore/global.h>
25 #include <ioncore/property.h>
26 #include <libmainloop/select.h>
27 #include <libtu/errorlog.h>
28 #include <libextl/extl.h>
30 #include "notionflux.h"
40 static int listenfd
=-1;
41 static char *listenfile
=NULL
;
42 static ExtlFn tostringfn
;
43 static int tmp
[CHUNK
];
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 *data
)
149 struct sockaddr_un from
;
150 socklen_t fromlen
=sizeof(from
);
152 fd
=accept(lfd
, (struct sockaddr
*)&from
, &fromlen
);
160 int fl
=fcntl(fd
, F_GETFL
);
162 fl
=fcntl(fd
, F_SETFL
, fl
|O_NONBLOCK
);
170 /* close socket on exec */ {
171 int fl
=fcntl(fd
, F_GETFD
);
173 fl
=fcntl(fd
, F_SETFD
, fl
|FD_CLOEXEC
);
182 for(i
=0; i
<MAX_SERVED
; i
++){
188 writes(fd
, "Error: busy\n");
193 assert(bufs
[i
].data
==NULL
&& bufs
[i
].ndata
==0);
195 bufs
[i
].data
=ALLOC_N(char, MAX_DATA
);
197 if(bufs
[i
].data
!=NULL
){
198 if(mainloop_register_input_fd(fd
, &(bufs
[i
]), receive_data
)){
204 writes(fd
, "Error: malloc\n");
209 static bool start_listening()
211 struct sockaddr_un addr
;
214 listenfile
=tmpnam(NULL
);
215 if(listenfile
==NULL
){
220 if(strlen(listenfile
)>SOCK_MAX
){
221 warn("Too long socket path");
225 listenfd
=socket(AF_UNIX
, SOCK_STREAM
, 0);
229 if(fchmod(listenfd
, S_IRUSR
|S_IWUSR
)<0)
232 addr
.sun_family
=AF_UNIX
;
233 strcpy(addr
.sun_path
, listenfile
);
236 int fl
=fcntl(listenfd
, F_GETFD
);
238 fl
=fcntl(listenfd
, F_SETFD
, fl
|FD_CLOEXEC
);
243 if(bind(listenfd
, (struct sockaddr
*) &addr
,
244 strlen(addr
.sun_path
)+sizeof(addr
.sun_family
))<0){
248 if(listen(listenfd
, MAX_SERVED
)<0)
251 if(!mainloop_register_input_fd(listenfd
, NULL
, connection_attempt
))
257 warn_err_obj("mod_notionflux listening socket");
264 /*if(listenfile!=NULL){
273 void close_connections()
278 mainloop_unregister_input_fd(listenfd
);
283 if(listenfile
!=NULL
){
289 for(i
=0; i
<MAX_SERVED
; i
++){
291 close_conn(&(bufs
[i
]));
294 extl_unref_fn(tostringfn
);
297 char mod_notionflux_ion_api_version
[]=ION_API_VERSION
;
299 static Atom flux_socket
=None
;
301 bool mod_notionflux_init()
306 for(i
=0; i
<MAX_SERVED
; i
++){
312 if(!extl_loadstring(tostringstr
, &tostringfn
))
315 if(!start_listening()){
316 extl_unref_fn(tostringfn
);
321 flux_socket
=XInternAtom(ioncore_g
.dpy
, "_NOTION_MOD_NOTIONFLUX_SOCKET", False
);
323 FOR_ALL_ROOTWINS(rw
){
324 xwindow_set_string_property(region_xwindow((WRegion
*)rw
), flux_socket
, listenfile
);
331 void mod_notionflux_deinit()
335 if(flux_socket
!=None
){
336 FOR_ALL_ROOTWINS(rw
){
337 XDeleteProperty(ioncore_g
.dpy
, region_xwindow((WRegion
*)rw
), flux_socket
);