@@ -335,12 +335,138 @@ static wbt_status on_timeout(wbt_timer_t *timer) {
335335 return WBT_OK ;
336336}
337337
338+ static wbt_status try_connect (wbt_socket_t fd , char * ip , int port ) {
339+ struct sockaddr_in addr ;
340+ addr .sin_family = AF_INET ;
341+ addr .sin_port = htons (port );
342+ #ifdef WIN32
343+ addr .sin_addr .S_un .S_addr = inet_addr (ip );
344+ #else
345+ addr .sin_addr .s_addr = inet_addr (ip );
346+ #endif
347+ memset (addr .sin_zero , 0x00 , 8 );
348+
349+ int ret = connect (fd , (struct sockaddr * )& addr , sizeof (addr ));
350+ if (ret < 0 ) {
351+ wbt_err_t err = wbt_socket_errno ;
352+
353+ if (err != WBT_EINPROGRESS
354+ #ifdef WIN32
355+ /* Winsock returns WSAEWOULDBLOCK (WBT_EAGAIN) */
356+ && err != WBT_EAGAIN
357+ #endif
358+ )
359+ {
360+ if (err == WBT_ECONNREFUSED
361+ #ifndef WIN32 // TODO 判断 LINUX 平台
362+ /*
363+ * Linux returns EAGAIN instead of ECONNREFUSED
364+ * for unix sockets if listen queue is full
365+ */
366+ || err == WBT_EAGAIN
367+ #endif
368+ || err == WBT_ECONNRESET
369+ || err == WBT_ENETDOWN
370+ || err == WBT_ENETUNREACH
371+ || err == WBT_EHOSTDOWN
372+ || err == WBT_EHOSTUNREACH )
373+ {
374+ // 普通错误
375+ return WBT_ERROR ;
376+ } else {
377+ // 未知错误
378+ return WBT_ERROR ;
379+ }
380+ } else {
381+ return WBT_AGAIN ;
382+ }
383+ }
384+
385+ return WBT_OK ;
386+ }
387+
388+ static wbt_status on_connect (wbt_event_t * ev ) {
389+ lgx_socket_t * sock = (lgx_socket_t * )ev -> ctx ;
390+
391+ wbt_debug ("socket:on_connect %d" , ev -> fd );
392+
393+ wbt_event_del (sock -> co -> vm -> events , ev );
394+
395+ lgx_co_resume (sock -> co -> vm , sock -> co );
396+
397+ sock -> co = NULL ;
398+
399+ return WBT_OK ;
400+ }
401+
338402LGX_METHOD (Socket , connect ) {
339403 LGX_METHOD_ARGS_INIT ();
340404 LGX_METHOD_ARGS_THIS (obj );
405+ LGX_METHOD_ARGS_GET (ip , 0 , T_STRING );
406+ LGX_METHOD_ARGS_GET (port , 1 , T_LONG );
341407
342- LGX_RETURN_TRUE ();
343- return 0 ;
408+ if (ip -> v .str -> length > 32 ) {
409+ lgx_vm_throw_s (vm , "invalid param `ip`" );
410+ return 1 ;
411+ }
412+
413+ if (port -> v .l <= 0 || port -> v .l >= 65535 ) {
414+ lgx_vm_throw_s (vm , "invalid param `port`" );
415+ return 1 ;
416+ }
417+
418+ lgx_val_t * res = lgx_obj_get_s (obj -> v .obj , "ctx" );
419+ if (!res || res -> type != T_RESOURCE ) {
420+ lgx_vm_throw_s (vm , "invalid property `ctx`" );
421+ return 1 ;
422+ }
423+
424+ lgx_socket_t * sock = (lgx_socket_t * )res -> v .res -> buf ;
425+ if (sock -> fd < 0 ) {
426+ lgx_vm_throw_s (vm , "socket alreay closed" );
427+ return 1 ;
428+ }
429+
430+ // 不能在多个协程中并发执行
431+ if (sock -> co ) {
432+ lgx_vm_throw_s (vm , "concurrent connect" );
433+ return 1 ;
434+ }
435+ sock -> co = vm -> co_running ;
436+
437+ char ip_str [32 ];
438+ memcpy (ip_str , ip -> v .str -> buffer , ip -> v .str -> length );
439+ ip_str [ip -> v .str -> length ] = '\0' ;
440+
441+ wbt_status ret = try_connect (sock -> fd , ip_str , port -> v .l );
442+
443+ if (ret == WBT_ERROR ) {
444+ sock -> co = NULL ;
445+ lgx_vm_throw_s (vm , "connect faild" );
446+ return 1 ;
447+ } else if (ret == WBT_OK ) {
448+ sock -> co = NULL ;
449+ LGX_RETURN_TRUE ();
450+ return 0 ;
451+ } else { // ret == WBT_AGAIN
452+ // 添加事件
453+ wbt_event_t * p_ev , tmp_ev ;
454+ tmp_ev .timer .on_timeout = on_timeout ;
455+ tmp_ev .timer .timeout = wbt_cur_mtime + 15 * 1000 ;
456+ tmp_ev .on_recv = NULL ;
457+ tmp_ev .on_send = on_connect ;
458+ tmp_ev .events = WBT_EV_WRITE | WBT_EV_ET ;
459+ tmp_ev .fd = sock -> fd ;
460+
461+ if ((p_ev = wbt_event_add (vm -> events , & tmp_ev )) == NULL ) {
462+ lgx_vm_throw_s (vm , "add event faild" );
463+ return 1 ;
464+ }
465+
466+ p_ev -> ctx = sock ;
467+ lgx_co_suspend (vm );
468+ return 0 ;
469+ }
344470}
345471
346472static wbt_status on_send (wbt_event_t * ev );
@@ -610,8 +736,10 @@ LGX_CLASS(Socket) {
610736 LGX_METHOD_ACCESS (P_PUBLIC )
611737 LGX_METHOD_END
612738
613- LGX_METHOD_BEGIN (Socket , connect , 0 )
739+ LGX_METHOD_BEGIN (Socket , connect , 2 )
614740 LGX_METHOD_RET (T_BOOL )
741+ LGX_METHOD_ARG (0 , T_STRING )
742+ LGX_METHOD_ARG (1 , T_LONG )
615743 LGX_METHOD_ACCESS (P_PUBLIC )
616744 LGX_METHOD_END
617745
0 commit comments