@@ -133,7 +133,7 @@ defmodule Tds.Protocol do
133
133
def checkout ( % { sock: { mod , sock } } = s ) do
134
134
sock_mod = inspect ( mod )
135
135
136
- case :inet . setopts ( sock , active: false ) do
136
+ case setopts ( s . sock , active: false ) do
137
137
:ok ->
138
138
{ :ok , s }
139
139
@@ -154,7 +154,7 @@ defmodule Tds.Protocol do
154
154
def checkin ( % { sock: { mod , sock } } = s ) do
155
155
sock_mod = inspect ( mod )
156
156
157
- case :inet . setopts ( sock , active: :once ) do
157
+ case setopts ( s . sock , active: :once ) do
158
158
:ok ->
159
159
{ :ok , s }
160
160
@@ -382,13 +382,13 @@ defmodule Tds.Protocol do
382
382
383
383
:ok = :inet . setopts ( sock , buffer: buffer )
384
384
385
- case login ( % { s | sock: { :gen_tcp , sock } } ) do
385
+ case prelogin ( % { s | sock: { :gen_tcp , sock } } ) do
386
386
{ :error , error , _state } ->
387
387
:gen_tcp . close ( sock )
388
388
{ :error , error }
389
389
390
- r ->
391
- r
390
+ other ->
391
+ other
392
392
end
393
393
394
394
{ :error , error } ->
@@ -439,6 +439,26 @@ defmodule Tds.Protocol do
439
439
end
440
440
end
441
441
442
+ defp ssl_connect ( % { sock: { :gen_tcp , sock } , opts: opts } = s ) do
443
+ { :ok , _ } = Application . ensure_all_started ( :ssl )
444
+ :inet . setopts ( sock , active: false )
445
+
446
+ case Tds.Tls . connect ( sock , opts [ :ssl_opts ] || [ ] ) do
447
+ { :ok , ssl_sock } ->
448
+ state = % { s | sock: { :ssl , ssl_sock } }
449
+ { :ok , state }
450
+
451
+ { :error , reason } ->
452
+ error =
453
+ Tds.Error . exception (
454
+ "Unable to establish secure connection to server due #{ inspect ( reason ) } "
455
+ )
456
+
457
+ :gen_tcp . close ( sock )
458
+ { :error , error , s }
459
+ end
460
+ end
461
+
442
462
def handle_info ( { :udp_error , _ , :econnreset } , s ) do
443
463
msg =
444
464
"Tds encountered an error while connecting to the Sql Server " <>
@@ -451,10 +471,7 @@ defmodule Tds.Protocol do
451
471
{ :tcp , _ , _data } ,
452
472
% { sock: { mod , sock } , opts: opts , state: :prelogin } = s
453
473
) do
454
- case mod do
455
- :gen_tcp -> :inet . setopts ( sock , active: false )
456
- :ssl -> :ssl . setopts ( sock , active: false )
457
- end
474
+ setopts ( s . sock , active: false )
458
475
459
476
login ( % { s | opts: opts , sock: { mod , sock } } )
460
477
end
@@ -521,22 +538,16 @@ defmodule Tds.Protocol do
521
538
def prelogin ( % { opts: opts } = s ) do
522
539
msg = msg_prelogin ( params: opts )
523
540
524
- case msg_send ( msg , s ) do
525
- { :ok , s } ->
526
- { :noreply , % { s | state: :prelogin } }
527
-
528
- { :error , reason , s } ->
529
- error ( % Tds.Error { message: "tcp send: #{ reason } " } , s )
530
-
531
- any ->
532
- any
541
+ case msg_send ( msg , % { s | state: :prelogin } ) do
542
+ { :ok , s } -> login ( s )
543
+ any -> any
533
544
end
534
545
end
535
546
536
547
def login ( % { opts: opts } = s ) do
537
548
msg = msg_login ( params: opts )
538
549
539
- case login_send ( msg , s ) do
550
+ case login_send ( msg , % { s | state: :login } ) do
540
551
{ :ok , s } ->
541
552
{ :ok , % { s | state: :ready } }
542
553
@@ -740,14 +751,19 @@ defmodule Tds.Protocol do
740
751
end
741
752
end
742
753
754
+ def message ( :prelogin , msg_preloginack ( response: response ) , _ ) do
755
+ case response do
756
+ { :login , s } -> { :ok , s }
757
+ { :encrypt , s } -> ssl_connect ( s )
758
+ other -> other
759
+ end
760
+ end
761
+
743
762
def message (
744
763
:login ,
745
764
msg_loginack ( redirect: % { hostname: host , port: port } ) ,
746
- % { opts: opts } = s
765
+ % { opts: opts } = state
747
766
) do
748
- # we got an ENVCHANGE:redirection token, we need to disconnect and start over with new server
749
- disconnect ( "redirected" , s )
750
-
751
767
new_opts =
752
768
opts
753
769
|> Keyword . put ( :hostname , host )
@@ -814,16 +830,17 @@ defmodule Tds.Protocol do
814
830
end
815
831
816
832
# Send Command To Sql Server
817
- defp login_send ( msg , % { sock: { mod , sock } , env: env } = s ) do
833
+ defp login_send ( msg , % { sock: { mod , sock } , env: env , opts: opts } = s ) do
818
834
paks = encode_msg ( msg , env )
835
+ s = % { s | opts: clean_opts ( opts ) }
819
836
820
837
Enum . each ( paks , fn pak ->
821
838
mod . send ( sock , pak )
822
839
end )
823
840
824
841
case msg_recv ( s ) do
825
842
{ :disconnect , ex , s } ->
826
- { :error , ex , s }
843
+ { :disconnect , ex , s }
827
844
828
845
buffer ->
829
846
buffer
@@ -834,51 +851,33 @@ defmodule Tds.Protocol do
834
851
835
852
defp msg_send (
836
853
msg ,
837
- % { sock: { mod , sock } , env: env , state: state , opts: opts } = s
854
+ % { sock: { mod , port } , env: env , state: state , opts: opts } = s
838
855
) do
839
- :inet . setopts ( sock , active: false )
856
+ setopts ( s . sock , active: false )
840
857
841
858
opts
842
859
|> Keyword . get ( :use_elixir_calendar_types , false )
843
860
|> use_elixir_calendar_types ( )
844
861
845
- { t_send , _ } =
846
- :timer . tc ( fn ->
847
- msg
848
- |> encode_msg ( env )
849
- |> Enum . each ( & mod . send ( sock , & 1 ) )
850
- end )
851
-
852
- { t_recv , { t_decode , result } } =
853
- :timer . tc ( fn ->
854
- case msg_recv ( s ) do
855
- { :disconnect , _ex , _s } = res ->
856
- { 0 , res }
857
-
858
- buffer ->
859
- :timer . tc ( fn ->
860
- buffer
861
- |> IO . iodata_to_binary ( )
862
- |> decode ( s )
863
- end )
862
+ send_result =
863
+ msg
864
+ |> encode_msg ( env )
865
+ |> Enum . reduce_while ( :ok , fn chunk , _ ->
866
+ case mod . send ( port , chunk ) do
867
+ { :error , reason } -> { :halt , { :error , reason } }
868
+ :ok -> { :cont , :ok }
864
869
end
865
870
end )
866
871
867
- stm = Map . get ( s , :query )
868
-
869
- if Keyword . get ( s . opts , :trace , false ) == true do
870
- Logger . debug ( fn ->
871
- "[trace] [Tds.Protocod.msg_send/2] " <>
872
- "state=#{ inspect ( state ) } " <>
873
- "send=#{ Tds.Perf . to_string ( t_send ) } " <>
874
- "receive=#{ Tds.Perf . to_string ( t_recv - t_decode ) } " <>
875
- "decode=#{ Tds.Perf . to_string ( t_decode ) } " <>
876
- "\n " <>
877
- "#{ inspect ( stm ) } "
878
- end )
872
+ with :ok <- send_result ,
873
+ buffer when is_list ( buffer ) <- msg_recv ( s ) do
874
+ buffer
875
+ |> IO . iodata_to_binary ( )
876
+ |> decode ( s )
877
+ else
878
+ { :disconnect , _ex , _s } = res -> { 0 , res }
879
+ other -> other
879
880
end
880
-
881
- result
882
881
end
883
882
884
883
defp msg_recv ( % { sock: { mod , pid } } = s ) do
@@ -1152,4 +1151,11 @@ defmodule Tds.Protocol do
1152
1151
)
1153
1152
end
1154
1153
end
1154
+
1155
+ defp setopts ( { mod , sock } , options ) do
1156
+ case mod do
1157
+ :gen_tcp -> :inet . setopts ( sock , options )
1158
+ :ssl -> :ssl . setopts ( sock , options )
1159
+ end
1160
+ end
1155
1161
end
0 commit comments