1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 #include <fc_config.h>
18 #include "fc_prehdrs.h"
24 #ifdef FREECIV_HAVE_SYS_TYPES_H
25 #include <sys/types.h>
27 #ifdef HAVE_SYS_SELECT_H
28 /* For some platforms this must be below sys/types.h. */
29 #include <sys/select.h>
41 #include "support.h" /* fc_str(n)casecmp */
44 #include "game.h" /* game.all_connections */
47 #include "connection.h"
50 static void default_conn_close_callback(struct connection
*pconn
);
52 /* String used for connection.addr and related cases to indicate
53 * blank/unknown/not-applicable address:
55 const char blank_addr_str
[] = "---.---.---.---";
57 /****************************************************************************
58 This callback is used when an error occurs trying to write to the
59 connection. The effect of the callback should be to close the connection.
60 This is here so that the server and client can take appropriate
61 (different) actions: server lost a client, client lost connection to
62 server. Never attempt to call this function directly, call
63 connection_close() instead.
64 ****************************************************************************/
65 static conn_close_fn_t conn_close_callback
= default_conn_close_callback
;
67 /****************************************************************************
68 Default 'conn_close_fn_t' to close a connection.
69 ****************************************************************************/
70 static void default_conn_close_callback(struct connection
*pconn
)
72 fc_assert_msg(conn_close_callback
!= default_conn_close_callback
,
73 "Closing a socket (%s) before calling "
74 "close_socket_set_callback().", conn_description(pconn
));
77 /****************************************************************************
78 Register the close_callback.
79 ****************************************************************************/
80 void connections_set_close_callback(conn_close_fn_t func
)
82 conn_close_callback
= func
;
85 /****************************************************************************
86 Call the conn_close_callback.
87 ****************************************************************************/
88 void connection_close(struct connection
*pconn
, const char *reason
)
90 fc_assert_ret(NULL
!= pconn
);
92 if (NULL
!= reason
&& NULL
== pconn
->closing_reason
) {
93 /* NB: we don't overwrite the original reason. */
94 pconn
->closing_reason
= fc_strdup(reason
);
97 (*conn_close_callback
) (pconn
);
100 /**************************************************************************
101 Make sure that there is at least extra_space bytes free space in buffer,
102 allocating more memory if needed.
103 **************************************************************************/
104 static bool buffer_ensure_free_extra_space(struct socket_packet_buffer
*buf
,
108 if (buf
->nsize
- buf
->ndata
< extra_space
) {
109 buf
->nsize
= buf
->ndata
+ extra_space
;
111 /* added this check so we don't gobble up too much mem */
112 if (buf
->nsize
> MAX_LEN_BUFFER
) {
115 buf
->data
= (unsigned char *) fc_realloc(buf
->data
, buf
->nsize
);
120 /**************************************************************************
121 Read data from socket, and check if a packet is ready.
123 -1 : an error occurred - you should close the socket
124 -2 : the connection was closed
125 >0 : number of bytes read
126 =0 : non-blocking sockets only; no data read, would block
127 **************************************************************************/
128 int read_socket_data(int sock
, struct socket_packet_buffer
*buffer
)
132 if (!buffer_ensure_free_extra_space(buffer
, MAX_LEN_PACKET
)) {
133 log_error("can't grow buffer");
137 log_debug("try reading %d bytes", buffer
->nsize
- buffer
->ndata
);
138 didget
= fc_readsocket(sock
, (char *) (buffer
->data
+ buffer
->ndata
),
139 buffer
->nsize
- buffer
->ndata
);
142 buffer
->ndata
+=didget
;
143 log_debug("didget:%d", didget
);
146 else if (didget
== 0) {
147 log_debug("EOF on socket read");
150 #ifdef NONBLOCKING_SOCKETS
151 else if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
) {
152 log_debug("EGAIN on socket read");
159 /**************************************************************************
160 write wrapper function -vasc
161 **************************************************************************/
162 static int write_socket_data(struct connection
*pc
,
163 struct socket_packet_buffer
*buf
, int limit
)
165 int start
, nput
, nblock
;
167 if (is_server() && pc
->server
.is_closing
) {
171 for (start
=0; buf
->ndata
-start
>limit
;) {
172 fd_set writefs
, exceptfs
;
175 FC_FD_ZERO(&writefs
);
176 FC_FD_ZERO(&exceptfs
);
177 FD_SET(pc
->sock
, &writefs
);
178 FD_SET(pc
->sock
, &exceptfs
);
180 tv
.tv_sec
= 0; tv
.tv_usec
= 0;
182 if (fc_select(pc
->sock
+1, NULL
, &writefs
, &exceptfs
, &tv
) <= 0) {
183 if (errno
!= EINTR
) {
186 /* EINTR can happen sometimes, especially when compiling with -pg.
187 * Generally we just want to run select again. */
192 if (FD_ISSET(pc
->sock
, &exceptfs
)) {
193 connection_close(pc
, _("network exception"));
197 if (FD_ISSET(pc
->sock
, &writefs
)) {
198 nblock
=MIN(buf
->ndata
-start
, MAX_LEN_PACKET
);
199 log_debug("trying to write %d limit=%d", nblock
, limit
);
200 if ((nput
= fc_writesocket(pc
->sock
,
201 (const char *)buf
->data
+start
, nblock
)) == -1) {
202 #ifdef NONBLOCKING_SOCKETS
203 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
) {
207 connection_close(pc
, _("lagging connection"));
216 memmove(buf
->data
, buf
->data
+start
, buf
->ndata
);
217 pc
->last_write
= timer_renew(pc
->last_write
, TIMER_USER
, TIMER_ACTIVE
);
218 timer_start(pc
->last_write
);
224 /**************************************************************************
226 **************************************************************************/
227 void flush_connection_send_buffer_all(struct connection
*pc
)
229 if (pc
&& pc
->used
&& pc
->send_buffer
->ndata
> 0) {
230 write_socket_data(pc
, pc
->send_buffer
, 0);
231 if (pc
->notify_of_writable_data
) {
232 pc
->notify_of_writable_data(pc
, pc
->send_buffer
233 && pc
->send_buffer
->ndata
> 0);
238 /**************************************************************************
240 **************************************************************************/
241 #ifndef FREECIV_JSON_CONNECTION
242 static void flush_connection_send_buffer_packets(struct connection
*pc
)
244 if (pc
&& pc
->used
&& pc
->send_buffer
->ndata
>= MAX_LEN_PACKET
) {
245 write_socket_data(pc
, pc
->send_buffer
, MAX_LEN_PACKET
-1);
246 if (pc
->notify_of_writable_data
) {
247 pc
->notify_of_writable_data(pc
, pc
->send_buffer
248 && pc
->send_buffer
->ndata
> 0);
252 #endif /* FREECIV_JSON_CONNECTION */
254 /****************************************************************************
255 Add data to send to the connection.
256 ****************************************************************************/
257 static bool add_connection_data(struct connection
*pconn
,
258 const unsigned char *data
, int len
)
260 struct socket_packet_buffer
*buf
;
264 || (is_server() && pconn
->server
.is_closing
)) {
268 buf
= pconn
->send_buffer
;
269 log_debug("add %d bytes to %d (space =%d)", len
, buf
->ndata
, buf
->nsize
);
270 if (!buffer_ensure_free_extra_space(buf
, len
)) {
271 connection_close(pconn
, _("buffer overflow"));
275 memcpy(buf
->data
+ buf
->ndata
, data
, len
);
280 /****************************************************************************
281 Write data to socket. Return TRUE on success.
282 ****************************************************************************/
283 bool connection_send_data(struct connection
*pconn
,
284 const unsigned char *data
, int len
)
288 || (is_server() && pconn
->server
.is_closing
)) {
292 pconn
->statistics
.bytes_send
+= len
;
294 #ifndef FREECIV_JSON_CONNECTION
295 if (0 < pconn
->send_buffer
->do_buffer_sends
) {
296 flush_connection_send_buffer_packets(pconn
);
297 if (!add_connection_data(pconn
, data
, len
)) {
298 log_verbose("cut connection %s due to huge send buffer (1)",
299 conn_description(pconn
));
302 flush_connection_send_buffer_packets(pconn
);
304 #endif /* FREECIV_JSON_CONNECTION */
306 flush_connection_send_buffer_all(pconn
);
307 if (!add_connection_data(pconn
, data
, len
)) {
308 log_verbose("cut connection %s due to huge send buffer (2)",
309 conn_description(pconn
));
312 flush_connection_send_buffer_all(pconn
);
317 /**************************************************************************
318 Turn on buffering, using a counter so that calls may be nested.
319 **************************************************************************/
320 void connection_do_buffer(struct connection
*pc
)
322 if (pc
&& pc
->used
) {
323 pc
->send_buffer
->do_buffer_sends
++;
327 /****************************************************************************
328 Turn off buffering if internal counter of number of times buffering
329 was turned on falls to zero, to handle nested buffer/unbuffer pairs.
330 When counter is zero, flush any pending data.
331 ***************************************************************************/
332 void connection_do_unbuffer(struct connection
*pc
)
334 if (NULL
== pc
|| !pc
->used
|| (is_server() && pc
->server
.is_closing
)) {
338 pc
->send_buffer
->do_buffer_sends
--;
339 if (0 > pc
->send_buffer
->do_buffer_sends
) {
340 log_error("Too many calls to unbuffer %s!", pc
->username
);
341 pc
->send_buffer
->do_buffer_sends
= 0;
344 if (0 == pc
->send_buffer
->do_buffer_sends
) {
345 flush_connection_send_buffer_all(pc
);
349 /**************************************************************************
350 Convenience functions to buffer/unbuffer a list of connections:
351 **************************************************************************/
352 void conn_list_do_buffer(struct conn_list
*dest
)
354 conn_list_iterate(dest
, pconn
)
355 connection_do_buffer(pconn
);
356 conn_list_iterate_end
;
358 void conn_list_do_unbuffer(struct conn_list
*dest
)
360 conn_list_iterate(dest
, pconn
)
361 connection_do_unbuffer(pconn
);
362 conn_list_iterate_end
;
365 /***************************************************************
366 Find connection by exact user name, from game.all_connections,
367 case-insensitve. Returns NULL if not found.
368 ***************************************************************/
369 struct connection
*conn_by_user(const char *user_name
)
371 conn_list_iterate(game
.all_connections
, pconn
) {
372 if (fc_strcasecmp(user_name
, pconn
->username
) == 0) {
375 } conn_list_iterate_end
;
380 /****************************************************************************
381 Like conn_by_username(), but allow unambigous prefix (i.e. abbreviation).
382 Returns NULL if could not match, or if ambiguous or other problem, and
383 fills *result with characterisation of match/non-match (see
384 "utility/shared.[ch]").
385 ****************************************************************************/
386 static const char *connection_accessor(int i
) {
387 return conn_list_get(game
.all_connections
, i
)->username
;
390 struct connection
*conn_by_user_prefix(const char *user_name
,
391 enum m_pre_result
*result
)
395 *result
= match_prefix(connection_accessor
,
396 conn_list_size(game
.all_connections
),
397 MAX_LEN_NAME
-1, fc_strncasequotecmp
,
398 effectivestrlenquote
, user_name
, &ind
);
400 if (*result
< M_PRE_AMBIGUOUS
) {
401 return conn_list_get(game
.all_connections
, ind
);
407 /***************************************************************
408 Find connection by id, from game.all_connections.
409 Returns NULL if not found.
410 Number of connections will always be relatively small given
411 current implementation, so linear search should be fine.
412 ***************************************************************/
413 struct connection
*conn_by_number(int id
)
415 conn_list_iterate(game
.all_connections
, pconn
) {
416 fc_assert_msg(pconn
!= NULL
,
417 "Trying to look at the id of a non existing connection");
419 if (pconn
->id
== id
) {
423 conn_list_iterate_end
;
427 /**************************************************************************
428 Return malloced struct, appropriately initialized.
429 **************************************************************************/
430 struct socket_packet_buffer
*new_socket_packet_buffer(void)
432 struct socket_packet_buffer
*buf
;
434 buf
= fc_malloc(sizeof(*buf
));
436 buf
->do_buffer_sends
= 0;
437 buf
->nsize
= 10*MAX_LEN_PACKET
;
438 buf
->data
= (unsigned char *)fc_malloc(buf
->nsize
);
442 /**************************************************************************
444 **************************************************************************/
445 static void free_socket_packet_buffer(struct socket_packet_buffer
*buf
)
455 /**************************************************************************
456 Return pointer to static string containing a description for this
457 connection, based on pconn->name, pconn->addr, and (if applicable)
458 pconn->playing->name. (Also pconn->established and pconn->observer.)
460 Note that when pconn is client.conn (connection to server),
461 pconn->name and pconn->addr contain empty string, and pconn->playing
462 is NULL: in this case return string "server".
463 **************************************************************************/
464 const char *conn_description(const struct connection
*pconn
)
466 static char buffer
[MAX_LEN_NAME
*2 + MAX_LEN_ADDR
+ 128];
470 if (*pconn
->username
!= '\0') {
471 fc_snprintf(buffer
, sizeof(buffer
), _("%s from %s"),
472 pconn
->username
, pconn
->addr
);
474 sz_strlcpy(buffer
, "server");
476 if (NULL
!= pconn
->closing_reason
) {
477 /* TRANS: Appending the reason why a connection has closed. */
478 cat_snprintf(buffer
, sizeof(buffer
), _(" (%s)"), pconn
->closing_reason
);
479 } else if (!pconn
->established
) {
480 sz_strlcat(buffer
, _(" (connection incomplete)"));
483 if (NULL
!= pconn
->playing
) {
484 cat_snprintf(buffer
, sizeof(buffer
), _(" (player %s)"),
485 player_name(pconn
->playing
));
487 if (pconn
->observer
) {
488 sz_strlcat(buffer
, _(" (observer)"));
493 /****************************************************************************
494 Return TRUE iff the connection is currently allowed to edit.
495 ****************************************************************************/
496 bool can_conn_edit(const struct connection
*pconn
)
498 return (can_conn_enable_editing(pconn
)
499 && game
.info
.is_edit_mode
500 && (NULL
!= pconn
->playing
|| pconn
->observer
));
503 /****************************************************************************
504 Return TRUE iff the connection is allowed to start editing.
505 ****************************************************************************/
506 bool can_conn_enable_editing(const struct connection
*pconn
)
508 return pconn
->access_level
== ALLOW_HACK
;
511 /**************************************************************************
512 Get next request id. Takes wrapping of the 16 bit wide unsigned int
514 **************************************************************************/
515 int get_next_request_id(int old_request_id
)
517 int result
= old_request_id
+ 1;
519 if ((result
& 0xffff) == 0) {
520 log_packet("INFORMATION: request_id has wrapped around; "
521 "setting from %d to 2", result
);
524 fc_assert(0 != result
);
528 /**************************************************************************
529 Free compression queue for given connection.
530 **************************************************************************/
531 void free_compression_queue(struct connection
*pc
)
533 #ifdef USE_COMPRESSION
534 byte_vector_free(&pc
->compression
.queue
);
538 /**************************************************************************
539 Allocate and initialize packet hashs for given connection.
540 **************************************************************************/
541 static void init_packet_hashs(struct connection
*pc
)
545 pc
->phs
.sent
= fc_malloc(sizeof(*pc
->phs
.sent
) * PACKET_LAST
);
546 pc
->phs
.received
= fc_malloc(sizeof(*pc
->phs
.received
) * PACKET_LAST
);
547 pc
->phs
.handlers
= packet_handlers_initial();
549 for (i
= 0; i
< PACKET_LAST
; i
++) {
550 pc
->phs
.sent
[i
] = NULL
;
551 pc
->phs
.received
[i
] = NULL
;
555 /**************************************************************************
556 Free packet hash resources from given connection.
557 **************************************************************************/
558 static void free_packet_hashes(struct connection
*pc
)
563 for (i
= 0; i
< PACKET_LAST
; i
++) {
564 if (pc
->phs
.sent
[i
] != NULL
) {
565 genhash_destroy(pc
->phs
.sent
[i
]);
572 if (pc
->phs
.received
) {
573 for (i
= 0; i
< PACKET_LAST
; i
++) {
574 if (pc
->phs
.received
[i
] != NULL
) {
575 genhash_destroy(pc
->phs
.received
[i
]);
578 free(pc
->phs
.received
);
579 pc
->phs
.received
= NULL
;
583 /**************************************************************************
584 Initialize common part of connection structure. This is used by
585 both server and client.
586 **************************************************************************/
587 void connection_common_init(struct connection
*pconn
)
589 pconn
->established
= FALSE
;
591 packet_header_init(&pconn
->packet_header
);
592 pconn
->closing_reason
= NULL
;
593 pconn
->last_write
= NULL
;
594 pconn
->buffer
= new_socket_packet_buffer();
595 pconn
->send_buffer
= new_socket_packet_buffer();
596 pconn
->statistics
.bytes_send
= 0;
598 init_packet_hashs(pconn
);
600 #ifdef USE_COMPRESSION
601 byte_vector_init(&pconn
->compression
.queue
);
602 pconn
->compression
.frozen_level
= 0;
606 /**************************************************************************
607 Connection closing part common to server and client.
608 **************************************************************************/
609 void connection_common_close(struct connection
*pconn
)
612 log_error("WARNING: Trying to close already closed connection");
614 fc_closesocket(pconn
->sock
);
616 pconn
->established
= FALSE
;
617 if (NULL
!= pconn
->closing_reason
) {
618 free(pconn
->closing_reason
);
621 free_socket_packet_buffer(pconn
->buffer
);
622 pconn
->buffer
= NULL
;
624 free_socket_packet_buffer(pconn
->send_buffer
);
625 pconn
->send_buffer
= NULL
;
627 if (pconn
->last_write
) {
628 timer_destroy(pconn
->last_write
);
629 pconn
->last_write
= NULL
;
632 free_compression_queue(pconn
);
633 free_packet_hashes(pconn
);
637 /****************************************************************************
638 Set the network capability string for 'pconn'.
639 ****************************************************************************/
640 void conn_set_capability(struct connection
*pconn
, const char *capability
)
642 fc_assert(strlen(capability
) < sizeof(pconn
->capability
));
643 sz_strlcpy(pconn
->capability
, capability
);
644 pconn
->phs
.handlers
= packet_handlers_get(capability
);
647 /**************************************************************************
648 Remove all is-game-info cached packets from the connection. This resets
649 the delta-state partially.
650 **************************************************************************/
651 void conn_reset_delta_state(struct connection
*pc
)
655 for (i
= 0; i
< PACKET_LAST
; i
++) {
656 if (packet_has_game_info_flag(i
)) {
657 if (NULL
!= pc
->phs
.sent
&& NULL
!= pc
->phs
.sent
[i
]) {
658 genhash_clear(pc
->phs
.sent
[i
]);
660 if (NULL
!= pc
->phs
.received
&& NULL
!= pc
->phs
.received
[i
]) {
661 genhash_clear(pc
->phs
.received
[i
]);
667 /****************************************************************************
668 Freeze the connection. Then the packets sent to it won't be sent
669 immediatly, but later, using a compression method. See futher details in
671 ****************************************************************************/
672 void conn_compression_freeze(struct connection
*pconn
)
674 #ifdef USE_COMPRESSION
675 if (0 == pconn
->compression
.frozen_level
) {
676 byte_vector_reserve(&pconn
->compression
.queue
, 0);
678 pconn
->compression
.frozen_level
++;
679 #endif /* USE_COMPRESSION */
682 /****************************************************************************
683 Returns TRUE if the connection is frozen. See also
684 conn_compression_freeze().
685 ****************************************************************************/
686 bool conn_compression_frozen(const struct connection
*pconn
)
688 #ifdef USE_COMPRESSION
689 return 0 < pconn
->compression
.frozen_level
;
692 #endif /* USE_COMPRESSION */
695 /****************************************************************************
696 Freeze a connection list.
697 ****************************************************************************/
698 void conn_list_compression_freeze(const struct conn_list
*pconn_list
)
700 #ifdef USE_COMPRESSION
701 conn_list_iterate(pconn_list
, pconn
) {
702 conn_compression_freeze(pconn
);
703 } conn_list_iterate_end
;
704 #endif /* USE_COMPRESSION */
707 /****************************************************************************
708 Thaw a connection list.
709 ****************************************************************************/
710 void conn_list_compression_thaw(const struct conn_list
*pconn_list
)
712 #ifdef USE_COMPRESSION
713 conn_list_iterate(pconn_list
, pconn
) {
714 conn_compression_thaw(pconn
);
715 } conn_list_iterate_end
;
716 #endif /* USE_COMPRESSION */
719 /**************************************************************************
720 Returns TRUE if the given connection is attached to a player which it
721 also controls (i.e. not a player observer).
722 **************************************************************************/
723 bool conn_controls_player(const struct connection
*pconn
)
725 return pconn
&& pconn
->playing
&& !pconn
->observer
;
728 /**************************************************************************
729 Returns TRUE if the given connection is a global observer.
730 **************************************************************************/
731 bool conn_is_global_observer(const struct connection
*pconn
)
733 return pconn
&& !pconn
->playing
&& pconn
->observer
;
736 /**************************************************************************
737 Returns the player that this connection is attached to, or NULL. Note
738 that this will return the observed player for connections that are
740 **************************************************************************/
741 struct player
*conn_get_player(const struct connection
*pconn
)
746 return pconn
->playing
;
749 /**************************************************************************
750 Returns the current access level of the given connection.
751 NB: If 'pconn' is NULL, this function will return ALLOW_NONE.
752 **************************************************************************/
753 enum cmdlevel
conn_get_access(const struct connection
*pconn
)
756 return ALLOW_NONE
; /* Would not want to give hack on error... */
758 return pconn
->access_level
;
762 /****************************************************************************
764 ****************************************************************************/
765 struct conn_pattern
{
766 enum conn_pattern_type type
;
770 /****************************************************************************
771 Creates a new connection pattern.
772 ****************************************************************************/
773 struct conn_pattern
*conn_pattern_new(enum conn_pattern_type type
,
774 const char *wildcard
)
776 struct conn_pattern
*ppattern
= fc_malloc(sizeof(*ppattern
));
778 ppattern
->type
= type
;
779 ppattern
->wildcard
= fc_strdup(wildcard
);
784 /****************************************************************************
785 Free a connection pattern.
786 ****************************************************************************/
787 void conn_pattern_destroy(struct conn_pattern
*ppattern
)
789 fc_assert_ret(NULL
!= ppattern
);
790 free(ppattern
->wildcard
);
794 /****************************************************************************
795 Returns TRUE whether the connection fits the connection pattern.
796 ****************************************************************************/
797 bool conn_pattern_match(const struct conn_pattern
*ppattern
,
798 const struct connection
*pconn
)
800 const char *test
= NULL
;
802 switch (ppattern
->type
) {
804 test
= pconn
->username
;
811 test
= pconn
->server
.ipaddr
;
817 return wildcard_fit_string(ppattern
->wildcard
, test
);
819 log_error("%s(): Invalid pattern type (%d)",
820 __FUNCTION__
, ppattern
->type
);
825 /****************************************************************************
826 Returns TRUE whether the connection fits one of the connection patterns.
827 ****************************************************************************/
828 bool conn_pattern_list_match(const struct conn_pattern_list
*plist
,
829 const struct connection
*pconn
)
831 conn_pattern_list_iterate(plist
, ppattern
) {
832 if (conn_pattern_match(ppattern
, pconn
)) {
835 } conn_pattern_list_iterate_end
;
839 /****************************************************************************
840 Put a string reprentation of the pattern in 'buf'.
841 ****************************************************************************/
842 size_t conn_pattern_to_string(const struct conn_pattern
*ppattern
,
843 char *buf
, size_t buf_len
)
845 return fc_snprintf(buf
, buf_len
, "<%s=%s>",
846 conn_pattern_type_name(ppattern
->type
),
850 /****************************************************************************
851 Creates a new connection pattern from the string. If the type is not
852 specified in 'pattern', then 'prefer' type will be used. If the type
853 is needed, then pass conn_pattern_type_invalid() for 'prefer'.
854 ****************************************************************************/
855 struct conn_pattern
*conn_pattern_from_string(const char *pattern
,
856 enum conn_pattern_type prefer
,
858 size_t error_buf_len
)
860 enum conn_pattern_type type
= conn_pattern_type_invalid();
863 /* Determine pattern type. */
864 if ((p
= strchr(pattern
, '='))) {
865 /* Special character to separate the type of the pattern. */
866 const size_t pattern_type_len
= ++p
- pattern
;
867 char pattern_type
[pattern_type_len
];
869 fc_strlcpy(pattern_type
, pattern
, pattern_type_len
);
870 remove_leading_trailing_spaces(pattern_type
);
871 type
= conn_pattern_type_by_name(pattern_type
, fc_strcasecmp
);
872 if (!conn_pattern_type_is_valid(type
)) {
873 if (NULL
!= error_buf
) {
874 fc_snprintf(error_buf
, error_buf_len
,
875 _("\"%s\" is not a valid pattern type"),
881 /* Use 'prefer' type. */
884 if (!conn_pattern_type_is_valid(type
)) {
885 if (NULL
!= error_buf
) {
886 fc_strlcpy(error_buf
, _("Missing pattern type"), error_buf_len
);
892 /* Remove leading spaces. */
893 while (fc_isspace(*p
)) {
898 if (NULL
!= error_buf
) {
899 fc_strlcpy(error_buf
, _("Missing pattern"), error_buf_len
);
904 return conn_pattern_new(type
, p
);
907 /**************************************************************************
908 Returns TRUE if the connection is valid, i.e. not NULL, not closed, not
910 **************************************************************************/
911 bool conn_is_valid(const struct connection
*pconn
)
913 return (pconn
&& pconn
->used
&& !pconn
->server
.is_closing
);