2023-04-09 13:54:29 +00:00
# include "../kms_shared.h"
2023-04-07 03:31:46 +00:00
# include <stdio.h>
# include <string.h>
# include <errno.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
# include <sys/socket.h>
# include <sys/un.h>
2023-04-17 21:53:18 +00:00
# include <time.h>
2023-04-07 03:31:46 +00:00
# include <xf86drm.h>
# include <xf86drmMode.h>
2023-10-21 20:46:30 +00:00
# include <drm_mode.h>
2023-04-07 03:31:46 +00:00
2023-05-12 01:49:29 +00:00
# define MAX_CONNECTORS 32
2023-04-07 03:31:46 +00:00
2023-04-10 00:25:43 +00:00
typedef struct {
int drmfd ;
2023-10-08 20:25:07 +00:00
drmModePlaneResPtr planes ;
2023-04-10 00:25:43 +00:00
} gsr_drm ;
2023-05-12 01:49:29 +00:00
typedef struct {
uint32_t connector_id ;
uint64_t crtc_id ;
} connector_crtc_pair ;
typedef struct {
connector_crtc_pair maps [ MAX_CONNECTORS ] ;
int num_maps ;
} connector_to_crtc_map ;
2023-04-07 03:31:46 +00:00
static int max_int ( int a , int b ) {
return a > b ? a : b ;
}
2023-05-12 01:49:29 +00:00
static int send_msg_to_client ( int client_fd , gsr_kms_response * response ) {
2023-04-07 03:31:46 +00:00
struct iovec iov ;
iov . iov_base = response ;
iov . iov_len = sizeof ( * response ) ;
struct msghdr response_message = { 0 } ;
response_message . msg_iov = & iov ;
response_message . msg_iovlen = 1 ;
2023-05-12 01:49:29 +00:00
char cmsgbuf [ CMSG_SPACE ( sizeof ( int ) * max_int ( 1 , response - > num_fds ) ) ] ;
2023-04-07 03:31:46 +00:00
memset ( cmsgbuf , 0 , sizeof ( cmsgbuf ) ) ;
2023-05-12 01:49:29 +00:00
if ( response - > num_fds > 0 ) {
2023-04-07 03:31:46 +00:00
response_message . msg_control = cmsgbuf ;
response_message . msg_controllen = sizeof ( cmsgbuf ) ;
2023-05-12 01:49:29 +00:00
struct cmsghdr * cmsg = CMSG_FIRSTHDR ( & response_message ) ;
cmsg - > cmsg_level = SOL_SOCKET ;
cmsg - > cmsg_type = SCM_RIGHTS ;
cmsg - > cmsg_len = CMSG_LEN ( sizeof ( int ) * response - > num_fds ) ;
int * fds = ( int * ) CMSG_DATA ( cmsg ) ;
for ( int i = 0 ; i < response - > num_fds ; + + i ) {
fds [ i ] = response - > fds [ i ] . fd ;
2023-04-07 03:31:46 +00:00
}
2023-05-12 01:49:29 +00:00
response_message . msg_controllen = cmsg - > cmsg_len ;
2023-04-07 03:31:46 +00:00
}
return sendmsg ( client_fd , & response_message , 0 ) ;
}
2023-11-18 12:55:27 +00:00
static int recv_msg_from_client ( int client_fd , gsr_kms_request * request ) {
struct iovec iov ;
iov . iov_base = request ;
iov . iov_len = sizeof ( * request ) ;
struct msghdr response_message = { 0 } ;
response_message . msg_iov = & iov ;
response_message . msg_iovlen = 1 ;
char cmsgbuf [ CMSG_SPACE ( sizeof ( int ) * 1 ) ] ;
memset ( cmsgbuf , 0 , sizeof ( cmsgbuf ) ) ;
response_message . msg_control = cmsgbuf ;
response_message . msg_controllen = sizeof ( cmsgbuf ) ;
int res = recvmsg ( client_fd , & response_message , MSG_WAITALL ) ;
if ( res < = 0 )
return res ;
if ( request - > new_connection_fd > 0 ) {
struct cmsghdr * cmsg = CMSG_FIRSTHDR ( & response_message ) ;
if ( cmsg ) {
int * fds = ( int * ) CMSG_DATA ( cmsg ) ;
request - > new_connection_fd = fds [ 0 ] ;
} else {
if ( request - > new_connection_fd > 0 ) {
close ( request - > new_connection_fd ) ;
request - > new_connection_fd = 0 ;
}
}
}
return res ;
}
2023-05-12 01:49:29 +00:00
static bool connector_get_property_by_name ( int drmfd , drmModeConnectorPtr props , const char * name , uint64_t * result ) {
for ( int i = 0 ; i < props - > count_props ; + + i ) {
drmModePropertyPtr prop = drmModeGetProperty ( drmfd , props - > props [ i ] ) ;
if ( prop ) {
if ( strcmp ( name , prop - > name ) = = 0 ) {
* result = props - > prop_values [ i ] ;
drmModeFreeProperty ( prop ) ;
return true ;
}
drmModeFreeProperty ( prop ) ;
}
}
return false ;
}
2023-07-22 00:57:38 +00:00
typedef enum {
PLANE_PROPERTY_X = 1 < < 0 ,
PLANE_PROPERTY_Y = 1 < < 1 ,
PLANE_PROPERTY_SRC_X = 1 < < 2 ,
PLANE_PROPERTY_SRC_Y = 1 < < 3 ,
PLANE_PROPERTY_SRC_W = 1 < < 4 ,
PLANE_PROPERTY_SRC_H = 1 < < 5 ,
PLANE_PROPERTY_IS_CURSOR = 1 < < 6 ,
} plane_property_mask ;
/* Returns plane_property_mask */
static uint32_t plane_get_properties ( int drmfd , uint32_t plane_id , bool * is_cursor , int * x , int * y , int * src_x , int * src_y , int * src_w , int * src_h ) {
* is_cursor = false ;
* x = 0 ;
* y = 0 ;
* src_x = 0 ;
* src_y = 0 ;
* src_w = 0 ;
* src_h = 0 ;
plane_property_mask property_mask = 0 ;
2023-05-12 03:03:12 +00:00
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties ( drmfd , plane_id , DRM_MODE_OBJECT_PLANE ) ;
if ( ! props )
return false ;
2023-12-02 23:59:07 +00:00
// TODO: Dont do this every frame
2023-05-12 03:03:12 +00:00
for ( uint32_t i = 0 ; i < props - > count_props ; + + i ) {
drmModePropertyPtr prop = drmModeGetProperty ( drmfd , props - > props [ i ] ) ;
2023-07-18 01:21:16 +00:00
if ( ! prop )
continue ;
2023-07-22 00:57:38 +00:00
// SRC_* values are fixed 16.16 points
2023-07-18 01:21:16 +00:00
const uint32_t type = prop - > flags & ( DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE ) ;
2023-07-22 00:57:38 +00:00
if ( ( type & DRM_MODE_PROP_SIGNED_RANGE ) & & strcmp ( prop - > name , " CRTC_X " ) = = 0 ) {
* x = ( int ) props - > prop_values [ i ] ;
property_mask | = PLANE_PROPERTY_X ;
} else if ( ( type & DRM_MODE_PROP_SIGNED_RANGE ) & & strcmp ( prop - > name , " CRTC_Y " ) = = 0 ) {
* y = ( int ) props - > prop_values [ i ] ;
property_mask | = PLANE_PROPERTY_Y ;
} else if ( ( type & DRM_MODE_PROP_RANGE ) & & strcmp ( prop - > name , " SRC_X " ) = = 0 ) {
* src_x = ( int ) ( props - > prop_values [ i ] > > 16 ) ;
property_mask | = PLANE_PROPERTY_SRC_X ;
} else if ( ( type & DRM_MODE_PROP_RANGE ) & & strcmp ( prop - > name , " SRC_Y " ) = = 0 ) {
* src_y = ( int ) ( props - > prop_values [ i ] > > 16 ) ;
property_mask | = PLANE_PROPERTY_SRC_Y ;
} else if ( ( type & DRM_MODE_PROP_RANGE ) & & strcmp ( prop - > name , " SRC_W " ) = = 0 ) {
* src_w = ( int ) ( props - > prop_values [ i ] > > 16 ) ;
property_mask | = PLANE_PROPERTY_SRC_W ;
} else if ( ( type & DRM_MODE_PROP_RANGE ) & & strcmp ( prop - > name , " SRC_H " ) = = 0 ) {
* src_h = ( int ) ( props - > prop_values [ i ] > > 16 ) ;
property_mask | = PLANE_PROPERTY_SRC_H ;
} else if ( ( type & DRM_MODE_PROP_ENUM ) & & strcmp ( prop - > name , " type " ) = = 0 ) {
2023-07-18 01:21:16 +00:00
const uint64_t current_enum_value = props - > prop_values [ i ] ;
for ( int j = 0 ; j < prop - > count_enums ; + + j ) {
if ( prop - > enums [ j ] . value = = current_enum_value & & strcmp ( prop - > enums [ j ] . name , " Cursor " ) = = 0 ) {
2023-07-22 00:57:38 +00:00
* is_cursor = true ;
property_mask | = PLANE_PROPERTY_IS_CURSOR ;
2023-07-18 01:21:16 +00:00
break ;
2023-05-12 03:03:12 +00:00
}
}
}
2023-07-22 00:57:38 +00:00
2023-07-18 01:21:16 +00:00
drmModeFreeProperty ( prop ) ;
2023-05-12 03:03:12 +00:00
}
drmModeFreeObjectProperties ( props ) ;
2023-07-22 00:57:38 +00:00
return property_mask ;
2023-05-12 03:03:12 +00:00
}
2023-05-12 01:49:29 +00:00
/* Returns 0 if not found */
static uint32_t get_connector_by_crtc_id ( const connector_to_crtc_map * c2crtc_map , uint32_t crtc_id ) {
for ( int i = 0 ; i < c2crtc_map - > num_maps ; + + i ) {
if ( c2crtc_map - > maps [ i ] . crtc_id = = crtc_id )
return c2crtc_map - > maps [ i ] . connector_id ;
}
return 0 ;
}
2023-07-22 18:12:41 +00:00
static void map_crtc_to_connector_ids ( gsr_drm * drm , connector_to_crtc_map * c2crtc_map ) {
c2crtc_map - > num_maps = 0 ;
drmModeResPtr resources = drmModeGetResources ( drm - > drmfd ) ;
if ( ! resources )
return ;
2023-05-12 01:49:29 +00:00
2023-07-22 18:12:41 +00:00
for ( int i = 0 ; i < resources - > count_connectors & & c2crtc_map - > num_maps < MAX_CONNECTORS ; + + i ) {
drmModeConnectorPtr connector = drmModeGetConnectorCurrent ( drm - > drmfd , resources - > connectors [ i ] ) ;
if ( ! connector )
2023-04-07 03:31:46 +00:00
continue ;
2023-06-18 18:48:36 +00:00
2023-07-22 18:12:41 +00:00
uint64_t crtc_id = 0 ;
connector_get_property_by_name ( drm - > drmfd , connector , " CRTC_ID " , & crtc_id ) ;
2023-04-10 00:25:43 +00:00
2023-07-22 18:12:41 +00:00
c2crtc_map - > maps [ c2crtc_map - > num_maps ] . connector_id = connector - > connector_id ;
c2crtc_map - > maps [ c2crtc_map - > num_maps ] . crtc_id = crtc_id ;
+ + c2crtc_map - > num_maps ;
2023-04-10 00:25:43 +00:00
2023-07-22 18:12:41 +00:00
drmModeFreeConnector ( connector ) ;
2023-05-12 01:49:29 +00:00
}
2023-07-22 18:12:41 +00:00
drmModeFreeResources ( resources ) ;
2023-05-12 01:49:29 +00:00
}
2023-10-22 02:56:34 +00:00
static void drm_mode_cleanup_handles ( int drmfd , drmModeFB2Ptr drmfb ) {
for ( int i = 0 ; i < 4 ; + + i ) {
if ( ! drmfb - > handles [ i ] )
continue ;
bool already_closed = false ;
for ( int j = 0 ; j < i ; + + j ) {
if ( drmfb - > handles [ i ] = = drmfb - > handles [ j ] ) {
already_closed = true ;
break ;
}
}
if ( already_closed )
continue ;
drmCloseBufferHandle ( drmfd , drmfb - > handles [ i ] ) ;
}
}
2023-07-22 18:12:41 +00:00
static int kms_get_fb ( gsr_drm * drm , gsr_kms_response * response , connector_to_crtc_map * c2crtc_map ) {
2023-04-10 00:25:43 +00:00
int result = - 1 ;
response - > result = KMS_RESULT_OK ;
2023-05-12 01:49:29 +00:00
response - > err_msg [ 0 ] = ' \0 ' ;
response - > num_fds = 0 ;
2023-04-10 00:25:43 +00:00
2023-10-08 20:25:07 +00:00
for ( uint32_t i = 0 ; i < drm - > planes - > count_planes & & response - > num_fds < GSR_KMS_MAX_PLANES ; + + i ) {
2023-05-12 01:49:29 +00:00
drmModePlanePtr plane = NULL ;
2023-10-22 02:56:34 +00:00
drmModeFB2Ptr drmfb = NULL ;
2023-04-10 00:25:43 +00:00
2023-10-08 20:25:07 +00:00
plane = drmModeGetPlane ( drm - > drmfd , drm - > planes - > planes [ i ] ) ;
2023-05-12 01:49:29 +00:00
if ( ! plane ) {
response - > result = KMS_RESULT_FAILED_TO_GET_PLANE ;
2023-10-08 20:25:07 +00:00
snprintf ( response - > err_msg , sizeof ( response - > err_msg ) , " failed to get drm plane with id %u, error: %s \n " , drm - > planes - > planes [ i ] , strerror ( errno ) ) ;
2023-05-12 01:49:29 +00:00
fprintf ( stderr , " kms server error: %s \n " , response - > err_msg ) ;
goto next ;
}
2023-04-07 03:31:46 +00:00
2023-07-22 00:57:38 +00:00
if ( ! plane - > fb_id )
goto next ;
2023-10-22 02:56:34 +00:00
drmfb = drmModeGetFB2 ( drm - > drmfd , plane - > fb_id ) ;
2023-05-12 01:49:29 +00:00
if ( ! drmfb ) {
// Commented out for now because we get here if the cursor is moved to another monitor and we dont care about the cursor
//response->result = KMS_RESULT_FAILED_TO_GET_PLANE;
//snprintf(response->err_msg, sizeof(response->err_msg), "drmModeGetFB2 failed, error: %s", strerror(errno));
//fprintf(stderr, "kms server error: %s\n", response->err_msg);
goto next ;
}
2023-04-07 03:31:46 +00:00
2023-10-22 02:56:34 +00:00
if ( ! drmfb - > handles [ 0 ] ) {
2023-05-12 01:49:29 +00:00
response - > result = KMS_RESULT_FAILED_TO_GET_PLANE ;
snprintf ( response - > err_msg , sizeof ( response - > err_msg ) , " drmfb handle is NULL " ) ;
fprintf ( stderr , " kms server error: %s \n " , response - > err_msg ) ;
2023-10-22 02:56:34 +00:00
goto cleanup_handles ;
2023-05-12 01:49:29 +00:00
}
2023-04-07 03:31:46 +00:00
2023-05-12 01:49:29 +00:00
// TODO: Check if dimensions have changed by comparing width and height to previous time this was called.
// TODO: Support other plane formats than rgb (with multiple planes, such as direct YUV420 on wayland).
2023-04-10 00:25:43 +00:00
2023-05-12 01:49:29 +00:00
int fb_fd = - 1 ;
2023-10-22 02:56:34 +00:00
const int ret = drmPrimeHandleToFD ( drm - > drmfd , drmfb - > handles [ 0 ] , O_RDONLY , & fb_fd ) ;
2023-05-12 01:49:29 +00:00
if ( ret ! = 0 | | fb_fd = = - 1 ) {
response - > result = KMS_RESULT_FAILED_TO_GET_PLANE ;
snprintf ( response - > err_msg , sizeof ( response - > err_msg ) , " failed to get fd from drm handle, error: %s " , strerror ( errno ) ) ;
fprintf ( stderr , " kms server error: %s \n " , response - > err_msg ) ;
2023-10-22 02:56:34 +00:00
goto cleanup_handles ;
2023-05-12 01:49:29 +00:00
}
2023-07-22 00:57:38 +00:00
bool is_cursor = false ;
int x = 0 , y = 0 , src_x = 0 , src_y = 0 , src_w = 0 , src_h = 0 ;
plane_get_properties ( drm - > drmfd , plane - > plane_id , & is_cursor , & x , & y , & src_x , & src_y , & src_w , & src_h ) ;
2023-05-12 01:49:29 +00:00
response - > fds [ response - > num_fds ] . fd = fb_fd ;
response - > fds [ response - > num_fds ] . width = drmfb - > width ;
response - > fds [ response - > num_fds ] . height = drmfb - > height ;
2023-10-22 02:56:34 +00:00
response - > fds [ response - > num_fds ] . pitch = drmfb - > pitches [ 0 ] ;
response - > fds [ response - > num_fds ] . offset = drmfb - > offsets [ 0 ] ;
2023-10-22 17:45:01 +00:00
response - > fds [ response - > num_fds ] . pixel_format = drmfb - > pixel_format ;
response - > fds [ response - > num_fds ] . modifier = drmfb - > modifier ;
2023-07-22 18:12:41 +00:00
response - > fds [ response - > num_fds ] . connector_id = get_connector_by_crtc_id ( c2crtc_map , plane - > crtc_id ) ;
2023-07-22 00:57:38 +00:00
response - > fds [ response - > num_fds ] . is_cursor = is_cursor ;
2023-10-21 20:46:30 +00:00
response - > fds [ response - > num_fds ] . is_combined_plane = false ;
2023-07-22 02:12:02 +00:00
if ( is_cursor ) {
2023-07-22 00:57:38 +00:00
response - > fds [ response - > num_fds ] . x = x ;
response - > fds [ response - > num_fds ] . y = y ;
response - > fds [ response - > num_fds ] . src_w = 0 ;
response - > fds [ response - > num_fds ] . src_h = 0 ;
} else {
response - > fds [ response - > num_fds ] . x = src_x ;
response - > fds [ response - > num_fds ] . y = src_y ;
response - > fds [ response - > num_fds ] . src_w = src_w ;
response - > fds [ response - > num_fds ] . src_h = src_h ;
}
2023-05-12 01:49:29 +00:00
+ + response - > num_fds ;
2023-10-22 02:56:34 +00:00
cleanup_handles :
drm_mode_cleanup_handles ( drm - > drmfd , drmfb ) ;
2023-05-12 01:49:29 +00:00
next :
if ( drmfb )
2023-10-22 02:56:34 +00:00
drmModeFreeFB2 ( drmfb ) ;
2023-05-12 01:49:29 +00:00
if ( plane )
drmModeFreePlane ( plane ) ;
}
2023-10-22 02:56:34 +00:00
if ( response - > num_fds > 0 )
response - > result = KMS_RESULT_OK ;
2023-10-21 20:46:30 +00:00
if ( response - > result = = KMS_RESULT_OK ) {
2023-05-12 01:49:29 +00:00
result = 0 ;
} else {
for ( int i = 0 ; i < response - > num_fds ; + + i ) {
close ( response - > fds [ i ] . fd ) ;
}
response - > num_fds = 0 ;
}
2023-04-10 00:25:43 +00:00
return result ;
2023-04-07 03:31:46 +00:00
}
2023-04-17 21:53:18 +00:00
static double clock_get_monotonic_seconds ( void ) {
struct timespec ts ;
ts . tv_sec = 0 ;
ts . tv_nsec = 0 ;
clock_gettime ( CLOCK_MONOTONIC , & ts ) ;
return ( double ) ts . tv_sec + ( double ) ts . tv_nsec * 0.000000001 ;
}
2023-05-17 16:49:16 +00:00
static void strncpy_safe ( char * dst , const char * src , int len ) {
int src_len = strlen ( src ) ;
int min_len = src_len ;
if ( len - 1 < min_len )
min_len = len - 1 ;
memcpy ( dst , src , min_len ) ;
dst [ min_len ] = ' \0 ' ;
}
2023-04-07 03:31:46 +00:00
int main ( int argc , char * * argv ) {
2023-10-08 20:25:07 +00:00
int res = 0 ;
int socket_fd = 0 ;
gsr_drm drm ;
drm . drmfd = 0 ;
drm . planes = NULL ;
2023-04-10 00:25:43 +00:00
if ( argc ! = 3 ) {
2023-07-17 20:27:14 +00:00
fprintf ( stderr , " usage: gsr-kms-server <domain_socket_path> <card_path> \n " ) ;
2023-04-07 03:31:46 +00:00
return 1 ;
}
const char * domain_socket_path = argv [ 1 ] ;
2023-10-08 20:25:07 +00:00
socket_fd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
2023-04-07 03:31:46 +00:00
if ( socket_fd = = - 1 ) {
fprintf ( stderr , " kms server error: failed to create socket, error: %s \n " , strerror ( errno ) ) ;
return 2 ;
}
2023-04-10 00:25:43 +00:00
const char * card_path = argv [ 2 ] ;
drm . drmfd = open ( card_path , O_RDONLY ) ;
if ( drm . drmfd < 0 ) {
fprintf ( stderr , " kms server error: failed to open %s, error: %s " , card_path , strerror ( errno ) ) ;
2023-10-08 20:25:07 +00:00
res = 2 ;
goto done ;
2023-04-10 00:25:43 +00:00
}
2023-07-22 18:12:41 +00:00
if ( drmSetClientCap ( drm . drmfd , DRM_CLIENT_CAP_UNIVERSAL_PLANES , 1 ) ! = 0 ) {
fprintf ( stderr , " kms server error: drmSetClientCap DRM_CLIENT_CAP_UNIVERSAL_PLANES failed, error: %s \n " , strerror ( errno ) ) ;
2023-10-08 20:25:07 +00:00
res = 2 ;
goto done ;
2023-04-10 00:25:43 +00:00
}
2023-07-22 18:12:41 +00:00
if ( drmSetClientCap ( drm . drmfd , DRM_CLIENT_CAP_ATOMIC , 1 ) ! = 0 ) {
fprintf ( stderr , " kms server warning: drmSetClientCap DRM_CLIENT_CAP_ATOMIC failed, error: %s. The wrong monitor may be captured as a result \n " , strerror ( errno ) ) ;
}
2023-10-08 20:25:07 +00:00
drm . planes = drmModeGetPlaneResources ( drm . drmfd ) ;
if ( ! drm . planes ) {
fprintf ( stderr , " kms server error: failed to get plane resources, error: %s \n " , strerror ( errno ) ) ;
res = 2 ;
goto done ;
}
2023-07-22 18:12:41 +00:00
connector_to_crtc_map c2crtc_map ;
c2crtc_map . num_maps = 0 ;
map_crtc_to_connector_ids ( & drm , & c2crtc_map ) ;
2023-04-10 00:25:43 +00:00
fprintf ( stderr , " kms server info: connecting to the client \n " ) ;
2023-04-17 21:53:18 +00:00
bool connected = false ;
const double connect_timeout_sec = 5.0 ;
const double start_time = clock_get_monotonic_seconds ( ) ;
while ( clock_get_monotonic_seconds ( ) - start_time < connect_timeout_sec ) {
2023-04-07 03:31:46 +00:00
struct sockaddr_un remote_addr = { 0 } ;
remote_addr . sun_family = AF_UNIX ;
2023-05-17 16:49:16 +00:00
strncpy_safe ( remote_addr . sun_path , domain_socket_path , sizeof ( remote_addr . sun_path ) ) ;
2023-04-07 03:31:46 +00:00
// TODO: Check if parent disconnected
if ( connect ( socket_fd , ( struct sockaddr * ) & remote_addr , sizeof ( remote_addr . sun_family ) + strlen ( remote_addr . sun_path ) ) = = - 1 ) {
2023-04-17 21:53:18 +00:00
if ( errno = = ECONNREFUSED | | errno = = ENOENT ) {
goto next ;
} else if ( errno = = EISCONN ) {
connected = true ;
2023-04-07 03:31:46 +00:00
break ;
2023-04-17 21:53:18 +00:00
}
2023-04-10 00:25:43 +00:00
2023-04-07 03:31:46 +00:00
fprintf ( stderr , " kms server error: connect failed, error: %s (%d) \n " , strerror ( errno ) , errno ) ;
2023-10-08 20:25:07 +00:00
res = 2 ;
goto done ;
2023-04-07 03:31:46 +00:00
}
2023-04-17 21:53:18 +00:00
next :
usleep ( 30 * 1000 ) ; // 30 milliseconds
}
if ( connected ) {
fprintf ( stderr , " kms server info: connected to the client \n " ) ;
} else {
fprintf ( stderr , " kms server error: failed to connect to the client in %f seconds \n " , connect_timeout_sec ) ;
2023-10-08 20:25:07 +00:00
res = 2 ;
goto done ;
2023-04-07 03:31:46 +00:00
}
for ( ; ; ) {
gsr_kms_request request ;
2023-11-12 09:55:02 +00:00
request . version = 0 ;
request . type = - 1 ;
2023-11-18 12:55:27 +00:00
request . new_connection_fd = 0 ;
const int recv_res = recv_msg_from_client ( socket_fd , & request ) ;
2023-04-07 03:31:46 +00:00
if ( recv_res = = 0 ) {
fprintf ( stderr , " kms server info: kms client shutdown, shutting down the server \n " ) ;
res = 3 ;
goto done ;
} else if ( recv_res = = - 1 ) {
const int err = errno ;
fprintf ( stderr , " kms server error: failed to read all data in client request (error: %s), ignoring \n " , strerror ( err ) ) ;
if ( err = = EBADF ) {
fprintf ( stderr , " kms server error: invalid client fd, shutting down the server \n " ) ;
res = 3 ;
goto done ;
}
continue ;
}
2023-11-12 09:55:02 +00:00
if ( request . version ! = GSR_KMS_PROTOCOL_VERSION ) {
fprintf ( stderr , " kms server error: expected gpu screen recorder protocol version to be %u, but it's %u \n " , GSR_KMS_PROTOCOL_VERSION , request . version ) ;
/*
if ( request . new_connection_fd > 0 )
close ( request . new_connection_fd ) ;
*/
continue ;
}
2023-04-07 03:31:46 +00:00
switch ( request . type ) {
2023-11-12 09:55:02 +00:00
case KMS_REQUEST_TYPE_REPLACE_CONNECTION : {
gsr_kms_response response ;
response . version = GSR_KMS_PROTOCOL_VERSION ;
response . num_fds = 0 ;
if ( request . new_connection_fd > 0 ) {
if ( socket_fd > 0 )
close ( socket_fd ) ;
socket_fd = request . new_connection_fd ;
response . result = KMS_RESULT_OK ;
if ( send_msg_to_client ( socket_fd , & response ) = = - 1 )
fprintf ( stderr , " kms server error: failed to respond to client KMS_REQUEST_TYPE_REPLACE_CONNECTION request \n " ) ;
} else {
response . result = KMS_RESULT_INVALID_REQUEST ;
snprintf ( response . err_msg , sizeof ( response . err_msg ) , " received invalid connection fd " ) ;
fprintf ( stderr , " kms server error: %s \n " , response . err_msg ) ;
if ( send_msg_to_client ( socket_fd , & response ) = = - 1 )
fprintf ( stderr , " kms server error: failed to respond to client request \n " ) ;
}
break ;
}
2023-04-07 03:31:46 +00:00
case KMS_REQUEST_TYPE_GET_KMS : {
gsr_kms_response response ;
2023-11-12 09:55:02 +00:00
response . version = GSR_KMS_PROTOCOL_VERSION ;
2023-10-21 20:46:30 +00:00
response . num_fds = 0 ;
2023-04-10 00:25:43 +00:00
2023-07-22 18:12:41 +00:00
if ( kms_get_fb ( & drm , & response , & c2crtc_map ) = = 0 ) {
2023-05-12 01:49:29 +00:00
if ( send_msg_to_client ( socket_fd , & response ) = = - 1 )
2023-04-10 00:25:43 +00:00
fprintf ( stderr , " kms server error: failed to respond to client KMS_REQUEST_TYPE_GET_KMS request \n " ) ;
} else {
2023-05-12 01:49:29 +00:00
if ( send_msg_to_client ( socket_fd , & response ) = = - 1 )
2023-04-10 00:25:43 +00:00
fprintf ( stderr , " kms server error: failed to respond to client KMS_REQUEST_TYPE_GET_KMS request \n " ) ;
2023-04-07 03:31:46 +00:00
}
2023-10-21 20:46:30 +00:00
for ( int i = 0 ; i < response . num_fds ; + + i ) {
close ( response . fds [ i ] . fd ) ;
}
2023-04-07 03:31:46 +00:00
break ;
}
default : {
gsr_kms_response response ;
2023-11-12 09:55:02 +00:00
response . version = GSR_KMS_PROTOCOL_VERSION ;
2023-04-07 03:31:46 +00:00
response . result = KMS_RESULT_INVALID_REQUEST ;
2023-11-12 09:55:02 +00:00
response . num_fds = 0 ;
2023-05-12 01:49:29 +00:00
snprintf ( response . err_msg , sizeof ( response . err_msg ) , " invalid request type %d, expected %d (%s) " , request . type , KMS_REQUEST_TYPE_GET_KMS , " KMS_REQUEST_TYPE_GET_KMS " ) ;
fprintf ( stderr , " kms server error: %s \n " , response . err_msg ) ;
2023-11-12 09:55:02 +00:00
if ( send_msg_to_client ( socket_fd , & response ) = = - 1 )
2023-04-07 03:31:46 +00:00
fprintf ( stderr , " kms server error: failed to respond to client request \n " ) ;
2023-11-12 09:55:02 +00:00
2023-04-07 03:31:46 +00:00
break ;
}
}
}
done :
2023-10-08 20:25:07 +00:00
if ( drm . planes )
drmModeFreePlaneResources ( drm . planes ) ;
if ( drm . drmfd > 0 )
close ( drm . drmfd ) ;
if ( socket_fd > 0 )
close ( socket_fd ) ;
2023-04-07 03:31:46 +00:00
return res ;
}