@@ -133,7 +133,7 @@ defmodule Tds.Protocol do
133133 def checkout ( % { sock: { mod , sock } } = s ) do
134134 sock_mod = inspect ( mod )
135135
136- case :inet . setopts ( sock , active: false ) do
136+ case setopts ( s . sock , active: false ) do
137137 :ok ->
138138 { :ok , s }
139139
@@ -154,7 +154,7 @@ defmodule Tds.Protocol do
154154 def checkin ( % { sock: { mod , sock } } = s ) do
155155 sock_mod = inspect ( mod )
156156
157- case :inet . setopts ( sock , active: :once ) do
157+ case setopts ( s . sock , active: :once ) do
158158 :ok ->
159159 { :ok , s }
160160
@@ -382,13 +382,13 @@ defmodule Tds.Protocol do
382382
383383 :ok = :inet . setopts ( sock , buffer: buffer )
384384
385- case login ( % { s | sock: { :gen_tcp , sock } } ) do
385+ case prelogin ( % { s | sock: { :gen_tcp , sock } } ) do
386386 { :error , error , _state } ->
387387 :gen_tcp . close ( sock )
388388 { :error , error }
389389
390- r ->
391- r
390+ other ->
391+ other
392392 end
393393
394394 { :error , error } ->
@@ -439,6 +439,26 @@ defmodule Tds.Protocol do
439439 end
440440 end
441441
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+
442462 def handle_info ( { :udp_error , _ , :econnreset } , s ) do
443463 msg =
444464 "Tds encountered an error while connecting to the Sql Server " <>
@@ -451,10 +471,7 @@ defmodule Tds.Protocol do
451471 { :tcp , _ , _data } ,
452472 % { sock: { mod , sock } , opts: opts , state: :prelogin } = s
453473 ) 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 )
458475
459476 login ( % { s | opts: opts , sock: { mod , sock } } )
460477 end
@@ -521,22 +538,16 @@ defmodule Tds.Protocol do
521538 def prelogin ( % { opts: opts } = s ) do
522539 msg = msg_prelogin ( params: opts )
523540
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
533544 end
534545 end
535546
536547 def login ( % { opts: opts } = s ) do
537548 msg = msg_login ( params: opts )
538549
539- case login_send ( msg , s ) do
550+ case login_send ( msg , % { s | state: :login } ) do
540551 { :ok , s } ->
541552 { :ok , % { s | state: :ready } }
542553
@@ -740,14 +751,19 @@ defmodule Tds.Protocol do
740751 end
741752 end
742753
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+
743762 def message (
744763 :login ,
745764 msg_loginack ( redirect: % { hostname: host , port: port } ) ,
746- % { opts: opts } = s
765+ % { opts: opts } = state
747766 ) do
748- # we got an ENVCHANGE:redirection token, we need to disconnect and start over with new server
749- disconnect ( "redirected" , s )
750-
751767 new_opts =
752768 opts
753769 |> Keyword . put ( :hostname , host )
@@ -814,16 +830,17 @@ defmodule Tds.Protocol do
814830 end
815831
816832 # 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
818834 paks = encode_msg ( msg , env )
835+ s = % { s | opts: clean_opts ( opts ) }
819836
820837 Enum . each ( paks , fn pak ->
821838 mod . send ( sock , pak )
822839 end )
823840
824841 case msg_recv ( s ) do
825842 { :disconnect , ex , s } ->
826- { :error , ex , s }
843+ { :disconnect , ex , s }
827844
828845 buffer ->
829846 buffer
@@ -834,51 +851,33 @@ defmodule Tds.Protocol do
834851
835852 defp msg_send (
836853 msg ,
837- % { sock: { mod , sock } , env: env , state: state , opts: opts } = s
854+ % { sock: { mod , port } , env: env , state: state , opts: opts } = s
838855 ) do
839- :inet . setopts ( sock , active: false )
856+ setopts ( s . sock , active: false )
840857
841858 opts
842859 |> Keyword . get ( :use_elixir_calendar_types , false )
843860 |> use_elixir_calendar_types ( )
844861
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 }
864869 end
865870 end )
866871
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
879880 end
880-
881- result
882881 end
883882
884883 defp msg_recv ( % { sock: { mod , pid } } = s ) do
@@ -1152,4 +1151,11 @@ defmodule Tds.Protocol do
11521151 )
11531152 end
11541153 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
11551161end
0 commit comments