summaryrefslogtreecommitdiff
path: root/lib/comm.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/comm.c')
-rw-r--r--lib/comm.c299
1 files changed, 299 insertions, 0 deletions
diff --git a/lib/comm.c b/lib/comm.c
new file mode 100644
index 0000000..0ddc349
--- /dev/null
+++ b/lib/comm.c
@@ -0,0 +1,299 @@
+#include "comm.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "comm_internal.h"
+
+static void getDisplay( char* ret, int max )
+ {
+ char hostname[ 256 ];
+ const char* disp = getenv( "DISPLAY" );
+ char* pos;
+ *ret = '\0';
+ if( disp == NULL )
+ disp = ":0";
+ if( *disp == ':' )
+ {
+ gethostname( ret, max );
+ hostname[ max - 1 ] = '\0';
+ }
+ strncat( ret, disp, max - 1 );
+ pos = strrchr( ret, '.' ); /* strip head */
+ if( pos != NULL && pos > strrchr( ret, ':' ))
+ *pos = '\0';
+ }
+
+static void socketName( char* name, int max )
+ {
+ const char* home;
+ char display[ 256 ];
+ home = getenv( "HOME" );
+ getDisplay( display, 255 );
+ snprintf( name, max - 1, "%s/.dapi-%s", home, display );
+ }
+
+DapiConnection* dapi_connect()
+ {
+ char sock_file[ 256 ];
+ int sock;
+ struct sockaddr_un addr;
+ DapiConnection* ret;
+ socketName( sock_file, 255 );
+ sock = socket( PF_UNIX, SOCK_STREAM, 0 );
+ if( sock < 0 )
+ {
+ perror( "socket" );
+ return NULL;
+ }
+ addr.sun_family = AF_UNIX;
+ strcpy( addr.sun_path, sock_file );
+ if( connect( sock, ( struct sockaddr* ) &addr, sizeof( addr )) < 0 )
+ {
+ perror( "connect" );
+ close( sock );
+ return NULL;
+ }
+ ret = malloc( sizeof( DapiConnection ));
+ if( ret != NULL )
+ {
+ ret->sock = sock;
+ ret->sync_callback = NULL;
+ ret->in_server = 0;
+ ret->last_seq = 0;
+ }
+ return ret;
+ }
+
+int dapi_bindSocket()
+ {
+ char sock_file[ 256 ];
+ int sock;
+ struct sockaddr_un addr;
+ socketName( sock_file, 255 );
+ sock = socket( PF_UNIX, SOCK_STREAM, 0 );
+ if( sock < 0 )
+ {
+ perror( "socket" );
+ return -1;
+ }
+ int opt = fcntl( sock, F_GETFL );
+ if( opt < 0 )
+ {
+ perror( "fcntl" );
+ close( sock );
+ return -1;
+ }
+ if( fcntl( sock, F_SETFL, opt | O_NONBLOCK ) < 0 )
+ {
+ perror( "nonblock" );
+ close( sock );
+ return -1;
+ }
+ unlink( sock_file );
+ addr.sun_family = AF_UNIX;
+ strcpy( addr.sun_path, sock_file );
+ if( bind( sock, ( struct sockaddr* ) &addr, sizeof( addr )) < 0 )
+ {
+ perror( "bind" );
+ close( sock );
+ return -1;
+ }
+ if( chmod( sock_file, 0600 ) != 0 )
+ {
+ perror( "chmod" );
+ close( sock );
+ return -1;
+ }
+ if( listen( sock, SOMAXCONN ) < 0 )
+ {
+ perror( "listen" );
+ close( sock );
+ return -1;
+ }
+ return sock;
+ }
+
+int dapi_socket( DapiConnection* conn )
+ {
+ return conn->sock;
+ }
+
+static int writeSocket( DapiConnection* conn, const char* data, int size )
+ {
+ int written = 0;
+ for(;;)
+ {
+ int len = write( conn->sock, data + written, size - written );
+ if( len < 0 && errno != EINTR && errno != EAGAIN )
+ return -1;
+ if( len > 0 )
+ written += len;
+ if( written == size )
+ return 1;
+ }
+ }
+
+static int readSocket( DapiConnection* conn, char* data, int size )
+ {
+ int rd = 0;
+ for(;;)
+ {
+ int len = read( conn->sock, data + rd, size - rd );
+ if( len < 0 && errno != EINTR && errno != EAGAIN )
+ return -1;
+ if( len == 0 )
+ return 0;
+ if( len > 0 )
+ rd += len;
+ if( rd == size )
+ return 1;
+ }
+ }
+
+DapiConnection* dapi_acceptSocket( int sock )
+ {
+ struct sockaddr_un addr;
+ DapiConnection* ret = NULL;
+ socklen_t addr_len = sizeof( addr );
+ int sock2 = accept( sock, ( struct sockaddr* ) &addr, &addr_len );
+ if( sock2 > 0 )
+ {
+ ret = malloc( sizeof( DapiConnection ));
+ if( ret != NULL )
+ {
+ ret->sock = sock2;
+ ret->sync_callback = NULL;
+ ret->in_server = 1;
+ ret->last_seq = 0;
+ }
+ else
+ close( sock2 );
+ }
+ return ret;
+ }
+
+void dapi_close( DapiConnection* conn )
+ {
+ close( conn->sock );
+ }
+
+static int getNextSeq( DapiConnection* conn )
+ {
+ return ++conn->last_seq;
+ }
+
+static char* readString( DapiConnection* conn, int len )
+ {
+ char* ret = malloc( len + 1 );
+ if( ret == NULL )
+ return NULL;
+ if( readSocket( conn, ret, len + 1 ) > 0 )
+ {
+ ret[ len ] = '\0';
+ return ret;
+ }
+ free( ret );
+ return NULL;
+ }
+
+static void writeString( DapiConnection* conn, const char* str )
+ {
+ if( str == NULL )
+ {
+ char c = '\0';
+ writeSocket( conn, &c, 1 );
+ return;
+ }
+ writeSocket( conn, str, strlen( str ) + 1 );
+ }
+
+static int stringSize( const char** strs )
+ {
+ int cnt = 0;
+ if( strs == NULL || *strs == NULL )
+ return 0;
+ for(;
+ *strs != NULL;
+ ++strs )
+ cnt += strlen( *strs ) + 1;
+ return cnt;
+ }
+
+static char** readStringList( DapiConnection* conn, int len )
+ {
+ char* buf;
+ char** ret;
+ int cnt;
+ int i;
+ int pos;
+ int set;
+ if( len == 0 )
+ {
+ ret = malloc( sizeof( char* ));
+ if( ret == NULL )
+ return NULL;
+ *ret = NULL;
+ return ret;
+ }
+ buf = malloc( len );
+ if( buf == NULL )
+ return NULL;
+ if( readSocket( conn, buf, len ) <= 0 )
+ {
+ free( buf );
+ return NULL;
+ }
+ cnt = 1; /* extra for terminating NULL */
+ for( i = 0;
+ i < len;
+ ++i )
+ if( buf[ i ] == '\0' )
+ ++cnt;
+ if( cnt == 0 )
+ {
+ free( buf );
+ return NULL;
+ }
+ ret = malloc( sizeof( char* ) * cnt + len );
+ if( ret == NULL )
+ {
+ free( buf );
+ return NULL;
+ }
+ memcpy( ret + cnt, buf, len ); /* place string data right after the pointers */
+ free( buf );
+ buf = ( char* )( ret + cnt );
+ pos = 0;
+ set = 1;
+ for( i = 0;
+ i < len;
+ ++i )
+ {
+ if( set )
+ ret[ pos++ ] = buf + i;
+ set = buf[ i ] == '\0';
+ }
+ ret[ pos ] = NULL; /* terminating NULL */
+ return ret;
+ }
+
+static void writeStringList( DapiConnection* conn, const char** strs )
+ {
+ if( strs == NULL || *strs == NULL )
+ return;
+ for(;
+ *strs != NULL;
+ ++strs )
+ writeSocket( conn, *strs, strlen( *strs ) + 1 );
+ }
+
+#include "../kde/gen/comm_generated.c"