@@ -242,4 +242,109 @@ void sockwrite_statement(struct basic_ctx* ctx)
242242}
243243
244244static void basic_udp_handle_packet (uint32_t src_ip , uint16_t src_port , uint16_t dst_port , void * data , uint32_t length , void * opaque ) {
245- }
245+ basic_ctx * ctx = (basic_ctx * )opaque ;
246+ if (!opaque ) {
247+ return ;
248+ }
249+ queued_udp_packet * packet = buddy_malloc (ctx -> allocator , sizeof (queued_udp_packet ));
250+ char ip [MAX_STRINGLEN ];
251+ get_ip_str (ip , src_ip );
252+ packet -> length = length ;
253+ packet -> data = buddy_strdup (ctx -> allocator , data );
254+ packet -> ip = buddy_strdup (ctx -> allocator , ip );
255+ packet -> source_port = src_port ;
256+ packet -> next = NULL ;
257+ uint64_t flags ;
258+ lock_spinlock_irq (& ctx -> udp_read_lock , & flags );
259+ packet -> prev = (struct queued_udp_packet * )ctx -> udp_list_tail [dst_port ];
260+ if (ctx -> udp_list_tail [dst_port ] == NULL ) {
261+ ctx -> udp_list_tail [dst_port ] = packet ;
262+ ctx -> udp_packets [dst_port ] = packet ;
263+ } else {
264+ ctx -> udp_list_tail [dst_port ]-> next = (struct queued_udp_packet * )packet ;
265+ ctx -> udp_list_tail [dst_port ] = packet ;
266+ }
267+ unlock_spinlock_irq (& ctx -> udp_read_lock , flags );
268+ }
269+
270+ void udpwrite_statement (struct basic_ctx * ctx ) {
271+ accept_or_return (UDPWRITE , ctx );
272+ const char * dest_ip = str_expr (ctx );
273+ accept_or_return (COMMA , ctx );
274+ int64_t source_port = expr (ctx );
275+ accept_or_return (COMMA , ctx );
276+ int64_t dest_port = expr (ctx );
277+ accept_or_return (COMMA , ctx );
278+ const char * data = str_expr (ctx );
279+ accept_or_return (NEWLINE , ctx );
280+ if (source_port > 65535 || source_port < 0 || dest_port > 65535 || dest_port < 0 ) {
281+ tokenizer_error_print (ctx , "Invalid UDP port number" );
282+ }
283+ if (strlen (data ) == 0 || strlen (data ) > 65530 ) {
284+ tokenizer_error_print (ctx , "Invalid UDP packet length" );
285+ }
286+ udp_send_packet (str_to_ip (dest_ip ), source_port , dest_port , (void * )data , strlen (data ));
287+ }
288+
289+ void udpbind_statement (struct basic_ctx * ctx ) {
290+ accept_or_return (UDPBIND , ctx );
291+ const char * bind_ip = str_expr (ctx );
292+ (void )bind_ip ;
293+ accept_or_return (COMMA , ctx );
294+ int64_t port = expr (ctx );
295+ if (port > 65535 || port < 0 ) {
296+ tokenizer_error_print (ctx , "Invalid UDP port number" );
297+ }
298+ accept_or_return (NEWLINE , ctx );
299+ udp_register_daemon (port , & basic_udp_handle_packet , ctx );
300+ }
301+
302+ void udpunbind_statement (struct basic_ctx * ctx ) {
303+ accept_or_return (UDPUNBIND , ctx );
304+ const char * bind_ip = str_expr (ctx );
305+ (void )bind_ip ;
306+ accept_or_return (COMMA , ctx );
307+ int64_t port = expr (ctx );
308+ if (port > 65535 || port < 0 ) {
309+ tokenizer_error_print (ctx , "Invalid UDP port number" );
310+ }
311+ accept_or_return (NEWLINE , ctx );
312+ udp_unregister_daemon (port , & basic_udp_handle_packet );
313+ }
314+
315+ char * basic_udpread (struct basic_ctx * ctx ) {
316+ PARAMS_START ;
317+ PARAMS_GET_ITEM (BIP_INT );
318+ PARAMS_END ("UDPREAD$" ,"" );
319+ int64_t port = intval ;
320+ if (port > 65535 || port < 0 ) {
321+ tokenizer_error_print (ctx , "Invalid UDP port number" );
322+ }
323+ if (ctx -> last_packet .ip ) {
324+ buddy_free (ctx -> allocator , ctx -> last_packet .ip );
325+ }
326+ if (ctx -> last_packet .data ) {
327+ buddy_free (ctx -> allocator , ctx -> last_packet .data );
328+ }
329+ memset (& ctx -> last_packet , 0 , sizeof (ctx -> last_packet ));
330+ uint64_t flags ;
331+ lock_spinlock_irq (& ctx -> udp_read_lock , & flags );
332+ queued_udp_packet * queue = ctx -> udp_packets [port ];
333+ if (queue ) {
334+ ctx -> last_packet = * queue ;
335+ if (queue == ctx -> udp_list_tail [port ]) {
336+ /* This packet is the tail packet */
337+ ctx -> udp_list_tail [port ] = (queued_udp_packet * )ctx -> udp_list_tail [port ]-> prev ;
338+ if (ctx -> udp_list_tail [port ]) {
339+ ctx -> udp_list_tail [port ]-> next = NULL ;
340+ }
341+ }
342+ ctx -> udp_packets [port ] = (queued_udp_packet * )queue -> next ;
343+ if (ctx -> udp_packets [port ]) {
344+ ctx -> udp_packets [port ]-> prev = NULL ;
345+ }
346+ buddy_free (ctx -> allocator , queue );
347+ }
348+ unlock_spinlock_irq (& ctx -> udp_read_lock , flags );
349+ return ctx -> last_packet .data ? (char * )ctx -> last_packet .data : "" ;
350+ }
0 commit comments