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