@@ -190,6 +190,7 @@ static const char *const onoff_atom = ATOM_STR("\x5", "onoff");
190190static const char * const port_atom = ATOM_STR ("\x4" , "port" );
191191static const char * const rcvbuf_atom = ATOM_STR ("\x6" , "rcvbuf" );
192192static const char * const reuseaddr_atom = ATOM_STR ("\x9" , "reuseaddr" );
193+ static const char * const type_atom = ATOM_STR ("\x4" , "type" );
193194
194195#define CLOSED_FD 0
195196
@@ -1064,6 +1065,95 @@ static term nif_socket_select_stop(Context *ctx, int argc, term argv[])
10641065 return OK_ATOM ;
10651066}
10661067
1068+ //
1069+ // getopt
1070+ //
1071+
1072+ static term nif_socket_getopt (Context * ctx , int argc , term argv [])
1073+ {
1074+ TRACE ("nif_socket_getopt\n" );
1075+ UNUSED (argc );
1076+
1077+ VALIDATE_VALUE (argv [0 ], term_is_otp_socket );
1078+
1079+ GlobalContext * global = ctx -> global ;
1080+
1081+ struct SocketResource * rsrc_obj ;
1082+ if (UNLIKELY (!term_to_otp_socket (argv [0 ], & rsrc_obj , ctx ))) {
1083+ RAISE_ERROR (BADARG_ATOM );
1084+ }
1085+
1086+ SMP_RWLOCK_RDLOCK (rsrc_obj -> socket_lock );
1087+
1088+ #if OTP_SOCKET_BSD
1089+ if (rsrc_obj -> fd == 0 ) {
1090+ #elif OTP_SOCKET_LWIP
1091+ if (rsrc_obj -> socket_state == SocketStateClosed ) {
1092+ #endif
1093+ SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1094+ return make_error_tuple (CLOSED_ATOM , ctx );
1095+ }
1096+ term level_tuple = argv [1 ];
1097+
1098+ term level = term_get_tuple_element (level_tuple , 0 );
1099+ int level_val = interop_atom_term_select_int (otp_socket_setopt_level_table , level , global );
1100+ switch (level_val ) {
1101+ case OtpSocketSetoptLevelSocket : {
1102+ term opt = term_get_tuple_element (level_tuple , 1 );
1103+ if (globalcontext_is_term_equal_to_atom_string (global , opt , type_atom )) {
1104+ enum inet_type type ;
1105+ #if OTP_SOCKET_BSD
1106+ int option_value ;
1107+ socklen_t option_len = sizeof (option_value );
1108+ int res = getsockopt (rsrc_obj -> fd , SOL_SOCKET , SO_TYPE , & option_value , & option_len );
1109+ if (UNLIKELY (res != 0 )) {
1110+ SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1111+ return make_errno_tuple (ctx );
1112+ } else {
1113+ switch (option_value ) {
1114+ case SOCK_STREAM :
1115+ type = InetStreamType ;
1116+ break ;
1117+ case SOCK_DGRAM :
1118+ type = InetDgramType ;
1119+ break ;
1120+ default :
1121+ SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1122+ RAISE_ERROR (BADARG_ATOM );
1123+ }
1124+ }
1125+ #elif OTP_SOCKET_LWIP
1126+ LWIP_BEGIN ();
1127+ if (rsrc_obj -> socket_state & SocketStateTCP ) {
1128+ type = InetStreamType ;
1129+ } else {
1130+ type = InetDgramType ;
1131+ }
1132+ LWIP_END ();
1133+ #endif
1134+ if (UNLIKELY (memory_ensure_free_with_roots (ctx , TUPLE_SIZE (2 ), 1 , argv , MEMORY_CAN_SHRINK ) != MEMORY_GC_OK )) {
1135+ AVM_LOGW (TAG , "Failed to allocate memory: %s:%i." , __FILE__ , __LINE__ );
1136+ SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1137+ RAISE_ERROR (OUT_OF_MEMORY_ATOM );
1138+ }
1139+ term result = term_alloc_tuple (2 , & ctx -> heap );
1140+ term_put_tuple_element (result , 0 , OK_ATOM );
1141+ term_put_tuple_element (result , 1 , inet_type_to_atom (type , global ));
1142+ SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1143+ return result ;
1144+ } else {
1145+ SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1146+ RAISE_ERROR (BADARG_ATOM );
1147+ }
1148+ }
1149+ default : {
1150+ AVM_LOGE (TAG , "socket:getopt: Unsupported level" );
1151+ SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1152+ RAISE_ERROR (BADARG_ATOM );
1153+ }
1154+ }
1155+ }
1156+
10671157//
10681158// setopt
10691159//
@@ -1090,7 +1180,7 @@ static term nif_socket_setopt(Context *ctx, int argc, term argv[])
10901180 if (rsrc_obj -> socket_state == SocketStateClosed ) {
10911181#endif
10921182 SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1093- return make_error_tuple (posix_errno_to_term ( EBADF , global ) , ctx );
1183+ return make_error_tuple (CLOSED_ATOM , ctx );
10941184 }
10951185 term level_tuple = argv [1 ];
10961186 term value = argv [2 ];
@@ -2573,6 +2663,10 @@ static const struct Nif socket_select_stop_nif = {
25732663 .base .type = NIFFunctionType ,
25742664 .nif_ptr = nif_socket_select_stop
25752665};
2666+ static const struct Nif socket_getopt_nif = {
2667+ .base .type = NIFFunctionType ,
2668+ .nif_ptr = nif_socket_getopt
2669+ };
25762670static const struct Nif socket_setopt_nif = {
25772671 .base .type = NIFFunctionType ,
25782672 .nif_ptr = nif_socket_setopt
@@ -2643,6 +2737,10 @@ const struct Nif *otp_socket_nif_get_nif(const char *nifname)
26432737 TRACE ("Resolved platform nif %s ...\n" , nifname );
26442738 return & socket_select_stop_nif ;
26452739 }
2740+ if (strcmp ("getopt/2" , rest ) == 0 ) {
2741+ TRACE ("Resolved platform nif %s ...\n" , nifname );
2742+ return & socket_getopt_nif ;
2743+ }
26462744 if (strcmp ("setopt/3" , rest ) == 0 ) {
26472745 TRACE ("Resolved platform nif %s ...\n" , nifname );
26482746 return & socket_setopt_nif ;
0 commit comments