SPDX: Mass-update to GPL-2.0-or-later
[exim.git] / src / src / enq.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2015 */
6 /* Copyright (c) The Exim Maintainers 2021 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
9
10 /* Functions concerned with serialization. */
11
12
13 #include "exim.h"
14
15
16
17
18 /*************************************************
19 *       Test for host or ETRN serialization      *
20 *************************************************/
21
22 /* This function is called when a host is listed for serialization of
23 connections. It is also called when ETRN is listed for serialization. We open
24 the misc database and look for a record, which implies an existing connection
25 or ETRN run. If increasing the count would take us past the given limit
26 value return FALSE.  If not, bump it and return TRUE.  If not found, create
27 one with value 1 and return TRUE.
28
29 Arguments:
30   key            string on which to serialize
31   lim            parallelism limit
32
33 Returns:         TRUE if OK to proceed; FALSE otherwise
34 */
35
36
37 BOOL
38 enq_start(uschar *key, unsigned lim)
39 {
40 dbdata_serialize *serial_record;
41 dbdata_serialize new_record;
42 open_db dbblock;
43 open_db *dbm_file;
44
45 DEBUG(D_transport) debug_printf("check serialized: %s\n", key);
46
47 /* Open and lock the waiting information database. The absence of O_CREAT is
48 deliberate; the dbfn_open() function - which is an Exim function - always tries
49 to create if it can't open a read/write file. It expects only O_RDWR or
50 O_RDONLY as its argument. */
51
52 if (!(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
53   return FALSE;
54
55 /* See if there is a record for this host or queue run; if there is, we cannot
56 proceed with the connection unless the record is very old. */
57
58 serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize));
59 if (serial_record && time(NULL) - serial_record->time_stamp < 6*60*60)
60   {
61   if (serial_record->count >= lim)
62     {
63     dbfn_close(dbm_file);
64     DEBUG(D_transport) debug_printf("outstanding serialization record for %s\n",
65       key);
66     return FALSE;
67     }
68   new_record.count = serial_record->count + 1;
69   }
70 else
71   new_record.count = 1;
72
73 /* We can proceed - insert a new record or update the old one. */
74
75 DEBUG(D_transport) debug_printf("write serialization record for %s val %d\n",
76       key, new_record.count);
77 dbfn_write(dbm_file, key, &new_record, (int)sizeof(dbdata_serialize));
78 dbfn_close(dbm_file);
79 return TRUE;
80 }
81
82
83
84 /*************************************************
85 *              Release serialization             *
86 *************************************************/
87
88 /* This function is called when a serialized host's connection or serialized
89 ETRN queue run ends. We open the relevant database and delete its record.
90
91 Arguments:
92   key          the serialization key
93
94 Returns:       nothing
95 */
96
97 void
98 enq_end(uschar *key)
99 {
100 open_db dbblock;
101 open_db *dbm_file;
102 dbdata_serialize *serial_record;
103
104 DEBUG(D_transport) debug_printf("end serialized: %s\n", key);
105
106 if (  !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE))
107    || !(serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize)))
108    )
109   return;
110 if (--serial_record->count > 0)
111   {
112   DEBUG(D_transport) debug_printf("write serialization record for %s val %d\n",
113       key, serial_record->count);
114   dbfn_write(dbm_file, key, serial_record, (int)sizeof(dbdata_serialize));
115   }
116 else
117   {
118   DEBUG(D_transport) debug_printf("remove serialization record for %s\n", key);
119   dbfn_delete(dbm_file, key);
120   }
121 dbfn_close(dbm_file);
122 }
123
124 /* End of enq.c */